Пример #1
0
        /// <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.");
            }
        }
Пример #2
0
        /// <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();
                }
            }
        }
Пример #3
0
        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;
            }
        }
Пример #4
0
        /// <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));
        }
Пример #6
0
        /// <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.");
        }
Пример #8
0
        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);
        }
Пример #12
0
        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.");
        }