// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNet.Server.Kestrel.Networking; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNet.Server.Kestrel.Http; using Microsoft.Framework.Runtime; using System.IO; namespace Microsoft.AspNet.Server.Kestrel { public class KestrelEngine : IDisposable { public KestrelEngine(ILibraryManager libraryManager, IApplicationShutdown appShutdownService) { AppShutdown = appShutdownService; Threads = new List(); Listeners = new List(); Memory = new MemoryPool(); Libuv = new Libuv(); var libraryPath = default(string); if (libraryManager != null) { var library = libraryManager.GetLibraryInformation("Microsoft.AspNet.Server.Kestrel"); libraryPath = library.Path; if (library.Type == "Project") { libraryPath = Path.GetDirectoryName(libraryPath); } if (Libuv.IsWindows) { var architecture = IntPtr.Size == 4 ? "x86" : "amd64"; libraryPath = Path.Combine( libraryPath, "native", "windows", architecture, "libuv.dll"); } else if (Libuv.IsDarwin) { libraryPath = Path.Combine( libraryPath, "native", "darwin", "universal", "libuv.dylib"); } else { libraryPath = "libuv.so.1"; } } Libuv.Load(libraryPath); } public Libuv Libuv { get; private set; } public IMemoryPool Memory { get; set; } public IApplicationShutdown AppShutdown { get; private set; } public List Threads { get; private set; } public List Listeners { get; private set; } public void Start(int count) { for (var index = 0; index != count; ++index) { Threads.Add(new KestrelThread(this)); } foreach (var thread in Threads) { thread.StartAsync().Wait(); } } public void Dispose() { foreach (var thread in Threads) { thread.Stop(TimeSpan.FromSeconds(2.5)); } Threads.Clear(); } public IDisposable CreateServer(string scheme, string host, int port, Func application) { var listeners = new List(); 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 = new Listener(Memory); listeners.Add(listener); listener.StartAsync(scheme, host, port, thread, application).Wait(); } else if (first) { var listener = new ListenerPrimary(Memory); listeners.Add(listener); listener.StartAsync(pipeName, scheme, host, port, thread, application).Wait(); } else { var listener = new ListenerSecondary(Memory); listeners.Add(listener); listener.StartAsync(pipeName, thread, application).Wait(); } first = false; } return new Disposable(() => { foreach (var listener in listeners) { listener.Dispose(); } }); } catch { foreach (var listener in listeners) { listener.Dispose(); } throw; } } } }