/// <summary> /// Initialises a SIP transport to act as the client in a single request/response exchange. /// </summary> /// <param name="testClientChannel">The client SIP channel to test.</param> /// <param name="serverUri">The URI of the server end point to test the client against.</param> /// <param name="tcs">The task completion source that this method will set if it receives the expected response.</param> private async Task RunClient(SIPChannel testClientChannel, SIPURI serverUri, TaskCompletionSource <bool> tcs, CancellationTokenSource cts, ManualResetEventSlim serverReadyEvent) { logger.LogDebug($"RunClient Starting client task for {testClientChannel.ListeningSIPEndPoint}."); var clientSIPTransport = new SIPTransport(); try { clientSIPTransport.AddSIPChannel(testClientChannel); logger.LogDebug($"RunClient test channel created on {testClientChannel.ListeningSIPEndPoint}."); clientSIPTransport.SIPTransportResponseReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse) => { logger.LogDebug($"Expected response received {localSIPEndPoint}<-{remoteEndPoint}: {sipResponse.ShortDescription}"); if (sipResponse.Status == SIPResponseStatusCodesEnum.Ok) { // Got the expected response, set the signal. if (!tcs.TrySetResult(true)) { logger.LogWarning($"RunClient on test channel {testClientChannel.ListeningSIPEndPoint} FAILED to set result on CompletionSource."); } } return(Task.FromResult(0)); }; clientSIPTransport.SIPRequestOutTraceEvent += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) => { logger.LogDebug($"CLIENT REQUEST OUT {localSIPEndPoint}->{remoteEndPoint}"); logger.LogDebug(sipRequest.ToString()); }; clientSIPTransport.SIPResponseInTraceEvent += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse) => { logger.LogDebug($"CLIENT RESPONSE IN {localSIPEndPoint}<-{remoteEndPoint}"); logger.LogDebug(sipResponse.ToString()); }; var optionsRequest = SIPRequest.GetRequest(SIPMethodsEnum.OPTIONS, serverUri); logger.LogDebug($"RunClient waiting for server to get ready on {serverUri.CanonicalAddress}."); serverReadyEvent.Wait(cts.Token); await clientSIPTransport.SendRequestAsync(optionsRequest); await tcs.Task; } catch (Exception excp) { logger.LogError($"Exception RunClient. {excp.Message}"); } finally { logger.LogDebug($"Client task completed for {testClientChannel.ListeningSIPEndPoint}."); clientSIPTransport.Shutdown(); logger.LogDebug($"Client task SIP transport shutdown."); } }
/// <summary> /// Sends in initial notification request for a new subscription where it makes sense to do so. /// </summary> /// <param name="subscribeRequest">The client request that resulted in the subscription creation.</param> /// <param name="sipAccount">The authenticated SIP account that created the subscription.</param> private void SendInitialNotification(SIPRequest subscribeRequest, ISIPAccount sipAccount) { if (SIPEventPackageType.IsValid(subscribeRequest.Header.Event)) { var eventPackage = SIPEventPackageType.Parse(subscribeRequest.Header.Event); if (eventPackage == SIPEventPackagesEnum.MessageSummary) { // Send a dummy message waiting indicator message so that a client can verify a notification request can // be received. var dstUri = subscribeRequest.Header.Contact[0].ContactURI; var accountURI = new SIPURI(sipAccount.SIPUsername, sipAccount.SIPDomain, null, dstUri.Scheme, dstUri.Protocol); var notifyReq = SIPRequest.GetRequest(SIPMethodsEnum.NOTIFY, subscribeRequest.Header.Contact[0].ContactURI, new SIPToHeader(null, accountURI.CopyOf(), CallProperties.CreateNewTag()), new SIPFromHeader(null, accountURI.CopyOf(), CallProperties.CreateNewTag())); notifyReq.Header.CallId = subscribeRequest.Header.CallId; notifyReq.Header.CSeq = subscribeRequest.Header.CSeq++; notifyReq.Header.Server = m_serverAgent; notifyReq.Header.Event = SIPEventPackageType.MESSAGE_SUMMARY_EVENT_VALUE; notifyReq.Header.SubscriptionState = "active"; notifyReq.Header.SetDateHeader(); notifyReq.Header.ContentType = SIPMIMETypes.MWI_CONTENT_TYPE; notifyReq.Body = "Messages-Waiting: no"; // A little trick here is using the remote SIP end point as the destination rather than the Contact URI. // Ideally some extra logic to check for IPv4 NAT should be applied. But since this server is known to // be operating in the cloud and only send NOTIFY requests to Internet clients it should be a reasonable // option. SIPNonInviteTransaction notifyTx = new SIPNonInviteTransaction(m_sipTransport, notifyReq, subscribeRequest.RemoteSIPEndPoint); notifyTx.SendRequest(); } } }
private SIPRequest GetRegistrationRequest() { try { SIPURI registerURI = m_sipAccountAOR.CopyOf(); registerURI.User = null; SIPRequest registerRequest = SIPRequest.GetRequest( SIPMethodsEnum.REGISTER, registerURI, new SIPToHeader(this.UserDisplayName, m_sipAccountAOR, null), new SIPFromHeader(this.UserDisplayName, m_sipAccountAOR, CallProperties.CreateNewTag())); registerRequest.Header.Contact = new List <SIPContactHeader> { new SIPContactHeader(this.UserDisplayName, m_contactURI) }; registerRequest.Header.CSeq = ++m_cseq; registerRequest.Header.CallId = m_callID; registerRequest.Header.UserAgent = (!UserAgent.IsNullOrBlank()) ? UserAgent : m_userAgent; registerRequest.Header.Expires = m_expiry; return(registerRequest); } catch (Exception excp) { logger.LogError("Exception GetRegistrationRequest. " + excp.Message); throw excp; } }
/// <summary> /// Initiates a SUBSCRIBE request to a notification server. /// </summary> /// <param name="subscribeToURI">The SIP user that dialog notifications are being subscribed to.</param> public void Subscribe(SIPURI subscribeURI, int expiry, SIPEventPackage sipEventPackage, string subscribeCallID, SIPURI contactURI) { try { if (m_attempts >= MAX_SUBSCRIBE_ATTEMPTS) { logger.LogWarning("Subscription to " + subscribeURI.ToString() + " reached the maximum number of allowed attempts without a failure condition."); m_subscribed = false; SubscriptionFailed(subscribeURI, SIPResponseStatusCodesEnum.InternalServerError, "Subscription reached the maximum number of allowed attempts."); m_waitForSubscribeResponse.Set(); } else { m_attempts++; m_localCSeq++; SIPRequest subscribeRequest = SIPRequest.GetRequest( SIPMethodsEnum.SUBSCRIBE, m_resourceURI, new SIPToHeader(null, subscribeURI, m_subscriptionToTag), null); if (contactURI != null) { subscribeRequest.Header.Contact = new List <SIPContactHeader>() { new SIPContactHeader(null, contactURI) }; } subscribeRequest.Header.From = new SIPFromHeader(null, new SIPURI(m_authUsername, m_authDomain, null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp), m_subscriptionFromTag); subscribeRequest.Header.CSeq = m_localCSeq; subscribeRequest.Header.Expires = expiry; subscribeRequest.Header.Event = sipEventPackage.ToString(); subscribeRequest.Header.CallId = subscribeCallID; if (!m_filter.IsNullOrBlank()) { subscribeRequest.Body = m_filter; subscribeRequest.Header.ContentLength = m_filter.Length; subscribeRequest.Header.ContentType = m_filterTextType; } SIPNonInviteTransaction subscribeTransaction = new SIPNonInviteTransaction(m_sipTransport, subscribeRequest, m_outboundProxy); subscribeTransaction.NonInviteTransactionFinalResponseReceived += SubscribeTransactionFinalResponseReceived; subscribeTransaction.NonInviteTransactionTimedOut += SubsribeTransactionTimedOut; m_sipTransport.SendTransaction(subscribeTransaction); LastSubscribeAttempt = DateTime.Now; } } catch (Exception excp) { logger.LogError("Exception SIPNotifierClient Subscribe. " + excp.Message); SubscriptionFailed(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, "Exception Subscribing. " + excp.Message); m_waitForSubscribeResponse.Set(); } }
private SIPRequest GetRegistrationRequest() { SIPURI registerURI = m_sipAccountAOR.CopyOf(); registerURI.User = null; SIPRequest registerRequest = SIPRequest.GetRequest( SIPMethodsEnum.REGISTER, registerURI, new SIPToHeader(this.UserDisplayName, m_sipAccountAOR, null), new SIPFromHeader(this.UserDisplayName, m_sipAccountAOR, CallProperties.CreateNewTag())); registerRequest.Header.Contact = new List <SIPContactHeader> { new SIPContactHeader(this.UserDisplayName, m_contactURI) }; registerRequest.Header.CSeq = ++m_cseq; registerRequest.Header.CallId = m_callID; registerRequest.Header.UserAgent = (!UserAgent.IsNullOrBlank()) ? UserAgent : SIPConstants.SipUserAgentVersionString; registerRequest.Header.Expires = m_expiry; if (m_customHeaders != null && m_customHeaders.Length > 0) { foreach (var header in m_customHeaders) { registerRequest.Header.UnknownHeaders.Add(header); } } if (AdjustRegister == null) { return(registerRequest); } return(AdjustRegister(registerRequest)); }
/// <summary> /// An asynchronous task that attempts to send a single OPTIONS request. /// </summary> /// <param name="sipTransport">The transport object to use for the send.</param> /// <param name="dst">The destination end point to send the request to.</param> /// <returns>True if the expected response was received, false otherwise.</returns> private static async Task <bool> SendOptionsTaskAsync(SIPTransport sipTransport, SIPURI dst) { TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>(); //UdpClient hepClient = new UdpClient(0, AddressFamily.InterNetwork); try { sipTransport.SIPRequestOutTraceEvent += (localEP, remoteEP, req) => { logger.LogDebug($"Request sent: {localEP}->{remoteEP}"); logger.LogDebug(req.ToString()); //var hepBuffer = HepPacket.GetBytes(localEP, remoteEP, DateTimeOffset.Now, 333, "myHep", req.ToString()); //hepClient.SendAsync(hepBuffer, hepBuffer.Length, "192.168.11.49", 9060); }; sipTransport.SIPResponseInTraceEvent += (localEP, remoteEP, resp) => { logger.LogDebug($"Response received: {localEP}<-{remoteEP}"); logger.LogDebug(resp.ToString()); //var hepBuffer = HepPacket.GetBytes(remoteEP, localEP, DateTimeOffset.Now, 333, "myHep", resp.ToString()); //hepClient.SendAsync(hepBuffer, hepBuffer.Length, "192.168.11.49", 9060); }; var optionsRequest = SIPRequest.GetRequest(SIPMethodsEnum.OPTIONS, dst); sipTransport.SIPTransportResponseReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse) => { if (sipResponse.Header.CSeqMethod == SIPMethodsEnum.OPTIONS && sipResponse.Header.CallId == optionsRequest.Header.CallId) { logger.LogDebug($"Expected response received {localSIPEndPoint}<-{remoteEndPoint}: {sipResponse.ShortDescription}"); tcs.SetResult(true); } return(Task.FromResult(0)); }; SocketError sendResult = await sipTransport.SendRequestAsync(optionsRequest); if (sendResult != SocketError.Success) { logger.LogWarning($"Attempt to send request failed with {sendResult}."); tcs.SetResult(false); } } catch (Exception excp) { logger.LogError($"Exception SendOptionsTask. {excp.Message}"); tcs.SetResult(false); } return(await tcs.Task); }
public async void WebSocketLoopbackLargeSendReceiveTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); var serverChannel = new SIPWebSocketChannel(IPAddress.Loopback, 9001); var clientChannel = new SIPClientWebSocketChannel(); var sipTransport = new SIPTransport(); sipTransport.AddSIPChannel(new List <SIPChannel> { serverChannel, clientChannel }); ManualResetEvent gotResponseMre = new ManualResetEvent(false); SIPRequest receivedRequest = null; SIPResponse receivedResponse = null; sipTransport.SIPTransportRequestReceived += (localSIPEndPoint, remoteEndPoint, sipRequest) => { receivedRequest = sipRequest; SIPResponse optionsResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); optionsResponse.Header.UnknownHeaders.Add($"X-Response-Random:{Crypto.GetRandomString(1000)}"); optionsResponse.Header.UnknownHeaders.Add("X-Response-Final: TheEnd"); return(sipTransport.SendResponseAsync(optionsResponse)); }; sipTransport.SIPTransportResponseReceived += (localSIPEndPoint, remoteEndPoint, sipResponse) => { receivedResponse = sipResponse; gotResponseMre.Set(); return(Task.CompletedTask); }; var serverUri = serverChannel.GetContactURI(SIPSchemesEnum.sip, clientChannel.ListeningSIPEndPoint); var optionsRequest = SIPRequest.GetRequest(SIPMethodsEnum.OPTIONS, serverUri); optionsRequest.Header.UnknownHeaders.Add($"X-Request-Random:{Crypto.GetRandomString(1000)}"); optionsRequest.Header.UnknownHeaders.Add("X-Request-Final: TheEnd"); await sipTransport.SendRequestAsync(optionsRequest); gotResponseMre.WaitOne(TRANSPORT_TEST_TIMEOUT, false); Assert.NotNull(receivedRequest); Assert.NotNull(receivedResponse); //rj2: confirm that we have received the whole SIP-Message by checking for the last x-header (issue #175, websocket fragmented send/receive) Assert.Contains("X-Request-Final: TheEnd", receivedRequest.Header.UnknownHeaders); Assert.Contains("X-Response-Final: TheEnd", receivedResponse.Header.UnknownHeaders); sipTransport.Shutdown(); logger.LogDebug("Test complete."); }
public async void InterChannelCommsUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); var udpChan1 = new SIPUDPChannel(IPAddress.Any, 0); logger.LogDebug($"Listening end point {udpChan1.ListeningSIPEndPoint}."); var udpChan2 = new SIPUDPChannel(IPAddress.Any, 0); logger.LogDebug($"Listening end point {udpChan2.ListeningSIPEndPoint}."); TaskCompletionSource <bool> gotMessage = new TaskCompletionSource <bool>(); SIPEndPoint receivedFromEP = null; SIPEndPoint receivedOnEP = null; udpChan2.SIPMessageReceived = (SIPChannel sipChannel, SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, byte[] buffer) => { logger.LogDebug($"SIP message received from {remoteEndPoint}."); logger.LogDebug($"SIP message received on {localSIPEndPoint}."); logger.LogDebug(Encoding.UTF8.GetString(buffer)); receivedFromEP = remoteEndPoint; receivedOnEP = localSIPEndPoint; gotMessage.SetResult(true); return(Task.CompletedTask); }; var dstEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, IPAddress.Loopback, udpChan2.Port); var optionsReq = SIPRequest.GetRequest(SIPMethodsEnum.OPTIONS, new SIPURI(SIPSchemesEnum.sip, dstEndPoint)); logger.LogDebug($"Attempting to send OPTIONS request to {dstEndPoint}."); // Give sockets a chance to start up. //await Task.Delay(500); await udpChan1.SendAsync(dstEndPoint, Encoding.UTF8.GetBytes(optionsReq.ToString()), null); bool res = gotMessage.Task.Wait(1000); Assert.True(res); Assert.NotNull(receivedFromEP); Assert.NotNull(receivedOnEP); Assert.Equal(IPAddress.Loopback, receivedFromEP.Address); Assert.Equal(IPAddress.Any, receivedOnEP.Address); udpChan1.Close(); udpChan2.Close(); logger.LogDebug("-----------------------------------------"); }
private SIPRequest GetRegistrationRequest() { try { SIPURI registerURI = m_sipAccountAOR.CopyOf(); registerURI.User = null; SIPRequest registerRequest = SIPRequest.GetRequest( SIPMethodsEnum.REGISTER, registerURI, new SIPToHeader(this.UserDisplayName, m_sipAccountAOR, null), new SIPFromHeader(this.UserDisplayName, m_sipAccountAOR, CallProperties.CreateNewTag())); registerRequest.Header.Contact = new List <SIPContactHeader> { new SIPContactHeader(this.UserDisplayName, m_contactURI) }; registerRequest.Header.CSeq = ++m_cseq; registerRequest.Header.CallId = m_callID; registerRequest.Header.UserAgent = (!UserAgent.IsNullOrBlank()) ? UserAgent : m_userAgent; registerRequest.Header.Expires = m_expiry; if (m_customHeaders != null && m_customHeaders.Length > 0) { foreach (var header in m_customHeaders) { registerRequest.Header.UnknownHeaders.Add(header); } } if (AdjustRegister == null) { return(registerRequest); } return(AdjustRegister(registerRequest)); } catch (Exception excp) { Logger.Logger.Error("Exception GetRegistrationRequest. ->" + excp.Message); throw excp; } }
public async void WebSocketLoopbackSendReceiveTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); var serverChannel = new SIPWebSocketChannel(IPAddress.Loopback, 9000); var clientChannel = new SIPClientWebSocketChannel(); var sipTransport = new SIPTransport(); sipTransport.AddSIPChannel(new List <SIPChannel> { serverChannel, clientChannel }); ManualResetEvent gotResponseMre = new ManualResetEvent(false); sipTransport.SIPTransportRequestReceived += (localSIPEndPoint, remoteEndPoint, sipRequest) => { SIPResponse optionsResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); return(sipTransport.SendResponseAsync(optionsResponse)); }; SIPResponse rtnResponse = null; sipTransport.SIPTransportResponseReceived += (localSIPEndPoint, remoteEndPoint, sipResponse) => { rtnResponse = sipResponse; gotResponseMre.Set(); return(Task.CompletedTask); }; var serverUri = serverChannel.GetContactURI(SIPSchemesEnum.sip, clientChannel.ListeningSIPEndPoint); var optionsRequest = SIPRequest.GetRequest(SIPMethodsEnum.OPTIONS, serverUri); await sipTransport.SendRequestAsync(optionsRequest); gotResponseMre.WaitOne(TRANSPORT_TEST_TIMEOUT, false); Assert.NotNull(rtnResponse); sipTransport.Shutdown(); logger.LogDebug("Test complete."); }
public void BinarySerialisationRoundTripTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); SIPURI uri = new SIPURI("dummy", "dummy", null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp); SIPRequest req = SIPRequest.GetRequest(SIPMethodsEnum.MESSAGE, uri); SIPResponse resp = SIPResponse.GetResponse(req, SIPResponseStatusCodesEnum.Ok, null); resp.Header.ContentType = "application/octet-stream"; resp.BodyBuffer = new byte[100]; Crypto.GetRandomBytes(resp.BodyBuffer); string bodyHash = null; using (var sha256 = new SHA256Managed()) { bodyHash = sha256.ComputeHash(resp.BodyBuffer).HexStr(); } logger.LogDebug(resp.ToString()); logger.LogDebug($"Body sha256: {bodyHash}."); SIPMessageBuffer msgBuffer = SIPMessageBuffer.ParseSIPMessage(resp.GetBytes(), SIPEndPoint.Empty, SIPEndPoint.Empty); SIPResponse rndTripResp = SIPResponse.ParseSIPResponse(msgBuffer); string rndTripBodyHash = null; using (var sha256 = new SHA256Managed()) { rndTripBodyHash = sha256.ComputeHash(rndTripResp.BodyBuffer).HexStr(); } logger.LogDebug(rndTripResp.ToString()); logger.LogDebug($"Round Trip Body sha256: {rndTripBodyHash}."); Assert.Equal(bodyHash, rndTripBodyHash); }
public void TcpTrickleReceiveTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); TaskCompletionSource <bool> testComplete = new TaskCompletionSource <bool>(); // TCP server. TcpListener listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); var actualEP = listener.LocalEndpoint as IPEndPoint; // SIP TCP Channel var transport = new SIPTransport(); var tcpChannel = new SIPTCPChannel(new IPEndPoint(IPAddress.Loopback, 0)); tcpChannel.DisableLocalTCPSocketsCheck = true; transport.AddSIPChannel(tcpChannel); int requestCount = 10; int recvdReqCount = 0; Task.Run(() => { try { var tcpClient = listener.AcceptTcpClient(); logger.LogDebug($"Dummy TCP listener accepted client with remote end point {tcpClient.Client.RemoteEndPoint}."); for (int i = 0; i < requestCount; i++) { logger.LogDebug($"Sending request {i}."); var req = SIPRequest.GetRequest(SIPMethodsEnum.OPTIONS, new SIPURI(SIPSchemesEnum.sip, tcpChannel.ListeningSIPEndPoint)); byte[] reqBytes = Encoding.UTF8.GetBytes(req.ToString()); tcpClient.GetStream().Write(reqBytes, 0, reqBytes.Length); tcpClient.GetStream().Flush(); Task.Delay(30).Wait(); } tcpClient.GetStream().Close(); } catch (Exception excp) { logger.LogError($"Exception on dummy TCP listener task. {excp.Message}"); testComplete.SetResult(false); } }); transport.SIPTransportRequestReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) => { logger.LogDebug($"Request received {localSIPEndPoint.ToString()}<-{remoteEndPoint.ToString()}: {sipRequest.StatusLine}"); logger.LogDebug(sipRequest.ToString()); Interlocked.Increment(ref recvdReqCount); if (recvdReqCount == requestCount) { if (!testComplete.TrySetResult(true)) { logger.LogWarning($"TcpTrickleReceiveTest: FAILED to set result on CompletionSource."); } } return(Task.FromResult(0)); }; transport.SIPTransportResponseReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse) => { logger.LogDebug($"Response received {localSIPEndPoint.ToString()}<-{remoteEndPoint.ToString()}: {sipResponse.ShortDescription}"); logger.LogDebug(sipResponse.ToString()); return(Task.FromResult(0)); }; if (!tcpChannel.ConnectClientAsync(actualEP, null, null).Wait(TimeSpan.FromMilliseconds(TRANSPORT_TEST_TIMEOUT))) { logger.LogWarning($"ConnectClientAsync timed out"); } logger.LogDebug("Test client connected."); if (!Task.WhenAny(new Task[] { testComplete.Task }).Wait(TRANSPORT_TEST_TIMEOUT)) { logger.LogWarning($"Tasks timed out"); } logger.LogDebug("Test completed, shutting down SIP transport layer."); transport.Shutdown(); logger.LogDebug("SIP transport layer shutdown."); // Give the SIP transport time to shutdown. Keeps exception messages out of the logs. Task.Delay(500).Wait(); Assert.True(testComplete.Task.IsCompleted); Assert.True(testComplete.Task.Result); Assert.True(requestCount == recvdReqCount, $"The count of {recvdReqCount} for the requests received did not match what was expected."); }