Пример #1
0
        public async Task UnacceptedConnectionsAreAborted()
        {
            var transportContext = new TestLibuvTransportContext();
            var transport = new LibuvConnectionListener(transportContext, new IPEndPoint(IPAddress.Loopback, 0));

            await transport.BindAsync();
            var endpoint = (IPEndPoint)transport.EndPoint;

            async Task ConnectAsync()
            {
                using (var socket = TestConnection.CreateConnectedLoopbackSocket(endpoint.Port))
                {
                    try
                    {
                        var read = await socket.ReceiveAsync(new byte[10], SocketFlags.None);
                        Assert.Equal(0, read);
                    }
                    catch (SocketException)
                    {
                        // The connection can be reset sometimes
                    }
                }
            }

            var connectTask = ConnectAsync();

            await transport.UnbindAsync();
            await transport.DisposeAsync();

            // The connection was accepted because libuv eagerly accepts connections
            // they sit in a queue in each listener, we want to make sure that resources
            // are cleaned up if they are never accepted by the caller

            await connectTask.DefaultTimeout();
        }
Пример #2
0
        public async Task ConnectionCanReadAndWrite()
        {
            var transportContext = new TestLibuvTransportContext();

            await using var transport = new LibuvConnectionListener(transportContext, new IPEndPoint(IPAddress.Loopback, 0));

            await transport.BindAsync();

            var endpoint = (IPEndPoint)transport.EndPoint;

            async Task EchoServerAsync()
            {
                while (true)
                {
                    await using var connection = await transport.AcceptAsync();

                    if (connection == null)
                    {
                        break;
                    }

                    while (true)
                    {
                        var result = await connection.Transport.Input.ReadAsync();

                        if (result.IsCompleted)
                        {
                            break;
                        }
                        await connection.Transport.Output.WriteAsync(result.Buffer.ToArray());

                        connection.Transport.Input.AdvanceTo(result.Buffer.End);
                    }
                }
            }

            var serverTask = EchoServerAsync();

            using (var socket = TestConnection.CreateConnectedLoopbackSocket(endpoint.Port))
            {
                var data = Encoding.ASCII.GetBytes("Hello World");
                await socket.SendAsync(data, SocketFlags.None);

                var buffer = new byte[data.Length];
                var read   = 0;
                while (read < data.Length)
                {
                    read += await socket.ReceiveAsync(buffer.AsMemory(read, buffer.Length - read), SocketFlags.None);
                }

                Assert.Equal(data, buffer);
            }

            await transport.UnbindAsync();

            await serverTask.DefaultTimeout();
        }
Пример #3
0
        public async Task TransportCanBindUnbindAndStop()
        {
            var transportContext = new TestLibuvTransportContext();
            var transport = new LibuvConnectionListener(transportContext, new IPEndPoint(IPAddress.Loopback, 0));

            await transport.BindAsync();
            await transport.UnbindAsync();
            await transport.DisposeAsync();
        }
Пример #4
0
        public async Task TransportCanBindAndStop()
        {
            var transportContext = new TestLibuvTransportContext();
            var transport = new LibuvConnectionListener(transportContext, new IPEndPoint(IPAddress.Loopback, 0));

            // The transport can no longer start threads without binding to an endpoint.
            await transport.BindAsync();
            await transport.DisposeAsync();
        }
Пример #5
0
        public async Task CallingAcceptAfterDisposeAsyncThrows()
        {
            var transportContext = new TestLibuvTransportContext();
            var transport = new LibuvConnectionListener(transportContext, new IPEndPoint(IPAddress.Loopback, 0));

            await transport.BindAsync();
            var endpoint = (IPEndPoint)transport.EndPoint;

            await transport.UnbindAsync();
            await transport.DisposeAsync();

            await Assert.ThrowsAsync<ObjectDisposedException>(() => transport.AcceptAsync().AsTask());
        }
Пример #6
0
        public Listener(IPEndPoint ipep)
        {
            m_EndPoint = ipep;
            LibuvTransportContext transport = new LibuvTransportContext
            {
                Options     = new LibuvTransportOptions(),
                AppLifetime = new ApplicationLifetime(
                    LoggerFactory.Create(builder => { builder.AddConsole(); }).CreateLogger <ApplicationLifetime>()
                    ),
                Log = new LibuvTrace(LoggerFactory.Create(builder => { builder.AddConsole(); }).CreateLogger("network"))
            };

            m_Listener = new LibuvConnectionListener(functions, transport, ipep);
        }
Пример #7
0
        public async Task OneToTenThreads(int threadCount)
        {
            var listenOptions   = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
            var serviceContext  = new TestServiceContext();
            var testApplication = new DummyApplication(context =>
            {
                return(context.Response.WriteAsync("Hello World"));
            });

            listenOptions.UseHttpServer(serviceContext, testApplication, Core.HttpProtocols.Http1, addAltSvcHeader: false);

            var transportContext = new TestLibuvTransportContext
            {
#pragma warning disable CS0618
                Options = new LibuvTransportOptions {
                    ThreadCount = threadCount
                }
#pragma warning restore CS0618
            };

            await using var transport = new LibuvConnectionListener(transportContext, listenOptions.EndPoint);
            await transport.BindAsync();

            listenOptions.EndPoint = transport.EndPoint;

            var transportConnectionManager = new TransportConnectionManager(serviceContext.ConnectionManager);
            var dispatcher = new ConnectionDispatcher <ConnectionContext>(serviceContext, c => listenOptions.Build()(c), transportConnectionManager);
            var acceptTask = dispatcher.StartAcceptingConnections(new GenericConnectionListener(transport));

            using (var client = new HttpClient())
            {
                // Send 20 requests just to make sure we don't get any failures
                var requestTasks = new List <Task <string> >();
                for (int i = 0; i < 20; i++)
                {
                    var requestTask = client.GetStringAsync($"http://127.0.0.1:{listenOptions.IPEndPoint.Port}/");
                    requestTasks.Add(requestTask);
                }

                foreach (var result in await Task.WhenAll(requestTasks))
                {
                    Assert.Equal("Hello World", result);
                }
            }

            await transport.UnbindAsync();

            await acceptTask;

            if (!await transportConnectionManager.CloseAllConnectionsAsync(default))
Пример #8
0
        public async Task CallingDisposeAsyncWillYieldPendingAccepts()
        {
            var transportContext = new TestLibuvTransportContext();
            await using var transport = new LibuvConnectionListener(transportContext, new IPEndPoint(IPAddress.Loopback, 0));

            await transport.BindAsync();

            var acceptTask = transport.AcceptAsync();

            await transport.UnbindAsync();

            var connection = await acceptTask.DefaultTimeout();

            Assert.Null(connection);
        }
Пример #9
0
        public virtual async Task Start(MessagePump pump)
        {
            try
            {
                await m_Listener.BindAsync();
            }
            catch (AddressInUseException)
            {
                Console.WriteLine("Listener Failed: {0}:{1} (In Use)", m_EndPoint.Address, m_EndPoint.Port);
                m_Listener = null;
                return;
            }
            catch (Exception e)
            {
                Console.WriteLine("Listener Exception:");
                Console.WriteLine(e);

                m_Listener = null;
                return;
            }

            DisplayListener();

            while (true)
            {
                ConnectionContext context;
                try
                {
                    context = await m_Listener.AcceptAsync();
                }
                catch (SocketException ex)
                {
                    NetState.TraceException(ex);
                    continue;
                }

                if (VerifySocket(context))
                {
                    _ = new NetState(context, pump);
                }
                else
                {
                    Release(context);
                }
            }
        }
Пример #10
0
        public async Task Dispose()
        {
            LibuvConnectionListener listener = Interlocked.Exchange(ref m_Listener, null);

            if (listener != null)
            {
                try
                {
                    await listener.UnbindAsync();

                    await listener.DisposeAsync();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Listener: Failed to dispose.");
                    Console.WriteLine(ex);
                }
            }

            GC.SuppressFinalize(this);
        }
Пример #11
0
        static void Main(string[] args)
        {
            Console.WriteLine("Main: {0}", Thread.CurrentThread.ManagedThreadId);

            // Use the factory
            LibuvTransportContext transport = new LibuvTransportContext
            {
                Options     = new LibuvTransportOptions(),
                AppLifetime = new ApplicationLifetime(null),
                Log         = new LibuvTrace(LoggerFactory.Create(builder =>
                {
                    builder.AddConsole();
                }).CreateLogger("core"))
            };

            LibuvThread uvThread = new LibuvThread(libUv, transport);

            uvThread.StartAsync().Wait();

            Task.Run(async() =>
            {
                Console.WriteLine("NIO: {0}", Thread.CurrentThread.ManagedThreadId);

                LibuvConnectionListener listener = new LibuvConnectionListener(libUv, transport, new IPEndPoint(IPAddress.Parse("0.0.0.0"), 2593));
                Console.WriteLine("Binding... ({0})", Thread.CurrentThread.ManagedThreadId);
                await listener.BindAsync();

                Console.WriteLine("Listening... ({0})", Thread.CurrentThread.ManagedThreadId);
                ConnectionContext connectionContext = await listener.AcceptAsync();
                Console.WriteLine("Accepted Connection from {0}", connectionContext.RemoteEndPoint);
                PipeReader reader = connectionContext.Transport.Input;

                while (true)
                {
                    ReadResult readResult = await reader.ReadAsync();
                    int packetId          = readResult.Buffer.FirstSpan[0];
                    Console.WriteLine($"[0x{packetId:X}] Processing Packet");
                    int length     = PacketLengths[packetId];
                    int bodyLength = length - 1;
                    int bodyStart  = 1;
                    if (length == 0)
                    {
                        length     = BinaryPrimitives.ReadUInt16BigEndian(readResult.Buffer.FirstSpan.Slice(1, 2));
                        bodyLength = length - 3;
                        bodyStart  = 3;
                    }
                    else if (length == 0xFFFF)
                    {
                        Console.WriteLine($"[0x{packetId:X}] Unknown Packet");
                        throw new Exception($"[0x{packetId:X}] Unknown Packet");
                    }
                    Console.WriteLine($"[0x{packetId:X}] Found length {length}");
                    Console.WriteLine($"Packet Data: {ByteArrayToString(readResult.Buffer.FirstSpan.ToArray()):X}");
                    Memory <byte> mem = new Memory <byte>(readResult.Buffer.FirstSpan.Slice(bodyStart, bodyLength).ToArray());
                    Console.WriteLine($"[0x{packetId:X}] Buffer length {mem.Length}");

                    _ = uvThread.PostAsync((Tuple <ConnectionContext, Memory <byte> > t) =>
                    {
                        // stuff
                        var(conn, mem) = t;
                        // Do stuff wtih memOwner.Memory.Span;
                        Console.WriteLine($"Packet ID: 0x{packetId:X} - Length: {length} - Data: 0x{ByteArrayToString(mem.ToArray())}");
                    }, Tuple.Create(connectionContext, mem));

                    reader.AdvanceTo(readResult.Buffer.GetPosition(length));
                }
            });

            // Manually putting something on the queue from another thread (or the main thread)
            uvThread.PostAsync <object>(_ =>
            {
                Console.WriteLine("Game: {0}", Thread.CurrentThread.ManagedThreadId);
            }, null);

            // Send an Initialization Request for Timers

            /*
             * uvThread.PostAsync<object>(_ =>
             * {
             * UvTimerHandle timerHandle = new UvTimerHandle(null);
             * timerHandle.Init(uvThread.Loop, (callback, handle) =>
             * {
             *  Console.WriteLine("Closed ({0})", Thread.CurrentThread.ManagedThreadId);
             * });
             * Console.WriteLine("Timer Stuff {0}", Thread.CurrentThread.ManagedThreadId);
             * int count = 10;
             * void cb2(UvTimerHandle handle)
             * {
             *  Console.WriteLine("Called!2 {0} ({1})", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
             *  timerHandle.Start(cb2, 2000, 0);
             * }
             * void cb1(UvTimerHandle handle)
             * {
             *  Console.WriteLine("Called!1 {0} ({1})", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
             *  count--;
             *  if (count < 0)
             *    timerHandle.Start(cb2, 2000, 0);
             *  else
             *    timerHandle.Start(cb1, 1000, 0);
             * }
             * timerHandle.Start(cb1, 1000, 0);
             * }, null);
             */

            Console.ReadLine();
        }