| File: DiagnosticsIpc\IpcEndpointConfig.cs | Web Access |
| Project: src\diagnostics\src\Microsoft.Diagnostics.NETCore.Client\Microsoft.Diagnostics.NETCore.Client.csproj (Microsoft.Diagnostics.NETCore.Client) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Runtime.InteropServices; namespace Microsoft.Diagnostics.NETCore.Client { internal class IpcEndpointConfig { public enum PortType { Connect, Listen } public enum TransportType { NamedPipe, UnixDomainSocket, #if DIAGNOSTICS_RUNTIME TcpSocket #endif } private PortType _portType; private TransportType _transportType; // For TcpSocket TransportType, the address format will be <hostname_or_ip>:<port> public string Address { get; } public bool IsConnectConfig => _portType == PortType.Connect; public bool IsListenConfig => _portType == PortType.Listen; public TransportType Transport => _transportType; private const string NamedPipeSchema = "namedpipe"; private const string UnixDomainSocketSchema = "uds"; private const string NamedPipeDefaultIPCRoot = @"\\.\pipe\"; private const string NamedPipeSchemaDefaultIPCRootPath = "/pipe/"; public IpcEndpointConfig(string address, TransportType transportType, PortType portType) { if (string.IsNullOrEmpty(address)) { throw new ArgumentException("Address is null or empty."); } switch (transportType) { case TransportType.NamedPipe: { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { throw new PlatformNotSupportedException($"{NamedPipeSchema} is only supported on Windows."); } break; } case TransportType.UnixDomainSocket: { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { throw new PlatformNotSupportedException($"{UnixDomainSocketSchema} is not supported on Windows, use {NamedPipeSchema}."); } break; } #if DIAGNOSTICS_RUNTIME case TransportType.TcpSocket: { break; } #endif default: { throw new NotSupportedException($"{transportType} not supported."); } } Address = address; _transportType = transportType; _portType = portType; } // Config format: [Address],[PortType] // // Address in UnixDomainSocket formats: // myport => myport // uds:myport => myport // /User/mrx/myport.sock => /User/mrx/myport.sock // uds:/User/mrx/myport.sock => /User/mrx/myport.sock // uds://authority/User/mrx/myport.sock => /User/mrx/myport.sock // uds:///User/mrx/myport.sock => /User/mrx/myport.sock // // Address in NamedPipe formats: // myport => myport // namedpipe:myport => myport // \\.\pipe\myport => myport (dropping \\.\pipe\ is inline with implemented namedpipe client/server) // namedpipe://./pipe/myport => myport (dropping authority and /pipe/ is inline with implemented namedpipe client/server) // namedpipe:/pipe/myport => myport (dropping /pipe/ is inline with implemented namedpipe client/server) // namedpipe://authority/myport => myport // namedpipe:///myport => myport // // PortType: Listen|Connect, default Listen. public static bool TryParse(string config, out IpcEndpointConfig result) { try { result = Parse(config); } catch (Exception) { result = null; } return result != null; } public static IpcEndpointConfig Parse(string config) { if (string.IsNullOrEmpty(config)) { throw new FormatException("Missing IPC endpoint config."); } string address = ""; PortType portType = PortType.Connect; TransportType transportType = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? TransportType.NamedPipe : TransportType.UnixDomainSocket; if (!string.IsNullOrEmpty(config)) { string[] parts = config.Split(','); if (parts.Length > 2) { throw new FormatException($"Unknown IPC endpoint config format, {config}."); } if (string.IsNullOrEmpty(parts[0])) { throw new FormatException($"Missing IPC endpoint config address, {config}."); } portType = PortType.Listen; address = parts[0]; if (parts.Length == 2) { if (string.Equals(parts[1], "connect", StringComparison.OrdinalIgnoreCase)) { portType = PortType.Connect; } else if (string.Equals(parts[1], "listen", StringComparison.OrdinalIgnoreCase)) { portType = PortType.Listen; } else { throw new FormatException($"Unknown IPC endpoint config keyword, {parts[1]} in {config}."); } } } if (Uri.TryCreate(address, UriKind.Absolute, out Uri parsedAddress)) { if (string.Equals(parsedAddress.Scheme, NamedPipeSchema, StringComparison.OrdinalIgnoreCase)) { transportType = TransportType.NamedPipe; address = parsedAddress.AbsolutePath; } else if (string.Equals(parsedAddress.Scheme, UnixDomainSocketSchema, StringComparison.OrdinalIgnoreCase)) { transportType = TransportType.UnixDomainSocket; address = parsedAddress.AbsolutePath; } else if (string.Equals(parsedAddress.Scheme, Uri.UriSchemeFile, StringComparison.OrdinalIgnoreCase)) { address = parsedAddress.AbsolutePath; } else if (!string.IsNullOrEmpty(parsedAddress.Scheme)) { throw new FormatException($"{parsedAddress.Scheme} not supported."); } } else { if (address.StartsWith(NamedPipeDefaultIPCRoot, StringComparison.OrdinalIgnoreCase)) { transportType = TransportType.NamedPipe; } } if (transportType == TransportType.NamedPipe) { if (address.StartsWith(NamedPipeDefaultIPCRoot, StringComparison.OrdinalIgnoreCase)) { address = address.Substring(NamedPipeDefaultIPCRoot.Length); } else if (address.StartsWith(NamedPipeSchemaDefaultIPCRootPath, StringComparison.OrdinalIgnoreCase)) { address = address.Substring(NamedPipeSchemaDefaultIPCRootPath.Length); } else if (address.StartsWith("/", StringComparison.OrdinalIgnoreCase)) { address = address.Substring("/".Length); } } return new IpcEndpointConfig(address, transportType, portType); } } }