public async Task CompletingOutputCancelsInput()
        {
            var inputCompletedTcs = new TaskCompletionSource <object>();
            TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) =>
            {
                output.Complete();
                bool exceptionThrown = true;
                try
                {
                    await input.ReadAsync();
                }
                catch (ConnectionAbortedException)
                {
                    exceptionThrown = true;
                }
                Assert.True(exceptionThrown);
                inputCompletedTcs.SetResult(null);
            };

            using (var testServer = CreateTestServer(connectionDispatcher))
            {
                await testServer.BindAsync();

                using (var client = testServer.ConnectTo())
                {
                    await inputCompletedTcs.Task;
                }

                await testServer.StopAsync();
            }
        }
Ejemplo n.º 2
0
        public async Task Write_Timeout()
        {
            const int bufferSize        = 2048;
            var       waitingForTimeout = new TaskCompletionSource <object>();
            TestServerConnectionDispatcher connectionDispatcher = async(input, output, connection) =>
            {
                Timer writeTimeout = new Timer(
                    _ => connection.Abort(),
                    null, Timeout.Infinite, Timeout.Infinite
                    );

                Exception exception = null;
                try
                {
                    do
                    {
                        var memory = output.GetMemory(bufferSize);
                        output.Advance(bufferSize);

                        // If it takes 1 second to write, assume the socket
                        // is no longer writable
                        writeTimeout.Change(1000, Timeout.Infinite);
                        var flushResult = await output.FlushAsync();

                        if (flushResult.IsCanceled || flushResult.IsCompleted)
                        {
                            break;
                        }
                        // cancel the timeout
                        writeTimeout.Change(Timeout.Infinite, Timeout.Infinite);
                    } while (true);
                }
                catch (Exception e)
                {
                    exception = e;
                }
                Assert.NotNull(exception);
                Assert.IsType <ConnectionAbortedException>(exception);

                waitingForTimeout.SetResult(null);

                writeTimeout.Dispose();
                output.Complete();
                input.Complete();
            };

            using (var testServer = CreateTestServer(connectionDispatcher))
            {
                await testServer.BindAsync();

                using (var client = testServer.ConnectTo())
                {
                    // wait for the server to timeout our connection
                    // because we aren't reading
                    await waitingForTimeout.Task;
                }

                await testServer.StopAsync();
            }
        }
        public TestServer(TestServerOptions options = null)
        {
            options = options ?? new TestServerOptions();
            _connectionDispatcher = options.ConnectionDispatcher;
            var transportOptions = new LinuxTransportOptions()
            {
                ThreadCount = options.ThreadCount,
                DeferAccept = options.DeferAccept,
                AioReceive  = options.AioReceive,
                AioSend     = options.AioSend,
                ApplicationSchedulingMode = options.ApplicationSchedulingMode,
            };
            var      loggerFactory = new LoggerFactory();
            EndPoint endPoint      = null;

            if (options.UnixSocketPath != null)
            {
                _unixSocketPath = options.UnixSocketPath;
                endPoint        = new UnixDomainSocketEndPoint(_unixSocketPath);
            }
            else
            {
                _serverAddress = options.IPEndPoint ?? new IPEndPoint(IPAddress.Loopback, 0);
                endPoint       = _serverAddress;
            }
            _transport = new Transport(endPoint, transportOptions, loggerFactory);
        }
        public async Task UnixSocketListenType()
        {
            TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) =>
            {
                int threadId = Thread.CurrentThread.ManagedThreadId;
                var data     = Encoding.UTF8.GetBytes(threadId.ToString());

                output.Write(data);
                await output.FlushAsync();

                output.Complete();
                input.Complete();
            };

            using (var testServer = CreateTestServer(options =>
                                                     { options.ConnectionDispatcher = connectionDispatcher;
                                                       options.ThreadCount = 2;
                                                       options.ApplicationSchedulingMode = PipeScheduler.Inline;
                                                       options.UnixSocketPath = $"{Path.GetTempPath()}/{Path.GetRandomFileName()}"; }))
            {
                await testServer.BindAsync();

                // This test is racy, it's ok to ignore occasional failure.
                // PipeScheduler.Inline isn't inline when there is no pending IConnectionListener.AcceptAsync.
                // Wait a little to increase probability of AcceptAsync.
                await Task.Delay(50);

                int[] threadIds = new int[4];
                for (int i = 0; i < 4; i++)
                {
                    using (var client = testServer.ConnectTo())
                    {
                        byte[] receiveBuffer = new byte[10];
                        int    received      = client.Receive(new ArraySegment <byte>(receiveBuffer));
                        int    threadId;
                        Assert.NotEqual(0, received);
                        Assert.True(int.TryParse(Encoding.UTF8.GetString(receiveBuffer, 0, received), out threadId));
                        threadIds[i] = threadId;

                        // check if the server closed the client.
                        // this would fail if not all fds for this client are closed
                        received = client.Receive(new ArraySegment <byte>(receiveBuffer));
                        Assert.Equal(0, received);
                    }

                    // See earlier comment, wait a little to increase probability of AcceptAsync.
                    await Task.Delay(50);
                }

                // check we are doing round robin over 2 handling threads
                Assert.NotEqual(threadIds[0], threadIds[1]);
                Assert.Equal(threadIds[0], threadIds[2]);
                Assert.Equal(threadIds[1], threadIds[3]);

                await testServer.StopAsync();
            }
        }
        public async Task Writable()
        {
            const int bufferSize         = 2048;
            int       bytesWritten       = 0;
            var       waitingForWritable = new TaskCompletionSource <object>();
            TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) =>
            {
                Timer writeTimeout = new Timer(
                    // timeout -> we are waiting for the socket to become writable
                    o => waitingForWritable.SetResult(null),
                    null, Timeout.Infinite, Timeout.Infinite
                    );

                do
                {
                    var memory = output.GetMemory(bufferSize);
                    output.Advance(bufferSize);
                    bytesWritten += bufferSize;

                    // If it takes 1 second to write, assume the socket
                    // is no longer writable
                    writeTimeout.Change(1000, Timeout.Infinite);
                    await output.FlushAsync();

                    // cancel the timeout
                    writeTimeout.Change(Timeout.Infinite, Timeout.Infinite);
                } while (!waitingForWritable.Task.IsCompleted);

                writeTimeout.Dispose();
                output.Complete();
                input.Complete();
            };

            using (var testServer = CreateTestServer(connectionDispatcher))
            {
                await testServer.BindAsync();

                using (var client = testServer.ConnectTo())
                {
                    // wait for the server to have sent so much data
                    // so it waiting for us to read some
                    await waitingForWritable.Task;

                    // read all the data
                    int    receivedBytes = 0;
                    byte[] receiveBuffer = new byte[bufferSize];
                    while (receivedBytes < bytesWritten)
                    {
                        var received = client.Receive(new ArraySegment <byte>(receiveBuffer));
                        receivedBytes += received;
                    }
                }

                await testServer.StopAsync();
            }
        }
        public async Task Receive()
        {
            // client send 1M bytes which are an int counter
            // server receives and checkes the counting
            const int receiveLength = 1000000;
            TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) =>
            {
                int bytesReceived = 0;
                int remainder     = 0; // remaining bytes between ReadableBuffers
                while (true)
                {
                    var readResult = await input.ReadAsync();

                    var buffer = readResult.Buffer;
                    if (buffer.IsEmpty && readResult.IsCompleted)
                    {
                        input.AdvanceTo(buffer.End);
                        break;
                    }
                    AssertCounter(ref buffer, ref bytesReceived, ref remainder);
                    input.AdvanceTo(buffer.End);
                }
                Assert.Equal(receiveLength, bytesReceived);
                output.Complete();
                input.Complete();
            };

            using (var testServer = CreateTestServer(connectionDispatcher))
            {
                await testServer.BindAsync();

                using (var client = testServer.ConnectTo())
                {
                    var buffer = new byte[1000000];
                    FillBuffer(new ArraySegment <byte>(buffer), 0);
                    int offset = 0;
                    do
                    {
                        offset += client.Send(new ArraySegment <byte>(buffer, offset, buffer.Length - offset));
                    } while (offset != buffer.Length);
                    client.Shutdown(SHUT_WR);

                    // wait for the server to stop
                    var receiveBuffer = new byte[1];
                    client.Receive(new ArraySegment <byte>(receiveBuffer));
                }

                await testServer.StopAsync();
            }
        }
        public async Task UnixSocketListenType()
        {
            TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) =>
            {
                int threadId = Thread.CurrentThread.ManagedThreadId;
                var data     = Encoding.UTF8.GetBytes(threadId.ToString());

                output.Write(data);
                await output.FlushAsync();

                output.Complete();
                input.Complete();
            };

            using (var testServer = CreateTestServer(options =>
                                                     { options.ConnectionDispatcher = connectionDispatcher;
                                                       options.ThreadCount = 2;
                                                       options.UnixSocketPath = $"{Path.GetTempPath()}/{Path.GetRandomFileName()}"; }))
            {
                await testServer.BindAsync();

                int[] threadIds = new int[4];
                for (int i = 0; i < 4; i++)
                {
                    using (var client = testServer.ConnectTo())
                    {
                        byte[] receiveBuffer = new byte[10];
                        int    received      = client.Receive(new ArraySegment <byte>(receiveBuffer));
                        int    threadId;
                        Assert.NotEqual(0, received);
                        Assert.True(int.TryParse(Encoding.UTF8.GetString(receiveBuffer, 0, received), out threadId));
                        threadIds[i] = threadId;

                        // check if the server closed the client.
                        // this would fail if not all fds for this client are closed
                        received = client.Receive(new ArraySegment <byte>(receiveBuffer));
                        Assert.Equal(0, received);
                    }
                }

                // check we are doing round robin over 2 handling threads
                Assert.NotEqual(threadIds[0], threadIds[1]);
                Assert.Equal(threadIds[0], threadIds[2]);
                Assert.Equal(threadIds[1], threadIds[3]);

                await testServer.StopAsync();
            }
        }
        public async Task StopDisconnectsClient(bool waitForAccept)
        {
            var clientAcceptedTcs = new TaskCompletionSource <object>();
            TestServerConnectionDispatcher connectionDispatcher = (input, output, context) =>
            {
                clientAcceptedTcs.SetResult(output);
                return(Task.Delay(int.MaxValue, context.ConnectionClosed));
            };

            using (var testServer = CreateTestServer(connectionDispatcher))
            {
                await testServer.BindAsync();

                using (var client = testServer.ConnectTo())
                {
                    // Make sure the client is accepted.
                    if (waitForAccept)
                    {
                        await clientAcceptedTcs.Task;
                    }
                    // Server shutdown:
                    await testServer.UnbindAsync();

                    await testServer.StopAsync();

                    byte[] receiveBuffer = new byte[10];

                    var received = client.Receive(new ArraySegment <byte>(receiveBuffer));
                    // Socket was accepted by the server, which will do a normal TCP close.
                    Assert.Equal(0, received);

                    // send returns EPIPE
                    var exception = Assert.Throws <IOException>(() =>
                    {
                        for (int i = 0; i < 10; i++)
                        {
                            byte[] sendBuffer = new byte[] { 1, 2, 3 };
                            client.Send(new ArraySegment <byte>(sendBuffer));
                        }
                    });
                    Assert.Equal(EPIPE, exception.HResult);
                }

                await testServer.StopAsync();
            }
        }
        public async Task Send()
        {
            // server send 1M bytes which are an int counter
            // client receives and checkes the counting
            const int sendLength = 1_000_000;
            TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) =>
            {
                FillBuffer(output, sendLength / 4);
                await output.FlushAsync();

                output.Complete();
                input.Complete();
            };

            using (var testServer = CreateTestServer(connectionDispatcher))
            {
                await testServer.BindAsync();

                using (var client = testServer.ConnectTo())
                {
                    int  totalReceived = 0;
                    var  receiveBuffer = new byte[4000];
                    bool eof           = false;
                    do
                    {
                        int offset   = 0;
                        int received = 0;
                        do
                        {
                            var receive = client.Receive(new ArraySegment <byte>(receiveBuffer, offset, receiveBuffer.Length - offset));
                            received += receive;
                            offset   += receive;
                            eof       = receive == 0;
                        } while (!eof && offset != receiveBuffer.Length);

                        AssertCounter(new ArraySegment <byte>(receiveBuffer, 0, received), totalReceived / 4);
                        totalReceived += received;
                    } while (!eof);
                    Assert.True(totalReceived == sendLength);
                }

                await testServer.StopAsync();
            }
        }
        public async Task StopDisconnectsClient()
        {
            var outputTcs = new TaskCompletionSource <PipeWriter>();
            TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) =>
            {
                outputTcs.SetResult(output);
            };

            using (var testServer = CreateTestServer(connectionDispatcher))
            {
                await testServer.BindAsync();

                using (var client = testServer.ConnectTo())
                {
                    // Server shutdown:
                    await testServer.UnbindAsync();

                    // Complete existing connections
                    PipeWriter clientOutput = await outputTcs.Task;
                    clientOutput.Complete(new ConnectionAbortedException());
                    await testServer.StopAsync();

                    // receive returns EOF
                    byte[] receiveBuffer = new byte[10];
                    var    received      = client.Receive(new ArraySegment <byte>(receiveBuffer));
                    Assert.Equal(0, received);

                    // send returns EPIPE
                    var exception = Assert.Throws <IOException>(() =>
                    {
                        for (int i = 0; i < 10; i++)
                        {
                            byte[] sendBuffer = new byte[] { 1, 2, 3 };
                            client.Send(new ArraySegment <byte>(sendBuffer));
                        }
                    });
                    Assert.Equal(EPIPE, exception.HResult);
                }

                await testServer.StopAsync();
            }
        }
Ejemplo n.º 11
0
        public async Task CompletingOutputCancelsInput()
        {
            var inputCompletedTcs = new TaskCompletionSource <object>();
            TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) =>
            {
                output.Complete();
                await input.ReadAsync();

                inputCompletedTcs.SetResult(null);
            };

            using (var testServer = CreateTestServer(connectionDispatcher))
            {
                await testServer.BindAsync();

                using (var client = testServer.ConnectTo())
                {
                    await inputCompletedTcs.Task;
                }

                await testServer.StopAsync();
            }
        }
        public async Task BatchedSendReceive()
        {
            // We block the TransportThread to ensure 2 clients are sending multiple buffers with random data.
            // These buffers are echoed back.
            // The clients verify they each receive the random data they sent.

            const int DataLength = 10_000;

            int           connectionCount          = 0;
            SemaphoreSlim clientsAcceptedSemaphore = new SemaphoreSlim(0, 1);
            SemaphoreSlim dataSentSemaphore        = new SemaphoreSlim(0, 1);

            TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) =>
            {
                connectionCount++;

                if (connectionCount == 3)
                {
                    // Ensure we accepted the clients.
                    clientsAcceptedSemaphore.Release();

                    // Now wait for clients to send data.
                    dataSentSemaphore.Wait();
                }

                // Echo
                while (true)
                {
                    var result = await input.ReadAsync();

                    var request = result.Buffer;

                    if (request.IsEmpty && result.IsCompleted)
                    {
                        input.AdvanceTo(request.End);
                        break;
                    }

                    // Clients send more data than what fits in a single segment.
                    Assert.True(!request.IsSingleSegment);

                    foreach (var memory in request)
                    {
                        output.Write(memory.Span);
                    }
                    await output.FlushAsync();

                    input.AdvanceTo(request.End);
                }

                output.Complete();
                input.Complete();
            };

            using (var testServer = CreateTestServer(connectionDispatcher))
            {
                await testServer.BindAsync();

                using (var client1 = testServer.ConnectTo())
                {
                    using (var client2 = testServer.ConnectTo())
                    {
                        using (var client3 = testServer.ConnectTo())
                        { }

                        // Wait for all clients to be accepted.
                        // The TransportThread will now be blocked.
                        clientsAcceptedSemaphore.Wait();

                        // Send data
                        var client1DataSent = new byte[DataLength];
                        FillRandom(client1DataSent);
                        var client2DataSent = new byte[DataLength];
                        FillRandom(client2DataSent);
                        int bytesSent = client1.Send(new ArraySegment <byte>(client1DataSent));
                        Assert.Equal(DataLength, bytesSent);
                        bytesSent = client2.Send(new ArraySegment <byte>(client2DataSent));
                        Assert.Equal(DataLength, bytesSent);

                        // Unblock the TransportThread
                        dataSentSemaphore.Release();

                        // Receive echoed data.
                        var client1DataReceived = new byte[DataLength];
                        int bytesReceived       = client1.Receive(new ArraySegment <byte>(client1DataReceived));
                        Assert.Equal(DataLength, bytesReceived);
                        Assert.Equal(client1DataSent, client1DataReceived);
                        var client2DataReceived = new byte[DataLength];
                        bytesReceived = client2.Receive(new ArraySegment <byte>(client2DataReceived));
                        Assert.Equal(DataLength, bytesReceived);
                        Assert.Equal(client2DataSent, client2DataReceived);
                    }
                }

                await testServer.StopAsync();
            }
        }
 private TestServer CreateTestServer(TestServerConnectionDispatcher connectionDispatcher)
 => CreateTestServer(options => options.ConnectionDispatcher = connectionDispatcher);
 public TestServer(TestServerConnectionDispatcher connectionDispatcher) :
     this(new TestServerOptions() { ConnectionDispatcher = connectionDispatcher })
 {
 }