Exemple #1
0
        private static void SIPTransportRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest)
        {
            if (sipRequest.Method == SIPMethodsEnum.INVITE)
            {
                Console.WriteLine("INVITE received from  " + localSIPEndPoint.ToString());
                IPEndPoint sipPhoneEndPoint = SDP.GetSDPRTPEndPoint(sipRequest.Body);

                UASInviteTransaction uasTransaction = m_sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                SIPServerUserAgent   uas            = new SIPServerUserAgent(m_sipTransport, null, null, null, SIPCallDirection.In, null, null, null, uasTransaction);

                SIPResponse tryingResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Trying, null);
                uasTransaction.SendInformationalResponse(tryingResponse);

                if (m_xmppClient == null)
                {
                    m_xmppClient = new XMPPClient(XMPP_SERVER, XMPP_SERVER_PORT, XMPP_REALM, m_xmppUsername, m_xmppPassword);
                    m_xmppClient.Disconnected += XMPPDisconnected;
                    m_xmppClient.IsBound      += () => { XMPPPlaceCall(uas); };
                    ThreadPool.QueueUserWorkItem(delegate { m_xmppClient.Connect(); });
                }
                else
                {
                    XMPPPlaceCall(uas);
                }
            }
            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() + ".");
                    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() + ".");
                    SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null);
                    m_sipTransport.SendResponse(noCallLegResponse);
                }
            }
            else if (sipRequest.Method == SIPMethodsEnum.BYE)
            {
                Console.WriteLine("BYE request received.");

                if (m_activeCalls.ContainsKey(sipRequest.Header.CallId))
                {
                    SIPResponse okResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    m_sipTransport.SendResponse(okResponse);
                    m_activeCalls[sipRequest.Header.CallId].TerminateXMPPCall();
                    m_activeCalls.Remove(sipRequest.Header.CallId);
                }
                else
                {
                    SIPResponse doesntExistResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null);
                    m_sipTransport.SendResponse(doesntExistResponse);
                }
            }
        }
        public async Task CancelCallUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            SIPTransport aliceTransport = new SIPTransport();

            aliceTransport.AddSIPChannel(new SIPUDPChannel(IPAddress.Loopback, 0));
            var alice = new SIPUserAgent(aliceTransport, null, true);
            SIPServerUserAgent uas = null;

            // Auto accept but NOT answering.
            alice.OnIncomingCall += (ua, req) => uas = ua.AcceptCall(req);

            SIPTransport bobTransport = new SIPTransport();

            bobTransport.AddSIPChannel(new SIPUDPChannel(IPAddress.Loopback, 0));
            var bob = new SIPUserAgent(bobTransport, null, true);

            var callTask = bob.Call(alice.ContactURI.ToString(), null, null, CreateMediaSession());

            await Task.Delay(500);

            Assert.True(bob.IsRinging);
            Assert.NotNull(uas);
            Assert.False(uas.IsCancelled);

            bob.Cancel();

            await Task.Delay(500);

            Assert.False(alice.IsCallActive);
            Assert.False(bob.IsCallActive);
            Assert.True(uas.IsCancelled);
        }
Exemple #3
0
        /// <summary>
        /// Answers an incoming SIP call.
        /// </summary>
        public async Task <bool> Answer()
        {
            if (m_pendingIncomingCall == null)
            {
                StatusMessage(this, $"There was no pending call available to answer.");
                return(false);
            }
            else
            {
                var sipRequest = m_pendingIncomingCall.ClientTransaction.TransactionRequest;

                // Assume that if the INVITE request does not contain an SDP offer that it will be an
                // audio only call.
                bool hasAudio = true;
                bool hasVideo = false;

                if (sipRequest.Body != null)
                {
                    SDP offerSDP = SDP.ParseSDPDescription(sipRequest.Body);
                    hasAudio = offerSDP.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.MediaStreamStatus != MediaStreamStatusEnum.Inactive);
                    hasVideo = offerSDP.Media.Any(x => x.Media == SDPMediaTypesEnum.video && x.MediaStreamStatus != MediaStreamStatusEnum.Inactive);
                }

                MediaSession = CreateMediaSession();

                m_userAgent.RemotePutOnHold   += OnRemotePutOnHold;
                m_userAgent.RemoteTookOffHold += OnRemoteTookOffHold;

                bool result = await m_userAgent.Answer(m_pendingIncomingCall, MediaSession);

                m_pendingIncomingCall = null;

                return(result);
            }
        }
Exemple #4
0
 private static void XMPPPlaceCall(SIPServerUserAgent uas)
 {
     if (!uas.IsCancelled)
     {
         XMPPPhoneSession phoneSession = m_xmppClient.GetPhoneSession();
         SIPToXMPPCall    call         = new SIPToXMPPCall(uas, phoneSession, m_sipTransport, m_ipAddress);
         m_activeCalls.Add(uas.CallRequest.Header.CallId, call);
         call.Call(uas.CallRequest.URI.User);
     }
 }
        public async Task BlindTransferCancelUnitTest()
        {
            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)));

            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.Any, 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());

            CancellationTokenSource cts = new CancellationTokenSource();
            var blindTransferTask       = userAgent.BlindTransfer(SIPURI.ParseSIPURIRelaxed("127.0.0.1"), TimeSpan.FromSeconds(2), cts.Token);

            cts.Cancel();

            Assert.False(await blindTransferTask);

            //await Assert.ThrowsAnyAsync<TaskCanceledException>(async () => { bool result = ; });
        }
Exemple #6
0
        /// <summary>
        /// Answers an incoming SIP call.
        /// </summary>
        public async Task <bool> Answer()
        {
            if (m_pendingIncomingCall == null)
            {
                StatusMessage(this, $"There was no pending call available to answer.");
                return(false);
            }
            else
            {
                var sipRequest = m_pendingIncomingCall.ClientTransaction.TransactionRequest;

                SDP  offerSDP = SDP.ParseSDPDescription(sipRequest.Body);
                bool hasAudio = offerSDP.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.MediaStreamStatus != MediaStreamStatusEnum.Inactive);
                bool hasVideo = offerSDP.Media.Any(x => x.Media == SDPMediaTypesEnum.video && x.MediaStreamStatus != MediaStreamStatusEnum.Inactive);

                AudioOptions audioOpts = new AudioOptions {
                    AudioSource = AudioSourcesEnum.None
                };
                if (hasAudio)
                {
                    audioOpts = new AudioOptions
                    {
                        AudioSource       = AudioSourcesEnum.CaptureDevice,
                        OutputDeviceIndex = m_audioOutDeviceIndex,
                        AudioCodecs       = new List <SDPMediaFormatsEnum> {
                            SDPMediaFormatsEnum.PCMU, SDPMediaFormatsEnum.PCMA
                        }
                    };
                }

                VideoOptions videoOpts = new VideoOptions {
                    VideoSource = VideoSourcesEnum.None
                };
                if (hasVideo)
                {
                    videoOpts = new VideoOptions
                    {
                        VideoSource           = VideoSourcesEnum.TestPattern,
                        SourceFile            = RtpAVSession.VIDEO_TESTPATTERN,
                        SourceFramesPerSecond = VIDEO_LIVE_FRAMES_PER_SECOND
                    };
                }

                MediaSession = new RtpAVSession(audioOpts, videoOpts);

                m_userAgent.RemotePutOnHold   += OnRemotePutOnHold;
                m_userAgent.RemoteTookOffHold += OnRemoteTookOffHold;

                bool result = await m_userAgent.Answer(m_pendingIncomingCall, MediaSession);

                m_pendingIncomingCall = null;

                return(result);
            }
        }
Exemple #7
0
        public SIPToXMPPCall(SIPServerUserAgent uas, XMPPPhoneSession xmppCall, SIPTransport sipTransport, IPAddress ipAddress)
        {
            m_uas          = uas;
            m_xmppCall     = xmppCall;
            m_sipTransport = sipTransport;
            m_ipAddress    = ipAddress;

            m_uas.CallCancelled += SIPCallCancelled;
            m_xmppCall.Accepted += Answered;
            m_xmppCall.Rejected += CallFailed;
            m_xmppCall.Hungup   += Hangup;
        }
Exemple #8
0
        /// <summary>
        /// Cleans up after a SIP call has completely finished.
        /// </summary>
        private void CallFinished()
        {
            if (_mediaManager != null)
            {
                _mediaManager.EndCall();
                _mediaManager = null;
            }

            m_uac = null;
            m_uas = null;

            CallEnded();
        }
        private DialPlanLineContext GetDummyDialPlanContext(string testDialPlan, string dst)
        {
            SIPDialPlan          dialPlan          = new SIPDialPlan(null, null, null, testDialPlan, SIPDialPlanScriptTypesEnum.Asterisk);
            SIPTransactionEngine transactionEngine = new SIPTransactionEngine();
            SIPTransport         sipTransport      = new SIPTransport(MockSIPDNSManager.Resolve, transactionEngine);
            SIPURI               dummyURI          = SIPURI.ParseSIPURI(dst);
            SIPRequest           inviteRequest     = GetDummyINVITERequest(dummyURI);
            SIPEndPoint          dummyEndPoint     = SIPEndPoint.ParseSIPEndPoint("udp:0.0.0.0:5060");
            UASInviteTransaction uasTransaction    = sipTransport.CreateUASTransaction(inviteRequest, dummyEndPoint, dummyEndPoint, null);
            SIPServerUserAgent   uas             = new SIPServerUserAgent(sipTransport, null, "test", "sipsorcery.com", SIPCallDirection.In, null, null, null, uasTransaction);
            DialPlanLineContext  dialPlanContext = new DialPlanLineContext(null, null, null, null, uas, dialPlan, null, null, null, null);

            return(dialPlanContext);
        }
Exemple #10
0
        /// <summary>
        /// Cleans up after a SIP call has completely finished.
        /// </summary>
        private void CallFinished()
        {
            if (_mediaManager != null)
            {
                _mediaManager.EndCall();
                _mediaManager = null;
            }

            //_cancelCallTokenSource.Cancel();

            m_uac = null;
            m_uas = null;

            CallEnded();
        }
Exemple #11
0
        /// <summary>
        /// Answers an incoming SIP call.
        /// </summary>
        public async Task Answer()
        {
            if (m_pendingIncomingCall == null)
            {
                StatusMessage(this, $"There was no pending call available to answer.");
            }
            else
            {
                var sipRequest = m_pendingIncomingCall.ClientTransaction.TransactionRequest;

                SDP  offerSDP = SDP.ParseSDPDescription(sipRequest.Body);
                bool hasAudio = offerSDP.Media.Any(x => x.Media == SDPMediaTypesEnum.audio);
                bool hasVideo = offerSDP.Media.Any(x => x.Media == SDPMediaTypesEnum.video);

                AudioOptions audioOpts = new AudioOptions {
                    AudioSource = AudioSourcesEnum.None
                };
                if (hasAudio)
                {
                    audioOpts = new AudioOptions {
                        AudioSource = AudioSourcesEnum.Microphone
                    };
                }

                VideoOptions videoOpts = new VideoOptions {
                    VideoSource = VideoSourcesEnum.None
                };
                if (hasVideo)
                {
                    videoOpts = new VideoOptions
                    {
                        VideoSource           = VideoSourcesEnum.TestPattern,
                        SourceFile            = RtpAVSession.VIDEO_TESTPATTERN,
                        SourceFramesPerSecond = VIDEO_LIVE_FRAMES_PER_SECOND
                    };
                }

                MediaSession = new RtpAVSession(sipRequest.RemoteSIPEndPoint.Address.AddressFamily, audioOpts, videoOpts);

                m_userAgent.RemotePutOnHold   += OnRemotePutOnHold;
                m_userAgent.RemoteTookOffHold += OnRemoteTookOffHold;

                await m_userAgent.Answer(m_pendingIncomingCall, MediaSession);

                m_pendingIncomingCall = null;
            }
        }
Exemple #12
0
        /// <summary>
        /// Hangs up the current call.
        /// </summary>
        /// <param name="uas">The user agent server to hangup the call on.</param>
        private static async Task Hangup(SIPServerUserAgent uas)
        {
            try
            {
                if (uas?.IsHungup == false)
                {
                    uas?.Hangup(false);

                    // Give the BYE or CANCEL request time to be transmitted.
                    SIPSorcery.Sys.Log.Logger.LogInformation("Waiting 1s for call to hangup...");
                    await Task.Delay(1000);
                }
            }
            catch (Exception excp)
            {
                SIPSorcery.Sys.Log.Logger.LogError($"Exception Hangup. {excp.Message}");
            }
        }
Exemple #13
0
        /// <summary>
        /// Answers an incoming SIP call.
        /// </summary>
        public async Task Answer()
        {
            if (m_pendingIncomingCall == null)
            {
                StatusMessage(this, $"There was no pending call available to answer.");
            }
            else
            {
                var sipRequest = m_pendingIncomingCall.ClientTransaction.TransactionRequest;
                m_rtpMediaSessionManager.Create(sipRequest.RemoteSIPEndPoint.Address.AddressFamily);
                m_rtpMediaSessionManager.RTPMediaSession.RemotePutOnHold   += OnRemotePutOnHold;
                m_rtpMediaSessionManager.RTPMediaSession.RemoteTookOffHold += OnRemoteTookOffHold;

                await m_userAgent.Answer(m_pendingIncomingCall, m_rtpMediaSessionManager.RTPMediaSession);

                m_pendingIncomingCall = null;
            }
        }
Exemple #14
0
        /// <param name="rtpListenAddress">The local IP address to establish the RTP listener socket on.</param>
        /// <param name="sdpAdvertiseAddress">The public IP address to put into the SDP sent back to the caller.</param>
        /// <param name="request">The INVITE request that instigated the RTP diagnostics job.</param>
        public RTPDiagnosticsJob(IPAddress rtpListenAddress, IPAddress sdpAdvertiseAddress, SIPServerUserAgent uas, SIPRequest request)
        {
            m_request         = request;
            m_remoteSDP       = SDP.ParseSDPDescription(request.Body);
            RemoteRTPEndPoint = new IPEndPoint(IPAddress.Parse(m_remoteSDP.Connection.ConnectionAddress), m_remoteSDP.Media[0].Port);
            UAS = uas;
            //m_rawSourceStream = new RawSourceWaveStream(m_outStream, WaveFormat.CreateMuLawFormat(8000, 1));
            //m_waveFileWriter = new WaveFileWriter("out.wav", new WaveFormat(8000, 16, 1));
            m_waveFileWriter = new WaveFileWriter("out.wav", new WaveFormat(8000, 16, 1));
            //m_outPCMStream = WaveFormatConversionStream.CreatePcmStream(m_rawSourceStream);
            //m_rawRTPPayloadWriter = new StreamWriter("out.rtp");
            //m_rawRTPPayloadReader = new StreamReader("in.rtp");
            //IPEndPoint rtpListenEndPoint = null;
            IPEndPoint rtpListenEndPoint = null;

            NetServices.CreateRandomUDPListener(rtpListenAddress, RTP_PORTRANGE_START, RTP_PORTRANGE_END, m_inUsePorts, out rtpListenEndPoint);
            RTPListenEndPoint = rtpListenEndPoint;
            m_inUsePorts.Add(rtpListenEndPoint.Port);
            //RTPListenEndPoint = new IPEndPoint(rtpListenAddress, RTP_PORTRANGE_START);
            m_rtpChannel = new RTPChannel(RTPListenEndPoint);
            m_rtpChannel.SampleReceived += SampleReceived;
            ThreadPool.QueueUserWorkItem(delegate { GetAudioSamples(); });

            LocalSDP = new SDP()
            {
                SessionId   = Crypto.GetRandomString(6),
                Address     = sdpAdvertiseAddress.ToString(),
                SessionName = "sipsorcery",
                Timing      = "0 0",
                Connection  = new SDPConnectionInformation(sdpAdvertiseAddress.ToString()),
                Media       = new List <SDPMediaAnnouncement>()
                {
                    new SDPMediaAnnouncement()
                    {
                        Media        = SDPMediaTypesEnum.audio,
                        Port         = RTPListenEndPoint.Port,
                        MediaFormats = new List <SDPMediaFormat>()
                        {
                            new SDPMediaFormat((int)SDPMediaFormatsEnum.PCMU)
                        }
                    }
                }
            };
        }
Exemple #15
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.");

            EnableConsoleLogger();

            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("localhost.pfx");

            // 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.
            RtpAVSession            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)
                    {
                        SIPSorcery.Sys.Log.Logger.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.");
                            rtpSession = new RtpAVSession(
                                new AudioOptions {
                                AudioSource = AudioSourcesEnum.Music, SourceFile = executableDir + "/" + AUDIO_FILE_PCMU
                            }, null);
                            rtpSession.setRemoteDescription(new RTCSessionDescription {
                                type = RTCSdpType.offer, sdp = offerSdp
                            });
                        }

                        if (rtpSession == null)
                        {
                            // Didn't get a match on the codecs we support.
                            SIPResponse noMatchingCodecResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptableHere, null);
                            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, null, uasTransaction);
                            uas.CallCancelled += (uasAgent) =>
                            {
                                rtpCts?.Cancel();
                                rtpSession.CloseSession(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 = await rtpSession.createAnswer(null);

                            uas.Answer(SDP.SDP_MIME_CONTENTTYPE, answerSdp.ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);

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

                        uas?.Hangup(true);
                        rtpSession?.CloseSession(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)
                {
                    SIPSorcery.Sys.Log.Logger.LogWarning($"Exception handling {sipRequest.Method}. {reqExcp.Message}");
                }
            };

            ManualResetEvent exitMre = new ManualResetEvent(false);

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

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

                Hangup(uas).Wait();

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

                if (sipTransport != null)
                {
                    SIPSorcery.Sys.Log.Logger.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?.CloseSession(null);
                            rtpCts?.Cancel();
                        }

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

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

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

            exitMre.WaitOne();
        }
        public async Task HandleInvalidSdpPortOnPlaceCallUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            // This transport will act as the call receiver. It allows the test to provide a
            // tailored response to an incoming call.
            SIPTransport calleeTransport = new SIPTransport();

            // This transport will be used by the SIPUserAgent being tested to place the call.
            SIPTransport callerTransport = new SIPTransport();
            RTPSession   rtpSession      = new RTPSession(false, false, false);

            try
            {
                calleeTransport.AddSIPChannel(new SIPUDPChannel(IPAddress.Loopback, 0));
                calleeTransport.SIPTransportRequestReceived += async(lep, rep, req) =>
                {
                    if (req.Method != SIPMethodsEnum.INVITE)
                    {
                        SIPResponse notAllowedResponse = SIPResponse.GetResponse(req, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                        await calleeTransport.SendResponseAsync(notAllowedResponse);
                    }
                    else
                    {
                        UASInviteTransaction uasTransaction = new UASInviteTransaction(calleeTransport, req, null);
                        var uas = new SIPServerUserAgent(calleeTransport, null, null, null, SIPCallDirection.In, null, null, null, uasTransaction);
                        uas.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null);
                        uas.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null);

                        var answerSdp = @"
v=0
o=- 1838015445 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=audio 79762 RTP/AVP 0
a=rtpmap:0 PCMU/8000
a=sendrecv";
                        uas.Answer(SDP.SDP_MIME_CONTENTTYPE, answerSdp, null, SIPDialogueTransferModesEnum.NotAllowed);
                    }
                };

                SIPUserAgent userAgent = new SIPUserAgent(callerTransport, null);

                MediaStreamTrack audioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> {
                    new SDPMediaFormat(SDPMediaFormatsEnum.PCMU)
                });
                rtpSession.addTrack(audioTrack);

                SIPURI dstUri = new SIPURI(SIPSchemesEnum.sip, calleeTransport.GetSIPChannels().First().ListeningSIPEndPoint);
                var    result = await userAgent.Call(dstUri.ToString(), null, null, rtpSession);

                Assert.False(result);
            }
            finally
            {
                rtpSession?.Close("normal");
                callerTransport?.Shutdown();
                calleeTransport?.Shutdown();
            }
        }
        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));
        }
Exemple #18
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery client user agent server example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // 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();

            sipTransport.ContactHost = Dns.GetHostName();

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

            //if (File.Exists("localhost.pfx"))
            //{
            //    var certificate = new X509Certificate2(@"localhost.pfx", "");
            //    sipTransport.AddSIPChannel(new SIPTLSChannel(certificate, new IPEndPoint(IPAddress.Any, SIPS_LISTEN_PORT)));
            //    sipTransport.AddSIPChannel(new SIPTLSChannel(certificate, new IPEndPoint(IPAddress.IPv6Any, SIPS_LISTEN_PORT)));
            //}

            //EnableTraceLogs(sipTransport);

            // 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.

            // 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) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.INVITE)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation("Incoming call request: " + localSIPEndPoint + "<-" + remoteEndPoint + " " + sipRequest.URI.ToString() + ".");
                    //SIPSorcery.Sys.Log.Logger.LogDebug(sipRequest.ToString());

                    // 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();

                    UASInviteTransaction uasTransaction = sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    uas    = new SIPServerUserAgent(sipTransport, null, null, null, SIPCallDirection.In, null, null, null, uasTransaction);
                    rtpCts = new CancellationTokenSource();

                    // In practice there could be a number of reasons to reject the call. Unsupported extensions, mo matching codecs etc. etc.
                    if (sipRequest.Header.HasUnknownRequireExtension)
                    {
                        // The caller requires an extension that we don't support.
                        SIPSorcery.Sys.Log.Logger.LogWarning($"Rejecting incoming call due to one or more required exensions not being supported, required extensions: {sipRequest.Header.Require}.");
                        uas.Reject(SIPResponseStatusCodesEnum.NotImplemented, "Unsupported Require Extension", null);
                    }
                    else
                    {
                        uas.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null);
                        uas.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null);

                        // Simulating answer delay to test provisional response retransmits.
                        await Task.Delay(2000);

                        // Initialise an RTP session to receive the RTP packets from the remote SIP server.
                        Socket rtpSocket     = null;
                        Socket controlSocket = null;
                        NetServices.CreateRtpSocket(localSIPEndPoint.Address, 49000, 49100, false, out rtpSocket, out controlSocket);

                        IPEndPoint rtpEndPoint    = rtpSocket.LocalEndPoint as IPEndPoint;
                        IPEndPoint dstRtpEndPoint = SDP.GetSDPRTPEndPoint(sipRequest.Body);
                        var        rtpSession     = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

                        var rtpTask = Task.Run(() => SendRecvRtp(rtpSocket, rtpSession, dstRtpEndPoint, AUDIO_FILE, rtpCts))
                                      .ContinueWith(_ => { if (uas?.IsHungup == false)
                                                           {
                                                               uas?.Hangup(false);
                                                           }
                                                    });

                        uas.Answer(SDP.SDP_MIME_CONTENTTYPE, GetSDP(rtpEndPoint).ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);
                    }
                }
                else if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation("Call hungup.");
                    SIPNonInviteTransaction byeTransaction = sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    byeTransaction.SendFinalResponse(byeResponse);
                    uas?.Hangup(true);
                    rtpCts?.Cancel();
                }
                else if (sipRequest.Method == SIPMethodsEnum.OPTIONS)
                {
                    try
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation($"{localSIPEndPoint.ToString()}<-{remoteEndPoint.ToString()}: {sipRequest.StatusLine}");
                        //SIPSorcery.Sys.Log.Logger.LogDebug(sipRequest.ToString());
                        SIPResponse optionsResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        sipTransport.SendResponse(optionsResponse);
                    }
                    catch (Exception optionsExcp)
                    {
                        SIPSorcery.Sys.Log.Logger.LogWarning($"Failed to send SIP OPTIONS response. {optionsExcp.Message}");
                    }
                }
            };

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

                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");
                rtpCts?.Cancel();
                if (uas?.IsHungup == false)
                {
                    uas?.Hangup(false);

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

                if (sipTransport != null)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                    sipTransport.Shutdown();
                }
            };
        }
Exemple #19
0
 /// <summary>
 /// Cleans up after a SIP call has completely finished.
 /// </summary>
 private void CallFinished(SIPDialogue dialogue)
 {
     m_pendingIncomingCall = null;
     CallEnded(this);
 }
Exemple #20
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;
            }
        }
 private void Agent_CallCancelled(ISIPServerUserAgent uas)
 {
     agent = null;
 }
Exemple #22
0
        /// <summary>
        /// Handler for processing incomign 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.");
                    m_uas.SIPDialogue.Hangup(m_sipTransport, null);
                    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;
                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);
            }
        }
        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 server example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // 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.
            IPAddress defaultAddr  = LocalIPConfig.GetDefaultIPv4Address();
            var       sipTransport = new SIPTransport(SIPDNSManager.ResolveSIPService, new SIPTransactionEngine());
            int       port         = FreePort.FindNextAvailableUDPPort(SIPConstants.DEFAULT_SIP_PORT);
            var       sipChannel   = new SIPUDPChannel(new IPEndPoint(defaultAddr, port));

            sipTransport.AddSIPChannel(sipChannel);

            // 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 uasCts = null;

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

                    // 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 a little it simpler.
                    uas?.Hangup();

                    UASInviteTransaction uasTransaction = sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    uas    = new SIPServerUserAgent(sipTransport, null, null, null, SIPCallDirection.In, null, null, null, uasTransaction);
                    uasCts = new CancellationTokenSource();

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

                    // Initialise an RTP session to receive the RTP packets from the remote SIP server.
                    Socket rtpSocket     = null;
                    Socket controlSocket = null;
                    NetServices.CreateRtpSocket(defaultAddr, 49000, 49100, false, out rtpSocket, out controlSocket);

                    IPEndPoint rtpEndPoint    = rtpSocket.LocalEndPoint as IPEndPoint;
                    IPEndPoint dstRtpEndPoint = SDP.GetSDPRTPEndPoint(sipRequest.Body);
                    var        rtpSession     = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

                    var rtpTask = Task.Run(() => SendRecvRtp(rtpSocket, rtpSession, dstRtpEndPoint, AUDIO_FILE, uasCts))
                                  .ContinueWith(_ => { if (uas?.IsHungup == false)
                                                       {
                                                           uas?.Hangup();
                                                       }
                                                });

                    uas.Answer(SDP.SDP_MIME_CONTENTTYPE, GetSDP(rtpEndPoint).ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);
                }
                else if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation("Call hungup.");
                    SIPNonInviteTransaction byeTransaction = sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    byeTransaction.SendFinalResponse(byeResponse);
                    uas?.Hangup();
                    uasCts?.Cancel();
                }
            };

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

                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");
                if (uas?.IsHungup == false)
                {
                    uas?.Hangup();
                }
                uasCts?.Cancel();

                if (sipTransport != null)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                    sipTransport.Shutdown();
                }
            };
        }
Exemple #24
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);
            }
        }
Exemple #25
0
 /// <summary>
 /// Accepts an incoming call. This is the first step in answering a call.
 /// From this point the call can still be rejected, redirected or answered.
 /// </summary>
 /// <param name="sipRequest">The SIP request containing the incoming call request.</param>
 public void Accept(SIPRequest sipRequest)
 {
     m_pendingIncomingCall = m_userAgent.AcceptCall(sipRequest);
 }
Exemple #26
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.");

            EnableConsoleLogger();

            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("localhost.pfx");

            // 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);

            // 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.
            Socket rtpSocket     = null;
            Socket controlSocket = null;

            // Because this is a server user agent the SIP transport must start listening for client user agents.
            sipTransport.SIPTransportRequestReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                try
                {
                    if (sipRequest.Method == SIPMethodsEnum.INVITE)
                    {
                        SIPSorcery.Sys.Log.Logger.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);
                        RTPSession rtpSession     = null;
                        string     audioFile      = null;

                        if (offerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.HasMediaFormat((int)RTPPayloadTypesEnum.G722)))
                        {
                            Log.LogDebug($"Using G722 RTP media type and audio file {AUDIO_FILE_G722}.");
                            rtpSession = new RTPSession((int)RTPPayloadTypesEnum.G722, null, null);
                            audioFile  = AUDIO_FILE_G722;
                        }
                        else if (offerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.HasMediaFormat((int)RTPPayloadTypesEnum.PCMU)))
                        {
                            Log.LogDebug($"Using PCMU RTP media type and audio file {AUDIO_FILE_PCMU}.");
                            rtpSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);
                            audioFile  = AUDIO_FILE_PCMU;
                        }

                        if (rtpSession == null)
                        {
                            // Didn't get a match on the codecs we support.
                            SIPResponse noMatchingCodecResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptableHere, null);
                            sipTransport.SendResponse(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();

                            UASInviteTransaction uasTransaction = sipTransport.CreateUASTransaction(sipRequest, null);
                            uas    = new SIPServerUserAgent(sipTransport, null, null, null, SIPCallDirection.In, null, null, null, uasTransaction);
                            rtpCts = new CancellationTokenSource();

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

                            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
                            NetServices.CreateRtpSocket(dstRtpEndPoint.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, RTP_PORT_START, RTP_PORT_END, false, out rtpSocket, out controlSocket);

                            // The RTP socket is listening on IPAddress.Any but the IP address placed into the SDP needs to be one the caller can reach.
                            IPAddress  rtpAddress  = NetServices.GetLocalAddressForRemote(dstRtpEndPoint.Address);
                            IPEndPoint rtpEndPoint = new IPEndPoint(rtpAddress, (rtpSocket.LocalEndPoint as IPEndPoint).Port);

                            var rtpTask = Task.Run(() => SendRecvRtp(rtpSocket, rtpSession, dstRtpEndPoint, audioFile, rtpCts))
                                          .ContinueWith(_ =>
                            {
                                if (uas?.IsHungup == false)
                                {
                                    uas?.Hangup(false);
                                }
                            });

                            uas.Answer(SDP.SDP_MIME_CONTENTTYPE, GetSDP(rtpEndPoint).ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);
                        }
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.BYE)
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation("Call hungup.");
                        SIPNonInviteTransaction byeTransaction = sipTransport.CreateNonInviteTransaction(sipRequest, null);
                        SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        byeTransaction.SendFinalResponse(byeResponse);
                        uas?.Hangup(true);
                        rtpCts?.Cancel();
                        rtpSocket?.Close();
                        controlSocket?.Close();
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.SUBSCRIBE)
                    {
                        SIPResponse notAllowededResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                        sipTransport.SendResponse(notAllowededResponse);
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.OPTIONS || sipRequest.Method == SIPMethodsEnum.REGISTER)
                    {
                        SIPResponse optionsResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        sipTransport.SendResponse(optionsResponse);
                    }
                }
                catch (Exception reqExcp)
                {
                    SIPSorcery.Sys.Log.Logger.LogWarning($"Exception handling {sipRequest.Method}. {reqExcp.Message}");
                }
            };

            ManualResetEvent exitMre = new ManualResetEvent(false);

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

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

                Hangup(uas).Wait();

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

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

                exitMre.Set();
            };

            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();

                            rtpCts?.Cancel();
                            rtpSocket?.Close();
                            controlSocket?.Close();
                        }

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

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

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

            exitMre.WaitOne();
        }
Exemple #27
0
 /// <summary>
 /// Cleans up after a SIP call has completely finished.
 /// </summary>
 private void CallFinished()
 {
     m_pendingIncomingCall = null;
     CallEnded(this);
 }
        private void Transport_SIPTransportRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest)
        {
            var endpoint = new SIPEndPoint(SIPProtocolsEnum.udp, publicIPAddress, localSIPEndPoint.Port);

            if (sipRequest.Method == SIPMethodsEnum.INVITE)
            {
                if (transaction != null)
                {
                    return;
                }

                logger.DebugFormat("{0} Incoming call from {1}", prefix, sipRequest.Header.From.FromURI.User);

                transaction = transport.CreateUASTransaction(sipRequest, remoteEndPoint, endpoint, null);
                agent       = new SIPServerUserAgent(
                    transport,
                    null,
                    sipRequest.Header.From.FromURI.User,
                    null,
                    SIPCallDirection.In,
                    null,
                    null,
                    null,
                    transaction);

                agent.CallCancelled       += Agent_CallCancelled;
                agent.TransactionComplete += Agent_TransactionComplete;

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

                var answer  = SDP.ParseSDPDescription(agent.CallRequest.Body);
                var address = IPAddress.Parse(answer.Connection.ConnectionAddress);
                var port    = answer.Media.FirstOrDefault(m => m.Media == SDPMediaTypesEnum.audio).Port;
                var random  = Crypto.GetRandomInt(5).ToString();
                var sdp     = new SDP
                {
                    Version     = 2,
                    Username    = "******",
                    SessionId   = random,
                    Address     = localIPEndPoint.Address.ToString(),
                    SessionName = "redfox_" + random,
                    Timing      = "0 0",
                    Connection  = new SDPConnectionInformation(publicIPAddress.ToString())
                };

                rtpChannel = new RTPChannel
                {
                    DontTimeout    = true,
                    RemoteEndPoint = new IPEndPoint(address, port)
                };

                rtpChannel.SetFrameType(FrameTypesEnum.Audio);
                // TODO Fix hardcoded ports
                rtpChannel.ReservePorts(15000, 15090);
                rtpChannel.OnFrameReady += Channel_OnFrameReady;
                rtpChannel.Start();

                // Send some setup parameters to punch a hole in the firewall/router
                rtpChannel.SendRTPRaw(new byte[] { 80, 95, 198, 88, 55, 96, 225, 141, 215, 205, 185, 242, 00 });

                rtpChannel.OnControlDataReceived       += (b) => { logger.Debug($"{prefix} Control Data Received; {b.Length} bytes"); };
                rtpChannel.OnControlSocketDisconnected += () => { logger.Debug($"{prefix} Control Socket Disconnected"); };

                var announcement = new SDPMediaAnnouncement
                {
                    Media        = SDPMediaTypesEnum.audio,
                    MediaFormats = new List <SDPMediaFormat>()
                    {
                        new SDPMediaFormat((int)SDPMediaFormatsEnum.PCMU, "PCMU", 8000)
                    },
                    Port = rtpChannel.RTPPort
                };

                sdp.Media.Add(announcement);

                SetState(State.Listening, sipRequest.Header.From.FromURI.User);

                agent.Progress(SIPResponseStatusCodesEnum.Accepted, null, null, null, null);
                agent.Answer(SDP.SDP_MIME_CONTENTTYPE, sdp.ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);

                SetState(State.Busy, "");
                return;
            }
            if (sipRequest.Method == SIPMethodsEnum.BYE)
            {
                if (State != State.Busy)
                {
                    return;
                }

                logger.DebugFormat("{0} Hangup from {1}", prefix, sipRequest.Header.From.FromURI.User);

                var noninvite = transport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, endpoint, null);
                var response  = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);

                noninvite.SendFinalResponse(response);

                SetState(State.Finished, Endpoint);

                rtpChannel.OnFrameReady -= Channel_OnFrameReady;
                rtpChannel.Close();

                agent.TransactionComplete -= Agent_TransactionComplete;
                agent.CallCancelled       -= Agent_CallCancelled;
                agent       = null;
                transaction = null;

                SetState(State.Ready, Endpoint);

                return;
            }
            if (sipRequest.Method == SIPMethodsEnum.ACK)
            {
            }
            if (sipRequest.Method == SIPMethodsEnum.CANCEL)
            {
            }
        }