public IDisposable CreateServer(ServerAddress address) { var listeners = new List <IAsyncDisposable>(); var usingPipes = address.IsUnixPipe; try { var pipeName = (Libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); var single = Threads.Count == 1; var first = true; foreach (var thread in Threads) { if (single) { var listener = usingPipes ? (Listener) new PipeListener(this) : new TcpListener(this); listeners.Add(listener); listener.StartAsync(address, thread).Wait(); } else if (first) { var listener = usingPipes ? (ListenerPrimary) new PipeListenerPrimary(this) : new TcpListenerPrimary(this); listeners.Add(listener); listener.StartAsync(pipeName, address, thread).Wait(); } else { var listener = usingPipes ? (ListenerSecondary) new PipeListenerSecondary(this) : new TcpListenerSecondary(this); listeners.Add(listener); listener.StartAsync(pipeName, address, thread).Wait(); } first = false; } return(new Disposable(() => { DisposeListeners(listeners); })); } catch { DisposeListeners(listeners); throw; } }
public void Start <TContext>(IHttpApplication <TContext> application) { if (_disposables != null) { // The server has already started and/or has not been cleaned up yet throw new InvalidOperationException("Server has already started."); } _disposables = new Stack <IDisposable>(); try { var dateHeaderValueManager = new DateHeaderValueManager(); var trace = new KestrelTrace(_logger); var engine = new KestrelEngine(new ServiceContext { FrameFactory = context => { return(new Frame <TContext>(application, context)); }, AppLifetime = _applicationLifetime, Log = trace, ThreadPool = new LoggingThreadPool(trace), DateHeaderValueManager = dateHeaderValueManager, ServerOptions = Options }); _disposables.Push(engine); _disposables.Push(dateHeaderValueManager); var threadCount = Options.ThreadCount; if (threadCount <= 0) { throw new ArgumentOutOfRangeException(nameof(threadCount), threadCount, "ThreadCount must be positive."); } if (!Constants.ECONNRESET.HasValue) { _logger.LogWarning("Unable to determine ECONNRESET value on this platform."); } if (!Constants.EADDRINUSE.HasValue) { _logger.LogWarning("Unable to determine EADDRINUSE value on this platform."); } engine.Start(threadCount); var atLeastOneListener = false; foreach (var address in _serverAddresses.Addresses.ToArray()) { var parsedAddress = ServerAddress.FromUrl(address); atLeastOneListener = true; if (!parsedAddress.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase)) { _disposables.Push(engine.CreateServer( parsedAddress)); } else { if (parsedAddress.Port == 0) { throw new InvalidOperationException("Dynamic port binding is not supported when binding to localhost. You must either bind to 127.0.0.1:0 or [::1]:0, or both."); } var ipv4Address = parsedAddress.WithHost("127.0.0.1"); var exceptions = new List <UvException>(); try { _disposables.Push(engine.CreateServer(ipv4Address)); } catch (AggregateException ex) { var uvException = ex.InnerException as UvException; if (uvException != null && uvException.StatusCode != Constants.EADDRINUSE) { _logger.LogWarning(0, ex, $"Unable to bind to {parsedAddress.ToString()} on the IPv4 loopback interface."); exceptions.Add(uvException); } else { throw; } } var ipv6Address = parsedAddress.WithHost("[::1]"); try { _disposables.Push(engine.CreateServer(ipv6Address)); } catch (AggregateException ex) { var uvException = ex.InnerException as UvException; if (uvException != null && uvException.StatusCode != Constants.EADDRINUSE) { _logger.LogWarning(0, ex, $"Unable to bind to {parsedAddress.ToString()} on the IPv6 loopback interface."); exceptions.Add(uvException); } else { throw; } } if (exceptions.Count == 2) { var ex = new AggregateException(exceptions); _logger.LogError(0, ex, $"Unable to bind to {parsedAddress.ToString()} on any loopback interface."); throw ex; } } // If requested port was "0", replace with assigned dynamic port. _serverAddresses.Addresses.Remove(address); _serverAddresses.Addresses.Add(parsedAddress.ToString()); } if (!atLeastOneListener) { throw new InvalidOperationException("No recognized listening addresses were configured."); } } catch { Dispose(); throw; } }
public void Start <TContext>(IHttpApplication <TContext> application) { if (_disposables != null) { // The server has already started and/or has not been cleaned up yet throw new InvalidOperationException("Server has already started."); } _disposables = new Stack <IDisposable>(); try { var componentFactory = Features.Get <IHttpComponentFactory>(); var dateHeaderValueManager = new DateHeaderValueManager(); var trace = new KestrelTrace(_logger); var engine = new KestrelEngine(new ServiceContext { FrameFactory = context => { return(new Frame <TContext>(application, context)); }, AppLifetime = _applicationLifetime, Log = trace, ThreadPool = new LoggingThreadPool(trace), DateHeaderValueManager = dateHeaderValueManager, ServerOptions = Options, HttpComponentFactory = componentFactory }); _disposables.Push(engine); _disposables.Push(dateHeaderValueManager); var threadCount = Options.ThreadCount; if (threadCount <= 0) { throw new ArgumentOutOfRangeException(nameof(threadCount), threadCount, "ThreadCount must be positive."); } engine.Start(threadCount); var atLeastOneListener = false; foreach (var address in _serverAddresses.Addresses) { var parsedAddress = ServerAddress.FromUrl(address); if (parsedAddress == null) { throw new FormatException("Unrecognized listening address: " + address); } else { atLeastOneListener = true; _disposables.Push(engine.CreateServer( parsedAddress)); } } if (!atLeastOneListener) { throw new InvalidOperationException("No recognized listening addresses were configured."); } } catch { Dispose(); throw; } }
public static ServerAddress FromUrl(string url) { url = url ?? string.Empty; int schemeDelimiterStart = url.IndexOf("://", StringComparison.Ordinal); if (schemeDelimiterStart < 0) { int port; if (int.TryParse(url, NumberStyles.None, CultureInfo.InvariantCulture, out port)) { return(new ServerAddress() { Scheme = "http", Host = "+", Port = port, PathBase = "/" }); } return(null); } int schemeDelimiterEnd = schemeDelimiterStart + "://".Length; var isUnixPipe = url.IndexOf(Constants.UnixPipeHostPrefix, schemeDelimiterEnd, StringComparison.Ordinal) == schemeDelimiterEnd; int pathDelimiterStart; int pathDelimiterEnd; if (!isUnixPipe) { pathDelimiterStart = url.IndexOf("/", schemeDelimiterEnd, StringComparison.Ordinal); pathDelimiterEnd = pathDelimiterStart; } else { pathDelimiterStart = url.IndexOf(":", schemeDelimiterEnd + Constants.UnixPipeHostPrefix.Length, StringComparison.Ordinal); pathDelimiterEnd = pathDelimiterStart + ":".Length; } if (pathDelimiterStart < 0) { pathDelimiterStart = pathDelimiterEnd = url.Length; } var serverAddress = new ServerAddress(); serverAddress.Scheme = url.Substring(0, schemeDelimiterStart); var hasSpecifiedPort = false; if (!isUnixPipe) { int portDelimiterStart = url.LastIndexOf(":", pathDelimiterStart - 1, pathDelimiterStart - schemeDelimiterEnd, StringComparison.Ordinal); if (portDelimiterStart >= 0) { int portDelimiterEnd = portDelimiterStart + ":".Length; string portString = url.Substring(portDelimiterEnd, pathDelimiterStart - portDelimiterEnd); int portNumber; if (int.TryParse(portString, NumberStyles.Integer, CultureInfo.InvariantCulture, out portNumber)) { hasSpecifiedPort = true; serverAddress.Host = url.Substring(schemeDelimiterEnd, portDelimiterStart - schemeDelimiterEnd); serverAddress.Port = portNumber; } } if (!hasSpecifiedPort) { if (string.Equals(serverAddress.Scheme, "http", StringComparison.OrdinalIgnoreCase)) { serverAddress.Port = 80; } else if (string.Equals(serverAddress.Scheme, "https", StringComparison.OrdinalIgnoreCase)) { serverAddress.Port = 443; } } } if (!hasSpecifiedPort) { serverAddress.Host = url.Substring(schemeDelimiterEnd, pathDelimiterStart - schemeDelimiterEnd); } // Path should not end with a / since it will be used as PathBase later if (url[url.Length - 1] == '/') { serverAddress.PathBase = url.Substring(pathDelimiterEnd, url.Length - pathDelimiterEnd - 1); } else { serverAddress.PathBase = url.Substring(pathDelimiterEnd); } serverAddress.PathBase = PathNormalizer.NormalizeToNFC(serverAddress.PathBase); return(serverAddress); }