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(); }
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(); }
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(); }
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(); }
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()); }
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); }
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))
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); }
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); } } }
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); }
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(); }