public TestLibuvTransportContext() { var logger = new TestApplicationErrorLogger(); AppLifetime = new LifetimeNotImplemented(); Log = new LibuvTrace(logger); Options = new LibuvTransportOptions { ThreadCount = 1 }; }
public TestLibuvTransportContext() { var logger = new TestApplicationErrorLogger(); AppLifetime = new LifetimeNotImplemented(); Log = new LibuvTrace(logger); #pragma warning disable CS0618 Options = new LibuvTransportOptions { ThreadCount = 1 }; #pragma warning restore CS0618 }
public void ReadStopIsIdempotent() { var libuvTrace = new LibuvTrace(new TestApplicationErrorLogger()); using (var uvLoopHandle = new UvLoopHandle(libuvTrace)) using (var uvTcpHandle = new UvTcpHandle(libuvTrace)) { uvLoopHandle.Init(new MockLibuv()); uvTcpHandle.Init(uvLoopHandle, null); UvStreamHandle uvStreamHandle = uvTcpHandle; uvStreamHandle.ReadStop(); uvStreamHandle.ReadStop(); } }
public LibuvTransportFactory( IOptions <LibuvTransportOptions> options, IApplicationLifetime applicationLifetime, ILoggerFactory loggerFactory) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (applicationLifetime == null) { throw new ArgumentNullException(nameof(applicationLifetime)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"); var trace = new LibuvTrace(logger); var threadCount = options.Value.ThreadCount; if (threadCount <= 0) { throw new ArgumentOutOfRangeException(nameof(threadCount), threadCount, "ThreadCount must be positive."); } if (!LibuvConstants.ECONNRESET.HasValue) { trace.LogWarning("Unable to determine ECONNRESET value on this platform."); } if (!LibuvConstants.EADDRINUSE.HasValue) { trace.LogWarning("Unable to determine EADDRINUSE value on this platform."); } _baseTransportContext = new LibuvTransportContext { Options = options.Value, AppLifetime = applicationLifetime, Log = trace, }; }
public async Task NonListenerPipeConnectionsAreLoggedAndIgnored() { var libuv = new LibuvFunctions(); var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0)); var logger = new TestApplicationErrorLogger(); var serviceContextPrimary = new TestServiceContext(); var builderPrimary = new ConnectionBuilder(); builderPrimary.UseHttpServer(serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")), HttpProtocols.Http1); var transportContextPrimary = new TestLibuvTransportContext() { Log = new LibuvTrace(logger) }; transportContextPrimary.ConnectionDispatcher = new ConnectionDispatcher(serviceContextPrimary, builderPrimary.Build()); var serviceContextSecondary = new TestServiceContext { DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager, ServerOptions = serviceContextPrimary.ServerOptions, Scheduler = serviceContextPrimary.Scheduler, HttpParser = serviceContextPrimary.HttpParser, }; var builderSecondary = new ConnectionBuilder(); builderSecondary.UseHttpServer(serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")), HttpProtocols.Http1); var transportContextSecondary = new TestLibuvTransportContext(); transportContextSecondary.ConnectionDispatcher = new ConnectionDispatcher(serviceContextSecondary, builderSecondary.Build()); var libuvTransport = new LibuvTransport(libuv, transportContextPrimary, listenOptions); var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); var pipeMessage = Guid.NewGuid().ToByteArray(); // Start primary listener var libuvThreadPrimary = new LibuvThread(libuvTransport); await libuvThreadPrimary.StartAsync(); var listenerPrimary = new ListenerPrimary(transportContextPrimary); await listenerPrimary.StartAsync(pipeName, pipeMessage, listenOptions, libuvThreadPrimary); var address = GetUri(listenOptions); // Add secondary listener var libuvThreadSecondary = new LibuvThread(libuvTransport); await libuvThreadSecondary.StartAsync(); var listenerSecondary = new ListenerSecondary(transportContextSecondary); await listenerSecondary.StartAsync(pipeName, pipeMessage, listenOptions, libuvThreadSecondary); // TCP Connections get round-robined await AssertResponseEventually(address, "Secondary", allowed : new[] { "Primary" }); Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address)); // Create a pipe connection and keep it open without sending any data var connectTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); var connectionTrace = new LibuvTrace(new TestApplicationErrorLogger()); var pipe = new UvPipeHandle(connectionTrace); libuvThreadPrimary.Post(_ => { var connectReq = new UvConnectRequest(connectionTrace); pipe.Init(libuvThreadPrimary.Loop, libuvThreadPrimary.QueueCloseHandle); connectReq.Init(libuvThreadPrimary); connectReq.Connect( pipe, pipeName, (req, status, ex, __) => { req.Dispose(); if (ex != null) { connectTcs.SetException(ex); } else { connectTcs.SetResult(null); } }, null); }, (object)null); await connectTcs.Task; // TCP connections will still get round-robined between only the two listeners Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address)); Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address)); Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address)); await libuvThreadPrimary.PostAsync(_ => pipe.Dispose(), (object)null); // Wait up to 10 seconds for error to be logged for (var i = 0; i < 10 && logger.TotalErrorsLogged == 0; i++) { await Task.Delay(100); } // Same for after the non-listener pipe connection is closed Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address)); Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address)); Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address)); await listenerSecondary.DisposeAsync(); await libuvThreadSecondary.StopAsync(TimeSpan.FromSeconds(5)); await listenerPrimary.DisposeAsync(); await libuvThreadPrimary.StopAsync(TimeSpan.FromSeconds(5)); Assert.Equal(1, logger.TotalErrorsLogged); var errorMessage = logger.Messages.First(m => m.LogLevel == LogLevel.Error); Assert.Equal(TestConstants.EOF, Assert.IsType <UvException>(errorMessage.Exception).StatusCode); }
public async Task NonListenerPipeConnectionsAreLoggedAndIgnored() { var libuv = new LibuvFunctions(); var endpoint = new IPEndPoint(IPAddress.Loopback, 0); var logger = new TestApplicationErrorLogger(); var transportContextPrimary = new TestLibuvTransportContext { Log = new LibuvTrace(logger) }; var transportContextSecondary = new TestLibuvTransportContext(); var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); var pipeMessage = Guid.NewGuid().ToByteArray(); // Start primary listener var libuvThreadPrimary = new LibuvThread(libuv, transportContextPrimary); await libuvThreadPrimary.StartAsync(); var listenerPrimary = new ListenerPrimary(transportContextPrimary); await listenerPrimary.StartAsync(pipeName, pipeMessage, endpoint, libuvThreadPrimary); var address = GetUri(listenerPrimary.EndPoint); // Add secondary listener var libuvThreadSecondary = new LibuvThread(libuv, transportContextSecondary); await libuvThreadSecondary.StartAsync(); var listenerSecondary = new ListenerSecondary(transportContextSecondary); await listenerSecondary.StartAsync(pipeName, pipeMessage, endpoint, libuvThreadSecondary); // TCP Connections get round-robined var primary = await WaitForSecondaryListener(address, listenerPrimary, listenerSecondary); // Make sure the pending accept get yields using (var socket = await HttpClientSlim.GetSocket(address)) { await(await primary.DefaultTimeout()).DisposeAsync(); } // Create a pipe connection and keep it open without sending any data var connectTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var connectionTrace = new LibuvTrace(new TestApplicationErrorLogger()); var pipe = new UvPipeHandle(connectionTrace); libuvThreadPrimary.Post(_ => { var connectReq = new UvConnectRequest(connectionTrace); pipe.Init(libuvThreadPrimary.Loop, libuvThreadPrimary.QueueCloseHandle); connectReq.Init(libuvThreadPrimary); connectReq.Connect( pipe, pipeName, (req, status, ex, __) => { req.Dispose(); if (ex != null) { connectTcs.SetException(ex); } else { connectTcs.SetResult(); } }, null); }, (object)null); await connectTcs.Task; // TCP connections will still get round-robined between only the two listeners await AssertRoundRobin(address, listenerPrimary, listenerSecondary, listenerPrimary); await libuvThreadPrimary.PostAsync(_ => pipe.Dispose(), (object)null); // Wait up to 10 seconds for error to be logged for (var i = 0; i < 10 && logger.TotalErrorsLogged == 0; i++) { await Task.Delay(100); } // Same for after the non-listener pipe connection is closed await AssertRoundRobin(address, listenerPrimary, listenerSecondary, listenerPrimary); await listenerSecondary.DisposeAsync(); await libuvThreadSecondary.StopAsync(TimeSpan.FromSeconds(5)); await listenerPrimary.DisposeAsync(); await libuvThreadPrimary.StopAsync(TimeSpan.FromSeconds(5)); Assert.Equal(0, logger.TotalErrorsLogged); var logMessage = logger.Messages.Single(m => m.Message == "An internal pipe was opened unexpectedly."); Assert.Equal(LogLevel.Debug, logMessage.LogLevel); }