using System.Diagnostics; using System.IO.Pipes; using LumaTunnel.Shared.Windows; var options = WatchdogOptions.Parse(args); if (options is null) return 2; try { using var parent = Process.GetProcessById(options.ParentProcessId); using var pipe = new NamedPipeClientStream(".", options.PipeName, PipeDirection.In, PipeOptions.Asynchronous); try { using var connectTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); await pipe.ConnectAsync(connectTimeout.Token).ConfigureAwait(false); } catch (OperationCanceledException) { } var parentExit = parent.WaitForExitAsync(); var buffer = new byte[16]; var pipeSignal = pipe.IsConnected ? pipe.ReadAsync(buffer).AsTask() : Task.FromResult(0); var completed = await Task.WhenAny(parentExit, pipeSignal).ConfigureAwait(false); if (completed == pipeSignal && await pipeSignal.ConfigureAwait(false) > 0) return 0; var snapshot = await SystemProxyRegistry.LoadSnapshotAsync(options.SnapshotPath).ConfigureAwait(false); if (snapshot is not null && snapshot.OwnerId == options.OwnerId) SystemProxyRegistry.RestoreIfOwned(snapshot, options.HttpPort); return 0; } catch (ArgumentException) { var snapshot = await SystemProxyRegistry.LoadSnapshotAsync(options.SnapshotPath).ConfigureAwait(false); if (snapshot is not null && snapshot.OwnerId == options.OwnerId) SystemProxyRegistry.RestoreIfOwned(snapshot, options.HttpPort); return 0; } internal sealed record WatchdogOptions(int ParentProcessId, string PipeName, string SnapshotPath, string OwnerId, int HttpPort) { public static WatchdogOptions? Parse(string[] args) { string? Read(string name) { var index = Array.FindIndex(args, item => item.Equals(name, StringComparison.OrdinalIgnoreCase)); return index >= 0 && index + 1 < args.Length ? args[index + 1] : null; } return int.TryParse(Read("--parent"), out var parent) && int.TryParse(Read("--port"), out var port) && Read("--pipe") is { Length: > 0 } pipe && Read("--snapshot") is { Length: > 0 } snapshot && Read("--owner") is { Length: > 0 } owner ? new WatchdogOptions(parent, pipe, snapshot, owner, port) : null; } }