/// <summary> /// Starts a runner instance /// </summary> /// <returns>The awaitable task.</returns> /// <param name="domain">The AppDomain to use.</param> /// <param name="config">The server configuration.</param> /// <param name="usessl">If set to <c>true</c> use ssl.</param> /// <param name="port">The port to listen on.</param> private async Task StartRunnerAsync(System.AppDomain domain, ServerConfig config, bool usessl, string address, int port) { var enabled = !string.IsNullOrWhiteSpace(address); // Ensure it parses ParseUtil.ParseEndPoint(address, port); var prev = m_handlers.Where(x => x.UseSSL == usessl).FirstOrDefault(); if (enabled) { var addcrashhandler = true; var wrapper = new AppDomainWrapper(domain); wrapper.SetupFromFile(usessl, m_path, config.Storage); if (prev == null) { prev = new RunnerInstance(wrapper, address, port, usessl, config); m_handlers.Add(prev); } else { if (prev.RunnerTask.IsFaulted || prev.RunnerTask.IsCanceled || prev.RunnerTask.IsCompleted) { var cur = new RunnerInstance(wrapper, address, port, usessl, config); m_handlers.Remove(prev); m_handlers.Add(cur); prev = cur; } else if (prev.Port != port || !string.Equals(prev.Address, address, StringComparison.Ordinal)) { // Address or port change, start new listener first var cur = new RunnerInstance(wrapper, address, port, usessl, config); if (!prev.RunnerTask.IsFaulted) { await prev.StopAsync(); } m_handlers.Remove(prev); m_handlers.Add(cur); prev = cur; } else if (prev.Config.SocketBacklog != config.SocketBacklog) { await prev.RestartAsync(wrapper, address, port, usessl, config); } else { addcrashhandler = false; // We already have it prev.Wrapper = wrapper; // Assign the new wrapper } } if (addcrashhandler) { var dummy = prev.RunnerTask.ContinueWith(x => { if (!prev.ShouldStop && InstanceCrashed != null) { InstanceCrashed(address, usessl, x.IsFaulted ? x.Exception : new Exception("Unexpected stop")); } }); } } else if (prev != null) { await prev.StopAsync(); m_handlers.Remove(prev); } }