/// <summary>
        /// Listens at the transport path for new connections.
        /// </summary>
        /// <param name="maxConnections">The maximum number of connections the server will support.</param>
        /// <param name="token">The token to monitor for cancellation requests.</param>
        /// <returns>A task that completes when the server is no longer listening at the transport path.</returns>
        private async Task ListenAsync(int maxConnections, CancellationToken token)
        {
            using var transport = IpcServerTransport.Create(_transportPath, maxConnections);
            while (!token.IsCancellationRequested)
            {
                Stream       stream    = null;
                IpcAdvertise advertise = null;
                try
                {
                    stream = await transport.AcceptAsync(token).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception)
                {
                    // The advertise data could be incomplete if the runtime shuts down before completely writing
                    // the information. Catch the exception and continue waiting for a new connection.
                }

                if (null != stream)
                {
                    // Cancel parsing of advertise data after timeout period to
                    // mitigate runtimes that write partial data and do not close the stream (avoid waiting forever).
                    using var parseCancellationSource = new CancellationTokenSource();
                    using var linkedSource            = CancellationTokenSource.CreateLinkedTokenSource(token, parseCancellationSource.Token);
                    try
                    {
                        parseCancellationSource.CancelAfter(ParseAdvertiseTimeout);

                        advertise = await IpcAdvertise.ParseAsync(stream, linkedSource.Token).ConfigureAwait(false);
                    }
                    catch (Exception)
                    {
                    }
                }

                if (null != advertise)
                {
                    Guid runtimeCookie = advertise.RuntimeInstanceCookie;
                    int  pid           = unchecked ((int)advertise.ProcessId);

                    lock (_streamLock)
                    {
                        ProvideStream(runtimeCookie, stream);
                        if (!_cachedEndpoints.ContainsKey(runtimeCookie))
                        {
                            ServerIpcEndpoint endpoint = new ServerIpcEndpoint(this, runtimeCookie);
                            _cachedEndpoints.Add(runtimeCookie, endpoint);
                            ProvideEndpointInfo(new IpcEndpointInfo(endpoint, pid, runtimeCookie));
                        }
                    }
                }
            }
        }
        public IpcServerRouterFactory(string ipcServer, ILogger logger)
        {
            _logger        = logger;
            _ipcServerPath = ipcServer;
            if (string.IsNullOrEmpty(_ipcServerPath))
            {
                _ipcServerPath = GetDefaultIpcServerPath();
            }

            _ipcServer = IpcServerTransport.Create(_ipcServerPath, IpcServerTransport.MaxAllowedConnections, false);
        }
        public IpcServerTcpServerRouterFactory(string ipcServer, string tcpServer, int runtimeTimeoutMs, ILogger logger)
            : base(tcpServer, runtimeTimeoutMs, logger)
        {
            _ipcServerPath = ipcServer;
            if (string.IsNullOrEmpty(_ipcServerPath))
            {
                _ipcServerPath = GetDefaultIpcServerPath();
            }

            _ipcServer = IpcServerTransport.Create(_ipcServerPath, IpcServerTransport.MaxAllowedConnections, false);
            _tcpServer.TransportCallback = this;
        }
        /// <summary>
        /// Listens at the address for new connections.
        /// </summary>
        /// <param name="maxConnections">The maximum number of connections the server will support.</param>
        /// <param name="token">The token to monitor for cancellation requests.</param>
        /// <returns>A task that completes when the server is no longer listening at the address.</returns>
        private async Task ListenAsync(int maxConnections, CancellationToken token)
        {
            // This disposal shuts down the transport in case an exception is thrown.
            using var transport = IpcServerTransport.Create(_address, maxConnections, _enableTcpIpProtocol, TransportCallback);
            // This disposal shuts down the transport in case of cancellation; causes the transport
            // to not recreate the server stream before the AcceptAsync call observes the cancellation.
            using var _ = token.Register(() => transport.Dispose());

            while (!token.IsCancellationRequested)
            {
                Stream       stream    = null;
                IpcAdvertise advertise = null;
                try
                {
                    stream = await transport.AcceptAsync(token).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception)
                {
                    // The advertise data could be incomplete if the runtime shuts down before completely writing
                    // the information. Catch the exception and continue waiting for a new connection.
                }

                if (null != stream)
                {
                    // Cancel parsing of advertise data after timeout period to
                    // mitigate runtimes that write partial data and do not close the stream (avoid waiting forever).
                    using var parseCancellationSource = new CancellationTokenSource();
                    using var linkedSource            = CancellationTokenSource.CreateLinkedTokenSource(token, parseCancellationSource.Token);
                    try
                    {
                        parseCancellationSource.CancelAfter(ParseAdvertiseTimeout);

                        advertise = await IpcAdvertise.ParseAsync(stream, linkedSource.Token).ConfigureAwait(false);
                    }
                    catch (Exception)
                    {
                        stream.Dispose();
                    }
                }

                if (null != advertise)
                {
                    Guid runtimeCookie = advertise.RuntimeInstanceCookie;
                    int  pid           = unchecked ((int)advertise.ProcessId);

                    // The valueFactory parameter of the GetOrAdd overload that uses Func<TKey, TValue> valueFactory
                    // does not execute the factory under a lock thus it is not thread-safe. Create the collection and
                    // use a thread-safe version of GetOrAdd; use equality comparison on the result to determine if
                    // the new collection was added to the dictionary or if an existing one was returned.
                    var newStreamCollection = new HandleableCollection <Stream>();
                    var streamCollection    = _streamCollections.GetOrAdd(runtimeCookie, newStreamCollection);

                    try
                    {
                        streamCollection.ClearItems();
                        streamCollection.Add(stream);

                        if (newStreamCollection == streamCollection)
                        {
                            ServerIpcEndpoint endpoint = new ServerIpcEndpoint(this, runtimeCookie);
                            _endpointInfos.Add(new IpcEndpointInfo(endpoint, pid, runtimeCookie));
                        }
                        else
                        {
                            newStreamCollection.Dispose();
                        }
                    }
                    catch (ObjectDisposedException)
                    {
                        // The stream collection could be disposed by RemoveConnection which would cause an
                        // ObjectDisposedException to be thrown if trying to clear/add the stream.
                        stream.Dispose();
                    }
                }
            }
        }
Пример #5
0
 /// <summary>
 /// Constructs the <see cref="ReversedDiagnosticsServer"/> instance with an endpoint bound
 /// to the location specified by <paramref name="transportPath"/>.
 /// </summary>
 /// <param name="transportPath">
 /// The path of the server endpoint.
 /// On Windows, this can be a full pipe path or the name without the "\\.\pipe\" prefix.
 /// On all other systems, this must be the full file path of the socket.
 /// </param>
 /// <param name="maxConnections">The maximum number of connections the server will support.</param>
 public ReversedDiagnosticsServer(string transportPath, int maxConnections)
 {
     _transport = IpcServerTransport.Create(transportPath, maxConnections);
 }