diff --git a/FastGithub.DomainResolve/DnscryptProxy.cs b/FastGithub.DomainResolve/DnscryptProxy.cs index 55c4870..383c03f 100644 --- a/FastGithub.DomainResolve/DnscryptProxy.cs +++ b/FastGithub.DomainResolve/DnscryptProxy.cs @@ -10,6 +10,7 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; +using static PInvoke.AdvApi32; namespace FastGithub.DomainResolve { @@ -18,10 +19,11 @@ namespace FastGithub.DomainResolve /// sealed class DnscryptProxy { - private const string PATH = "dnscrypt-proxy"; - private const string NAME = "dnscrypt-proxy"; - private readonly ILogger logger; + private readonly string processName; + private readonly string serviceName; + private readonly string exeFilePath; + private readonly string tomlFilePath; /// /// 相关进程 @@ -39,7 +41,14 @@ namespace FastGithub.DomainResolve /// public DnscryptProxy(ILogger logger) { + const string PATH = "dnscrypt-proxy"; + const string NAME = "dnscrypt-proxy"; + this.logger = logger; + this.processName = NAME; + this.serviceName = $"{nameof(FastGithub)}.{NAME}"; + this.exeFilePath = Path.Combine(PATH, OperatingSystem.IsWindows() ? $"{NAME}.exe" : NAME); + this.tomlFilePath = Path.Combine(PATH, $"{NAME}.toml"); } /// @@ -55,7 +64,7 @@ namespace FastGithub.DomainResolve } catch (Exception ex) { - this.logger.LogWarning($"{NAME}启动失败:{ex.Message}"); + this.logger.LogWarning($"{this.processName}启动失败:{ex.Message}"); } } @@ -66,30 +75,22 @@ namespace FastGithub.DomainResolve /// private async Task StartCoreAsync(CancellationToken cancellationToken) { - var tomlPath = Path.Combine(PATH, $"{NAME}.toml"); var port = GetAvailablePort(IPAddress.Loopback.AddressFamily); var localEndPoint = new IPEndPoint(IPAddress.Loopback, port); - await TomlUtil.SetListensAsync(tomlPath, localEndPoint, cancellationToken); - await TomlUtil.SetlogLevelAsync(tomlPath, 6, cancellationToken); - await TomlUtil.SetEdnsClientSubnetAsync(tomlPath, cancellationToken); - - foreach (var process in Process.GetProcessesByName(NAME)) - { - process.Kill(); - process.WaitForExit(); - } + await TomlUtil.SetListensAsync(this.tomlFilePath, localEndPoint, cancellationToken); + await TomlUtil.SetlogLevelAsync(this.tomlFilePath, 6, cancellationToken); + await TomlUtil.SetEdnsClientSubnetAsync(this.tomlFilePath, cancellationToken); if (OperatingSystem.IsWindows() && Process.GetCurrentProcess().SessionId == 0) { - StartDnscryptProxy("-service uninstall")?.WaitForExit(); - StartDnscryptProxy("-service install")?.WaitForExit(); - StartDnscryptProxy("-service start")?.WaitForExit(); - this.process = Process.GetProcessesByName(NAME).FirstOrDefault(item => item.SessionId == 0); + ServiceInstallUtil.StopAndDeleteService(this.serviceName); + ServiceInstallUtil.InstallAndStartService(this.serviceName, this.exeFilePath, ServiceStartType.SERVICE_DEMAND_START); + this.process = Process.GetProcessesByName(this.processName).FirstOrDefault(item => item.SessionId == 0); } else { - this.process = StartDnscryptProxy(string.Empty); + this.process = StartDnscryptProxy(); } if (this.process != null) @@ -109,9 +110,9 @@ namespace FastGithub.DomainResolve { if (OperatingSystem.IsWindows() && Process.GetCurrentProcess().SessionId == 0) { - StartDnscryptProxy("-service stop")?.WaitForExit(); - StartDnscryptProxy("-service uninstall")?.WaitForExit(); + ServiceInstallUtil.StopAndDeleteService(this.serviceName); } + if (this.process != null && this.process.HasExited == false) { this.process.Kill(); @@ -119,7 +120,7 @@ namespace FastGithub.DomainResolve } catch (Exception ex) { - this.logger.LogWarning($"{NAME}停止失败:{ex.Message }"); + this.logger.LogWarning($"{this.processName}停止失败:{ex.Message }"); } finally { @@ -160,16 +161,14 @@ namespace FastGithub.DomainResolve /// /// 启动DnscryptProxy进程 - /// - /// - private static Process? StartDnscryptProxy(string arguments) + /// + /// + private Process? StartDnscryptProxy() { - var fileName = OperatingSystem.IsWindows() ? $"{NAME}.exe" : NAME; return Process.Start(new ProcessStartInfo { - FileName = Path.Combine(PATH, fileName), - Arguments = arguments, - WorkingDirectory = PATH, + FileName = this.exeFilePath, + WorkingDirectory = Path.GetDirectoryName(this.exeFilePath), UseShellExecute = false, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden @@ -182,7 +181,7 @@ namespace FastGithub.DomainResolve /// public override string ToString() { - return NAME; + return this.processName; } } } diff --git a/FastGithub.DomainResolve/FastGithub.DomainResolve.csproj b/FastGithub.DomainResolve/FastGithub.DomainResolve.csproj index f7441b6..abb3220 100644 --- a/FastGithub.DomainResolve/FastGithub.DomainResolve.csproj +++ b/FastGithub.DomainResolve/FastGithub.DomainResolve.csproj @@ -1,6 +1,7 @@  + diff --git a/FastGithub.DomainResolve/ServiceInstallUtil.cs b/FastGithub.DomainResolve/ServiceInstallUtil.cs new file mode 100644 index 0000000..417fb9b --- /dev/null +++ b/FastGithub.DomainResolve/ServiceInstallUtil.cs @@ -0,0 +1,88 @@ +using System.IO; +using System.Runtime.Versioning; +using static PInvoke.AdvApi32; + +namespace FastGithub.DomainResolve +{ + public static class ServiceInstallUtil + { + /// + /// 安装并启动服务 + /// + /// + /// + /// + /// + [SupportedOSPlatform("windows")] + public static bool InstallAndStartService(string serviceName, string binaryPath, ServiceStartType startType = ServiceStartType.SERVICE_AUTO_START) + { + using var hSCManager = OpenSCManager(null, null, ServiceManagerAccess.SC_MANAGER_ALL_ACCESS); + if (hSCManager.IsInvalid == true) + { + return false; + } + + var hService = OpenService(hSCManager, serviceName, ServiceAccess.SERVICE_ALL_ACCESS); + if (hService.IsInvalid == true) + { + hService = CreateService( + hSCManager, + serviceName, + serviceName, + ServiceAccess.SERVICE_ALL_ACCESS, + ServiceType.SERVICE_WIN32_OWN_PROCESS, + startType, + ServiceErrorControl.SERVICE_ERROR_NORMAL, + Path.GetFullPath(binaryPath), + lpLoadOrderGroup: null, + lpdwTagId: 0, + lpDependencies: null, + lpServiceStartName: null, + lpPassword: null); + } + + if (hService.IsInvalid == true) + { + return false; + } + + using (hService) + { + return StartService(hService, 0, null); + } + } + + /// + /// 停止并删除服务 + /// + /// + /// + [SupportedOSPlatform("windows")] + public static bool StopAndDeleteService(string serviceName) + { + using var hSCManager = OpenSCManager(null, null, ServiceManagerAccess.SC_MANAGER_ALL_ACCESS); + if (hSCManager.IsInvalid == true) + { + return false; + } + + using var hService = OpenService(hSCManager, serviceName, ServiceAccess.SERVICE_ALL_ACCESS); + if (hService.IsInvalid == true) + { + return true; + } + + var status = new SERVICE_STATUS(); + if (QueryServiceStatus(hService, ref status) == true) + { + if (status.dwCurrentState != ServiceState.SERVICE_STOP_PENDING && + status.dwCurrentState != ServiceState.SERVICE_STOPPED) + { + ControlService(hService, ServiceControl.SERVICE_CONTROL_STOP, ref status); + } + } + + return DeleteService(hService); + } + } +} diff --git a/FastGithub.sln b/FastGithub.sln index df8b62e..45ccc94 100644 --- a/FastGithub.sln +++ b/FastGithub.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31808.319 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31320.298 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub", "FastGithub\FastGithub.csproj", "{C1099390-6103-4917-A740-A3002B542FE0}" EndProject @@ -15,7 +15,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.HttpServer", "Fa EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.PacketIntercept", "FastGithub.PacketIntercept\FastGithub.PacketIntercept.csproj", "{701FF90C-E651-4E0B-AE7F-84D1F17DD178}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastGithub.UI", "FastGithub.UI\FastGithub.UI.csproj", "{5082061F-38D5-4F50-945E-791C85B9BDB5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.UI", "FastGithub.UI\FastGithub.UI.csproj", "{5082061F-38D5-4F50-945E-791C85B9BDB5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.FlowAnalyze", "FastGithub.FlowAnalyze\FastGithub.FlowAnalyze.csproj", "{93478EAF-739C-47DA-B8FE-AEBA78A75E11}" EndProject diff --git a/FastGithub/FastGithub.csproj b/FastGithub/FastGithub.csproj index 7b6b6d4..9cc69ec 100644 --- a/FastGithub/FastGithub.csproj +++ b/FastGithub/FastGithub.csproj @@ -9,7 +9,6 @@ - @@ -18,7 +17,7 @@ - + diff --git a/FastGithub/WindowServiceExtensions.cs b/FastGithub/WindowServiceExtensions.cs deleted file mode 100644 index 02c640f..0000000 --- a/FastGithub/WindowServiceExtensions.cs +++ /dev/null @@ -1,185 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using PInvoke; -using System; -using System.IO; -using System.Linq; -using System.Runtime.Versioning; -using System.Threading; -using static PInvoke.AdvApi32; - -namespace FastGithub -{ - /// - /// IHostBuilder扩展 - /// - static class WindowServiceExtensions - { - /// - /// 控制命令 - /// - private enum Command - { - Start, - Stop, - } - - /// - /// 使用windows服务 - /// - /// - /// - public static IHostBuilder UseWindowsService(this IHostBuilder hostBuilder) - { - var contentRoot = Path.GetDirectoryName(Environment.GetCommandLineArgs().First()); - if (contentRoot != null) - { - Environment.CurrentDirectory = contentRoot; - hostBuilder.UseContentRoot(contentRoot); - } - return WindowsServiceLifetimeHostBuilderExtensions.UseWindowsService(hostBuilder); - } - - /// - /// 运行主机 - /// - /// - /// - public static void Run(this IHost host, bool singleton = true) - { - if (OperatingSystem.IsWindows() && TryGetCommand(out var cmd)) - { - try - { - UseCommand(cmd); - } - catch (Exception ex) - { - var loggerFactory = host.Services.GetRequiredService(); - loggerFactory.CreateLogger(nameof(FastGithub)).LogError(ex.Message); - } - } - else - { - using var mutex = new Mutex(true, "Global\\FastGithub", out var firstInstance); - if (singleton == false || firstInstance) - { - HostingAbstractionsHostExtensions.Run(host); - } - } - } - - /// - /// 获取控制指令 - /// - /// - /// - private static bool TryGetCommand(out Command cmd) - { - var args = Environment.GetCommandLineArgs(); - return Enum.TryParse(args.Skip(1).FirstOrDefault(), true, out cmd); - } - - /// - /// 应用控制指令 - /// - /// - [SupportedOSPlatform("windows")] - private static void UseCommand(Command cmd) - { - var binaryPath = Environment.GetCommandLineArgs().First(); - var serviceName = Path.GetFileNameWithoutExtension(binaryPath); - if (cmd == Command.Start) - { - InstallAndStartService(serviceName, binaryPath); - } - else if (cmd == Command.Stop) - { - StopAndDeleteService(serviceName); - } - } - - /// - /// 安装并启动服务 - /// - /// - /// - /// - [SupportedOSPlatform("windows")] - private static void InstallAndStartService(string serviceName, string binaryPath) - { - using var hSCManager = OpenSCManager(null, null, ServiceManagerAccess.SC_MANAGER_ALL_ACCESS); - if (hSCManager.IsInvalid == true) - { - throw new Win32Exception(); - } - - var hService = OpenService(hSCManager, serviceName, ServiceAccess.SERVICE_ALL_ACCESS); - if (hService.IsInvalid == true) - { - hService = CreateService( - hSCManager, - serviceName, - serviceName, - ServiceAccess.SERVICE_ALL_ACCESS, - ServiceType.SERVICE_WIN32_OWN_PROCESS, - ServiceStartType.SERVICE_AUTO_START, - ServiceErrorControl.SERVICE_ERROR_NORMAL, - binaryPath, - lpLoadOrderGroup: null, - lpdwTagId: 0, - lpDependencies: null, - lpServiceStartName: null, - lpPassword: null); - } - - if (hService.IsInvalid == true) - { - throw new Win32Exception(); - } - - using (hService) - { - StartService(hService, 0, null); - } - } - - /// - /// 停止并删除服务 - /// - /// - /// - [SupportedOSPlatform("windows")] - private static void StopAndDeleteService(string serviceName) - { - using var hSCManager = OpenSCManager(null, null, ServiceManagerAccess.SC_MANAGER_ALL_ACCESS); - if (hSCManager.IsInvalid == true) - { - throw new Win32Exception(); - } - - using var hService = OpenService(hSCManager, serviceName, ServiceAccess.SERVICE_ALL_ACCESS); - if (hService.IsInvalid == true) - { - return; - } - - var status = new SERVICE_STATUS(); - if (QueryServiceStatus(hService, ref status) == true) - { - if (status.dwCurrentState != ServiceState.SERVICE_STOP_PENDING && - status.dwCurrentState != ServiceState.SERVICE_STOPPED) - { - ControlService(hService, ServiceControl.SERVICE_CONTROL_STOP, ref status); - } - } - - if (DeleteService(hService) == false) - { - throw new Win32Exception(); - } - } - - } -} diff --git a/FastGithub/WindowsServiceExtensions.cs b/FastGithub/WindowsServiceExtensions.cs new file mode 100644 index 0000000..917f948 --- /dev/null +++ b/FastGithub/WindowsServiceExtensions.cs @@ -0,0 +1,110 @@ +using FastGithub.DomainResolve; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using PInvoke; +using System; +using System.IO; +using System.Linq; +using System.Runtime.Versioning; +using System.Threading; + +namespace FastGithub +{ + /// + /// IHostBuilder扩展 + /// + static class WindowsServiceExtensions + { + /// + /// 控制命令 + /// + private enum Command + { + Start, + Stop, + } + + /// + /// 使用windows服务 + /// + /// + /// + public static IHostBuilder UseWindowsService(this IHostBuilder hostBuilder) + { + var contentRoot = Path.GetDirectoryName(Environment.GetCommandLineArgs().First()); + if (contentRoot != null) + { + Environment.CurrentDirectory = contentRoot; + hostBuilder.UseContentRoot(contentRoot); + } + return WindowsServiceLifetimeHostBuilderExtensions.UseWindowsService(hostBuilder); + } + + /// + /// 运行主机 + /// + /// + /// + public static void Run(this IHost host, bool singleton = true) + { + if (OperatingSystem.IsWindows() && TryGetCommand(out var cmd)) + { + try + { + UseCommand(cmd); + } + catch (Exception ex) + { + var loggerFactory = host.Services.GetRequiredService(); + loggerFactory.CreateLogger(nameof(FastGithub)).LogError(ex.Message); + } + } + else + { + using var mutex = new Mutex(true, "Global\\FastGithub", out var firstInstance); + if (singleton == false || firstInstance) + { + HostingAbstractionsHostExtensions.Run(host); + } + } + } + + /// + /// 获取控制指令 + /// + /// + /// + private static bool TryGetCommand(out Command cmd) + { + var args = Environment.GetCommandLineArgs(); + return Enum.TryParse(args.Skip(1).FirstOrDefault(), true, out cmd); + } + + /// + /// 应用控制指令 + /// + /// + [SupportedOSPlatform("windows")] + private static void UseCommand(Command cmd) + { + var binaryPath = Environment.GetCommandLineArgs().First(); + var serviceName = Path.GetFileNameWithoutExtension(binaryPath); + var state = true; + if (cmd == Command.Start) + { + state = ServiceInstallUtil.InstallAndStartService(serviceName, binaryPath); + } + else if (cmd == Command.Stop) + { + state = ServiceInstallUtil.StopAndDeleteService(serviceName); + } + + if (state == false) + { + throw new Win32Exception(); + } + } + + } +}