public void IPv4TcpLoopbackConsecutiveSendReceiveTest()
        {
            CancellationTokenSource cancelServer = new CancellationTokenSource();
            var serverChannel = new SIPTCPChannel(IPAddress.Loopback, 7064);

            serverChannel.DisableLocalTCPSocketsCheck = true;

            var serverTask = Task.Run(() => { RunServer(serverChannel, cancelServer); });

            for (int i = 1; i < 3; i++)
            {
                TaskCompletionSource <bool> testComplete = new TaskCompletionSource <bool>();

                var clientChannel = new SIPTCPChannel(IPAddress.Any, 7065);
                clientChannel.DisableLocalTCPSocketsCheck = true;
                SIPURI serverUri = serverChannel.GetContactURI(SIPSchemesEnum.sip, IPAddress.Loopback);

                logger.LogDebug($"Server URI {serverUri.ToString()}.");

                var clientTask = Task.Run(async() => { await RunClient(clientChannel, serverUri, testComplete); });
                Task.WhenAny(new Task[] { clientTask, Task.Delay(TRANSPORT_TEST_TIMEOUT) }).Wait();

                if (testComplete.Task.IsCompleted == false)
                {
                    // The client did not set the completed signal. This means the delay task must have completed and hence the test failed.
                    testComplete.SetResult(false);
                }

                Assert.True(testComplete.Task.Result);

                logger.LogDebug($"Completed for test run {i}.");
            }

            cancelServer.Cancel();
        }
        public void IPv6TcpLoopbackSendReceiveTest()
        {
            CancellationTokenSource     cancelServer = new CancellationTokenSource();
            TaskCompletionSource <bool> testComplete = new TaskCompletionSource <bool>();

            var serverChannel = new SIPTCPChannel(IPAddress.IPv6Loopback, 7060);

            serverChannel.DisableLocalTCPSocketsCheck = true;
            var clientChannel = new SIPTCPChannel(IPAddress.IPv6Loopback, 7061);

            clientChannel.DisableLocalTCPSocketsCheck = true;

            var serverTask = Task.Run(() => { RunServer(serverChannel, cancelServer); });
            var clientTask = Task.Run(async() => { await RunClient(clientChannel, new SIPURI(SIPSchemesEnum.sip, serverChannel.SIPChannelEndPoint), testComplete); });

            Task.WhenAny(new Task[] { serverTask, clientTask, Task.Delay(2000) }).Wait();

            if (testComplete.Task.IsCompleted == false)
            {
                // The client did not set the completed signal. This means the delay task must have completed and hence the test failed.
                testComplete.SetResult(false);
            }

            Assert.IsTrue(testComplete.Task.Result);

            cancelServer.Cancel();
        }
        /// <summary>
        /// Initialises the SIP transport layer.
        /// </summary>
        public async Task InitialiseSIP()
        {
            if (_isInitialised == false)
            {
                await Task.Run(() =>
                {
                    _isInitialised = true;

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

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

                    if (sipChannelAdded == false)
                    {
                        // Use default options to set up a SIP channel.
                        SIPUDPChannel udpChannel = null;
                        try
                        {
                            udpChannel = new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_DEFAULT_PORT));
                        }
                        catch (SocketException bindExcp)
                        {
                            logger.LogWarning($"Socket exception attempting to bind UDP channel to port {SIP_DEFAULT_PORT}, will use random port. {bindExcp.Message}.");
                            udpChannel = new SIPUDPChannel(new IPEndPoint(IPAddress.Any, 0));
                        }
                        var tcpChannel = new SIPTCPChannel(new IPEndPoint(IPAddress.Any, udpChannel.Port));
                        SIPTransport.AddSIPChannel(new List <SIPChannel> {
                            udpChannel, tcpChannel
                        });
                    }
                });

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

                // Log all SIP packets received to a log file.
                SIPTransport.SIPRequestInTraceEvent   += SIPRequestInTraceEvent;
                SIPTransport.SIPRequestOutTraceEvent  += SIPRequestOutTraceEvent;
                SIPTransport.SIPResponseInTraceEvent  += SIPResponseInTraceEvent;
                SIPTransport.SIPResponseOutTraceEvent += SIPResponseOutTraceEvent;
            }
        }
        public void IPv4TcpLoopbackConsecutiveSendReceiveTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            // This test fails on WSL and Linux due to closed TCP sockets going into the TIME_WAIT state.
            // See comment in SIPTCPChannel.OnSIPStreamDisconnected for additional info.
            if (Environment.OSVersion.Platform != PlatformID.Unix)
            {
                ManualResetEventSlim    serverReadyEvent = new ManualResetEventSlim(false);
                CancellationTokenSource cancelServer     = new CancellationTokenSource();
                var serverChannel = new SIPTCPChannel(IPAddress.Loopback, 0);
                serverChannel.DisableLocalTCPSocketsCheck = true;

                var serverTask = Task.Run(() => { RunServer(serverChannel, cancelServer, serverReadyEvent); });

                for (int i = 1; i < 3; i++)
                {
                    TaskCompletionSource <bool> testComplete = new TaskCompletionSource <bool>();

                    var clientChannel = new SIPTCPChannel(IPAddress.Loopback, 0);
                    clientChannel.DisableLocalTCPSocketsCheck = true;
                    SIPURI serverUri = serverChannel.GetContactURI(SIPSchemesEnum.sip, new SIPEndPoint(SIPProtocolsEnum.tcp, new IPEndPoint(IPAddress.Loopback, 0)));

                    logger.LogDebug($"Server URI {serverUri.ToString()}.");

                    var clientTask = Task.Run(async() => { await RunClient(clientChannel, serverUri, testComplete, cancelServer, serverReadyEvent); });

                    serverReadyEvent.Wait();
                    if (!Task.WhenAny(new Task[] { clientTask }).Wait(TRANSPORT_TEST_TIMEOUT))
                    {
                        logger.LogWarning($"Tasks timed out");
                    }

                    if (testComplete.Task.IsCompleted == false)
                    {
                        // The client did not set the completed signal. This means the delay task must have completed and hence the test failed.
                        testComplete.SetResult(false);
                    }

                    Assert.True(testComplete.Task.Result);

                    logger.LogDebug($"Completed for test run {i}.");

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

                cancelServer.Cancel();
            }
        }
Beispiel #5
0
        public void IPv6TcpLoopbackSendReceiveTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            if (!Socket.OSSupportsIPv6)
            {
                logger.LogDebug("Test skipped as OS does not support IPv6.");
            }
            else
            {
                ManualResetEventSlim        serverReadyEvent = new ManualResetEventSlim(false);
                CancellationTokenSource     cancelServer     = new CancellationTokenSource();
                TaskCompletionSource <bool> testComplete     = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

                var serverChannel = new SIPTCPChannel(IPAddress.IPv6Loopback, 0);
                serverChannel.DisableLocalTCPSocketsCheck = true;
                var clientChannel = new SIPTCPChannel(IPAddress.IPv6Loopback, 0);
                clientChannel.DisableLocalTCPSocketsCheck = true;

                var serverTask = Task.Run(() => { RunServer(serverChannel, cancelServer, serverReadyEvent); });
                var clientTask = Task.Run(async() =>
                {
#pragma warning disable RCS1090 // Add call to 'ConfigureAwait' (or vice versa).
                    await RunClient(
                        clientChannel,
                        serverChannel.GetContactURI(SIPSchemesEnum.sip, new SIPEndPoint(SIPProtocolsEnum.tcp, new IPEndPoint(IPAddress.IPv6Loopback, 0))),
                        testComplete,
                        cancelServer,
                        serverReadyEvent);
#pragma warning restore RCS1090 // Add call to 'ConfigureAwait' (or vice versa).
                });

                serverReadyEvent.Wait();
                if (!Task.WhenAny(new Task[] { serverTask, clientTask }).Wait(TRANSPORT_TEST_TIMEOUT))
                {
                    logger.LogWarning($"Tasks timed out");
                }

                if (testComplete.Task.IsCompleted == false)
                {
                    // The client did not set the completed signal. This means the delay task must have completed and hence the test failed.
                    testComplete.SetResult(false);
                }

                Assert.True(testComplete.Task.Result);

                cancelServer.Cancel();
            }
        }
        public void IPv4TcpLoopbackSendReceiveTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            ManualResetEventSlim        serverReadyEvent = new ManualResetEventSlim(false);
            CancellationTokenSource     cancelServer     = new CancellationTokenSource();
            TaskCompletionSource <bool> testComplete     = new TaskCompletionSource <bool>();

            var serverChannel = new SIPTCPChannel(IPAddress.Loopback, 0);

            serverChannel.DisableLocalTCPSocketsCheck = true;
            var clientChannel = new SIPTCPChannel(IPAddress.Loopback, 0);

            clientChannel.DisableLocalTCPSocketsCheck = true;

            Task.Run(() => { RunServer(serverChannel, cancelServer, serverReadyEvent); });
            var clientTask = Task.Run(async() => { await RunClient(
                                                       clientChannel,
                                                       serverChannel.GetContactURI(SIPSchemesEnum.sip, new SIPEndPoint(SIPProtocolsEnum.tcp, new IPEndPoint(IPAddress.Loopback, 0))),
                                                       testComplete,
                                                       cancelServer,
                                                       serverReadyEvent); });

            serverReadyEvent.Wait();
            if (!Task.WhenAny(new Task[] { clientTask }).Wait(TRANSPORT_TEST_TIMEOUT))
            {
                logger.LogWarning($"Tasks timed out");
            }

            if (testComplete.Task.IsCompleted == false)
            {
                // The client did not set the completed signal. This means the delay task must have completed and hence the test failed.
                testComplete.SetResult(false);
            }

            Assert.True(testComplete.Task.Result);

            cancelServer.Cancel();
        }
Beispiel #7
0
        /// <summary>
        /// Runs a single task as part of the overall job.
        /// </summary>
        /// <param name="options">The options that dictate the type of task to run.</param>
        /// <param name="taskNumber">The number assigned to this task.</param>
        /// <returns>A boolean indicating whether this single task succeeded or not.</returns>
        private static async Task <bool> RunTask(Options options, int taskNumber)
        {
            SIPTransport sipTransport = new SIPTransport();

            try
            {
                DateTime startTime = DateTime.Now;

                (var dstEp, var dstUri) = ParseDestination(options.Destination);

                logger.LogDebug($"Destination IP end point {dstEp} and SIP URI {dstUri}");

                IPAddress  localAddress = (dstEp.Address.AddressFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Any : IPAddress.Any;
                SIPChannel sipChannel   = null;

                switch (dstEp.Protocol)
                {
                case SIPProtocolsEnum.tcp:
                    sipChannel = new SIPTCPChannel(new IPEndPoint(localAddress, DEFAULT_SIP_CLIENT_PORT));
                    (sipChannel as SIPTCPChannel).DisableLocalTCPSocketsCheck = true;     // Allow sends to listeners on this host.
                    break;

                case SIPProtocolsEnum.tls:
                    var certificate = new X509Certificate2(@"localhost.pfx", "");
                    sipChannel = new SIPTLSChannel(certificate, new IPEndPoint(localAddress, DEFAULT_SIPS_CLIENT_PORT));
                    break;

                case SIPProtocolsEnum.udp:
                    sipChannel = new SIPUDPChannel(new IPEndPoint(localAddress, DEFAULT_SIP_CLIENT_PORT));
                    break;

                case SIPProtocolsEnum.ws:
                    sipChannel = new SIPClientWebSocketChannel();
                    break;

                case SIPProtocolsEnum.wss:
                    sipChannel = new SIPClientWebSocketChannel();
                    break;

                default:
                    throw new ApplicationException($"Don't know how to create SIP channel for transport {dstEp.Protocol}.");
                }

                sipTransport.AddSIPChannel(sipChannel);

                Task <bool> task = null;

                switch (options.Scenario)
                {
                case Scenarios.uac:
                    task = InitiateCallTaskAsync(sipTransport, dstUri);
                    break;

                case Scenarios.opt:
                default:
                    task = SendOptionsTaskAsync(sipTransport, dstUri);
                    break;
                }

                var result = await Task.WhenAny(task, Task.Delay(options.Timeout * 1000));

                TimeSpan duration = DateTime.Now.Subtract(startTime);
                bool     failed   = false;

                if (!task.IsCompleted)
                {
                    logger.LogWarning($"=> Request to {dstEp} did not get a response on task {taskNumber} after {duration.TotalMilliseconds.ToString("0")}ms.");
                    failed = true;
                }
                else if (!task.Result)
                {
                    logger.LogWarning($"=> Request to {dstEp} did not get the expected response on task {taskNumber} after {duration.TotalMilliseconds.ToString("0")}ms.");
                    failed = true;
                }
                else
                {
                    logger.LogInformation($"=> Got correct response on send {taskNumber} in {duration.TotalMilliseconds.ToString("0")}ms.");
                }

                return(!failed);
            }
            finally
            {
                logger.LogDebug("Shutting down the SIP transport...");
                sipTransport.Shutdown();
            }
        }
        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.");
        }
        public void TcpTrickleReceiveTest()
        {
            TaskCompletionSource <bool> testComplete = new TaskCompletionSource <bool>();

            IPEndPoint listenEP   = new IPEndPoint(IPAddress.Loopback, 9066);
            var        transport  = new SIPTransport();
            var        tcpChannel = new SIPTCPChannel(new IPEndPoint(IPAddress.Loopback, 9067));

            tcpChannel.DisableLocalTCPSocketsCheck = true;
            transport.AddSIPChannel(tcpChannel);

            int requestCount  = 10;
            int recvdReqCount = 0;

            Task.Run(() =>
            {
                TcpListener listener = new TcpListener(listenEP);
                listener.Start();
                var tcpClient = listener.AcceptTcpClient();
                logger.LogDebug($"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         = transport.GetRequest(SIPMethodsEnum.OPTIONS, SIPURI.ParseSIPURIRelaxed($"{i}@sipsorcery.com"));
                    byte[] reqBytes = Encoding.UTF8.GetBytes(req.ToString());

                    tcpClient.GetStream().Write(reqBytes, 0, reqBytes.Length);
                    tcpClient.GetStream().Flush();

                    Task.Delay(30).Wait();
                }
                tcpClient.GetStream().Close();
            });

            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)
                {
                    testComplete.SetResult(true);
                }
            };

            transport.SIPTransportResponseReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse) =>
            {
                logger.LogDebug($"Response received {localSIPEndPoint.ToString()}<-{remoteEndPoint.ToString()}: {sipResponse.ShortDescription}");
                logger.LogDebug(sipResponse.ToString());
            };

            tcpChannel.ConnectClientAsync(listenEP, null, null).Wait();

            Task.WhenAny(new Task[] { testComplete.Task, Task.Delay(5000) }).Wait();

            transport.Shutdown();

            Assert.IsTrue(testComplete.Task.IsCompleted);
            Assert.IsTrue(testComplete.Task.Result);
            Assert.AreEqual(requestCount, recvdReqCount, $"The count of {recvdReqCount} for the requests received did not match what was expected.");
        }
Beispiel #10
0
        /// <summary>
        /// Executes the command set by the program's command line arguments.
        /// </summary>
        /// <param name="options">The options that dictate the SIP command to execute.</param>
        static async Task RunCommand(Options options)
        {
            try
            {
                logger.LogDebug($"RunCommand {options.Destination}");

                (var dstEp, var dstUri) = ParseDestination(options.Destination);

                logger.LogDebug($"Destination IP end point {dstEp} and SIP URI {dstUri}");

                int  sendCount = 0;
                bool success   = true;

                do
                {
                    IPAddress  localAddress = (dstEp.Address.AddressFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Any : IPAddress.Any;
                    SIPChannel sipChannel   = null;

                    switch (dstEp.Protocol)
                    {
                    case SIPProtocolsEnum.tcp:
                        sipChannel = new SIPTCPChannel(new IPEndPoint(localAddress, DEFAULT_SIP_CLIENT_PORT));
                        (sipChannel as SIPTCPChannel).DisableLocalTCPSocketsCheck = true;     // Allow sends to listeners on this host.
                        break;

                    case SIPProtocolsEnum.tls:
                        var certificate = new X509Certificate2(@"localhost.pfx", "");
                        sipChannel = new SIPTLSChannel(certificate, new IPEndPoint(localAddress, DEFAULT_SIPS_CLIENT_PORT));
                        break;

                    case SIPProtocolsEnum.udp:
                        sipChannel = new SIPUDPChannel(new IPEndPoint(localAddress, DEFAULT_SIP_CLIENT_PORT));
                        break;

                    case SIPProtocolsEnum.ws:
                        sipChannel = new SIPClientWebSocketChannel();
                        break;

                    case SIPProtocolsEnum.wss:
                        sipChannel = new SIPClientWebSocketChannel();
                        break;

                    default:
                        throw new ApplicationException($"Don't know how to create SIP channel for transport {dstEp.Protocol}.");
                    }

                    SIPTransport sipTransport = new SIPTransport();
                    sipTransport.AddSIPChannel(sipChannel);

                    if (sendCount > 0 && options.Period > 0)
                    {
                        await Task.Delay(options.Period * 1000);
                    }

                    sendCount++;

                    DateTime sendTime = DateTime.Now;
                    var      sendTask = SendOptionsTaskAsync(sipTransport, dstUri);
                    var      result   = await Task.WhenAny(sendTask, Task.Delay(options.Timeout * 1000));

                    TimeSpan duration = DateTime.Now.Subtract(sendTime);

                    if (!sendTask.IsCompleted)
                    {
                        logger.LogWarning($"=> Request to {dstEp} did not get a response on send {sendCount} of {options.Count} after {duration.TotalMilliseconds.ToString("0")}ms.");
                        success = false;
                    }
                    else if (!sendTask.Result)
                    {
                        logger.LogWarning($"=> Request to {dstEp} did not get the expected response on request {sendCount} of {options.Count} after {duration.TotalMilliseconds.ToString("0")}ms.");
                        success = false;
                    }
                    else
                    {
                        logger.LogInformation($"=> Got correct response on send {sendCount} of {options.Count} in {duration.TotalMilliseconds.ToString("0")}ms.");
                    }

                    logger.LogDebug("Shutting down the SIP transport...");
                    sipTransport.Shutdown();

                    if (success == false)
                    {
                        break;
                    }
                }while (sendCount < options.Count);

                DNSManager.Stop();

                // Give the transport half a second to shutdown (puts the log messages in a better sequence).
                await Task.Delay(500);

                logger.LogInformation($"=> Command completed {((success) ? "successfully" : "with failure")}.");
            }
            catch (Exception excp)
            {
                logger.LogError($"Exception RunCommand. {excp.Message}");
            }
        }
        public void TcpTrickleReceiveTest()
        {
            TaskCompletionSource <bool> testComplete = new TaskCompletionSource <bool>();

            IPEndPoint listenEP   = new IPEndPoint(IPAddress.Loopback, 9067);
            var        transport  = new SIPTransport();
            var        tcpChannel = new SIPTCPChannel(new IPEndPoint(IPAddress.Loopback, 9066));

            tcpChannel.DisableLocalTCPSocketsCheck = true;
            transport.AddSIPChannel(tcpChannel);

            int requestCount  = 10;
            int recvdReqCount = 0;

            Task.Run(() =>
            {
                try
                {
                    TcpListener listener = new TcpListener(listenEP);
                    listener.Start();
                    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         = transport.GetRequest(SIPMethodsEnum.OPTIONS, tcpChannel.GetContactURI(SIPSchemesEnum.sip, listenEP.Address));
                        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)
                {
                    testComplete.SetResult(true);
                }
            };

            transport.SIPTransportResponseReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse) =>
            {
                logger.LogDebug($"Response received {localSIPEndPoint.ToString()}<-{remoteEndPoint.ToString()}: {sipResponse.ShortDescription}");
                logger.LogDebug(sipResponse.ToString());
            };

            tcpChannel.ConnectClientAsync(listenEP, null, null).Wait();

            Task.WhenAny(new Task[] { testComplete.Task, Task.Delay(TRANSPORT_TEST_TIMEOUT) }).Wait();

            transport.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.");
        }