@@ -0,0 +1,88 @@ | |||||
using System; | |||||
using System.IO.Pipes; | |||||
using System.Net; | |||||
using System.Text; | |||||
namespace Shadowsocks.Controller | |||||
{ | |||||
class RequestAddUrlEventArgs : EventArgs | |||||
{ | |||||
public readonly string Url; | |||||
public RequestAddUrlEventArgs(string url) | |||||
{ | |||||
this.Url = url; | |||||
} | |||||
} | |||||
internal class IPCService | |||||
{ | |||||
private const int INT32_LEN = 4; | |||||
private const int OP_OPEN_URL = 1; | |||||
private static readonly string PIPE_PATH = $"Shadowsocks\\{Program.ExecutablePath.GetHashCode()}"; | |||||
public event EventHandler<RequestAddUrlEventArgs> OpenUrlRequested; | |||||
public async void RunServer() | |||||
{ | |||||
byte[] buf = new byte[4096]; | |||||
while (true) | |||||
{ | |||||
using (NamedPipeServerStream stream = new NamedPipeServerStream(PIPE_PATH)) | |||||
{ | |||||
await stream.WaitForConnectionAsync(); | |||||
await stream.ReadAsync(buf, 0, INT32_LEN); | |||||
int opcode = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 0)); | |||||
if (opcode == OP_OPEN_URL) | |||||
{ | |||||
await stream.ReadAsync(buf, 0, INT32_LEN); | |||||
int strlen = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 0)); | |||||
await stream.ReadAsync(buf, 0, strlen); | |||||
string url = Encoding.UTF8.GetString(buf, 0, strlen); | |||||
OpenUrlRequested?.Invoke(this, new RequestAddUrlEventArgs(url)); | |||||
} | |||||
stream.Close(); | |||||
} | |||||
} | |||||
} | |||||
private static (NamedPipeClientStream, bool) TryConnect() | |||||
{ | |||||
NamedPipeClientStream pipe = new NamedPipeClientStream(PIPE_PATH); | |||||
bool exist; | |||||
try | |||||
{ | |||||
pipe.Connect(10); | |||||
exist = true; | |||||
} | |||||
catch (TimeoutException) | |||||
{ | |||||
exist = false; | |||||
} | |||||
return (pipe, exist); | |||||
} | |||||
public static bool AnotherInstanceRunning() | |||||
{ | |||||
(NamedPipeClientStream pipe, bool exist) = TryConnect(); | |||||
pipe.Dispose(); | |||||
return exist; | |||||
} | |||||
public static void RequestOpenUrl(string url) | |||||
{ | |||||
(NamedPipeClientStream pipe, bool exist) = TryConnect(); | |||||
if(!exist) return; | |||||
byte[] opAddUrl = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(OP_OPEN_URL)); | |||||
pipe.Write(opAddUrl, 0, INT32_LEN); // opcode addurl | |||||
byte[] b = Encoding.UTF8.GetBytes(url); | |||||
byte[] blen = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(b.Length)); | |||||
pipe.Write(blen, 0, INT32_LEN); | |||||
pipe.Write(b, 0, b.Length); | |||||
pipe.Close(); | |||||
pipe.Dispose(); | |||||
} | |||||
} | |||||
} |
@@ -1,47 +0,0 @@ | |||||
using System; | |||||
using System.IO; | |||||
using System.IO.Pipes; | |||||
using System.Net; | |||||
using System.Text; | |||||
namespace Shadowsocks.Controller | |||||
{ | |||||
class RequestAddUrlEventArgs : EventArgs | |||||
{ | |||||
public readonly string Url; | |||||
public RequestAddUrlEventArgs(string url) | |||||
{ | |||||
this.Url = url; | |||||
} | |||||
} | |||||
internal class NamedPipeServer | |||||
{ | |||||
public event EventHandler<RequestAddUrlEventArgs> AddUrlRequested; | |||||
public async void Run(string path) | |||||
{ | |||||
byte[] buf = new byte[4096]; | |||||
while (true) | |||||
{ | |||||
using (NamedPipeServerStream stream = new NamedPipeServerStream(path)) | |||||
{ | |||||
stream.WaitForConnection(); | |||||
await stream.ReadAsync(buf, 0, 4); | |||||
int opcode = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 0)); | |||||
if (opcode == 1) | |||||
{ | |||||
await stream.ReadAsync(buf, 0, 4); | |||||
int strlen = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 0)); | |||||
await stream.ReadAsync(buf, 0, strlen); | |||||
string url = Encoding.UTF8.GetString(buf, 0, strlen); | |||||
AddUrlRequested?.Invoke(this, new RequestAddUrlEventArgs(url)); | |||||
} | |||||
stream.Close(); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -67,48 +67,21 @@ namespace Shadowsocks | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
string pipename = $"Shadowsocks\\{ExecutablePath.GetHashCode()}"; | |||||
using (NamedPipeClientStream pipe = new NamedPipeClientStream(pipename)) | |||||
if (IPCService.AnotherInstanceRunning()) | |||||
{ | { | ||||
bool pipeExist = false; | |||||
try | |||||
if (!string.IsNullOrWhiteSpace(Options.OpenUrl)) | |||||
{ | { | ||||
pipe.Connect(10); | |||||
pipeExist = true; | |||||
IPCService.RequestOpenUrl(Options.OpenUrl); | |||||
} | } | ||||
catch (TimeoutException) | |||||
else | |||||
{ | { | ||||
pipeExist = false; | |||||
} | |||||
// --open-url exist, and no other instance, add it later | |||||
if (pipeExist && !string.IsNullOrWhiteSpace(Options.OpenUrl)) | |||||
{ | |||||
byte[] b = Encoding.UTF8.GetBytes(Options.OpenUrl); | |||||
byte[] opAddUrl = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(1)); | |||||
byte[] blen = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(b.Length)); | |||||
pipe.Write(opAddUrl, 0, 4); // opcode addurl | |||||
pipe.Write(blen, 0, 4); | |||||
pipe.Write(b, 0, b.Length); | |||||
pipe.Close(); | |||||
return; | |||||
} | |||||
// has another instance, and no need to communicate with it return | |||||
else if (pipeExist) | |||||
{ | |||||
Process[] oldProcesses = Process.GetProcessesByName("Shadowsocks"); | |||||
if (oldProcesses.Length > 0) | |||||
{ | |||||
Process oldProcess = oldProcesses[0]; | |||||
} | |||||
MessageBox.Show(I18N.GetString("Find Shadowsocks icon in your notify tray.") | MessageBox.Show(I18N.GetString("Find Shadowsocks icon in your notify tray.") | ||||
+ Environment.NewLine | |||||
+ I18N.GetString("If you want to start multiple Shadowsocks, make a copy in another directory."), | |||||
+ Environment.NewLine | |||||
+ I18N.GetString("If you want to start multiple Shadowsocks, make a copy in another directory."), | |||||
I18N.GetString("Shadowsocks is already running.")); | I18N.GetString("Shadowsocks is already running.")); | ||||
return; | |||||
} | } | ||||
return; | |||||
} | } | ||||
Utils.ReleaseMemory(true); | Utils.ReleaseMemory(true); | ||||
@@ -136,9 +109,10 @@ namespace Shadowsocks | |||||
HotKeys.Init(MainController); | HotKeys.Init(MainController); | ||||
MainController.Start(); | MainController.Start(); | ||||
NamedPipeServer namedPipeServer = new NamedPipeServer(); | |||||
Task.Run(() => namedPipeServer.Run(pipename)); | |||||
namedPipeServer.AddUrlRequested += (_1, e) => MainController.AskAddServerBySSURL(e.Url); | |||||
IPCService ipcService = new IPCService(); | |||||
Task.Run(() => ipcService.RunServer()); | |||||
ipcService.OpenUrlRequested += (_1, e) => MainController.AskAddServerBySSURL(e.Url); | |||||
if (!string.IsNullOrWhiteSpace(Options.OpenUrl)) | if (!string.IsNullOrWhiteSpace(Options.OpenUrl)) | ||||
{ | { | ||||
MainController.AskAddServerBySSURL(Options.OpenUrl); | MainController.AskAddServerBySSURL(Options.OpenUrl); | ||||
@@ -170,7 +170,7 @@ | |||||
<Compile Include="Controller\LoggerExtension.cs" /> | <Compile Include="Controller\LoggerExtension.cs" /> | ||||
<Compile Include="Controller\Service\GeositeUpdater.cs" /> | <Compile Include="Controller\Service\GeositeUpdater.cs" /> | ||||
<Compile Include="Controller\Service\PACDaemon.cs" /> | <Compile Include="Controller\Service\PACDaemon.cs" /> | ||||
<Compile Include="Controller\Service\NamedPipeServer.cs" /> | |||||
<Compile Include="Controller\Service\IPCService.cs" /> | |||||
<Compile Include="Controller\System\ProtocolHandler.cs" /> | <Compile Include="Controller\System\ProtocolHandler.cs" /> | ||||
<Compile Include="Controller\System\Hotkeys\HotkeyCallbacks.cs" /> | <Compile Include="Controller\System\Hotkeys\HotkeyCallbacks.cs" /> | ||||
<Compile Include="Encryption\AEAD\AEADEncryptor.cs" /> | <Compile Include="Encryption\AEAD\AEADEncryptor.cs" /> | ||||