/// <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(); } } } }
/// <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); }