public ServerConnection(Socket socket, ServiceDispatcher dispatcher, ServiceHostConfig config, ServiceHostCounters counters, ISerializer serializer, X509Certificate?certificate) { _dispatcher = dispatcher; _socket = socket; _config = config; _requestLogger = new RequestLogger(socket.GetRemoteAddressName(), dispatcher.MessageMap); Stream readerStream, writerStream; if (config.TlsSettings == null || certificate == null) { readerStream = new NetworkStream(socket, FileAccess.Read, false); writerStream = new NetworkStream(socket, FileAccess.Write, false); } else { var networkStream = new NetworkStream(socket, FileAccess.ReadWrite, false); var tlsStream = new SslStream(networkStream, true); readerStream = writerStream = tlsStream; _tls = new TlsData(certificate, tlsStream); } _messageReader = new DelimitedMessageReader(socket.GetRemoteAddressName(), readerStream, serializer); _messageWriter = new DelimitedMessageWriter(socket.GetRemoteAddressName(), writerStream, serializer); _responsePropagatorTask = PropagateResponses(); _counters = counters; }
private static ClusterConnection CreateClusterConnection(ServiceHostConfig config, ISerializer serializer) { return(new ClusterConnection(config.KnownHosts, new ClusterConnectionSettings { ReconnectionDelay = TimeSpan.FromSeconds(config.ClusterConnectionSettings.ReconnectionDelay), MaxRequestHoldTime = TimeSpan.FromSeconds(config.ClusterConnectionSettings.MaxRequestHoldTime), Serializer = serializer, TlsSettings = { AllowSelfSignedCertificates = config.TlsSettings?.AllowSelfSignedCertificates ?? false } })); }
private static async Task ConnectCluster(ServiceHostConfig config, ClusterConnection clusterConnection) { _logger.Info("Connecting cluster after {0} sec.", config.ClusterConnectionSettings.ConnectionDelay); try { await clusterConnection.Connect(TimeSpan.FromSeconds(config.ClusterConnectionSettings.ConnectionDelay)); _logger.Info("Cluster connected."); } catch (Exception ex) { _logger.Error(ex, "Failed to connect cluster. Interservice communication is not available."); } }
private async Task UpdateClusterConnection(ServiceHostConfig config, ClusterConnection clusterConnection) { try { while (_updateClusterConnection) { clusterConnection.Update(); await Task.Delay(TimeSpan.FromMilliseconds(config.ClusterConnectionSettings.UpdatePeriodMs)); } } catch (Exception ex) { // Server callbacks are just async completions. They are not expected to throw exceptions. _logger.Fatal(ex, "Callbacks invocation faulted. No more callbacks will be invoked."); } }
private static async Task <X509Certificate?> LoadCertificate(ServiceHostConfig config) { if (config.TlsSettings == null || string.IsNullOrEmpty(config.TlsSettings.CertificateFile) || string.IsNullOrEmpty(config.TlsSettings.PasswordFile)) { return(null); } byte[] certificateData = await File.ReadAllBytesAsync(config.TlsSettings.CertificateFile); string password = await File.ReadAllTextAsync(config.TlsSettings.PasswordFile); var certificate = new X509Certificate(certificateData, password); _logger.Info("Loaded TLS certificate issued by '{0}' for '{1}' SN:'{2}' expires: {3}", certificate.Issuer, certificate.Subject, certificate.GetSerialNumberString(), certificate.GetExpirationDateString() ); return(certificate); }
private async void ServeConnection(ServerConnection connection, ServiceHostConfig config, Session session, int connectionId) { var clientRemoteAddress = ((IPEndPoint)connection.Socket.RemoteEndPoint).Address; try { session.SetData(new Session.Data { InstanceId = config.InstanceId, ClientRemoteAddress = clientRemoteAddress, ConnectionId = connectionId }); await connection.Serve(session); } catch (Exception ex) { _logger.Error(ex, "Connection {0} faulted.", clientRemoteAddress); } finally { _logger.Info("Client disconnected {0}.", clientRemoteAddress); connection.Dispose(); } }
private void ConfigureLogger(ServiceHostConfig config) { LogManager.Configuration = new XmlLoggingConfiguration(config.NLogConfigFile); LogManager.Configuration.Variables["instanceId"] = config.InstanceId.ToString(); }
public async Task Start(ServiceHostConfig config) { if (_listeningSocket != null) { throw new InvalidOperationException("Service host is already started."); } try { ConfigureLogger(config); LoadMessageAssemblies(config.MessageAssemblies); LoadServiceAssemblies(config.ServiceAssemblies); var incomingSerializer = (ISerializer)Activator.CreateInstance(Type.GetType(config.Serializer)); var outgoingSerializer = (ISerializer)Activator.CreateInstance(Type.GetType(config.ClusterConnectionSettings.Serializer)); InitSignalHandlers(); X509Certificate?certificate = await LoadCertificate(config); var session = new Session(); var counters = new ServiceHostCounters(); using ClusterConnection clusterConnection = CreateClusterConnection(config, outgoingSerializer); using IContainer container = BuildContainer(config, clusterConnection, session); var dispatcher = new ServiceDispatcher(container, _serviceTypes, clusterConnection); _listeningSocket = new Socket(SocketType.Stream, ProtocolType.IP); _listeningSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); _listeningSocket.Bind(new IPEndPoint(IPAddress.Any, config.Port)); _listeningSocket.Listen(128); if (config.Gateway) { _logger.Info("Server started as gateway. Listening port {0}...", config.Port); } else { _logger.Info("Server started. Listening port {0}...", config.Port); } Task clusterConnectionTask = ConnectCluster(config, clusterConnection); Task callbacksInvocationTask = UpdateClusterConnection(config, clusterConnection); // If it is a gateway, the host waits for the cluster connection to obtain // message maps, initializes routes and only then accepts connections. // // The first connection attempt tries to connect only once, so it is assumed // that the cluster itself is completely up before all its gateways. if (config.Gateway) { await clusterConnectionTask; dispatcher.InitGatewayRouts(); } LogDispatcher(dispatcher); int nextConnectionId = 1; while (true) { Socket connectionSocket; try { connectionSocket = await _listeningSocket.AcceptAsync(); } catch (SocketException) { _logger.Info("The listening socket is closed. The host is going to shutdown."); break; } _logger.Info("Client connected {0}.", connectionSocket.GetRemoteAddressName()); ServeConnection( new ServerConnection( connectionSocket, dispatcher, config, counters, incomingSerializer, certificate ), config, session, nextConnectionId++ ); } _updateClusterConnection = false; await clusterConnectionTask; await callbacksInvocationTask; } catch (Exception ex) { _logger.Fatal(ex, "Service host faulted."); } finally { _listeningSocket?.Dispose(); _listeningSocket = null; _logger.Info("Service host stopped."); LogManager.Flush(); _serviceHostStopped.Set(); } }
private IContainer BuildContainer(ServiceHostConfig config, ClusterConnection clusterConnection, ISession session) { var containerBuilder = new ContainerBuilder(); var serviceConfigsProvider = new ServiceConfigsProvider(config.ServiceConfigs); containerBuilder .RegisterTypes(_serviceTypes.ToArray()) .SingleInstance(); containerBuilder .RegisterInstance(serviceConfigsProvider) .As <IConfig>(); containerBuilder .RegisterInstance(clusterConnection) .As <ICluster>() .ExternallyOwned(); containerBuilder .RegisterInstance(session) .As <ISession>(); var containerBuilderWrapper = new ContainerBuilderWrapper(containerBuilder); foreach (Type serviceType in _serviceTypes) { try { serviceType .GetMethods() .FirstOrDefault(IsContainerSetupMethod) ?.Invoke(null, new object[] { containerBuilderWrapper, serviceConfigsProvider }); } catch (Exception ex) { _logger.Error(ex, "Service {0} container setup faulted.", serviceType.FullName); } } return(containerBuilder.Build()); bool IsContainerSetupMethod(MethodInfo methodInfo) { if (!(methodInfo.IsStatic && methodInfo.IsPublic)) { return(false); } ParameterInfo[] methodParams = methodInfo.GetParameters(); if (methodParams.Length != 2) { return(false); } if (methodParams[0].ParameterType != typeof(IContainerBuilder)) { return(false); } if (methodParams[1].ParameterType != typeof(IConfig)) { return(false); } return(true); } }