public SIPFlow(SIPTransport sipTransport, List<ActionDiagram> actionDiagrams, List<DecisionDiagram> decisionDiagrams)
            : base(actionDiagrams, decisionDiagrams)
        {
            m_sipTransport = sipTransport;
            
            pythonHelper = new PythonHelper(m_pythonEngine, m_sipTransport);
            pythonHelper.LogEvent += new SIPFlowLogDelegate(pythonHelper_LogEvent);
            
            //m_sipTransport.SIPTransportResponseReceived += new SIPTransportResponseReceivedDelegate(pythonHelper.SIPTransportResponseReceived);
            
            //m_pythonEngine.Import("BlueFace.VoIP.Net.SIP.*");
            m_pythonEngine.Execute("import clr");
            //m_pythonEngine.Execute("clr.AddReference('BlueFace.VoIP.Net')");
            //m_pythonEngine.Execute("from BlueFace.VoIP.Net.SIP import *");
            //m_pythonEngine.Execute("clr.AddReference('siggui')");
            //m_pythonEngine.Execute("from BlueFace.Net.SignallingGUI import *");

            m_pythonEngine.Globals["pythonHelper"] = pythonHelper;
            //m_pythonEngine.Globals["sipRequest"] = sipRequest;
            
            //SIPTransaction transaction = new SIPTransaction(sipRequest);
            //SIPTransport.SendSIPReliable(transaction);

            m_sipFlowDebugStream = new MemoryStream();
            m_debugStreamReader = new StreamReader(m_sipFlowDebugStream);
            m_pythonEngine.SetStandardOutput(m_sipFlowDebugStream);
        }
        public SIPNonInviteServerUserAgent(
            SIPTransport sipTransport,
            SIPEndPoint outboundProxy,
            string sipUsername,
            string sipDomain,
            SIPCallDirection callDirection,
            SIPAssetGetDelegate<SIPAccount> getSIPAccount,
            SIPAuthenticateRequestDelegate sipAuthenticateRequest,
            SIPMonitorLogDelegate logDelegate,
            SIPNonInviteTransaction transaction)
        {
            m_sipTransport = sipTransport;
            m_outboundProxy = outboundProxy;
            m_sipUsername = sipUsername;
            m_sipDomain = sipDomain;
            m_sipCallDirection = callDirection;
            GetSIPAccount_External = getSIPAccount;
            SIPAuthenticateRequest_External = sipAuthenticateRequest;
            Log_External = logDelegate ?? Log_External;
            m_transaction = transaction;

            m_transaction.TransactionTraceMessage += TransactionTraceMessage;
            //m_uasTransaction.UASInviteTransactionTimedOut += ClientTimedOut;
            //m_uasTransaction.UASInviteTransactionCancelled += UASTransactionCancelled;
            //m_uasTransaction.TransactionRemoved += new SIPTransactionRemovedDelegate(UASTransaction_TransactionRemoved);
            //m_uasTransaction.TransactionStateChanged += (t) => { logger.Debug("Transaction state change to " + t.TransactionState + ", uri=" + t.TransactionRequestURI.ToString() + "."); };
        }
        public SIPReferServerUserAgent(SIPTransport sipTransport, SIPMonitorLogDelegate logDelegate, SIPNonInviteTransaction sipTransaction)
        {
            m_sipTransport = sipTransport;
            Log_External = logDelegate;
            m_sipTransaction = sipTransaction;

            m_sipTransaction.TransactionTraceMessage += TransactionTraceMessage;
            m_sipTransaction.NonInviteTransactionTimedOut += ClientTimedOut;

            // If external logging is not required assign an empty handler to stop null reference exceptions.
            if (Log_External == null)
            {
                Log_External = (e) => { };
            }

            var referTo = SIPURI.ParseSIPURI(m_sipTransaction.TransactionRequest.Header.ReferTo);
            var replacesParameter = SIPReplacesParameter.Parse(referTo.Headers.Get("Replaces"));

            ReplacedCall = new ReplacesCallDescriptor();
            ReplacedCall.CallId = replacesParameter.CallID;
            ReplacedCall.FromTag = replacesParameter.FromTag;
            ReplacedCall.ToTag = replacesParameter.ToTag;

            ReferToUri = referTo.CopyOf();
            ReferToUri.Headers.RemoveAll();
        }
        public SIPReferClientUserAgent(
            SIPTransport sipTransport,
            SIPEndPoint outboundProxy,
            string owner,
            string adminMemberId,
            SIPMonitorLogDelegate logDelegate)
        {
            m_sipTransport = sipTransport;
            m_outboundProxy = (outboundProxy != null) ? SIPEndPoint.ParseSIPEndPoint(outboundProxy.ToString()) : null;
            Owner = owner;
            AdminMemberId = adminMemberId;
            Log_External = logDelegate;

            // If external logging is not required assign an empty handler to stop null reference exceptions.
            if (Log_External == null)
            {
                Log_External = (e) => { };
            }
        }
 public SIPTransferServerUserAgent(            
     SIPMonitorLogDelegate logDelegate,
     BlindTransferDelegate blindTransfer,
     SIPTransport sipTransport,
     SIPEndPoint outboundProxy,
     SIPDialogue dialogueToReplace,
     SIPDialogue oppositeDialogue,
     string callDestination,
     string owner,
     string adminID)
 {
     Log_External = logDelegate;
     BlindTransfer_External = blindTransfer;
     m_sipTransport = sipTransport;
     m_outboundProxy = outboundProxy;
     m_dialogueToReplace = dialogueToReplace;
     m_oppositeDialogue = oppositeDialogue;
     m_callDestination = callDestination;
     m_owner = owner;
     m_adminID = adminID;
     m_dummyRequest = CreateDummyRequest(m_dialogueToReplace, m_callDestination);
 }
        /// <summary>
        /// Initialises the SIP transport layer.
        /// </summary>
        public async Task InitialiseSIP()
        {
            if (_isInitialised == false)
            {
                await Task.Run(() =>
                {
                    _isInitialised = true;

                    // Configure the SIP transport layer.
                    SIPTransport         = new SIPTransport();
                    bool sipChannelAdded = false;

                    if (m_sipSocketsNode != null)
                    {
                        // Set up the SIP channels based on the app.config file.
                        List <SIPChannel> sipChannels = SIPTransportConfig.ParseSIPChannelsNode(m_sipSocketsNode);
                        if (sipChannels?.Count > 0)
                        {
                            SIPTransport.AddSIPChannel(sipChannels);
                            sipChannelAdded = true;
                        }
                    }

                    if (sipChannelAdded == false)
                    {
                        // Use default options to set up a SIP channel.
                        SIPUDPChannel udpChannel = null;
                        try
                        {
                            udpChannel = new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_DEFAULT_PORT));
                        }
                        catch (ApplicationException bindExcp)
                        {
                            logger.LogWarning($"Socket exception attempting to bind UDP channel to port {SIP_DEFAULT_PORT}, will use random port. {bindExcp.Message}.");
                            udpChannel = new SIPUDPChannel(new IPEndPoint(IPAddress.Any, 0));
                        }

                        SIPTCPChannel tcpChannel = null;
                        try
                        {
                            tcpChannel = new SIPTCPChannel(new IPEndPoint(IPAddress.Any, udpChannel.Port));
                        }
                        catch (SocketException bindExcp)
                        {
                            logger.LogWarning($"Socket exception attempting to bind TCP channel to port {udpChannel.Port}, will use random port. {bindExcp.Message}.");
                            tcpChannel = new SIPTCPChannel(new IPEndPoint(IPAddress.Any, 0));
                        }

                        SIPTransport.AddSIPChannel(new List <SIPChannel> {
                            udpChannel, tcpChannel
                        });
                    }
                });

                // Wire up the transport layer so incoming SIP requests have somewhere to go.
                SIPTransport.SIPTransportRequestReceived += SIPTransportRequestReceived;

                // Log all SIP packets received to a log file.
                SIPTransport.SIPRequestInTraceEvent   += SIPRequestInTraceEvent;
                SIPTransport.SIPRequestOutTraceEvent  += SIPRequestOutTraceEvent;
                SIPTransport.SIPResponseInTraceEvent  += SIPResponseInTraceEvent;
                SIPTransport.SIPResponseOutTraceEvent += SIPResponseOutTraceEvent;
            }
        }
        public void AddRegisterRequest(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest registerRequest)
        {
            try
            {
                if (registerRequest.Method != SIPMethodsEnum.REGISTER)
                {
                    SIPResponse notSupportedResponse = GetErrorResponse(registerRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, "Registration requests only");
                    m_sipTransport.SendResponse(notSupportedResponse);
                }
                else
                {
                    SIPSorceryPerformanceMonitor.IncrementCounter(SIPSorceryPerformanceMonitor.REGISTRAR_REGISTRATION_REQUESTS_PER_SECOND);

                    int requestedExpiry = GetRequestedExpiry(registerRequest);

                    if (registerRequest.Header.To == null)
                    {
                        logger.Debug("Bad register request, no To header from " + remoteEndPoint + ".");
                        SIPResponse badReqResponse = SIPTransport.GetResponse(registerRequest, SIPResponseStatusCodesEnum.BadRequest, "Missing To header");
                        m_sipTransport.SendResponse(badReqResponse);
                    }
                    else if (registerRequest.Header.To.ToURI.User.IsNullOrBlank())
                    {
                        logger.Debug("Bad register request, no To user from " + remoteEndPoint + ".");
                        SIPResponse badReqResponse = SIPTransport.GetResponse(registerRequest, SIPResponseStatusCodesEnum.BadRequest, "Missing username on To header");
                        m_sipTransport.SendResponse(badReqResponse);
                    }
                    else if (registerRequest.Header.Contact == null || registerRequest.Header.Contact.Count == 0)
                    {
                        logger.Debug("Bad register request, no Contact header from " + remoteEndPoint + ".");
                        SIPResponse badReqResponse = SIPTransport.GetResponse(registerRequest, SIPResponseStatusCodesEnum.BadRequest, "Missing Contact header");
                        m_sipTransport.SendResponse(badReqResponse);
                    }
                    else if (requestedExpiry > 0 && requestedExpiry < m_minimumBindingExpiry)
                    {
                        logger.Debug("Bad register request, no expiry of " + requestedExpiry + " to small from " + remoteEndPoint + ".");
                        SIPResponse tooFrequentResponse = GetErrorResponse(registerRequest, SIPResponseStatusCodesEnum.IntervalTooBrief, null);
                        tooFrequentResponse.Header.MinExpires = m_minimumBindingExpiry;
                        m_sipTransport.SendResponse(tooFrequentResponse);
                    }
                    else
                    {
                        if (m_registerQueue.Count < MAX_REGISTER_QUEUE_SIZE)
                        {
                            SIPNonInviteTransaction registrarTransaction = m_sipTransport.CreateNonInviteTransaction(registerRequest, remoteEndPoint, localSIPEndPoint, null);
                            lock (m_registerQueue)
                            {
                                m_registerQueue.Enqueue(registrarTransaction);
                            }
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.BindingInProgress, "Register queued for " + registerRequest.Header.To.ToURI.ToString() + ".", null));
                        }
                        else
                        {
                            logger.Error("Register queue exceeded max queue size " + MAX_REGISTER_QUEUE_SIZE + ", overloaded response sent.");
                            SIPResponse overloadedResponse = SIPTransport.GetResponse(registerRequest, SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Registrar overloaded, please try again shortly");
                            m_sipTransport.SendResponse(overloadedResponse);
                        }

                        m_registerARE.Set();
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception AddRegisterRequest (" + remoteEndPoint.ToString() + "). " + excp.Message);
            }
        }
        /// <summary>
        /// Helper method for dynamic proxy runtime script.
        /// </summary>
        /// <param name="responseCode"></param>
        /// <param name="localEndPoint"></param>
        /// <param name="remoteEndPoint"></param>
        /// <param name="sipRequest"></param>
        public void Respond(SIPRequest sipRequest, SIPResponseStatusCodesEnum responseCode, string reasonPhrase)
        {
            SIPResponse response = SIPTransport.GetResponse(sipRequest, responseCode, reasonPhrase);

            m_sipTransport.SendResponse(response);
        }
Beispiel #9
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery call hold example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.
            bool isCallHungup  = false;
            bool hasCallFailed = false;

            AddConsoleLogger();

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT)));

            //EnableTraceLogs(sipTransport);

            // Get the default speaker.
            var(audioOutEvent, audioOutProvider) = GetAudioOutputDevice();
            WaveInEvent waveInEvent = GetAudioInputDevice();

            RTPMediaSession RtpMediaSession = null;

            // Create a client/server user agent to place a call to a remote SIP server along with event handlers for the different stages of the call.
            var userAgent = new SIPUserAgent(sipTransport, null);

            userAgent.ClientCallTrying  += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            userAgent.ClientCallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            userAgent.ClientCallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
                exitCts.Cancel();
            };
            userAgent.ClientCallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                    PlayRemoteMedia(RtpMediaSession, audioOutProvider);
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                    hasCallFailed = true;
                    exitCts.Cancel();
                }
            };
            userAgent.OnCallHungup += () =>
            {
                Log.LogInformation($"Call hungup by remote party.");
                exitCts.Cancel();
            };
            userAgent.ServerCallCancelled += (uas) => Log.LogInformation("Incoming call cancelled by caller.");

            sipTransport.SIPTransportRequestReceived += async(localEndPoint, remoteEndPoint, sipRequest) =>
            {
                if (sipRequest.Header.From != null &&
                    sipRequest.Header.From.FromTag != null &&
                    sipRequest.Header.To != null &&
                    sipRequest.Header.To.ToTag != null)
                {
                    // This is an in-dialog request that will be handled directly by a user agent instance.
                }
                else if (sipRequest.Method == SIPMethodsEnum.INVITE)
                {
                    if (userAgent?.IsCallActive == true)
                    {
                        Log.LogWarning($"Busy response returned for incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        // If we are already on a call return a busy response.
                        UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null);
                        SIPResponse          busyResponse   = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BusyHere, null);
                        uasTransaction.SendFinalResponse(busyResponse);
                    }
                    else
                    {
                        Log.LogInformation($"Incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        var incomingCall = userAgent.AcceptCall(sipRequest);

                        RtpMediaSession = new RTPMediaSession(SDPMediaTypesEnum.audio, (int)SDPMediaFormatsEnum.PCMU, AddressFamily.InterNetwork);
                        RtpMediaSession.RemotePutOnHold   += () => Log.LogInformation("Remote call party has placed us on hold.");
                        RtpMediaSession.RemoteTookOffHold += () => Log.LogInformation("Remote call party took us off hold.");
                        await userAgent.Answer(incomingCall, RtpMediaSession);

                        PlayRemoteMedia(RtpMediaSession, audioOutProvider);
                        waveInEvent.StartRecording();

                        Log.LogInformation($"Answered incoming call from {sipRequest.Header.From.FriendlyDescription()} at {remoteEndPoint}.");
                    }
                }
                else
                {
                    Log.LogDebug($"SIP {sipRequest.Method} request received but no processing has been set up for it, rejecting.");
                    SIPResponse notAllowedResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                    await sipTransport.SendResponseAsync(notAllowedResponse);
                }
            };

            // Wire up the RTP send session to the audio output device.
            uint rtpSendTimestamp = 0;

            waveInEvent.DataAvailable += (object sender, WaveInEventArgs args) =>
            {
                byte[] sample      = new byte[args.Buffer.Length / 2];
                int    sampleIndex = 0;

                for (int index = 0; index < args.BytesRecorded; index += 2)
                {
                    var ulawByte = NAudio.Codecs.MuLawEncoder.LinearToMuLawSample(BitConverter.ToInt16(args.Buffer, index));
                    sample[sampleIndex++] = ulawByte;
                }

                if (RtpMediaSession != null)
                {
                    RtpMediaSession.SendAudioFrame(rtpSendTimestamp, sample);
                    rtpSendTimestamp += (uint)(8000 / waveInEvent.BufferMilliseconds);
                }
            };

            // At this point the call has been initiated and everything will be handled in an event handler.
            Task.Run(async() =>
            {
                try
                {
                    while (!exitCts.Token.WaitHandle.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();

                        if (keyProps.KeyChar == 'c')
                        {
                            if (!userAgent.IsCallActive)
                            {
                                RtpMediaSession = new RTPMediaSession(SDPMediaTypesEnum.audio, (int)SDPMediaFormatsEnum.PCMU, AddressFamily.InterNetwork);
                                RtpMediaSession.RemotePutOnHold   += () => Log.LogInformation("Remote call party has placed us on hold.");
                                RtpMediaSession.RemoteTookOffHold += () => Log.LogInformation("Remote call party took us off hold.");

                                var callDescriptor = GetCallDescriptor(DEFAULT_DESTINATION_SIP_URI);
                                await userAgent.InitiateCall(callDescriptor, RtpMediaSession);
                            }
                            else
                            {
                                Log.LogWarning("There is already an active call.");
                            }
                        }
                        else if (keyProps.KeyChar == 'h')
                        {
                            // Place call on/off hold.
                            if (userAgent.IsCallActive)
                            {
                                if (RtpMediaSession.LocalOnHold)
                                {
                                    Log.LogInformation("Taking the remote call party off hold.");
                                    RtpMediaSession.TakeOffHold();
                                }
                                else
                                {
                                    Log.LogInformation("Placing the remote call party on hold.");
                                    RtpMediaSession.PutOnHold();
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to put on hold.");
                            }
                        }
                        else if (keyProps.KeyChar == 't')
                        {
                            if (userAgent.IsCallActive)
                            {
                                var transferURI = SIPURI.ParseSIPURI(TRANSFER_DESTINATION_SIP_URI);
                                bool result     = await userAgent.BlindTransfer(transferURI, TimeSpan.FromSeconds(TRANSFER_TIMEOUT_SECONDS), exitCts.Token);
                                if (result)
                                {
                                    // If the transfer was accepted the original call will already have been hungup.
                                    // Wait a second for the transfer NOTIFY request to arrive.
                                    await Task.Delay(1000);
                                    exitCts.Cancel();
                                }
                                else
                                {
                                    Log.LogWarning($"Transfer to {TRANSFER_DESTINATION_SIP_URI} failed.");
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to transfer.");
                            }
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            // Quit application.
                            exitCts.Cancel();
                        }
                    }
                }
                catch (Exception excp)
                {
                    SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            #region Cleanup.

            Log.LogInformation("Exiting...");

            RtpMediaSession?.Close();
            waveInEvent?.StopRecording();
            audioOutEvent?.Stop();

            if (!isCallHungup && userAgent != null)
            {
                if (userAgent.IsCallActive)
                {
                    Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }

            #endregion
        }
Beispiel #10
0
        /// <summary>
        /// Handler for processing incoming SIP requests.
        /// </summary>
        /// <param name="localSIPEndPoint">The end point the request was received on.</param>
        /// <param name="remoteEndPoint">The end point the request came from.</param>
        /// <param name="sipRequest">The SIP request received.</param>
        private void SIPTransportRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest)
        {
            if (sipRequest.Method == SIPMethodsEnum.BYE)
            {
                if (m_uac != null && m_uac.SIPDialogue != null && sipRequest.Header.CallId == m_uac.SIPDialogue.CallId)
                {
                    // Call has been hungup by remote end.
                    StatusMessage("Call hungup by remote end.");
                    SIPNonInviteTransaction byeTransaction = m_sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    byeTransaction.SendFinalResponse(byeResponse);
                    CallFinished();
                }
                else if (m_uas != null && m_uas.SIPDialogue != null && sipRequest.Header.CallId == m_uas.SIPDialogue.CallId)
                {
                    // Call has been hungup by remote end.
                    StatusMessage("Call hungup.");
                    SIPNonInviteTransaction byeTransaction = m_sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    byeTransaction.SendFinalResponse(byeResponse);
                    CallFinished();
                }
                else
                {
                    logger.Debug("Unmatched BYE request received for " + sipRequest.URI.ToString() + ".");
                    SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null);
                    m_sipTransport.SendResponse(noCallLegResponse);
                }
            }
            else if (sipRequest.Method == SIPMethodsEnum.INVITE)
            {
                StatusMessage("Incoming call request: " + localSIPEndPoint + "<-" + remoteEndPoint + " " + sipRequest.URI.ToString() + ".");
                UASInviteTransaction uasTransaction = m_sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                m_uas = new SIPServerUserAgent(m_sipTransport, null, null, null, SIPCallDirection.In, null, null, null, uasTransaction);
                m_uas.CallCancelled += UASCallCancelled;

                m_uas.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null);
                m_uas.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null);

                IncomingCall();
            }
            else if (sipRequest.Method == SIPMethodsEnum.CANCEL)
            {
                UASInviteTransaction inviteTransaction = (UASInviteTransaction)m_sipTransport.GetTransaction(SIPTransaction.GetRequestTransactionId(sipRequest.Header.Vias.TopViaHeader.Branch, SIPMethodsEnum.INVITE));

                if (inviteTransaction != null)
                {
                    StatusMessage("Call was cancelled by remote end.");
                    SIPCancelTransaction cancelTransaction = m_sipTransport.CreateCancelTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, inviteTransaction);
                    cancelTransaction.GotRequest(localSIPEndPoint, remoteEndPoint, sipRequest);
                }
                else
                {
                    logger.Debug("No matching transaction was found for CANCEL to " + sipRequest.URI.ToString() + ".");
                    SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null);
                    m_sipTransport.SendResponse(noCallLegResponse);
                }

                CallFinished();
            }
            else
            {
                logger.Debug("SIP " + sipRequest.Method + " request received but no processing has been set up for it, rejecting.");
                SIPResponse notAllowedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                m_sipTransport.SendResponse(notAllowedResponse);
            }
        }
Beispiel #11
0
        //private delegate void MediaSampleReadyDelegate(SDPMediaTypesEnum mediaType, uint duration, byte[] sample);
        //private static event MediaSampleReadyDelegate OnMediaFromSIPSampleReady;

        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery SIP to WebRTC example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.

            AddConsoleLogger();

            // Start web socket.
            Console.WriteLine("Starting web socket server...");
            _webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT, true);
            _webSocketServer.SslConfiguration.ServerCertificate          = new X509Certificate2(WEBSOCKET_CERTIFICATE_PATH);
            _webSocketServer.SslConfiguration.CheckCertificateRevocation = false;
            //_webSocketServer.Log.Level = WebSocketSharp.LogLevel.Debug;
            _webSocketServer.AddWebSocketService <SDPExchange>("/", (sdpExchanger) =>
            {
                sdpExchanger.WebSocketOpened   += SendSDPOffer;
                sdpExchanger.SDPAnswerReceived += SDPAnswerReceived;
            });
            _webSocketServer.Start();

            Console.WriteLine($"Waiting for browser web socket connection to {_webSocketServer.Address}:{_webSocketServer.Port}...");

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT)));

            //EnableTraceLogs(sipTransport);

            RtpAVSession rtpAVSession = null;

            // Create a SIP user agent to receive a call from a remote SIP client.
            // Wire up event handlers for the different stages of the call.
            var userAgent = new SIPUserAgent(sipTransport, null);

            // We're only answering SIP calls, not placing them.
            userAgent.OnCallHungup += (dialog) =>
            {
                Log.LogInformation($"Call hungup by remote party.");
                exitCts.Cancel();
            };
            userAgent.ServerCallCancelled += (uas) => Log.LogInformation("Incoming call cancelled by caller.");

            sipTransport.SIPTransportRequestReceived += async(localEndPoint, remoteEndPoint, sipRequest) =>
            {
                if (sipRequest.Header.From != null &&
                    sipRequest.Header.From.FromTag != null &&
                    sipRequest.Header.To != null &&
                    sipRequest.Header.To.ToTag != null)
                {
                    // This is an in-dialog request that will be handled directly by a user agent instance.
                }
                else if (sipRequest.Method == SIPMethodsEnum.INVITE)
                {
                    if (userAgent?.IsCallActive == true)
                    {
                        Log.LogWarning($"Busy response returned for incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        // If we are already on a call return a busy response.
                        UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null);
                        SIPResponse          busyResponse   = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BusyHere, null);
                        uasTransaction.SendFinalResponse(busyResponse);
                    }
                    else
                    {
                        Log.LogInformation($"Incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        var incomingCall = userAgent.AcceptCall(sipRequest);

                        rtpAVSession = new RtpAVSession(new AudioOptions {
                            AudioSource = AudioSourcesEnum.CaptureDevice
                        }, null);
                        await userAgent.Answer(incomingCall, rtpAVSession);

                        rtpAVSession.OnRtpPacketReceived += (mediaType, rtpPacket) => ForwardMedia(mediaType, rtpPacket);

                        Log.LogInformation($"Answered incoming call from {sipRequest.Header.From.FriendlyDescription()} at {remoteEndPoint}.");
                    }
                }
                else
                {
                    Log.LogDebug($"SIP {sipRequest.Method} request received but no processing has been set up for it, rejecting.");
                    SIPResponse notAllowedResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                    await sipTransport.SendResponseAsync(notAllowedResponse);
                }
            };

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            #region Cleanup.

            Log.LogInformation("Exiting...");

            rtpAVSession?.Close("app exit");

            if (userAgent != null)
            {
                if (userAgent.IsCallActive)
                {
                    Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Hangup();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }

            #endregion
        }
Beispiel #12
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            ManualResetEvent exitMre       = new ManualResetEvent(false);
            bool             isCallHungup  = false;
            bool             hasCallFailed = false;

            AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            if (args != null && args.Length > 0)
            {
                if (!SIPURI.TryParse(args[0], out callUri))
                {
                    Log.LogWarning($"Command line argument could not be parsed as a SIP URI {args[0]}");
                }
            }
            Log.LogInformation($"Call destination {callUri}.");

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            EnableTraceLogs(sipTransport);

            // Get the IP address the RTP will be sent from. While we can listen on IPAddress.Any | IPv6Any
            // we can't put 0.0.0.0 or [::0] in the SDP or the callee will treat our RTP stream as inactive.
            var lookupResult = SIPDNSManager.ResolveSIPService(callUri, false);

            Log.LogDebug($"DNS lookup result for {callUri}: {lookupResult?.GetSIPEndPoint()}.");
            var dstAddress        = lookupResult.GetSIPEndPoint().Address;
            var localOfferAddress = NetServices.GetLocalAddressForRemote(dstAddress);

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            var audioOptions = new AudioOptions
            {
                AudioSource = AudioSourcesEnum.CaptureDevice,
                AudioCodecs = new List <SDPMediaFormatsEnum> {
                    SDPMediaFormatsEnum.PCMA, SDPMediaFormatsEnum.PCMU
                },
                OutputDeviceIndex = AudioOptions.DEFAULT_OUTPUTDEVICE_INDEX
            };
            var rtpSession = new RtpAVSession(audioOptions, null);
            var offerSDP   = rtpSession.CreateOffer(localOfferAddress);

            // Create a client user agent to place a call to a remote SIP server along with event handlers for the different stages of the call.
            var uac = new SIPClientUserAgent(sipTransport);

            uac.CallTrying  += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallRinging += (uac, resp) =>
            {
                Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
                if (resp.Status == SIPResponseStatusCodesEnum.SessionProgress)
                {
                    rtpSession.Start();
                }
            };
            uac.CallFailed += (uac, err, resp) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (iuac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                    var result = rtpSession.SetRemoteDescription(SDP.ParseSDPDescription(resp.Body));
                    if (result == SetDescriptionResultEnum.OK)
                    {
                        rtpSession.Start();
                    }
                    else
                    {
                        Log.LogWarning($"Failed to set remote description {result}.");
                        uac.Hangup();
                    }
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    await sipTransport.SendResponseAsync(okResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        exitMre.Set();
                    }
                }
            };

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                callUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                callUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                offerSDP.ToString(),
                null);

            uac.Call(callDescriptor);
            uac.ServerTransaction.TransactionTraceMessage += (tx, msg) => Log.LogInformation($"UAC tx trace message. {msg}");

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitMre.Set();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitMre.WaitOne();

            Log.LogInformation("Exiting...");

            rtpSession.Close(null);

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
Beispiel #13
0
        private static SIPEndPoint OUTBOUND_PROXY = null; // SIPEndPoint.ParseSIPEndPoint("udp:192.168.0.148:5060");

        static async Task Main()
        {
            Console.WriteLine("SIPSorcery Getting Started Demo");

            AddConsoleLogger();
            CancellationTokenSource exitCts = new CancellationTokenSource();

            var sipTransport = new SIPTransport();

            EnableTraceLogs(sipTransport);

            var userAgent = new SIPUserAgent(sipTransport, OUTBOUND_PROXY);

            userAgent.ClientCallFailed += (uac, error, sipResponse) => Console.WriteLine($"Call failed {error}.");
            userAgent.OnCallHungup     += (dialog) => exitCts.Cancel();

            var windowsAudio     = new WindowsAudioEndPoint(new AudioEncoder());
            var voipMediaSession = new VoIPMediaSession(windowsAudio.ToMediaEndPoints());

            voipMediaSession.AcceptRtpFromAny = true;

            // Place the call and wait for the result.
            var callTask = userAgent.Call(DESTINATION, null, null, voipMediaSession);

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;

                if (userAgent != null)
                {
                    if (userAgent.IsCalling || userAgent.IsRinging)
                    {
                        Console.WriteLine("Cancelling in progress call.");
                        userAgent.Cancel();
                    }
                    else if (userAgent.IsCallActive)
                    {
                        Console.WriteLine("Hanging up established call.");
                        userAgent.Hangup();
                    }
                }
                ;

                exitCts.Cancel();
            };

            Console.WriteLine("press ctrl-c to exit...");

            bool callResult = await callTask;

            if (callResult)
            {
                Console.WriteLine($"Call to {DESTINATION} succeeded.");
                exitCts.Token.WaitHandle.WaitOne();
            }
            else
            {
                Console.WriteLine($"Call to {DESTINATION} failed.");
            }

            Console.WriteLine("Exiting...");

            if (userAgent?.IsHangingUp == true)
            {
                Console.WriteLine("Waiting 1s for the call hangup or cancel to complete...");
                await Task.Delay(1000);
            }

            // Clean up.
            sipTransport.Shutdown();
        }
 //private SIPAccount m_destinationSIPAccount;
 public SIPB2BUserAgent(
     SIPMonitorLogDelegate logDelegate,
     QueueNewCallDelegate queueCall,
     SIPTransport sipTranpsort,
     string uacOwner,
     string uacAdminMemberId
     )
 {
     Log_External = logDelegate;
     QueueNewCall_External = queueCall;
     m_sipTransport = sipTranpsort;
     m_uacOwner = uacOwner;
     m_uacAdminMemberId = uacAdminMemberId;
 }
Beispiel #15
0
        public PythonHelper(PythonEngine pythonEngine, SIPTransport sipTransport)
        {
            m_sipTransport = sipTransport;

            logger.Debug("PythonHelper SIP Transport local socket is " + m_sipTransport.GetDefaultTransportContact(SIPProtocolsEnum.UDP) + ".");
        }
Beispiel #16
0
        public bool AuthenticateCall()
        {
            m_isAuthenticated = false;

            try
            {
                if (SIPAuthenticateRequest_External == null)
                {
                    // No point trying to authenticate if we haven't been given an authentication delegate.
                    Reject(SIPResponseStatusCodesEnum.InternalServerError, null, null);
                }
                else if (GetSIPAccount_External == null)
                {
                    // No point trying to authenticate if we haven't been given a  delegate to load the SIP account.
                    Reject(SIPResponseStatusCodesEnum.InternalServerError, null, null);
                }
                else
                {
                    m_sipAccount = GetSIPAccount_External(s => s.SIPUsername == m_sipUsername && s.SIPDomain == m_sipDomain);

                    if (m_sipAccount == null)
                    {
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Rejecting authentication required call for " + m_sipUsername + "@" + m_sipDomain + ", SIP account not found.", null));
                        Reject(SIPResponseStatusCodesEnum.Forbidden, null, null);
                    }
                    else
                    {
                        SIPRequest  sipRequest       = m_uasTransaction.TransactionRequest;
                        SIPEndPoint localSIPEndPoint = (!sipRequest.Header.ProxyReceivedOn.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedOn) : sipRequest.LocalSIPEndPoint;
                        SIPEndPoint remoteEndPoint   = (!sipRequest.Header.ProxyReceivedFrom.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedFrom) : sipRequest.RemoteSIPEndPoint;

                        SIPRequestAuthenticationResult authenticationResult = SIPAuthenticateRequest_External(localSIPEndPoint, remoteEndPoint, sipRequest, m_sipAccount, Log_External);
                        if (authenticationResult.Authenticated)
                        {
                            if (authenticationResult.WasAuthenticatedByIP)
                            {
                                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "New call from " + remoteEndPoint.ToString() + " successfully authenticated by IP address.", m_sipAccount.Owner));
                            }
                            else
                            {
                                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "New call from " + remoteEndPoint.ToString() + " successfully authenticated by digest.", m_sipAccount.Owner));
                            }

                            SetOwner(m_sipAccount.Owner, m_sipAccount.AdminMemberId);
                            m_isAuthenticated = true;
                        }
                        else
                        {
                            // Send authorisation failure or required response
                            SIPResponse authReqdResponse = SIPTransport.GetResponse(sipRequest, authenticationResult.ErrorResponse, null);
                            authReqdResponse.Header.AuthenticationHeader = authenticationResult.AuthenticationRequiredHeader;
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call not authenticated for " + m_sipUsername + "@" + m_sipDomain + ", responding with " + authenticationResult.ErrorResponse + ".", null));
                            m_uasTransaction.SendFinalResponse(authReqdResponse);
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPServerUserAgent AuthenticateCall. " + excp.Message);
                Reject(SIPResponseStatusCodesEnum.InternalServerError, null, null);
            }

            return(m_isAuthenticated);
        }
Beispiel #17
0
        /// <summary>
        /// Enable detailed SIP log messages.
        /// </summary>
        private static void EnableTraceLogs(SIPTransport sipTransport, bool fullSIP)
        {
            sipTransport.SIPRequestInTraceEvent += (localEP, remoteEP, req) =>
            {
                Log.LogDebug($"Request received: {localEP}<-{remoteEP}");

                if (!fullSIP)
                {
                    Log.LogDebug(req.StatusLine);
                }
                else
                {
                    Log.LogDebug(req.ToString());
                }
            };

            sipTransport.SIPRequestOutTraceEvent += (localEP, remoteEP, req) =>
            {
                Log.LogDebug($"Request sent: {localEP}->{remoteEP}");

                if (!fullSIP)
                {
                    Log.LogDebug(req.StatusLine);
                }
                else
                {
                    Log.LogDebug(req.ToString());
                }
            };

            sipTransport.SIPResponseInTraceEvent += (localEP, remoteEP, resp) =>
            {
                Log.LogDebug($"Response received: {localEP}<-{remoteEP}");

                if (!fullSIP)
                {
                    Log.LogDebug(resp.ShortDescription);
                }
                else
                {
                    Log.LogDebug(resp.ToString());
                }
            };

            sipTransport.SIPResponseOutTraceEvent += (localEP, remoteEP, resp) =>
            {
                Log.LogDebug($"Response sent: {localEP}->{remoteEP}");

                if (!fullSIP)
                {
                    Log.LogDebug(resp.ShortDescription);
                }
                else
                {
                    Log.LogDebug(resp.ToString());
                }
            };

            sipTransport.SIPRequestRetransmitTraceEvent += (tx, req, count) =>
            {
                Log.LogDebug($"Request retransmit {count} for request {req.StatusLine}, initial transmit {DateTime.Now.Subtract(tx.InitialTransmit).TotalSeconds.ToString("0.###")}s ago.");
            };

            sipTransport.SIPResponseRetransmitTraceEvent += (tx, resp, count) =>
            {
                Log.LogDebug($"Response retransmit {count} for response {resp.ShortDescription}, initial transmit {DateTime.Now.Subtract(tx.InitialTransmit).TotalSeconds.ToString("0.###")}s ago.");
            };
        }
Beispiel #18
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery Attended Transfer Demo: Transfer Target");
            Console.WriteLine("Waiting for incoming call from Transferor.");
            Console.WriteLine("Press 'q' or ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.

            AddConsoleLogger();

            // Set up a default SIP transport.
            _sipTransport = new SIPTransport();
            _sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT)));

            EnableTraceLogs(_sipTransport);

            var userAgent = new SIPUserAgent(_sipTransport, null);

            userAgent.ServerCallCancelled += (uas) => Log.LogDebug("Incoming call cancelled by remote party.");
            userAgent.OnCallHungup        += (dialog) => Log.LogDebug("Call hungup by remote party.");
            userAgent.OnIncomingCall      += async(ua, req) =>
            {
                List <SDPMediaFormatsEnum> codecs = new List <SDPMediaFormatsEnum> {
                    SDPMediaFormatsEnum.PCMU, SDPMediaFormatsEnum.PCMA, SDPMediaFormatsEnum.G722
                };
                var audioOptions = new AudioSourceOptions {
                    AudioSource = AudioSourcesEnum.Silence
                };
                var rtpAudioSession = new RtpAudioSession(audioOptions, codecs, null, _rtpPort);
                _rtpPort += 2;

                rtpAudioSession.OnReceiveReport += RtpSession_OnReceiveReport;
                //rtpAudioSession.OnSendReport += RtpSession_OnSendReport;

                var  uas          = ua.AcceptCall(req);
                bool answerResult = await ua.Answer(uas, rtpAudioSession);

                Log.LogDebug($"Answer incoming call result {answerResult}.");

                _ = Task.Run(async() =>
                {
                    await Task.Delay(1000);

                    Log.LogDebug($"Sending DTMF sequence {string.Join("", DTMF_SEQUENCEFOR_TRANSFEROR.Select(x => x))}.");
                    foreach (byte dtmf in DTMF_SEQUENCEFOR_TRANSFEROR)
                    {
                        Log.LogDebug($"Sending DTMF tone to transferor {dtmf}.");
                        await ua.SendDtmf(dtmf);
                    }
                });
            };
            userAgent.OnDtmfTone += (key, duration) => Log.LogInformation($"Received DTMF tone {key}.");

            Task.Run(() => OnKeyPress(userAgent, exitCts));

            exitCts.Token.WaitHandle.WaitOne();

            #region Cleanup.

            Log.LogInformation("Exiting...");

            //userAgent?.Hangup();

            // Give any BYE or CANCEL requests time to be transmitted.
            Log.LogInformation("Waiting 1s for calls to be cleaned up...");
            Task.Delay(1000).Wait();

            SIPSorcery.Net.DNSManager.Stop();

            if (_sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                _sipTransport.Shutdown();
            }

            #endregion
        }
 public SIPClientUserAgent(
     SIPTransport sipTransport,
     SIPEndPoint outboundProxy,
     string owner,
     string adminMemberId,
     SIPMonitorLogDelegate logDelegate,
     RtccGetCustomerDelegate rtccGetCustomer,
     RtccGetRateDelegate rtccGetRate,
     RtccGetBalanceDelegate rtccGetBalance,
     RtccReserveInitialCreditDelegate rtccReserveInitialCredit,
     RtccUpdateCdrDelegate rtccUpdateCdr
     )
     : this(sipTransport, outboundProxy, owner, adminMemberId, logDelegate)
 {
     RtccGetCustomer_External = rtccGetCustomer;
     RtccGetRate_External = rtccGetRate;
     RtccGetBalance_External = rtccGetBalance;
     RtccReserveInitialCredit_External = rtccReserveInitialCredit;
     RtccUpdateCdr_External = rtccUpdateCdr;
 }
Beispiel #20
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery registration user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            AddConsoleLogger();

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();
            var sipChannel   = new SIPUDPChannel(IPAddress.Any, 0);

            sipTransport.AddSIPChannel(sipChannel);

            //EnableTraceLogs(sipTransport);

            // Create a client user agent to maintain a periodic registration with a SIP server.
            var regUserAgent = new SIPRegistrationUserAgent(
                sipTransport,
                "softphonesample",
                "password",
                "sipsorcery.com",
                120);

            int successCounter = 0;
            ManualResetEvent taskCompleteMre = new ManualResetEvent(false);

            // Event handlers for the different stages of the registration.
            regUserAgent.RegistrationFailed           += (uri, err) => SIPSorcery.Sys.Log.Logger.LogError($"{uri.ToString()}: {err}");
            regUserAgent.RegistrationTemporaryFailure += (uri, msg) => SIPSorcery.Sys.Log.Logger.LogWarning($"{uri.ToString()}: {msg}");
            regUserAgent.RegistrationRemoved          += (uri) => SIPSorcery.Sys.Log.Logger.LogError($"{uri.ToString()} registration failed.");
            regUserAgent.RegistrationSuccessful       += (uri) =>
            {
                SIPSorcery.Sys.Log.Logger.LogInformation($"{uri.ToString()} registration succeeded.");
                Interlocked.Increment(ref successCounter);
                SIPSorcery.Sys.Log.Logger.LogInformation($"Successful registrations {successCounter} of {SUCCESS_REGISTRATION_COUNT}.");

                if (successCounter == SUCCESS_REGISTRATION_COUNT)
                {
                    taskCompleteMre.Set();
                }
            };

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");
                taskCompleteMre.Set();
            };

            // Start the thread to perform the initial registration and then periodically resend it.
            regUserAgent.Start();

            taskCompleteMre.WaitOne();

            regUserAgent.Stop();
            if (sipTransport != null)
            {
                SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
            SIPSorcery.Net.DNSManager.Stop();
        }
Beispiel #21
0
        private static readonly int RTP_REPORTING_PERIOD_SECONDS = 5;       // Period at which to write RTP stats.

        static void Main()
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource cts = new CancellationTokenSource();
            bool isCallHungup           = false;
            bool hasCallFailed          = false;

            // Logging configuration. Can be ommitted if internal SIPSorcery debug and warning messages are not required.
            var loggerFactory = new Microsoft.Extensions.Logging.LoggerFactory();
            var loggerConfig  = new LoggerConfiguration()
                                .Enrich.FromLogContext()
                                .MinimumLevel.Is(Serilog.Events.LogEventLevel.Debug)
                                .WriteTo.Console()
                                .CreateLogger();

            loggerFactory.AddSerilog(loggerConfig);
            SIPSorcery.Sys.Log.LoggerFactory = loggerFactory;

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();
            int port         = SIPConstants.DEFAULT_SIP_PORT + 1000;

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Loopback, port)));
            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.IPv6Loopback, port)));
            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(LocalIPConfig.GetDefaultIPv4Address(), port)));
            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(LocalIPConfig.GetDefaultIPv6Address(), port)));

            // Select the IP address to use for RTP based on the destination SIP URI.
            SIPURI callURI         = SIPURI.ParseSIPURIRelaxed(DESTINATION_SIP_URI);
            var    endPointForCall = callURI.ToSIPEndPoint() == null?sipTransport.GetDefaultSIPEndPoint(callURI.Protocol) : sipTransport.GetDefaultSIPEndPoint(callURI.ToSIPEndPoint());

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            Socket rtpSocket     = null;
            Socket controlSocket = null;

            NetServices.CreateRtpSocket(endPointForCall.Address, 49000, 49100, false, out rtpSocket, out controlSocket);
            var rtpSendSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

            // Create a client user agent to place a call to a remote SIP server along with event handlers for the different stages of the call.
            var uac = new SIPClientUserAgent(sipTransport);

            uac.CallTrying += (uac, resp) =>
            {
                SIPSorcery.Sys.Log.Logger.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            };
            uac.CallRinging += (uac, resp) => SIPSorcery.Sys.Log.Logger.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallFailed  += (uac, err) =>
            {
                SIPSorcery.Sys.Log.Logger.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                    SIPSorcery.Sys.Log.Logger.LogDebug(resp.ToString());

                    IPEndPoint remoteRtpEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);

                    SIPSorcery.Sys.Log.Logger.LogDebug($"Sending initial RTP packet to remote RTP socket {remoteRtpEndPoint}.");

                    // Send a dummy packet to open the NAT session on the RTP path.
                    rtpSendSession.SendAudioFrame(rtpSocket, remoteRtpEndPoint, 0, new byte[] { 0x00 });
                }
                else
                {
                    SIPSorcery.Sys.Log.Logger.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPNonInviteTransaction byeTransaction = sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    byeTransaction.SendFinalResponse(byeResponse);

                    if (uac.IsUACAnswered)
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        cts.Cancel();
                    }
                }
            };

            // It's a good idea to start the RTP receiving socket before the call request is sent.
            // A SIP server will generally start sending RTP as soon as it has processed the incoming call request and
            // being ready to receive will stop any ICMP error response being generated.
            Task.Run(() => SendRecvRtp(rtpSocket, rtpSendSession, cts));

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                DESTINATION_SIP_URI,
                SIPConstants.SIP_DEFAULT_FROMURI,
                null, null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                GetSDP(rtpSocket.LocalEndPoint as IPEndPoint).ToString(),
                null);

            uac.Call(callDescriptor);

            // At this point the call has been initiated and everything will be handled in an event handler or on the RTP
            // receive task. The code below is to gracefully exit.
            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += async delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                cts.Cancel();

                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");

                rtpSocket?.Close();
                controlSocket?.Close();

                if (!isCallHungup && uac != null)
                {
                    if (uac.IsUACAnswered)
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                        uac.Hangup();
                    }
                    else if (!hasCallFailed)
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                        uac.Cancel();
                    }

                    // Give the BYE or CANCEL request time to be transmitted.
                    SIPSorcery.Sys.Log.Logger.LogInformation("Waiting 1s for call to clean up...");
                    await Task.Delay(1000);
                }

                SIPSorcery.Net.DNSManager.Stop();

                if (sipTransport != null)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                    sipTransport.Shutdown();
                }
            };
        }
Beispiel #22
0
        public async Task IncomingCallNoSdpWithACKUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            SIPTransport transport = new SIPTransport();

            transport.AddSIPChannel(new MockSIPChannel(new System.Net.IPEndPoint(IPAddress.Any, 0)));
            var dummySep = SIPEndPoint.ParseSIPEndPoint("udp:127.0.0.1:5060");

            SIPUserAgent userAgent = new SIPUserAgent(transport, null);

            string inviteReqStr = @"INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP 127.0.0.1:51200;branch=z9hG4bKbeed9b0cde8d43cc8a2aae91526b6a1d;rport
To: <sip:[email protected]>
From: <sip:[email protected]>;tag=GCLNRILCDU
Call-ID: 7265e19f53a146a1bacdf4f4f8ea70b2
CSeq: 1 INVITE
Contact: <sip:127.0.0.1:51200>
Max-Forwards: 70
User-Agent: www.sipsorcery.com
Content-Length: 0
Content-Type: application/sdp" + m_CRLF + m_CRLF;

            SIPEndPoint      dummySipEndPoint = new SIPEndPoint(new IPEndPoint(IPAddress.Loopback, 0));
            SIPMessageBuffer sipMessageBuffer = SIPMessageBuffer.ParseSIPMessage(inviteReqStr, dummySipEndPoint, dummySipEndPoint);
            SIPRequest       inviteReq        = SIPRequest.ParseSIPRequest(sipMessageBuffer);

            var uas          = userAgent.AcceptCall(inviteReq);
            var mediaSession = CreateMediaSession();

            _ = Task.Run(() =>
            {
                Task.Delay(2000).Wait();

                string ackReqStr = @"ACK sip:127.0.0.1:5060 SIP/2.0
Via: SIP/2.0/UDP 127.0.0.1:51200;branch=z9hG4bK76dfb1480ea14f778bd24afed1c8ded0;rport
To: <sip:[email protected]>;tag=YWPNZPMLPB
From: <sip:[email protected]>;tag=GCLNRILCDU
Call-ID: 7265e19f53a146a1bacdf4f4f8ea70b2
CSeq: 1 ACK
Max-Forwards: 70
Content-Length: 160

v=0
o=- 67424 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=audio 16976 RTP/AVP 8 101
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=sendrecv" + m_CRLF + m_CRLF;


                uas.ClientTransaction.ACKReceived(dummySep, dummySep, SIPRequest.ParseSIPRequest(ackReqStr));
            });

            await userAgent.Answer(uas, mediaSession);

            Assert.True(userAgent.IsCallActive);
        }
Beispiel #23
0
        private static void SIPTransportRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest)
        {
            if (sipRequest.Method == SIPMethodsEnum.BYE)
            {
                var rtpJob = (from job in m_rtpJobs.Values where job.UAS.CallRequest.Header.CallId == sipRequest.Header.CallId select job).FirstOrDefault();

                if (rtpJob != null)
                {
                    rtpJob.Stop();
                    // Call has been hungup by remote end.
                    Console.WriteLine("Call hungup by client: " + localSIPEndPoint + "<-" + remoteEndPoint + " " + sipRequest.URI.ToString() + ".\n");
                    Publish(rtpJob.QueueName, "BYE request received from " + remoteEndPoint + " for " + sipRequest.URI.ToString() + ".");
                    //Console.WriteLine("Request Received " + localSIPEndPoint + "<-" + remoteEndPoint + "\n" + sipRequest.ToString());
                    //m_uas.SIPDialogue.Hangup(m_sipTransport, null);
                    SIPResponse okResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    m_sipTransport.SendResponse(okResponse);
                }
                else
                {
                    Console.WriteLine("Unmatched BYE request received for " + sipRequest.URI.ToString() + ".\n");
                    SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null);
                    m_sipTransport.SendResponse(noCallLegResponse);
                }
            }
            else if (sipRequest.Method == SIPMethodsEnum.INVITE)
            {
                Console.WriteLine("Incoming call request: " + localSIPEndPoint + "<-" + remoteEndPoint + " " + sipRequest.URI.ToString() + ".\n");
                Publish(sipRequest.URI.User, "INVITE request received from " + remoteEndPoint + " for " + sipRequest.URI.ToString() + ".");

                Console.WriteLine(sipRequest.Body);

                SIPPacketMangler.MangleSIPRequest(SIPMonitorServerTypesEnum.Unknown, sipRequest, null, LogTraceMessage);

                UASInviteTransaction uasTransaction = m_sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                var uas = new SIPServerUserAgent(m_sipTransport, null, null, null, SIPCallDirection.In, null, null, LogTraceMessage, uasTransaction);
                uas.CallCancelled += UASCallCancelled;

                RTPDiagnosticsJob rtpJob = new RTPDiagnosticsJob(m_rtpListenIPAddress, m_publicIPAddress, uas, sipRequest);

                string sdpAddress = SDP.GetSDPRTPEndPoint(sipRequest.Body).Address.ToString();

                // Only mangle if there is something to change. For example the server could be on the same private subnet in which case it can't help.
                IPEndPoint expectedRTPEndPoint = new IPEndPoint(rtpJob.RemoteRTPEndPoint.Address, rtpJob.RemoteRTPEndPoint.Port);
                if (IPSocket.IsPrivateAddress(rtpJob.RemoteRTPEndPoint.Address.ToString()))
                {
                    expectedRTPEndPoint.Address = remoteEndPoint.Address;
                }

                Publish(sipRequest.URI.User, "Advertised RTP remote socket " + rtpJob.RemoteRTPEndPoint + ", expecting from " + expectedRTPEndPoint + ".");
                m_rtpJobs.Add(rtpJob.RTPListenEndPoint.Port, rtpJob);

                //ThreadPool.QueueUserWorkItem(delegate { StartRTPListener(rtpJob); });

                Console.WriteLine(rtpJob.LocalSDP.ToString());

                uas.Answer("application/sdp", rtpJob.LocalSDP.ToString(), CallProperties.CreateNewTag(), null, SIPDialogueTransferModesEnum.NotAllowed);

                var hangupTimer = new Timer(delegate
                {
                    if (!rtpJob.StopJob)
                    {
                        if (uas != null && uas.SIPDialogue != null)
                        {
                            if (rtpJob.RTPPacketReceived && !rtpJob.ErrorOnRTPSend)
                            {
                                Publish(sipRequest.URI.User, "Test completed. There were no RTP send or receive errors.");
                            }
                            else if (!rtpJob.RTPPacketReceived)
                            {
                                Publish(sipRequest.URI.User, "Test completed. An error was identified, no RTP packets were received.");
                            }
                            else
                            {
                                Publish(sipRequest.URI.User, "Test completed. An error was identified, there was a problem when attempting to send an RTP packet.");
                            }
                            rtpJob.Stop();
                            uas.SIPDialogue.Hangup(m_sipTransport, null);
                        }
                    }
                }, null, HANGUP_TIMEOUT, Timeout.Infinite);
            }
            else if (sipRequest.Method == SIPMethodsEnum.CANCEL)
            {
                UASInviteTransaction inviteTransaction = (UASInviteTransaction)m_sipTransport.GetTransaction(SIPTransaction.GetRequestTransactionId(sipRequest.Header.Vias.TopViaHeader.Branch, SIPMethodsEnum.INVITE));

                if (inviteTransaction != null)
                {
                    Console.WriteLine("Matching CANCEL request received " + sipRequest.URI.ToString() + ".\n");
                    Publish(sipRequest.URI.User, "CANCEL request received from " + remoteEndPoint + " for " + sipRequest.URI.ToString() + ".");
                    SIPCancelTransaction cancelTransaction = m_sipTransport.CreateCancelTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, inviteTransaction);
                    cancelTransaction.GotRequest(localSIPEndPoint, remoteEndPoint, sipRequest);
                }
                else
                {
                    Console.WriteLine("No matching transaction was found for CANCEL to " + sipRequest.URI.ToString() + ".\n");
                    SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null);
                    m_sipTransport.SendResponse(noCallLegResponse);
                }
            }
            else
            {
                Console.WriteLine("SIP " + sipRequest.Method + " request received but no processing has been set up for it, rejecting.\n");
                Publish(sipRequest.URI.User, sipRequest.Method + " request received from " + remoteEndPoint + " for " + sipRequest.URI.ToString() + ".");
                SIPResponse notAllowedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                m_sipTransport.SendResponse(notAllowedResponse);
            }
        }
Beispiel #24
0
        private void SIPTransportRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest)
        {
            try
            {
                switch (sipRequest.Method)
                {
                case SIPMethodsEnum.OPTIONS:
                    SIPNonInviteTransaction optionsTransaction = _sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    SIPResponse             optionsResponse    = SipHelper.WG67ResponseNormalize(
                        SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null));
                    optionsTransaction.SendFinalResponse(optionsResponse);
                    OptionsReceived?.Invoke(remoteEndPoint.ToString());
                    break;

                case SIPMethodsEnum.SUBSCRIBE:
                    m_sip_notifier.AddSubscribeRequest(localSIPEndPoint, remoteEndPoint, sipRequest);
                    break;

                case SIPMethodsEnum.PUBLISH:
                default:
                    throw new NotImplementedException();
                }
            }
            catch (NotImplementedException)
            {
                _logger.From().Debug(sipRequest.Method + " request processing not implemented for " + sipRequest.URI.ToParameterlessString() + " from " + remoteEndPoint + ".");

                SIPNonInviteTransaction notImplTransaction = _sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                SIPResponse             notImplResponse    = SipHelper.WG67ResponseNormalize(SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotImplemented, null));
                notImplTransaction.SendFinalResponse(notImplResponse);
            }
            catch (Exception x)
            {
                _logger.From().Debug($"SIPTransportRequestReceived Exception {x.Message}", x);
            }
        }
Beispiel #25
0
        static async Task Main()
        {
            Console.WriteLine("SIPSorcery Send DTMF Tones example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource rtpCts = new CancellationTokenSource(); // Cancellation token to stop the RTP stream.

            AddConsoleLogger();

            var sipTransport = new SIPTransport();
            var userAgent    = new SIPUserAgent(sipTransport, null);
            var rtpSession   = new RtpAVSession(AddressFamily.InterNetwork, new AudioOptions {
                AudioSource = AudioSourcesEnum.Microphone
            }, null);

            // Place the call and wait for the result.
            bool callResult = await userAgent.Call(DEFAULT_DESTINATION_SIP_URI, null, null, rtpSession);

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                rtpCts.Cancel();
            };

            if (callResult)
            {
                Console.WriteLine("Call attempt successful.");

                // Give the call some time to answer.
                await Task.Delay(1000);

                // Send the DTMF tones.
                await userAgent.SendDtmf(0x05);

                await Task.Delay(2000);

                await userAgent.SendDtmf(0x09);

                await Task.Delay(2000);

                await userAgent.SendDtmf(0x02);

                await Task.Delay(2000);

                if (userAgent.IsCallActive)
                {
                    Console.WriteLine("Hanging up.");
                    rtpCts.Cancel();
                    userAgent.Hangup();
                }
            }
            else
            {
                Console.WriteLine("Call attempt failed.");
            }

            Log.LogInformation("Exiting...");

            // Clean up.
            sipTransport.Shutdown();
            SIPSorcery.Net.DNSManager.Stop();
        }
Beispiel #26
0
 /// <summary>
 /// 计时器初始化
 /// </summary>
 /// <param name="request">sip响应</param>
 /// <param name="trans">sip传输</param>
 public TaskTiming(SIPRequest request, SIPTransport trans)
 {
     _request  = request;
     _trans    = trans;
     _timeSend = new Timer();
 }
Beispiel #27
0
        static async Task Main()
        {
            Console.WriteLine("SIPSorcery Getting Started Video Call Demo");
            Console.WriteLine("Press ctrl-c to exit.");

            Log = AddConsoleLogger();
            ManualResetEvent exitMRE = new ManualResetEvent(false);

            _sipTransport = new SIPTransport();

            EnableTraceLogs(_sipTransport);

            // Open a window to display the video feed from the remote SIP party.
            _form          = new Form();
            _form.AutoSize = true;
            _form.BackgroundImageLayout = ImageLayout.Center;
            _localVideoPicBox           = new PictureBox
            {
                Size     = new Size(VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT),
                Location = new Point(0, 0),
                Visible  = true
            };
            _remoteVideoPicBox = new PictureBox
            {
                Size     = new Size(VIDEO_FRAME_WIDTH, VIDEO_FRAME_HEIGHT),
                Location = new Point(0, VIDEO_FRAME_HEIGHT),
                Visible  = true
            };
            _form.Controls.Add(_localVideoPicBox);
            _form.Controls.Add(_remoteVideoPicBox);

            Application.EnableVisualStyles();
            ThreadPool.QueueUserWorkItem(delegate { Application.Run(_form); });

            ManualResetEvent formMre = new ManualResetEvent(false);

            _form.Activated += (object sender, EventArgs e) => formMre.Set();

            Console.WriteLine("Waiting for form activation.");
            formMre.WaitOne();

            _sipTransport.SIPTransportRequestReceived += OnSIPTransportRequestReceived;

            string executableDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            var userAgent = new SIPUserAgent(_sipTransport, null);

            userAgent.OnCallHungup += (dialog) => exitMRE.Set();
            var windowsAudioEndPoint = new WindowsAudioEndPoint(new AudioEncoder());

            windowsAudioEndPoint.RestrictFormats(format => format.Codec == AudioCodecsEnum.PCMU);
            var windowsVideoEndPoint = new WindowsVideoEndPoint();
            //windowsVideoEndPoint.OnVideoSourceError += (err) =>
            //{
            //    Log.LogError($"Video source error. {err}");
            //    if (userAgent.IsCallActive)
            //    {
            //        userAgent.Hangup();
            //    }
            //};

            // Fallback to a test pattern source if accessing the Windows webcam fails.
            var testPattern = new VideoTestPatternSource(new VideoEncoder());

            MediaEndPoints mediaEndPoints = new MediaEndPoints
            {
                AudioSink   = windowsAudioEndPoint,
                AudioSource = windowsAudioEndPoint,
                VideoSink   = windowsVideoEndPoint,
                VideoSource = windowsVideoEndPoint,
            };

            var voipMediaSession = new VoIPMediaSession(mediaEndPoints, testPattern);

            voipMediaSession.AcceptRtpFromAny = true;

            windowsVideoEndPoint.OnVideoSourceRawSample += (uint durationMilliseconds, int width, int height, byte[] sample, VideoPixelFormatsEnum pixelFormat) =>
            {
                _form?.BeginInvoke(new Action(() =>
                {
                    unsafe
                    {
                        fixed(byte *s = sample)
                        {
                            System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap((int)width, (int)height, (int)width * 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, (IntPtr)s);
                            _localVideoPicBox.Image        = bmpImage;
                        }
                    }
                }));
            };

            Console.WriteLine("Starting local video source...");
            await windowsVideoEndPoint.StartVideo().ConfigureAwait(false);

            // Place the call and wait for the result.
            Task <bool> callTask = userAgent.Call(DESTINATION, null, null, voipMediaSession);

            callTask.Wait(CALL_TIMEOUT_SECONDS * 1000);

            if (callTask.Result)
            {
                Log.LogInformation("Call attempt successful.");
                windowsVideoEndPoint.OnVideoSinkDecodedSample += (byte[] bmp, uint width, uint height, int stride, VideoPixelFormatsEnum pixelFormat) =>
                {
                    _form?.BeginInvoke(new Action(() =>
                    {
                        unsafe
                        {
                            fixed(byte *s = bmp)
                            {
                                System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap((int)width, (int)height, stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, (IntPtr)s);
                                _remoteVideoPicBox.Image       = bmpImage;
                            }
                        }
                    }));
                };

                windowsAudioEndPoint.PauseAudio().Wait();
                voipMediaSession.AudioExtrasSource.SetSource(AudioSourcesEnum.Music);
            }
            else
            {
                Log.LogWarning("Call attempt failed.");
                Console.WriteLine("Press ctrl-c to exit.");
            }

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                Log.LogInformation("Exiting...");
                exitMRE.Set();
            };
            exitMRE.WaitOne();

            if (userAgent.IsCallActive)
            {
                Log.LogInformation("Hanging up.");
                userAgent.Hangup();

                Task.Delay(1000).Wait();
            }

            // Clean up.
            _form.BeginInvoke(new Action(() => _form.Close()));
            _sipTransport.Shutdown();
        }
Beispiel #28
0
 public override void Initialize(SIPAuthenticateRequestDelegate sipRequestAuthenticator, SIPAccount account, SIPTransport transport)
 {
     PlatformType   = account.PlatformType;
     LocalSIPId     = account.LocalID;
     LocalEndPoint  = new SIPEndPoint(SIPProtocolsEnum.udp, account.LocalIP, account.LocalPort);
     RemoteSIPId    = account.RemoteID;
     RemoteEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, account.RemoteIP, account.RemotePort);
     Transport      = transport;
     if (PlatformType == Cores.PlatformType.UpPlatform)
     {
         Start();
     }
 }
        private RegisterResultEnum Register(SIPTransaction registerTransaction)
        {
            try
            {
                SIPRequest  sipRequest      = registerTransaction.TransactionRequest;
                SIPURI      registerURI     = sipRequest.URI;
                SIPToHeader toHeader        = sipRequest.Header.To;
                string      toUser          = toHeader.ToURI.User;
                string      canonicalDomain = (m_strictRealmHandling) ? GetCanonicalDomain_External(toHeader.ToURI.Host, true) : toHeader.ToURI.Host;
                int         requestedExpiry = GetRequestedExpiry(sipRequest);

                if (canonicalDomain == null)
                {
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Warn, "Register request for " + toHeader.ToURI.Host + " rejected as no matching domain found.", null));
                    SIPResponse noDomainResponse = GetErrorResponse(sipRequest, SIPResponseStatusCodesEnum.Forbidden, "Domain not serviced");
                    registerTransaction.SendFinalResponse(noDomainResponse);
                    return(RegisterResultEnum.DomainNotServiced);
                }

                SIPAccountAsset sipAccountAsset = GetSIPAccount_External(s => s.SIPUsername == toUser && s.SIPDomain == canonicalDomain);
                SIPRequestAuthenticationResult authenticationResult = SIPRequestAuthenticator_External(registerTransaction.LocalSIPEndPoint, registerTransaction.RemoteEndPoint, sipRequest, sipAccountAsset.SIPAccount, FireProxyLogEvent);

                if (!authenticationResult.Authenticated)
                {
                    // 401 Response with a fresh nonce needs to be sent.
                    SIPResponse authReqdResponse = SIPTransport.GetResponse(sipRequest, authenticationResult.ErrorResponse, null);
                    authReqdResponse.Header.AuthenticationHeader = authenticationResult.AuthenticationRequiredHeader;
                    registerTransaction.SendFinalResponse(authReqdResponse);

                    if (authenticationResult.ErrorResponse == SIPResponseStatusCodesEnum.Forbidden)
                    {
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Warn, "Forbidden " + toUser + "@" + canonicalDomain + " does not exist, " + sipRequest.Header.ProxyReceivedFrom + ", " + sipRequest.Header.UserAgent + ".", null));
                        return(RegisterResultEnum.Forbidden);
                    }
                    else
                    {
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Registrar, "Authentication required for " + toUser + "@" + canonicalDomain + " from " + sipRequest.Header.ProxyReceivedFrom + ".", toUser));
                        return(RegisterResultEnum.AuthenticationRequired);
                    }
                }
                else
                {
                    // Authenticated.
                    //if (!sipRequest.Header.UserAgent.IsNullOrBlank() && !m_switchboarduserAgentPrefix.IsNullOrBlank() && sipRequest.Header.UserAgent.StartsWith(m_switchboarduserAgentPrefix))
                    //{
                    //    // Check that the switchboard user is authorised.
                    //    var customer = CustomerPersistor_External.Get(x => x.CustomerUsername == sipAccount.Owner);
                    //    if (!(customer.ServiceLevel == CustomerServiceLevels.Switchboard.ToString() || customer.ServiceLevel == CustomerServiceLevels.Gold.ToString()))
                    //    {
                    //        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Warn, "Register request for switchboard from " + toHeader.ToURI.Host + " rejected as not correct service level.", sipAccount.Owner));
                    //        SIPResponse payReqdResponse = GetErrorResponse(sipRequest, SIPResponseStatusCodesEnum.PaymentRequired, "You need to purchase a Switchboard service");
                    //        registerTransaction.SendFinalResponse(payReqdResponse);
                    //        return RegisterResultEnum.SwitchboardPaymentRequired;
                    //    }
                    //}

                    if (sipRequest.Header.Contact == null || sipRequest.Header.Contact.Count == 0)
                    {
                        // No contacts header to update bindings with, return a list of the current bindings.
                        List <SIPRegistrarBinding> bindings = m_registrarBindingsManager.GetBindings(sipAccountAsset.Id);
                        //List<SIPContactHeader> contactsList = m_registrarBindingsManager.GetContactHeader(); // registration.GetContactHeader(true, null);
                        if (bindings != null)
                        {
                            sipRequest.Header.Contact = GetContactHeader(bindings);
                        }

                        SIPResponse okResponse = GetOkResponse(sipRequest);
                        registerTransaction.SendFinalResponse(okResponse);
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Empty registration request successful for " + toUser + "@" + canonicalDomain + " from " + sipRequest.Header.ProxyReceivedFrom + ".", toUser));
                    }
                    else
                    {
                        SIPEndPoint uacRemoteEndPoint = SIPEndPoint.TryParse(sipRequest.Header.ProxyReceivedFrom) ?? registerTransaction.RemoteEndPoint;
                        SIPEndPoint proxySIPEndPoint  = SIPEndPoint.TryParse(sipRequest.Header.ProxyReceivedOn);
                        SIPEndPoint registrarEndPoint = registerTransaction.LocalSIPEndPoint;

                        SIPResponseStatusCodesEnum updateResult = SIPResponseStatusCodesEnum.Ok;
                        string updateMessage = null;

                        DateTime startTime = DateTime.Now;

                        List <SIPRegistrarBinding> bindingsList = m_registrarBindingsManager.UpdateBindings(
                            sipAccountAsset.SIPAccount,
                            proxySIPEndPoint,
                            uacRemoteEndPoint,
                            registrarEndPoint,
                            //sipRequest.Header.Contact[0].ContactURI.CopyOf(),
                            sipRequest.Header.Contact,
                            sipRequest.Header.CallId,
                            sipRequest.Header.CSeq,
                            //sipRequest.Header.Contact[0].Expires,
                            sipRequest.Header.Expires,
                            sipRequest.Header.UserAgent,
                            out updateResult,
                            out updateMessage);

                        //int bindingExpiry = GetBindingExpiry(bindingsList, sipRequest.Header.Contact[0].ContactURI.ToString());
                        TimeSpan duration = DateTime.Now.Subtract(startTime);
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegistrarTiming, "Binding update time for " + toUser + "@" + canonicalDomain + " took " + duration.TotalMilliseconds + "ms.", null));

                        if (updateResult == SIPResponseStatusCodesEnum.Ok)
                        {
                            string proxySocketStr = (proxySIPEndPoint != null) ? " (proxy=" + proxySIPEndPoint.ToString() + ")" : null;

                            int bindingCount = 1;
                            foreach (SIPRegistrarBinding binding in bindingsList)
                            {
                                string bindingIndex = (bindingsList.Count == 1) ? String.Empty : " (" + bindingCount + ")";
                                //FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Registration successful for " + toUser + "@" + canonicalDomain + " from " + uacRemoteEndPoint + proxySocketStr + ", binding " + binding.ContactSIPURI.ToParameterlessString() + ";expiry=" + binding.Expiry + bindingIndex + ".", toUser));
                                FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Registration successful for " + toUser + "@" + canonicalDomain + " from " + uacRemoteEndPoint + ", binding " + binding.ContactSIPURI.ToParameterlessString() + ";expiry=" + binding.Expiry + bindingIndex + ".", toUser));
                                //FireProxyLogEvent(new SIPMonitorMachineEvent(SIPMonitorMachineEventTypesEnum.SIPRegistrarBindingUpdate, toUser, uacRemoteEndPoint, sipAccount.Id.ToString()));
                                bindingCount++;
                            }

                            // The standard states that the Ok response should contain the list of current bindings but that breaks some UAs. As a
                            // compromise the list is returned with the Contact that UAC sent as the first one in the list.
                            bool contactListSupported = m_userAgentConfigs.GetUserAgentContactListSupport(sipRequest.Header.UserAgent);
                            if (contactListSupported)
                            {
                                sipRequest.Header.Contact = GetContactHeader(bindingsList);
                            }
                            else
                            {
                                // Some user agents can't match the contact header if the expiry is added to it.
                                sipRequest.Header.Contact[0].Expires = GetBindingExpiry(bindingsList, sipRequest.Header.Contact[0].ContactURI.ToString());;
                            }

                            SIPResponse okResponse = GetOkResponse(sipRequest);

                            // If a request was made for a switchboard token and a certificate is available to sign the tokens then generate it.
                            //if (sipRequest.Header.SwitchboardTokenRequest > 0 && m_switchbboardRSAProvider != null)
                            //{
                            //    SwitchboardToken token = new SwitchboardToken(sipRequest.Header.SwitchboardTokenRequest, sipAccount.Owner, uacRemoteEndPoint.Address.ToString());

                            //    lock (m_switchbboardRSAProvider)
                            //    {
                            //        token.SignedHash = Convert.ToBase64String(m_switchbboardRSAProvider.SignHash(Crypto.GetSHAHash(token.GetHashString()), null));
                            //    }

                            //    string tokenXML = token.ToXML(true);
                            //    logger.Debug("Switchboard token set for " + sipAccount.Owner + " with expiry of " + token.Expiry + "s.");
                            //    okResponse.Header.SwitchboardToken = Crypto.SymmetricEncrypt(sipAccount.SIPPassword, sipRequest.Header.AuthenticationHeader.SIPDigest.Nonce, tokenXML);
                            //}

                            registerTransaction.SendFinalResponse(okResponse);
                        }
                        else
                        {
                            // The binding update failed even though the REGISTER request was authorised. This is probably due to a
                            // temporary problem connecting to the bindings data store. Send Ok but set the binding expiry to the minimum so
                            // that the UA will try again as soon as possible.
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Error, "Registration request successful but binding update failed for " + toUser + "@" + canonicalDomain + " from " + registerTransaction.RemoteEndPoint + ".", toUser));
                            sipRequest.Header.Contact[0].Expires = m_minimumBindingExpiry;
                            SIPResponse okResponse = GetOkResponse(sipRequest);
                            registerTransaction.SendFinalResponse(okResponse);
                        }
                    }

                    return(RegisterResultEnum.Authenticated);
                }
            }
            catch (Exception excp)
            {
                string regErrorMessage = "Exception registrarcore registering. " + excp.Message + "\r\n" + registerTransaction.TransactionRequest.ToString();
                logger.Error(regErrorMessage);
                FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Error, regErrorMessage, null));

                try
                {
                    SIPResponse errorResponse = GetErrorResponse(registerTransaction.TransactionRequest, SIPResponseStatusCodesEnum.InternalServerError, null);
                    registerTransaction.SendFinalResponse(errorResponse);
                }
                catch { }

                return(RegisterResultEnum.Error);
            }
        }
        public void AddSubscribeRequest(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest subscribeRequest)
        {
            try
            {
                if (subscribeRequest.Method != SIPMethodsEnum.SUBSCRIBE)
                {
                    SIPResponse notSupportedResponse = SIPTransport.GetResponse(
                        subscribeRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, "Subscribe requests only");
                    m_sipTransport.SendResponse(notSupportedResponse);
                }
                else
                {
                    #region Do as many validation checks as possible on the request before adding it to the queue.

                    if (subscribeRequest.Header.Event.IsNullOrBlank() ||
                        !(subscribeRequest.Header.Event.ToLower() == SIPEventPackage.Dialog.ToString().ToLower() ||
                          subscribeRequest.Header.Event.ToLower() == SIPEventPackage.Presence.ToString().ToLower()))
                    {
                        SIPResponse badEventResponse = SIPTransport.GetResponse(subscribeRequest, SIPResponseStatusCodesEnum.BadEvent, null);
                        m_sipTransport.SendResponse(badEventResponse);
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.Warn, "Event type " + subscribeRequest.Header.Event + " not supported for " + subscribeRequest.URI.ToString() + ".", null));
                    }
                    else if (subscribeRequest.Header.Expires > 0 && subscribeRequest.Header.Expires < MIN_SUBSCRIPTION_EXPIRY)
                    {
                        SIPResponse tooBriefResponse = SIPTransport.GetResponse(subscribeRequest, SIPResponseStatusCodesEnum.IntervalTooBrief, null);
                        tooBriefResponse.Header.MinExpires = MIN_SUBSCRIPTION_EXPIRY;
                        m_sipTransport.SendResponse(tooBriefResponse);
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.Warn, "Subscribe request was rejected as interval too brief " + subscribeRequest.Header.Expires + ".", null));
                    }
                    else if (subscribeRequest.Header.Contact == null || subscribeRequest.Header.Contact.Count == 0)
                    {
                        SIPResponse noContactResponse = SIPTransport.GetResponse(subscribeRequest, SIPResponseStatusCodesEnum.BadRequest, "Missing Contact header");
                        m_sipTransport.SendResponse(noContactResponse);
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.Warn, "Subscribe request was rejected due to no Contact header.", null));
                    }

                    #endregion

                    else
                    {
                        if (m_notifierQueue.Count < MAX_NOTIFIER_QUEUE_SIZE)
                        {
                            SIPNonInviteTransaction subscribeTransaction = m_sipTransport.CreateNonInviteTransaction(
                                subscribeRequest, remoteEndPoint, localSIPEndPoint, m_outboundProxy);
                            lock (m_notifierQueue)
                            {
                                m_notifierQueue.Enqueue(subscribeTransaction);
                            }
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeQueued, "Subscribe queued for " + subscribeRequest.Header.To.ToURI.ToString() + ".", null));
                        }
                        else
                        {
                            logger.Error("Subscribe queue exceeded max queue size " + MAX_NOTIFIER_QUEUE_SIZE + ", overloaded response sent.");
                            SIPResponse overloadedResponse = SIPTransport.GetResponse(subscribeRequest, SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Notifier overloaded, please try again shortly");
                            m_sipTransport.SendResponse(overloadedResponse);
                        }

                        m_notifierARE.Set();
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception AddNotifierRequest (" + remoteEndPoint.ToString() + "). " + excp.Message);
            }
        }
        public async Task HangupUserAgentUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            SIPTransport   transport   = new SIPTransport(false, MockSIPDNSManager.Resolve);
            MockSIPChannel mockChannel = new MockSIPChannel(new System.Net.IPEndPoint(IPAddress.Any, 0));

            transport.AddSIPChannel(mockChannel);

            SIPUserAgent userAgent = new SIPUserAgent(transport, null);

            string inviteReqStr = "INVITE sip:192.168.11.50:5060 SIP/2.0" + m_CRLF +
                                  "Via: SIP/2.0/UDP 192.168.11.50:60163;rport;branch=z9hG4bKPj869f70960bdd4204b1352eaf242a3691" + m_CRLF +
                                  "To: <sip:[email protected]>;tag=ZUJSXRRGXQ" + m_CRLF +
                                  "From: <sip:[email protected]>;tag=4a60ce364b774258873ff199e5e39938" + m_CRLF +
                                  "Call-ID: 17324d6df8744d978008c8997bfd208d" + m_CRLF +
                                  "CSeq: 3532 INVITE" + m_CRLF +
                                  "Contact: <sip:[email protected]:60163;ob>" + m_CRLF +
                                  "Max-Forwards: 70" + m_CRLF +
                                  "User-Agent: MicroSIP/3.19.22" + m_CRLF +
                                  "Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS" + m_CRLF +
                                  "Supported: replaces, 100rel, timer, norefersub" + m_CRLF +
                                  "Content-Length: 343" + m_CRLF +
                                  "Content-Type: application/sdp" + m_CRLF +
                                  "Session-Expires: 1800" + m_CRLF +
                                  "Min-SE: 90" + m_CRLF +
                                  "" + m_CRLF +
                                  "v=0" + m_CRLF +
                                  "o=- 3785527268 3785527269 IN IP4 192.168.11.50" + m_CRLF +
                                  "s=pjmedia" + m_CRLF +
                                  "t=0 0" + m_CRLF +
                                  "m=audio 4032 RTP/AVP 0 101" + m_CRLF +
                                  "c=IN IP4 192.168.11.50" + m_CRLF +
                                  "a=rtpmap:0 PCMU/8000" + m_CRLF +
                                  "a=rtpmap:101 telephone-event/8000" + m_CRLF +
                                  "a=fmtp:101 0-16" + m_CRLF +
                                  "a=sendrecv";

            SIPEndPoint      dummySipEndPoint = new SIPEndPoint(new IPEndPoint(IPAddress.Loopback, 0));
            SIPMessageBuffer sipMessageBuffer = SIPMessageBuffer.ParseSIPMessage(inviteReqStr, dummySipEndPoint, dummySipEndPoint);
            SIPRequest       inviteReq        = SIPRequest.ParseSIPRequest(sipMessageBuffer);

            UASInviteTransaction uasTx   = new UASInviteTransaction(transport, inviteReq, null);
            SIPServerUserAgent   mockUas = new SIPServerUserAgent(transport, null, null, null, SIPCallDirection.In, null, null, null, uasTx);
            await userAgent.Answer(mockUas, CreateMediaSession());

            // Incremented Cseq and modified Via header from original request. Means the request is the same dialog but different tx.
            string inviteReqStr2 = "BYE sip:192.168.11.50:5060 SIP/2.0" + m_CRLF +
                                   "Via: SIP/2.0/UDP 192.168.11.50:60163;rport;branch=z9hG4bKPj869f70960bdd4204b1352eaf242a3700" + m_CRLF +
                                   "To: <sip:[email protected]>;tag=ZUJSXRRGXQ" + m_CRLF +
                                   "From: <sip:[email protected]>;tag=4a60ce364b774258873ff199e5e39938" + m_CRLF +
                                   "Call-ID: 17324d6df8744d978008c8997bfd208d" + m_CRLF +
                                   "CSeq: 3533 BYE" + m_CRLF +
                                   "Contact: <sip:[email protected]:60163;ob>" + m_CRLF +
                                   "Max-Forwards: 70" + m_CRLF +
                                   "User-Agent: MicroSIP/3.19.22" + m_CRLF +
                                   "Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS" + m_CRLF +
                                   "Supported: replaces, 100rel, timer, norefersub" + m_CRLF +
                                   "";

            mockChannel.FireMessageReceived(dummySipEndPoint, dummySipEndPoint, Encoding.UTF8.GetBytes(inviteReqStr2));
        }
        private void Subscribe(SIPTransaction subscribeTransaction)
        {
            try
            {
                SIPRequest sipRequest      = subscribeTransaction.TransactionRequest;
                string     fromUser        = sipRequest.Header.From.FromURI.User;
                string     fromHost        = sipRequest.Header.From.FromURI.Host;
                string     canonicalDomain = GetCanonicalDomain_External(fromHost, true);

                if (canonicalDomain == null)
                {
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.Warn, "Subscribe request for " + fromHost + " rejected as no matching domain found.", null));
                    SIPResponse noDomainResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Forbidden, "Domain not serviced");
                    subscribeTransaction.SendFinalResponse(noDomainResponse);
                    return;
                }

                /** AGL */
                SIPAccount sipAccount = m_sipAssetPersistor.Get(s => s.SIPUsername == fromUser && s.SIPDomain == canonicalDomain);
                //SIPAccount sipAccount = SipServicesSimul.Services.SipHelper.ServerAccount;

                SIPRequestAuthenticationResult authenticationResult = SIPRequestAuthenticator_External(subscribeTransaction.LocalSIPEndPoint, subscribeTransaction.RemoteEndPoint, sipRequest, sipAccount, FireProxyLogEvent);

                if (!authenticationResult.Authenticated)
                {
                    // 401 Response with a fresh nonce needs to be sent.
                    SIPResponse authReqdResponse = SIPTransport.GetResponse(sipRequest, authenticationResult.ErrorResponse, null);
                    authReqdResponse.Header.AuthenticationHeader = authenticationResult.AuthenticationRequiredHeader;
                    subscribeTransaction.SendFinalResponse(authReqdResponse);

                    if (authenticationResult.ErrorResponse == SIPResponseStatusCodesEnum.Forbidden)
                    {
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.Warn, "Forbidden " + fromUser + "@" + canonicalDomain + " does not exist, " + sipRequest.Header.ProxyReceivedFrom.ToString() + ", " + sipRequest.Header.UserAgent + ".", null));
                    }
                    else
                    {
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeAuth, "Authentication required for " + fromUser + "@" + canonicalDomain + " from " + subscribeTransaction.RemoteEndPoint + ".", sipAccount.Owner));
                    }
                    return;
                }
                else
                {
                    if (sipRequest.Header.To.ToTag != null)
                    {
                        // Request is to renew an existing subscription.
                        SIPResponseStatusCodesEnum errorResponse = SIPResponseStatusCodesEnum.None;
                        string errorResponseReason = null;

                        string sessionID = m_subscriptionsManager.RenewSubscription(sipRequest, out errorResponse, out errorResponseReason);
                        if (errorResponse != SIPResponseStatusCodesEnum.None)
                        {
                            // A subscription renewal attempt failed
                            SIPResponse renewalErrorResponse = SIPTransport.GetResponse(sipRequest, errorResponse, errorResponseReason);
                            subscribeTransaction.SendFinalResponse(renewalErrorResponse);
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeFailed, "Subscription renewal failed for event type " + sipRequest.Header.Event + " " + sipRequest.URI.ToString() + ", " + errorResponse + " " + errorResponseReason + ".", sipAccount.Owner));
                        }
                        else if (sipRequest.Header.Expires == 0)
                        {
                            // Existing subscription was closed.
                            SIPResponse okResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                            subscribeTransaction.SendFinalResponse(okResponse);
                        }
                        else
                        {
                            // Existing subscription was found.
                            SIPResponse okResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                            subscribeTransaction.SendFinalResponse(okResponse);
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeRenew, "Subscription renewal for " + sipRequest.URI.ToString() + ", event type " + sipRequest.Header.Event + " and expiry " + sipRequest.Header.Expires + ".", sipAccount.Owner));
                            m_subscriptionsManager.SendFullStateNotify(sessionID);
                        }
                    }
                    else
                    {
                        // Authenticated but the this is a new subscription request and authorisation to subscribe to the requested resource also needs to be checked.
                        SIPURI canonicalResourceURI    = sipRequest.URI.CopyOf();
                        string resourceCanonicalDomain = GetCanonicalDomain_External(canonicalResourceURI.Host, true);
                        canonicalResourceURI.Host = resourceCanonicalDomain;
                        SIPAccount resourceSIPAccount = null;

                        if (resourceCanonicalDomain == null)
                        {
                            SIPResponse notFoundResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotFound, "Domain " + resourceCanonicalDomain + " not serviced");
                            subscribeTransaction.SendFinalResponse(notFoundResponse);
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeFailed, "Subscription failed for " + sipRequest.URI.ToString() + ", event type " + sipRequest.Header.Event + ", domain not serviced.", sipAccount.Owner));
                            return;
                        }

                        if (canonicalResourceURI.User != m_wildcardUser)
                        {
                            /** AGL */
                            resourceSIPAccount = SipServicesSimul.Services.SipHelper.ServerAccount;
                            //resourceSIPAccount = m_sipAssetPersistor.Get(s => s.SIPUsername == canonicalResourceURI.User && s.SIPDomain == canonicalResourceURI.Host);

                            if (resourceSIPAccount == null)
                            {
                                SIPResponse notFoundResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotFound, "Requested resource does not exist");
                                subscribeTransaction.SendFinalResponse(notFoundResponse);
                                FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeFailed, "Subscription failed for " + sipRequest.URI.ToString() + ", event type " + sipRequest.Header.Event + ", SIP account does not exist.", sipAccount.Owner));
                                return;
                            }
                        }

                        // Check the owner permissions on the requesting and subscribed resources.
                        bool   authorised = false;
                        string adminID    = null;

                        if (canonicalResourceURI.User == m_wildcardUser || sipAccount.Owner == resourceSIPAccount.Owner)
                        {
                            authorised = true;
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeAuth, "Subscription to " + canonicalResourceURI.ToString() + " authorised due to common owner.", sipAccount.Owner));
                        }
                        else
                        {
                            // Lookup the customer record for the requestor and check the administrative level on it.
                            Customer requestingCustomer = GetCustomer_External(c => c.CustomerUsername == sipAccount.Owner);
                            adminID = requestingCustomer.AdminId;
                            if (!resourceSIPAccount.AdminMemberId.IsNullOrBlank() && requestingCustomer.AdminId == resourceSIPAccount.AdminMemberId)
                            {
                                authorised = true;
                                FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeAuth, "Subscription to " + canonicalResourceURI.ToString() + " authorised due to requestor admin permissions for domain " + resourceSIPAccount.AdminMemberId + ".", sipAccount.Owner));
                            }
                            else if (requestingCustomer.AdminId == m_topLevelAdminID)
                            {
                                authorised = true;
                                FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeAuth, "Subscription to " + canonicalResourceURI.ToString() + " authorised due to requestor having top level admin permissions.", sipAccount.Owner));
                            }
                        }

                        if (authorised)
                        {
                            // Request is to create a new subscription.
                            SIPResponseStatusCodesEnum errorResponse = SIPResponseStatusCodesEnum.None;
                            string errorResponseReason = null;
                            string toTag     = CallProperties.CreateNewTag();
                            string sessionID = m_subscriptionsManager.SubscribeClient(sipAccount.Owner, adminID, sipRequest, toTag, canonicalResourceURI, out errorResponse, out errorResponseReason);

                            if (errorResponse != SIPResponseStatusCodesEnum.None)
                            {
                                SIPResponse subscribeErrorResponse = SIPTransport.GetResponse(sipRequest, errorResponse, errorResponseReason);
                                subscribeTransaction.SendFinalResponse(subscribeErrorResponse);
                                FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeAccept, "Subscription failed for " + sipRequest.URI.ToString() + ", event type " + sipRequest.Header.Event + ", " + errorResponse + " " + errorResponseReason + ".", sipAccount.Owner));
                            }
                            else
                            {
                                SIPResponse okResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                                okResponse.Header.To.ToTag = toTag;
                                okResponse.Header.Expires  = sipRequest.Header.Expires;
                                okResponse.Header.Contact  = new List <SIPContactHeader>()
                                {
                                    new SIPContactHeader(null, new SIPURI(SIPSchemesEnum.sip, subscribeTransaction.LocalSIPEndPoint))
                                };
                                subscribeTransaction.SendFinalResponse(okResponse);
                                FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeAccept, "Subscription accepted for " + sipRequest.URI.ToString() + ", event type " + sipRequest.Header.Event + " and expiry " + sipRequest.Header.Expires + ".", sipAccount.Owner));

                                if (sessionID != null)
                                {
                                    m_subscriptionsManager.SendFullStateNotify(sessionID);
                                }
                            }
                        }
                        else
                        {
                            SIPResponse forbiddenResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Forbidden, "Requested resource not authorised");
                            subscribeTransaction.SendFinalResponse(forbiddenResponse);
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeFailed, "Subscription failed for " + sipRequest.URI.ToString() + ", event type " + sipRequest.Header.Event + ", requesting account " + sipAccount.Owner + " was not authorised.", sipAccount.Owner));
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception notifiercore subscribing. " + excp.Message + "\r\n" + subscribeTransaction.TransactionRequest.ToString());
                FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.Error, "Exception notifiercore subscribing. " + excp.Message, null));
                SIPResponse errorResponse = SIPTransport.GetResponse(subscribeTransaction.TransactionRequest, SIPResponseStatusCodesEnum.InternalServerError, null);
                subscribeTransaction.SendFinalResponse(errorResponse);
            }
        }
Beispiel #33
0
        public void Progress(SIPResponseStatusCodesEnum progressStatus, string reasonPhrase, string[] customHeaders, string progressContentType, string progressBody)
        {
            try
            {
                if (!IsUASAnswered)
                {
                    if ((int)progressStatus >= 200)
                    {
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "UAS call was passed an invalid response status of " + (int)progressStatus + ", ignoring.", m_owner));
                    }
                    else
                    {
                        if (UASStateChanged != null)
                        {
                            UASStateChanged(this, progressStatus, reasonPhrase);
                        }

                        // Allow all Trying responses through as some may contain additional useful information on the call state for the caller.
                        // Also if the response is a 183 Session Progress with audio forward it.
                        if (m_uasTransaction.TransactionState == SIPTransactionStatesEnum.Proceeding && progressStatus != SIPResponseStatusCodesEnum.Trying &&
                            !(progressStatus == SIPResponseStatusCodesEnum.SessionProgress && progressBody != null))
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "UAS call ignoring progress response with status of " + (int)progressStatus + " as already in " + m_uasTransaction.TransactionState + ".", m_owner));
                        }
                        else
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "UAS call progressing with " + progressStatus + ".", m_owner));
                            SIPResponse progressResponse = SIPTransport.GetResponse(m_uasTransaction.TransactionRequest, progressStatus, reasonPhrase);

                            if (progressResponse.Status != SIPResponseStatusCodesEnum.Trying)
                            {
                                progressResponse.Header.To.ToTag = m_uasTransaction.LocalTag;
                            }

                            if (!progressBody.IsNullOrBlank())
                            {
                                progressResponse.Body = progressBody;
                                progressResponse.Header.ContentType   = progressContentType;
                                progressResponse.Header.ContentLength = progressBody.Length;
                            }

                            if (customHeaders != null && customHeaders.Length > 0)
                            {
                                foreach (string header in customHeaders)
                                {
                                    progressResponse.Header.UnknownHeaders.Add(header);
                                }
                            }

                            m_uasTransaction.SendInformationalResponse(progressResponse);
                        }
                    }
                }
                else
                {
                    logger.Warn("SIPServerUserAgent Progress fired on already answered call.");
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPServerUserAgent Progress. " + excp.Message);
            }
        }
Beispiel #34
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery Blind Transfer Demo: Transferee");
            Console.WriteLine("Waiting for incoming call from Transferor.");
            Console.WriteLine("Press 'q' or ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.

            AddConsoleLogger();

            // Set up a default SIP transport.
            _sipTransport = new SIPTransport();
            _sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT)));

            EnableTraceLogs(_sipTransport);

            var userAgent = new SIPUserAgent(_sipTransport, null);

            userAgent.ServerCallCancelled += (uas) => Log.LogDebug("Incoming call cancelled by remote party.");
            userAgent.OnCallHungup        += (dialog) => Log.LogDebug("Call hungup by remote party.");
            userAgent.OnIncomingCall      += async(ua, req) =>
            {
                var rtpAudioSession = new AudioSendOnlyMediaSession();

                var  uas          = ua.AcceptCall(req);
                bool answerResult = await ua.Answer(uas, rtpAudioSession);

                Log.LogDebug($"Answer incoming call result {answerResult}.");

                _ = Task.Run(async() =>
                {
                    await Task.Delay(1000);

                    Log.LogDebug($"Sending DTMF sequence {string.Join("", DTMF_SEQUENCEFOR_TRANSFEROR.Select(x => x))}.");
                    foreach (byte dtmf in DTMF_SEQUENCEFOR_TRANSFEROR)
                    {
                        Log.LogDebug($"Sending DTMF tone to transferor {dtmf}.");
                        await ua.SendDtmf(dtmf);
                    }
                });
            };
            userAgent.OnTransferRequested          += (referredTo, referredBy) => true;
            userAgent.OnTransferToTargetSuccessful += (dst) =>
            {
                Task.Run(async() =>
                {
                    await Task.Delay(1000);

                    Log.LogDebug($"Sending DTMF sequence {string.Join("", DTMF_SEQUENCEFOR_TRANSFEROR.Select(x => x))}.");
                    foreach (byte dtmf in DTMF_SEQUENCEFOR_TRANSFEROR)
                    {
                        Log.LogDebug($"Sending DTMF tone to target {dtmf}.");
                        await userAgent.SendDtmf(dtmf);
                    }
                });
            };

            Task.Run(() => OnKeyPress(userAgent, exitCts));

            exitCts.Token.WaitHandle.WaitOne();

            #region Cleanup.

            Log.LogInformation("Exiting...");

            //userAgent?.Hangup();

            // Give any BYE or CANCEL requests time to be transmitted.
            Log.LogInformation("Waiting 1s for calls to be cleaned up...");
            Task.Delay(1000).Wait();

            if (_sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                _sipTransport.Shutdown();
            }

            #endregion
        }
Beispiel #35
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery user agent server example.");
            Console.WriteLine("Press h to hangup a call or ctrl-c to exit.");

            Log = AddConsoleLogger();

            IPAddress listenAddress     = IPAddress.Any;
            IPAddress listenIPv6Address = IPAddress.IPv6Any;

            if (args != null && args.Length > 0)
            {
                if (!IPAddress.TryParse(args[0], out var customListenAddress))
                {
                    Log.LogWarning($"Command line argument could not be parsed as an IP address \"{args[0]}\"");
                    listenAddress = IPAddress.Any;
                }
                else
                {
                    if (customListenAddress.AddressFamily == AddressFamily.InterNetwork)
                    {
                        listenAddress = customListenAddress;
                    }
                    if (customListenAddress.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        listenIPv6Address = customListenAddress;
                    }
                }
            }

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            var localhostCertificate = new X509Certificate2(SIPS_CERTIFICATE_PATH);

            // IPv4 channels.
            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(listenAddress, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTCPChannel(new IPEndPoint(listenAddress, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTLSChannel(localhostCertificate, new IPEndPoint(listenAddress, SIPS_LISTEN_PORT)));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.Any, SIP_WEBSOCKET_LISTEN_PORT));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.Any, SIP_SECURE_WEBSOCKET_LISTEN_PORT, localhostCertificate));

            // IPv6 channels.
            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(listenIPv6Address, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTCPChannel(new IPEndPoint(listenIPv6Address, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTLSChannel(localhostCertificate, new IPEndPoint(listenIPv6Address, SIPS_LISTEN_PORT)));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.IPv6Any, SIP_WEBSOCKET_LISTEN_PORT));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.IPv6Any, SIP_SECURE_WEBSOCKET_LISTEN_PORT, localhostCertificate));

            EnableTraceLogs(sipTransport);

            string executableDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            // To keep things a bit simpler this example only supports a single call at a time and the SIP server user agent
            // acts as a singleton
            SIPServerUserAgent      uas        = null;
            CancellationTokenSource rtpCts     = null; // Cancellation token to stop the RTP stream.
            VoIPMediaSession        rtpSession = null;

            // Because this is a server user agent the SIP transport must start listening for client user agents.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                try
                {
                    if (sipRequest.Method == SIPMethodsEnum.INVITE)
                    {
                        Log.LogInformation($"Incoming call request: {localSIPEndPoint}<-{remoteEndPoint} {sipRequest.URI}.");

                        // Check there's a codec we support in the INVITE offer.
                        var        offerSdp       = SDP.ParseSDPDescription(sipRequest.Body);
                        IPEndPoint dstRtpEndPoint = SDP.GetSDPRTPEndPoint(sipRequest.Body);

                        if (offerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.HasMediaFormat((int)SDPMediaFormatsEnum.PCMU)))
                        {
                            Log.LogDebug($"Client offer contained PCMU audio codec.");
                            AudioExtrasSource extrasSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions {
                                AudioSource = AudioSourcesEnum.Music
                            });
                            rtpSession = new VoIPMediaSession(new MediaEndPoints {
                                AudioSource = extrasSource
                            });
                            rtpSession.AcceptRtpFromAny = true;

                            var setResult = rtpSession.SetRemoteDescription(SdpType.offer, offerSdp);

                            if (setResult != SetDescriptionResultEnum.OK)
                            {
                                // Didn't get a match on the codecs we support.
                                SIPResponse noMatchingCodecResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptableHere, setResult.ToString());
                                await sipTransport.SendResponseAsync(noMatchingCodecResponse);
                            }
                            else
                            {
                                // If there's already a call in progress hang it up. Of course this is not ideal for a real softphone or server but it
                                // means this example can be kept simpler.
                                if (uas?.IsHungup == false)
                                {
                                    uas?.Hangup(false);
                                }
                                rtpCts?.Cancel();
                                rtpCts = new CancellationTokenSource();

                                UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null);
                                uas = new SIPServerUserAgent(sipTransport, null, null, null, SIPCallDirection.In, null, null, uasTransaction);
                                uas.CallCancelled += (uasAgent) =>
                                {
                                    rtpCts?.Cancel();
                                    rtpSession.Close(null);
                                };
                                rtpSession.OnRtpClosed += (reason) => uas?.Hangup(false);
                                uas.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null);
                                uas.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null);

                                var answerSdp = rtpSession.CreateAnswer(null);
                                uas.Answer(SDP.SDP_MIME_CONTENTTYPE, answerSdp.ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);

                                await rtpSession.Start();
                            }
                        }
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.BYE)
                    {
                        Log.LogInformation("Call hungup.");
                        SIPResponse byeResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        await sipTransport.SendResponseAsync(byeResponse);

                        uas?.Hangup(true);
                        rtpSession?.Close(null);
                        rtpCts?.Cancel();
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.SUBSCRIBE)
                    {
                        SIPResponse notAllowededResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                        await sipTransport.SendResponseAsync(notAllowededResponse);
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.OPTIONS || sipRequest.Method == SIPMethodsEnum.REGISTER)
                    {
                        SIPResponse optionsResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        await sipTransport.SendResponseAsync(optionsResponse);
                    }
                }
                catch (Exception reqExcp)
                {
                    Log.LogWarning($"Exception handling {sipRequest.Method}. {reqExcp.Message}");
                }
            };

            ManualResetEvent exitMre = new ManualResetEvent(false);

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;

                Log.LogInformation("Exiting...");

                Hangup(uas).Wait();

                rtpSession?.Close(null);
                rtpCts?.Cancel();

                if (sipTransport != null)
                {
                    Log.LogInformation("Shutting down SIP transport...");
                    sipTransport.Shutdown();
                }

                exitMre.Set();
            };

            // Task to handle user key presses.
            Task.Run(() =>
            {
                try
                {
                    while (!exitMre.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();
                        if (keyProps.KeyChar == 'h' || keyProps.KeyChar == 'q')
                        {
                            Console.WriteLine();
                            Console.WriteLine("Hangup requested by user...");

                            Hangup(uas).Wait();

                            rtpSession?.Close(null);
                            rtpCts?.Cancel();
                        }

                        if (keyProps.KeyChar == 'q')
                        {
                            Log.LogInformation("Quitting...");

                            if (sipTransport != null)
                            {
                                Log.LogInformation("Shutting down SIP transport...");
                                sipTransport.Shutdown();
                            }

                            exitMre.Set();
                        }
                    }
                }
                catch (Exception excp)
                {
                    Log.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

            exitMre.WaitOne();
        }
Beispiel #36
0
        public void GotRequest(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest)
        {
            try
            {
                // Used in the proxy monitor messages only, plays no part in request routing.
                string fromUser   = (sipRequest.Header.From != null) ? sipRequest.Header.From.FromURI.User : null;
                string fromURIStr = (sipRequest.Header.From != null) ? sipRequest.Header.From.FromURI.ToString() : "null";
                //string toUser = (sipRequest.Header.To != null) ? sipRequest.Header.To.ToURI.User : null;
                //string summaryStr = "req " + sipRequest.Method + " from=" + fromUser + ", to=" + toUser + ", " + remoteEndPoint.ToString();
                //logger.Debug("AppServerCore GotRequest " + sipRequest.Method + " from " + remoteEndPoint.ToString() + " callid=" + sipRequest.Header.CallId + ".");

                SIPDialogue dialogue = null;

                // Check dialogue requests for an existing dialogue.
                if ((sipRequest.Method == SIPMethodsEnum.BYE || sipRequest.Method == SIPMethodsEnum.INFO || sipRequest.Method == SIPMethodsEnum.INVITE ||
                     sipRequest.Method == SIPMethodsEnum.MESSAGE || sipRequest.Method == SIPMethodsEnum.NOTIFY || sipRequest.Method == SIPMethodsEnum.OPTIONS ||
                     sipRequest.Method == SIPMethodsEnum.REFER) &&
                    sipRequest.Header.From != null && sipRequest.Header.From.FromTag != null && sipRequest.Header.To != null && sipRequest.Header.To.ToTag != null)
                {
                    dialogue = m_sipDialogueManager.GetDialogue(sipRequest);
                }

                if (dialogue != null && sipRequest.Method != SIPMethodsEnum.ACK)
                {
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Matching dialogue found for " + sipRequest.Method + " to " + sipRequest.URI.ToString() + " from " + remoteEndPoint + ".", dialogue.Owner));
                    if (sipRequest.Method != SIPMethodsEnum.REFER)
                    {
                        m_sipDialogueManager.ProcessInDialogueRequest(localSIPEndPoint, remoteEndPoint, sipRequest, dialogue);
                    }
                    else
                    {
                        m_sipDialogueManager.ProcessInDialogueReferRequest(localSIPEndPoint, remoteEndPoint, sipRequest, dialogue, m_callManager.BlindTransfer);
                    }
                }
                else if (sipRequest.Method == SIPMethodsEnum.CANCEL)
                {
                    #region CANCEL request handling.

                    UASInviteTransaction inviteTransaction = (UASInviteTransaction)m_sipTransport.GetTransaction(SIPTransaction.GetRequestTransactionId(sipRequest.Header.Vias.TopViaHeader.Branch, SIPMethodsEnum.INVITE));

                    if (inviteTransaction != null)
                    {
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Cancelling call for " + sipRequest.URI.ToString() + ".", fromUser));
                        SIPCancelTransaction cancelTransaction = m_sipTransport.CreateCancelTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, inviteTransaction);
                        cancelTransaction.GotRequest(localSIPEndPoint, remoteEndPoint, sipRequest);
                    }
                    else
                    {
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No matching transaction was found for CANCEL to " + sipRequest.URI.ToString() + ".", fromUser));
                        SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null);
                        m_sipTransport.SendResponse(noCallLegResponse);
                    }

                    #endregion
                }
                else if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No dialogue matched for BYE to " + sipRequest.URI.ToString() + ".", fromUser));
                    SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null);
                    m_sipTransport.SendResponse(noCallLegResponse);
                }
                else if (sipRequest.Method == SIPMethodsEnum.REFER)
                {
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No dialogue matched for REFER to " + sipRequest.URI.ToString() + ".", fromUser));
                    SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null);
                    m_sipTransport.SendResponse(noCallLegResponse);
                }
                else if (sipRequest.Method == SIPMethodsEnum.ACK)
                {
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No transaction matched for ACK for " + sipRequest.URI.ToString() + ".", fromUser));
                }
                else if (sipRequest.Method == SIPMethodsEnum.INVITE)
                {
                    #region INVITE request processing.

                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "AppServerCore INVITE received, uri=" + sipRequest.URI.ToString() + ", cseq=" + sipRequest.Header.CSeq + ".", null));

                    if (sipRequest.URI.User == m_dispatcherUsername)
                    {
                        // Incoming call from monitoring process checking the application server is still running.
                        UASInviteTransaction uasTransaction = m_sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, m_outboundProxy, true);
                        //uasTransaction.CDR = null;
                        SIPServerUserAgent incomingCall = new SIPServerUserAgent(m_sipTransport, m_outboundProxy, sipRequest.URI.User, sipRequest.URI.Host, SIPCallDirection.In, null, null, null, uasTransaction);
                        //incomingCall.NoCDR();
                        uasTransaction.NewCallReceived += (local, remote, transaction, request) => { m_callManager.QueueNewCall(incomingCall); };
                        uasTransaction.GotRequest(localSIPEndPoint, remoteEndPoint, sipRequest);
                    }
                    else if (GetCanonicalDomain_External(sipRequest.Header.From.FromUserField.URI.Host, false) != null)
                    {
                        // Call identified as outgoing call for application server serviced domain.
                        string fromDomain = GetCanonicalDomain_External(sipRequest.Header.From.FromUserField.URI.Host, false);
                        UASInviteTransaction uasTransaction = m_sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, m_outboundProxy);
                        SIPServerUserAgent   outgoingCall   = new SIPServerUserAgent(m_sipTransport, m_outboundProxy, fromUser, fromDomain, SIPCallDirection.Out, GetSIPAccount_External, SIPRequestAuthenticator.AuthenticateSIPRequest, FireProxyLogEvent, uasTransaction);
                        uasTransaction.NewCallReceived += (local, remote, transaction, request) => { m_callManager.QueueNewCall(outgoingCall); };
                        uasTransaction.GotRequest(localSIPEndPoint, remoteEndPoint, sipRequest);
                    }
                    else if (GetCanonicalDomain_External(sipRequest.URI.Host, true) != null)
                    {
                        // Call identified as incoming call for application server serviced domain.
                        if (sipRequest.URI.User.IsNullOrBlank())
                        {
                            // Cannot process incoming call if no user is specified.
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "INVITE received with an empty URI user " + sipRequest.URI.ToString() + ", returning address incomplete.", null));
                            UASInviteTransaction uasTransaction            = m_sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, m_outboundProxy);
                            SIPResponse          addressIncompleteResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.AddressIncomplete, "No user specified");
                            uasTransaction.SendFinalResponse(addressIncompleteResponse);
                        }
                        else
                        {
                            // Send the incoming call to the call manager for processing.
                            string uriUser   = sipRequest.URI.User;
                            string uriDomain = GetCanonicalDomain_External(sipRequest.URI.Host, true);
                            UASInviteTransaction uasTransaction = m_sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, m_outboundProxy);
                            SIPServerUserAgent   incomingCall   = new SIPServerUserAgent(m_sipTransport, m_outboundProxy, uriUser, uriDomain, SIPCallDirection.In, GetSIPAccount_External, null, FireProxyLogEvent, uasTransaction);
                            uasTransaction.NewCallReceived += (local, remote, transaction, request) => { m_callManager.QueueNewCall(incomingCall); };
                            uasTransaction.GotRequest(localSIPEndPoint, remoteEndPoint, sipRequest);
                        }
                    }
                    else
                    {
                        // Return not found for non-serviced domain.
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Domain not serviced " + sipRequest.URI.ToString() + ", returning not found.", null));
                        UASInviteTransaction uasTransaction      = m_sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, m_outboundProxy);
                        SIPResponse          notServicedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotFound, "Domain not serviced");
                        uasTransaction.SendFinalResponse(notServicedResponse);
                    }

                    #endregion
                }
                else if (sipRequest.Method == SIPMethodsEnum.MESSAGE)
                {
                    #region Processing non-INVITE requests that are accepted by the dialplan processing engine.

                    if (GetCanonicalDomain_External(sipRequest.Header.From.FromUserField.URI.Host, false) != null)
                    {
                        // Call identified as outgoing request for application server serviced domain.
                        string fromDomain = GetCanonicalDomain_External(sipRequest.Header.From.FromUserField.URI.Host, false);
                        SIPNonInviteTransaction     nonInviteTransaction = m_sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, m_outboundProxy);
                        SIPNonInviteServerUserAgent outgoingRequest      = new SIPNonInviteServerUserAgent(m_sipTransport, m_outboundProxy, fromUser, fromDomain, SIPCallDirection.Out, GetSIPAccount_External, SIPRequestAuthenticator.AuthenticateSIPRequest, FireProxyLogEvent, nonInviteTransaction);
                        nonInviteTransaction.NonInviteRequestReceived += (local, remote, transaction, request) => { m_callManager.QueueNewCall(outgoingRequest); };
                        nonInviteTransaction.GotRequest(localSIPEndPoint, remoteEndPoint, sipRequest);
                    }
                    else if (GetCanonicalDomain_External(sipRequest.URI.Host, true) != null)
                    {
                        // Call identified as incoming call for application server serviced domain.
                        if (sipRequest.URI.User.IsNullOrBlank())
                        {
                            // Cannot process incoming call if no user is specified.
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, sipRequest.Method + " request received with an empty URI user " + sipRequest.URI.ToString() + ", returning address incomplete.", null));
                            SIPResponse addressIncompleteResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.AddressIncomplete, "No user specified");
                            m_sipTransport.SendResponse(addressIncompleteResponse);
                        }
                        else
                        {
                            // Send the incoming call to the call manager for processing.
                            string uriUser   = sipRequest.URI.User;
                            string uriDomain = GetCanonicalDomain_External(sipRequest.URI.Host, true);
                            SIPNonInviteTransaction     nonInviteTransaction = m_sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, m_outboundProxy);
                            SIPNonInviteServerUserAgent incomingRequest      = new SIPNonInviteServerUserAgent(m_sipTransport, m_outboundProxy, uriUser, uriDomain, SIPCallDirection.In, GetSIPAccount_External, null, FireProxyLogEvent, nonInviteTransaction);
                            nonInviteTransaction.NonInviteRequestReceived += (local, remote, transaction, request) => { m_callManager.QueueNewCall(incomingRequest); };
                            nonInviteTransaction.GotRequest(localSIPEndPoint, remoteEndPoint, sipRequest);
                        }
                    }
                    else
                    {
                        // Return not found for non-serviced domain.
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Domain not serviced " + sipRequest.URI.ToString() + ", returning not found.", null));
                        SIPResponse notServicedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotFound, "Domain not serviced");
                        m_sipTransport.SendResponse(notServicedResponse);
                    }

                    #endregion
                }
                else
                {
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.UnrecognisedMessage, "MethodNotAllowed response for " + sipRequest.Method + " from " + fromUser + " socket " + remoteEndPoint.ToString() + ".", null));
                    SIPResponse notAllowedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                    m_sipTransport.SendResponse(notAllowedResponse);
                }
            }
            catch (Exception excp)
            {
                string reqExcpError = "Exception SIPAppServerCore GotRequest (" + remoteEndPoint + "). " + excp.Message;
                logger.Error(reqExcpError);
                SIPMonitorEvent reqExcpEvent = new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.Error, reqExcpError, sipRequest, null, localSIPEndPoint, remoteEndPoint, SIPCallDirection.In);
                FireProxyLogEvent(reqExcpEvent);
                throw excp;
            }
        }
Beispiel #37
0
        public SIPTransactionEngine(SIPTransport sipTransport)
        {
            m_sipTransport = sipTransport;

            Task.Factory.StartNew(ProcessPendingTransactions, TaskCreationOptions.LongRunning);
        }
 public virtual void Initialize(SIPAuthenticateRequestDelegate sipRequestAuthenticator, SIPAccount account, SIPTransport trasnport)
 {
 }