@@ -0,0 +1,4 @@ | |||||
* text=auto | |||||
# geosite database | |||||
*.dat binary |
@@ -1,110 +1,110 @@ | |||||
using System; | |||||
using System.Collections.Specialized; | |||||
using System.Diagnostics; | |||||
using System.IO; | |||||
using System.Net; | |||||
using System.Net.Sockets; | |||||
using System.Reflection; | |||||
using Shadowsocks.Model; | |||||
using Shadowsocks.Util.ProcessManagement; | |||||
namespace Shadowsocks.Controller.Service | |||||
{ | |||||
// https://github.com/shadowsocks/shadowsocks-org/wiki/Plugin | |||||
public sealed class Sip003Plugin : IDisposable | |||||
{ | |||||
public IPEndPoint LocalEndPoint { get; private set; } | |||||
public int ProcessId => _started ? _pluginProcess.Id : 0; | |||||
private readonly object _startProcessLock = new object(); | |||||
private readonly Job _pluginJob; | |||||
private readonly Process _pluginProcess; | |||||
private bool _started; | |||||
private bool _disposed; | |||||
public static Sip003Plugin CreateIfConfigured(Server server, bool showPluginOutput) | |||||
{ | |||||
if (server == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(server)); | |||||
} | |||||
if (string.IsNullOrWhiteSpace(server.plugin)) | |||||
{ | |||||
return null; | |||||
} | |||||
return new Sip003Plugin( | |||||
server.plugin, | |||||
server.plugin_opts, | |||||
server.plugin_args, | |||||
server.server, | |||||
server.server_port, | |||||
showPluginOutput); | |||||
} | |||||
private Sip003Plugin(string plugin, string pluginOpts, string pluginArgs, string serverAddress, int serverPort, bool showPluginOutput) | |||||
{ | |||||
if (plugin == null) throw new ArgumentNullException(nameof(plugin)); | |||||
if (string.IsNullOrWhiteSpace(serverAddress)) | |||||
{ | |||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(serverAddress)); | |||||
} | |||||
if (serverPort <= 0 || serverPort > 65535) | |||||
{ | |||||
throw new ArgumentOutOfRangeException("serverPort"); | |||||
} | |||||
var appPath = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath); | |||||
_pluginProcess = new Process | |||||
{ | |||||
StartInfo = new ProcessStartInfo | |||||
{ | |||||
FileName = plugin, | |||||
Arguments = pluginArgs, | |||||
UseShellExecute = false, | |||||
CreateNoWindow = !showPluginOutput, | |||||
ErrorDialog = false, | |||||
WindowStyle = ProcessWindowStyle.Hidden, | |||||
WorkingDirectory = appPath ?? Environment.CurrentDirectory, | |||||
Environment = | |||||
{ | |||||
["SS_REMOTE_HOST"] = serverAddress, | |||||
["SS_REMOTE_PORT"] = serverPort.ToString(), | |||||
["SS_PLUGIN_OPTIONS"] = pluginOpts | |||||
} | |||||
} | |||||
}; | |||||
_pluginJob = new Job(); | |||||
} | |||||
public bool StartIfNeeded() | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
lock (_startProcessLock) | |||||
{ | |||||
if (_started && !_pluginProcess.HasExited) | |||||
{ | |||||
return false; | |||||
} | |||||
var localPort = GetNextFreeTcpPort(); | |||||
LocalEndPoint = new IPEndPoint(IPAddress.Loopback, localPort); | |||||
_pluginProcess.StartInfo.Environment["SS_LOCAL_HOST"] = LocalEndPoint.Address.ToString(); | |||||
_pluginProcess.StartInfo.Environment["SS_LOCAL_PORT"] = LocalEndPoint.Port.ToString(); | |||||
_pluginProcess.StartInfo.Arguments = ExpandEnvironmentVariables(_pluginProcess.StartInfo.Arguments, _pluginProcess.StartInfo.EnvironmentVariables); | |||||
using System; | |||||
using System.Collections.Specialized; | |||||
using System.Diagnostics; | |||||
using System.IO; | |||||
using System.Net; | |||||
using System.Net.Sockets; | |||||
using System.Reflection; | |||||
using Shadowsocks.Model; | |||||
using Shadowsocks.Util.ProcessManagement; | |||||
namespace Shadowsocks.Controller.Service | |||||
{ | |||||
// https://github.com/shadowsocks/shadowsocks-org/wiki/Plugin | |||||
public sealed class Sip003Plugin : IDisposable | |||||
{ | |||||
public IPEndPoint LocalEndPoint { get; private set; } | |||||
public int ProcessId => _started ? _pluginProcess.Id : 0; | |||||
private readonly object _startProcessLock = new object(); | |||||
private readonly Job _pluginJob; | |||||
private readonly Process _pluginProcess; | |||||
private bool _started; | |||||
private bool _disposed; | |||||
public static Sip003Plugin CreateIfConfigured(Server server, bool showPluginOutput) | |||||
{ | |||||
if (server == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(server)); | |||||
} | |||||
if (string.IsNullOrWhiteSpace(server.plugin)) | |||||
{ | |||||
return null; | |||||
} | |||||
return new Sip003Plugin( | |||||
server.plugin, | |||||
server.plugin_opts, | |||||
server.plugin_args, | |||||
server.server, | |||||
server.server_port, | |||||
showPluginOutput); | |||||
} | |||||
private Sip003Plugin(string plugin, string pluginOpts, string pluginArgs, string serverAddress, int serverPort, bool showPluginOutput) | |||||
{ | |||||
if (plugin == null) throw new ArgumentNullException(nameof(plugin)); | |||||
if (string.IsNullOrWhiteSpace(serverAddress)) | |||||
{ | |||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(serverAddress)); | |||||
} | |||||
if (serverPort <= 0 || serverPort > 65535) | |||||
{ | |||||
throw new ArgumentOutOfRangeException("serverPort"); | |||||
} | |||||
var appPath = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath); | |||||
_pluginProcess = new Process | |||||
{ | |||||
StartInfo = new ProcessStartInfo | |||||
{ | |||||
FileName = plugin, | |||||
Arguments = pluginArgs, | |||||
UseShellExecute = false, | |||||
CreateNoWindow = !showPluginOutput, | |||||
ErrorDialog = false, | |||||
WindowStyle = ProcessWindowStyle.Hidden, | |||||
WorkingDirectory = appPath ?? Environment.CurrentDirectory, | |||||
Environment = | |||||
{ | |||||
["SS_REMOTE_HOST"] = serverAddress, | |||||
["SS_REMOTE_PORT"] = serverPort.ToString(), | |||||
["SS_PLUGIN_OPTIONS"] = pluginOpts | |||||
} | |||||
} | |||||
}; | |||||
_pluginJob = new Job(); | |||||
} | |||||
public bool StartIfNeeded() | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
lock (_startProcessLock) | |||||
{ | |||||
if (_started && !_pluginProcess.HasExited) | |||||
{ | |||||
return false; | |||||
} | |||||
var localPort = GetNextFreeTcpPort(); | |||||
LocalEndPoint = new IPEndPoint(IPAddress.Loopback, localPort); | |||||
_pluginProcess.StartInfo.Environment["SS_LOCAL_HOST"] = LocalEndPoint.Address.ToString(); | |||||
_pluginProcess.StartInfo.Environment["SS_LOCAL_PORT"] = LocalEndPoint.Port.ToString(); | |||||
_pluginProcess.StartInfo.Arguments = ExpandEnvironmentVariables(_pluginProcess.StartInfo.Arguments, _pluginProcess.StartInfo.EnvironmentVariables); | |||||
try | try | ||||
{ | { | ||||
_pluginProcess.Start(); | _pluginProcess.Start(); | ||||
} | |||||
catch (System.ComponentModel.Win32Exception ex) | |||||
} | |||||
catch (System.ComponentModel.Win32Exception ex) | |||||
{ | { | ||||
// do not use File.Exists(...), it can not handle the scenarios when the plugin file is in system environment path. | // do not use File.Exists(...), it can not handle the scenarios when the plugin file is in system environment path. | ||||
// https://docs.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values | // https://docs.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values | ||||
@@ -115,65 +115,65 @@ namespace Shadowsocks.Controller.Service | |||||
throw new FileNotFoundException(I18N.GetString("Cannot find the plugin program file"), _pluginProcess.StartInfo.FileName, ex); | throw new FileNotFoundException(I18N.GetString("Cannot find the plugin program file"), _pluginProcess.StartInfo.FileName, ex); | ||||
} | } | ||||
throw new ApplicationException(I18N.GetString("Plugin Program"), ex); | throw new ApplicationException(I18N.GetString("Plugin Program"), ex); | ||||
} | |||||
_pluginJob.AddProcess(_pluginProcess.Handle); | |||||
_started = true; | |||||
} | |||||
return true; | |||||
} | |||||
public string ExpandEnvironmentVariables(string name, StringDictionary environmentVariables = null) | |||||
{ | |||||
// Expand the environment variables from the new process itself | |||||
if (environmentVariables != null) | |||||
{ | |||||
foreach(string key in environmentVariables.Keys) | |||||
{ | |||||
name = name.Replace($"%{key}%", environmentVariables[key], StringComparison.OrdinalIgnoreCase); | |||||
} | |||||
} | |||||
// Also expand the environment variables from current main process (system) | |||||
name = Environment.ExpandEnvironmentVariables(name); | |||||
return name; | |||||
} | |||||
static int GetNextFreeTcpPort() | |||||
{ | |||||
var l = new TcpListener(IPAddress.Loopback, 0); | |||||
l.Start(); | |||||
int port = ((IPEndPoint)l.LocalEndpoint).Port; | |||||
l.Stop(); | |||||
return port; | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
return; | |||||
} | |||||
try | |||||
{ | |||||
if (!_pluginProcess.HasExited) | |||||
{ | |||||
_pluginProcess.Kill(); | |||||
_pluginProcess.WaitForExit(); | |||||
} | |||||
} | |||||
catch (Exception) { } | |||||
finally | |||||
{ | |||||
try | |||||
{ | |||||
_pluginProcess.Dispose(); | |||||
_pluginJob.Dispose(); | |||||
} | |||||
catch (Exception) { } | |||||
_disposed = true; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
_pluginJob.AddProcess(_pluginProcess.Handle); | |||||
_started = true; | |||||
} | |||||
return true; | |||||
} | |||||
public string ExpandEnvironmentVariables(string name, StringDictionary environmentVariables = null) | |||||
{ | |||||
// Expand the environment variables from the new process itself | |||||
if (environmentVariables != null) | |||||
{ | |||||
foreach(string key in environmentVariables.Keys) | |||||
{ | |||||
name = name.Replace($"%{key}%", environmentVariables[key], StringComparison.OrdinalIgnoreCase); | |||||
} | |||||
} | |||||
// Also expand the environment variables from current main process (system) | |||||
name = Environment.ExpandEnvironmentVariables(name); | |||||
return name; | |||||
} | |||||
static int GetNextFreeTcpPort() | |||||
{ | |||||
var l = new TcpListener(IPAddress.Loopback, 0); | |||||
l.Start(); | |||||
int port = ((IPEndPoint)l.LocalEndpoint).Port; | |||||
l.Stop(); | |||||
return port; | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
return; | |||||
} | |||||
try | |||||
{ | |||||
if (!_pluginProcess.HasExited) | |||||
{ | |||||
_pluginProcess.Kill(); | |||||
_pluginProcess.WaitForExit(); | |||||
} | |||||
} | |||||
catch (Exception) { } | |||||
finally | |||||
{ | |||||
try | |||||
{ | |||||
_pluginProcess.Dispose(); | |||||
_pluginJob.Dispose(); | |||||
} | |||||
catch (Exception) { } | |||||
_disposed = true; | |||||
} | |||||
} | |||||
} | |||||
} | } |
@@ -1,26 +1,26 @@ | |||||
using Microsoft.Win32; | |||||
using Microsoft.Win32; | |||||
using NLog; | using NLog; | ||||
using Shadowsocks.Controller; | using Shadowsocks.Controller; | ||||
using Shadowsocks.Controller.Hotkeys; | using Shadowsocks.Controller.Hotkeys; | ||||
using Shadowsocks.Util; | using Shadowsocks.Util; | ||||
using Shadowsocks.View; | using Shadowsocks.View; | ||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using System.IO; | |||||
using System.IO.Pipes; | |||||
using System.Linq; | |||||
using System.Net; | |||||
using System.Text; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
using System.Windows.Forms; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using System.IO; | |||||
using System.IO.Pipes; | |||||
using System.Linq; | |||||
using System.Net; | |||||
using System.Text; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
using System.Windows.Forms; | |||||
namespace Shadowsocks | namespace Shadowsocks | ||||
{ | { | ||||
internal static class Program | |||||
internal static class Program | |||||
{ | { | ||||
private static readonly Logger logger = LogManager.GetCurrentClassLogger(); | |||||
private static readonly Logger logger = LogManager.GetCurrentClassLogger(); | |||||
public static ShadowsocksController MainController { get; private set; } | public static ShadowsocksController MainController { get; private set; } | ||||
public static MenuViewController MenuController { get; private set; } | public static MenuViewController MenuController { get; private set; } | ||||
public static string[] Args { get; private set; } | public static string[] Args { get; private set; } | ||||
@@ -29,15 +29,15 @@ namespace Shadowsocks | |||||
/// </summary> | /// </summary> | ||||
/// </summary> | /// </summary> | ||||
[STAThread] | [STAThread] | ||||
private static void Main(string[] args) | |||||
private static void Main(string[] args) | |||||
{ | { | ||||
Directory.SetCurrentDirectory(Application.StartupPath); | Directory.SetCurrentDirectory(Application.StartupPath); | ||||
// todo: initialize the NLog configuartion | // todo: initialize the NLog configuartion | ||||
Model.NLogConfig.TouchAndApplyNLogConfig(); | Model.NLogConfig.TouchAndApplyNLogConfig(); | ||||
// .NET Framework 4.7.2 on Win7 compatibility | // .NET Framework 4.7.2 on Win7 compatibility | ||||
ServicePointManager.SecurityProtocol |= | |||||
SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; | |||||
ServicePointManager.SecurityProtocol |= | |||||
SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; | |||||
// store args for further use | // store args for further use | ||||
Args = args; | Args = args; | ||||
@@ -59,54 +59,54 @@ namespace Shadowsocks | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
string pipename = $"Shadowsocks\\{Application.StartupPath.GetHashCode()}"; | |||||
string pipename = $"Shadowsocks\\{Application.StartupPath.GetHashCode()}"; | |||||
string addedUrl = null; | |||||
using (NamedPipeClientStream pipe = new NamedPipeClientStream(pipename)) | |||||
string addedUrl = null; | |||||
using (NamedPipeClientStream pipe = new NamedPipeClientStream(pipename)) | |||||
{ | { | ||||
bool pipeExist = false; | |||||
try | |||||
{ | |||||
pipe.Connect(10); | |||||
pipeExist = true; | |||||
} | |||||
catch (TimeoutException) | |||||
{ | |||||
pipeExist = false; | |||||
} | |||||
// TODO: switch to better argv parser when it's getting complicate | |||||
List<string> alist = Args.ToList(); | |||||
// check --open-url param | |||||
int urlidx = alist.IndexOf("--open-url") + 1; | |||||
if (urlidx > 0) | |||||
{ | |||||
if (Args.Length <= urlidx) | |||||
{ | |||||
return; | |||||
} | |||||
// --open-url exist, and no other instance, add it later | |||||
if (!pipeExist) | |||||
{ | |||||
addedUrl = Args[urlidx]; | |||||
} | |||||
// has other instance, send url via pipe then exit | |||||
else | |||||
{ | |||||
byte[] b = Encoding.UTF8.GetBytes(Args[urlidx]); | |||||
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) | |||||
bool pipeExist = false; | |||||
try | |||||
{ | |||||
pipe.Connect(10); | |||||
pipeExist = true; | |||||
} | |||||
catch (TimeoutException) | |||||
{ | |||||
pipeExist = false; | |||||
} | |||||
// TODO: switch to better argv parser when it's getting complicate | |||||
List<string> alist = Args.ToList(); | |||||
// check --open-url param | |||||
int urlidx = alist.IndexOf("--open-url") + 1; | |||||
if (urlidx > 0) | |||||
{ | |||||
if (Args.Length <= urlidx) | |||||
{ | |||||
return; | |||||
} | |||||
// --open-url exist, and no other instance, add it later | |||||
if (!pipeExist) | |||||
{ | |||||
addedUrl = Args[urlidx]; | |||||
} | |||||
// has other instance, send url via pipe then exit | |||||
else | |||||
{ | |||||
byte[] b = Encoding.UTF8.GetBytes(Args[urlidx]); | |||||
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"); | Process[] oldProcesses = Process.GetProcessesByName("Shadowsocks"); | ||||
if (oldProcesses.Length > 0) | if (oldProcesses.Length > 0) | ||||
@@ -119,43 +119,43 @@ namespace Shadowsocks | |||||
I18N.GetString("Shadowsocks is already running.")); | I18N.GetString("Shadowsocks is already running.")); | ||||
return; | return; | ||||
} | } | ||||
} | |||||
Utils.ReleaseMemory(true); | |||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); | |||||
// handle UI exceptions | |||||
Application.ThreadException += Application_ThreadException; | |||||
// handle non-UI exceptions | |||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; | |||||
Application.ApplicationExit += Application_ApplicationExit; | |||||
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; | |||||
Application.EnableVisualStyles(); | |||||
Application.SetCompatibleTextRenderingDefault(false); | |||||
AutoStartup.RegisterForRestart(true); | |||||
Directory.SetCurrentDirectory(Application.StartupPath); | |||||
} | |||||
Utils.ReleaseMemory(true); | |||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); | |||||
// handle UI exceptions | |||||
Application.ThreadException += Application_ThreadException; | |||||
// handle non-UI exceptions | |||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; | |||||
Application.ApplicationExit += Application_ApplicationExit; | |||||
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; | |||||
Application.EnableVisualStyles(); | |||||
Application.SetCompatibleTextRenderingDefault(false); | |||||
AutoStartup.RegisterForRestart(true); | |||||
Directory.SetCurrentDirectory(Application.StartupPath); | |||||
#if DEBUG | #if DEBUG | ||||
// truncate privoxy log file while debugging | |||||
string privoxyLogFilename = Utils.GetTempPath("privoxy.log"); | |||||
if (File.Exists(privoxyLogFilename)) | |||||
using (new FileStream(privoxyLogFilename, FileMode.Truncate)) { } | |||||
// truncate privoxy log file while debugging | |||||
string privoxyLogFilename = Utils.GetTempPath("privoxy.log"); | |||||
if (File.Exists(privoxyLogFilename)) | |||||
using (new FileStream(privoxyLogFilename, FileMode.Truncate)) { } | |||||
#endif | #endif | ||||
MainController = new ShadowsocksController(); | |||||
MenuController = new MenuViewController(MainController); | |||||
HotKeys.Init(MainController); | |||||
MainController.Start(); | |||||
NamedPipeServer namedPipeServer = new NamedPipeServer(); | |||||
Task.Run(() => namedPipeServer.Run(pipename)); | |||||
namedPipeServer.AddUrlRequested += (_1, e) => MainController.AskAddServerBySSURL(e.Url); | |||||
if (!addedUrl.IsNullOrEmpty()) | |||||
{ | |||||
MainController.AskAddServerBySSURL(addedUrl); | |||||
} | |||||
Application.Run(); | |||||
MainController = new ShadowsocksController(); | |||||
MenuController = new MenuViewController(MainController); | |||||
HotKeys.Init(MainController); | |||||
MainController.Start(); | |||||
NamedPipeServer namedPipeServer = new NamedPipeServer(); | |||||
Task.Run(() => namedPipeServer.Run(pipename)); | |||||
namedPipeServer.AddUrlRequested += (_1, e) => MainController.AskAddServerBySSURL(e.Url); | |||||
if (!addedUrl.IsNullOrEmpty()) | |||||
{ | |||||
MainController.AskAddServerBySSURL(addedUrl); | |||||
} | |||||
Application.Run(); | |||||
} | } | ||||
private static int exited = 0; | private static int exited = 0; | ||||
@@ -193,7 +193,7 @@ namespace Shadowsocks | |||||
logger.Info("os wake up"); | logger.Info("os wake up"); | ||||
if (MainController != null) | if (MainController != null) | ||||
{ | { | ||||
Task.Factory.StartNew(() => | |||||
Task.Factory.StartNew(() => | |||||
{ | { | ||||
Thread.Sleep(10 * 1000); | Thread.Sleep(10 * 1000); | ||||
try | try | ||||
@@ -1,212 +1,212 @@ | |||||
using System; | |||||
using System.Net; | |||||
using System.Net.Sockets; | |||||
using System.Text; | |||||
using System.Text.RegularExpressions; | |||||
using System.Threading; | |||||
using System; | |||||
using System.Net; | |||||
using System.Net.Sockets; | |||||
using System.Text; | |||||
using System.Text.RegularExpressions; | |||||
using System.Threading; | |||||
using NLog; | using NLog; | ||||
using Shadowsocks.Controller; | |||||
using Shadowsocks.Util.Sockets; | |||||
namespace Shadowsocks.Proxy | |||||
{ | |||||
public class HttpProxy : IProxy | |||||
{ | |||||
private static Logger logger = LogManager.GetCurrentClassLogger(); | |||||
private class FakeAsyncResult : IAsyncResult | |||||
{ | |||||
public readonly HttpState innerState; | |||||
private readonly IAsyncResult r; | |||||
public FakeAsyncResult(IAsyncResult orig, HttpState state) | |||||
{ | |||||
r = orig; | |||||
innerState = state; | |||||
} | |||||
public bool IsCompleted => r.IsCompleted; | |||||
public WaitHandle AsyncWaitHandle => r.AsyncWaitHandle; | |||||
public object AsyncState => innerState.AsyncState; | |||||
public bool CompletedSynchronously => r.CompletedSynchronously; | |||||
} | |||||
private class HttpState | |||||
{ | |||||
public AsyncCallback Callback { get; set; } | |||||
public object AsyncState { get; set; } | |||||
public int BytesToRead; | |||||
public Exception ex { get; set; } | |||||
} | |||||
public EndPoint LocalEndPoint => _remote.LocalEndPoint; | |||||
public EndPoint ProxyEndPoint { get; private set; } | |||||
public EndPoint DestEndPoint { get; private set; } | |||||
private readonly WrappedSocket _remote = new WrappedSocket(); | |||||
public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) | |||||
{ | |||||
ProxyEndPoint = remoteEP; | |||||
_remote.BeginConnect(remoteEP, callback, state); | |||||
} | |||||
public void EndConnectProxy(IAsyncResult asyncResult) | |||||
{ | |||||
_remote.EndConnect(asyncResult); | |||||
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); | |||||
} | |||||
private const string HTTP_CRLF = "\r\n"; | |||||
private const string HTTP_CONNECT_TEMPLATE = | |||||
"CONNECT {0} HTTP/1.1" + HTTP_CRLF + | |||||
"Host: {0}" + HTTP_CRLF + | |||||
"Proxy-Connection: keep-alive" + HTTP_CRLF + | |||||
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + HTTP_CRLF + | |||||
"{1}" + // Proxy-Authorization if any | |||||
"" + HTTP_CRLF; // End with an empty line | |||||
private const string PROXY_AUTH_TEMPLATE = "Proxy-Authorization: Basic {0}" + HTTP_CRLF; | |||||
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state, NetworkCredential auth = null) | |||||
{ | |||||
DestEndPoint = destEndPoint; | |||||
using Shadowsocks.Controller; | |||||
using Shadowsocks.Util.Sockets; | |||||
namespace Shadowsocks.Proxy | |||||
{ | |||||
public class HttpProxy : IProxy | |||||
{ | |||||
private static Logger logger = LogManager.GetCurrentClassLogger(); | |||||
private class FakeAsyncResult : IAsyncResult | |||||
{ | |||||
public readonly HttpState innerState; | |||||
private readonly IAsyncResult r; | |||||
public FakeAsyncResult(IAsyncResult orig, HttpState state) | |||||
{ | |||||
r = orig; | |||||
innerState = state; | |||||
} | |||||
public bool IsCompleted => r.IsCompleted; | |||||
public WaitHandle AsyncWaitHandle => r.AsyncWaitHandle; | |||||
public object AsyncState => innerState.AsyncState; | |||||
public bool CompletedSynchronously => r.CompletedSynchronously; | |||||
} | |||||
private class HttpState | |||||
{ | |||||
public AsyncCallback Callback { get; set; } | |||||
public object AsyncState { get; set; } | |||||
public int BytesToRead; | |||||
public Exception ex { get; set; } | |||||
} | |||||
public EndPoint LocalEndPoint => _remote.LocalEndPoint; | |||||
public EndPoint ProxyEndPoint { get; private set; } | |||||
public EndPoint DestEndPoint { get; private set; } | |||||
private readonly WrappedSocket _remote = new WrappedSocket(); | |||||
public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) | |||||
{ | |||||
ProxyEndPoint = remoteEP; | |||||
_remote.BeginConnect(remoteEP, callback, state); | |||||
} | |||||
public void EndConnectProxy(IAsyncResult asyncResult) | |||||
{ | |||||
_remote.EndConnect(asyncResult); | |||||
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); | |||||
} | |||||
private const string HTTP_CRLF = "\r\n"; | |||||
private const string HTTP_CONNECT_TEMPLATE = | |||||
"CONNECT {0} HTTP/1.1" + HTTP_CRLF + | |||||
"Host: {0}" + HTTP_CRLF + | |||||
"Proxy-Connection: keep-alive" + HTTP_CRLF + | |||||
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + HTTP_CRLF + | |||||
"{1}" + // Proxy-Authorization if any | |||||
"" + HTTP_CRLF; // End with an empty line | |||||
private const string PROXY_AUTH_TEMPLATE = "Proxy-Authorization: Basic {0}" + HTTP_CRLF; | |||||
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state, NetworkCredential auth = null) | |||||
{ | |||||
DestEndPoint = destEndPoint; | |||||
String authInfo = ""; | String authInfo = ""; | ||||
if (auth != null) | if (auth != null) | ||||
{ | { | ||||
string authKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth.UserName + ":" + auth.Password)); | string authKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth.UserName + ":" + auth.Password)); | ||||
authInfo = string.Format(PROXY_AUTH_TEMPLATE, authKey); | authInfo = string.Format(PROXY_AUTH_TEMPLATE, authKey); | ||||
} | } | ||||
string request = string.Format(HTTP_CONNECT_TEMPLATE, destEndPoint, authInfo); | |||||
var b = Encoding.UTF8.GetBytes(request); | |||||
var st = new HttpState(); | |||||
st.Callback = callback; | |||||
st.AsyncState = state; | |||||
_remote.BeginSend(b, 0, b.Length, 0, HttpRequestSendCallback, st); | |||||
} | |||||
public void EndConnectDest(IAsyncResult asyncResult) | |||||
{ | |||||
var state = ((FakeAsyncResult)asyncResult).innerState; | |||||
if (state.ex != null) | |||||
{ | |||||
throw state.ex; | |||||
} | |||||
} | |||||
public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, | |||||
object state) | |||||
{ | |||||
_remote.BeginSend(buffer, offset, size, socketFlags, callback, state); | |||||
} | |||||
public int EndSend(IAsyncResult asyncResult) | |||||
{ | |||||
return _remote.EndSend(asyncResult); | |||||
} | |||||
public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, | |||||
object state) | |||||
{ | |||||
_remote.BeginReceive(buffer, offset, size, socketFlags, callback, state); | |||||
} | |||||
public int EndReceive(IAsyncResult asyncResult) | |||||
{ | |||||
return _remote.EndReceive(asyncResult); | |||||
} | |||||
public void Shutdown(SocketShutdown how) | |||||
{ | |||||
_remote.Shutdown(how); | |||||
} | |||||
public void Close() | |||||
{ | |||||
_remote.Dispose(); | |||||
} | |||||
private void HttpRequestSendCallback(IAsyncResult ar) | |||||
{ | |||||
var state = (HttpState) ar.AsyncState; | |||||
try | |||||
{ | |||||
_remote.EndSend(ar); | |||||
// start line read | |||||
new LineReader(_remote, OnLineRead, OnException, OnFinish, Encoding.UTF8, HTTP_CRLF, 1024, new FakeAsyncResult(ar, state)); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
state.ex = ex; | |||||
state.Callback?.Invoke(new FakeAsyncResult(ar, state)); | |||||
} | |||||
} | |||||
private void OnFinish(byte[] lastBytes, int index, int length, object state) | |||||
{ | |||||
var st = (FakeAsyncResult)state; | |||||
if (st.innerState.ex == null) | |||||
{ | |||||
if (!_established) | |||||
{ | |||||
st.innerState.ex = new Exception(I18N.GetString("Proxy request failed")); | |||||
} | |||||
// TODO: save last bytes | |||||
} | |||||
st.innerState.Callback?.Invoke(st); | |||||
} | |||||
private void OnException(Exception ex, object state) | |||||
{ | |||||
var st = (FakeAsyncResult) state; | |||||
st.innerState.ex = ex; | |||||
} | |||||
private static readonly Regex HttpRespondHeaderRegex = new Regex(@"^(HTTP/1\.\d) (\d{3}) (.+)$", RegexOptions.Compiled); | |||||
private int _respondLineCount = 0; | |||||
private bool _established = false; | |||||
private bool OnLineRead(string line, object state) | |||||
{ | |||||
logger.Trace(line); | |||||
if (_respondLineCount == 0) | |||||
{ | |||||
var m = HttpRespondHeaderRegex.Match(line); | |||||
if (m.Success) | |||||
{ | |||||
var resultCode = m.Groups[2].Value; | |||||
if ("200" != resultCode) | |||||
{ | |||||
return true; | |||||
} | |||||
_established = true; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
if (line.IsNullOrEmpty()) | |||||
{ | |||||
return true; | |||||
} | |||||
} | |||||
_respondLineCount++; | |||||
return false; | |||||
} | |||||
} | |||||
} | |||||
string request = string.Format(HTTP_CONNECT_TEMPLATE, destEndPoint, authInfo); | |||||
var b = Encoding.UTF8.GetBytes(request); | |||||
var st = new HttpState(); | |||||
st.Callback = callback; | |||||
st.AsyncState = state; | |||||
_remote.BeginSend(b, 0, b.Length, 0, HttpRequestSendCallback, st); | |||||
} | |||||
public void EndConnectDest(IAsyncResult asyncResult) | |||||
{ | |||||
var state = ((FakeAsyncResult)asyncResult).innerState; | |||||
if (state.ex != null) | |||||
{ | |||||
throw state.ex; | |||||
} | |||||
} | |||||
public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, | |||||
object state) | |||||
{ | |||||
_remote.BeginSend(buffer, offset, size, socketFlags, callback, state); | |||||
} | |||||
public int EndSend(IAsyncResult asyncResult) | |||||
{ | |||||
return _remote.EndSend(asyncResult); | |||||
} | |||||
public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, | |||||
object state) | |||||
{ | |||||
_remote.BeginReceive(buffer, offset, size, socketFlags, callback, state); | |||||
} | |||||
public int EndReceive(IAsyncResult asyncResult) | |||||
{ | |||||
return _remote.EndReceive(asyncResult); | |||||
} | |||||
public void Shutdown(SocketShutdown how) | |||||
{ | |||||
_remote.Shutdown(how); | |||||
} | |||||
public void Close() | |||||
{ | |||||
_remote.Dispose(); | |||||
} | |||||
private void HttpRequestSendCallback(IAsyncResult ar) | |||||
{ | |||||
var state = (HttpState) ar.AsyncState; | |||||
try | |||||
{ | |||||
_remote.EndSend(ar); | |||||
// start line read | |||||
new LineReader(_remote, OnLineRead, OnException, OnFinish, Encoding.UTF8, HTTP_CRLF, 1024, new FakeAsyncResult(ar, state)); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
state.ex = ex; | |||||
state.Callback?.Invoke(new FakeAsyncResult(ar, state)); | |||||
} | |||||
} | |||||
private void OnFinish(byte[] lastBytes, int index, int length, object state) | |||||
{ | |||||
var st = (FakeAsyncResult)state; | |||||
if (st.innerState.ex == null) | |||||
{ | |||||
if (!_established) | |||||
{ | |||||
st.innerState.ex = new Exception(I18N.GetString("Proxy request failed")); | |||||
} | |||||
// TODO: save last bytes | |||||
} | |||||
st.innerState.Callback?.Invoke(st); | |||||
} | |||||
private void OnException(Exception ex, object state) | |||||
{ | |||||
var st = (FakeAsyncResult) state; | |||||
st.innerState.ex = ex; | |||||
} | |||||
private static readonly Regex HttpRespondHeaderRegex = new Regex(@"^(HTTP/1\.\d) (\d{3}) (.+)$", RegexOptions.Compiled); | |||||
private int _respondLineCount = 0; | |||||
private bool _established = false; | |||||
private bool OnLineRead(string line, object state) | |||||
{ | |||||
logger.Trace(line); | |||||
if (_respondLineCount == 0) | |||||
{ | |||||
var m = HttpRespondHeaderRegex.Match(line); | |||||
if (m.Success) | |||||
{ | |||||
var resultCode = m.Groups[2].Value; | |||||
if ("200" != resultCode) | |||||
{ | |||||
return true; | |||||
} | |||||
_established = true; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
if (line.IsNullOrEmpty()) | |||||
{ | |||||
return true; | |||||
} | |||||
} | |||||
_respondLineCount++; | |||||
return false; | |||||
} | |||||
} | |||||
} |
@@ -1,182 +1,182 @@ | |||||
using System; | |||||
using System.Diagnostics; | |||||
using System.Runtime.InteropServices; | |||||
using System; | |||||
using System.Diagnostics; | |||||
using System.Runtime.InteropServices; | |||||
using NLog; | using NLog; | ||||
using Shadowsocks.Controller; | |||||
namespace Shadowsocks.Util.ProcessManagement | |||||
{ | |||||
/* | |||||
* See: | |||||
* http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net | |||||
*/ | |||||
public class Job : IDisposable | |||||
{ | |||||
private static Logger logger = LogManager.GetCurrentClassLogger(); | |||||
private IntPtr handle = IntPtr.Zero; | |||||
public Job() | |||||
{ | |||||
handle = CreateJobObject(IntPtr.Zero, null); | |||||
var extendedInfoPtr = IntPtr.Zero; | |||||
var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION | |||||
{ | |||||
LimitFlags = 0x2000 | |||||
}; | |||||
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION | |||||
{ | |||||
BasicLimitInformation = info | |||||
}; | |||||
try | |||||
{ | |||||
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); | |||||
extendedInfoPtr = Marshal.AllocHGlobal(length); | |||||
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); | |||||
if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, | |||||
(uint) length)) | |||||
throw new Exception(string.Format("Unable to set information. Error: {0}", | |||||
Marshal.GetLastWin32Error())); | |||||
} | |||||
finally | |||||
{ | |||||
if (extendedInfoPtr != IntPtr.Zero) | |||||
{ | |||||
Marshal.FreeHGlobal(extendedInfoPtr); | |||||
extendedInfoPtr = IntPtr.Zero; | |||||
} | |||||
} | |||||
} | |||||
public bool AddProcess(IntPtr processHandle) | |||||
{ | |||||
var succ = AssignProcessToJobObject(handle, processHandle); | |||||
if (!succ) | |||||
{ | |||||
logger.Error("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error()); | |||||
} | |||||
return succ; | |||||
} | |||||
public bool AddProcess(int processId) | |||||
{ | |||||
return AddProcess(Process.GetProcessById(processId).Handle); | |||||
} | |||||
#region IDisposable | |||||
private bool disposed; | |||||
public void Dispose() | |||||
{ | |||||
Dispose(true); | |||||
GC.SuppressFinalize(this); | |||||
} | |||||
protected virtual void Dispose(bool disposing) | |||||
{ | |||||
if (disposed) return; | |||||
disposed = true; | |||||
using Shadowsocks.Controller; | |||||
namespace Shadowsocks.Util.ProcessManagement | |||||
{ | |||||
/* | |||||
* See: | |||||
* http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net | |||||
*/ | |||||
public class Job : IDisposable | |||||
{ | |||||
private static Logger logger = LogManager.GetCurrentClassLogger(); | |||||
private IntPtr handle = IntPtr.Zero; | |||||
public Job() | |||||
{ | |||||
handle = CreateJobObject(IntPtr.Zero, null); | |||||
var extendedInfoPtr = IntPtr.Zero; | |||||
var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION | |||||
{ | |||||
LimitFlags = 0x2000 | |||||
}; | |||||
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION | |||||
{ | |||||
BasicLimitInformation = info | |||||
}; | |||||
try | |||||
{ | |||||
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); | |||||
extendedInfoPtr = Marshal.AllocHGlobal(length); | |||||
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); | |||||
if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, | |||||
(uint) length)) | |||||
throw new Exception(string.Format("Unable to set information. Error: {0}", | |||||
Marshal.GetLastWin32Error())); | |||||
} | |||||
finally | |||||
{ | |||||
if (extendedInfoPtr != IntPtr.Zero) | |||||
{ | |||||
Marshal.FreeHGlobal(extendedInfoPtr); | |||||
extendedInfoPtr = IntPtr.Zero; | |||||
} | |||||
} | |||||
} | |||||
public bool AddProcess(IntPtr processHandle) | |||||
{ | |||||
var succ = AssignProcessToJobObject(handle, processHandle); | |||||
if (!succ) | |||||
{ | |||||
logger.Error("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error()); | |||||
} | |||||
return succ; | |||||
} | |||||
public bool AddProcess(int processId) | |||||
{ | |||||
return AddProcess(Process.GetProcessById(processId).Handle); | |||||
} | |||||
#region IDisposable | |||||
private bool disposed; | |||||
public void Dispose() | |||||
{ | |||||
Dispose(true); | |||||
GC.SuppressFinalize(this); | |||||
} | |||||
protected virtual void Dispose(bool disposing) | |||||
{ | |||||
if (disposed) return; | |||||
disposed = true; | |||||
if (disposing) | if (disposing) | ||||
{ | |||||
// no managed objects to free | |||||
} | |||||
if (handle != IntPtr.Zero) | |||||
{ | |||||
CloseHandle(handle); | |||||
handle = IntPtr.Zero; | |||||
} | |||||
} | |||||
~Job() | |||||
{ | |||||
Dispose(false); | |||||
} | |||||
#endregion | |||||
#region Interop | |||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] | |||||
private static extern IntPtr CreateJobObject(IntPtr a, string lpName); | |||||
[DllImport("kernel32.dll", SetLastError = true)] | |||||
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); | |||||
[DllImport("kernel32.dll", SetLastError = true)] | |||||
private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); | |||||
[DllImport("kernel32.dll", SetLastError = true)] | |||||
[return: MarshalAs(UnmanagedType.Bool)] | |||||
private static extern bool CloseHandle(IntPtr hObject); | |||||
#endregion | |||||
} | |||||
#region Helper classes | |||||
[StructLayout(LayoutKind.Sequential)] | |||||
struct IO_COUNTERS | |||||
{ | |||||
public UInt64 ReadOperationCount; | |||||
public UInt64 WriteOperationCount; | |||||
public UInt64 OtherOperationCount; | |||||
public UInt64 ReadTransferCount; | |||||
public UInt64 WriteTransferCount; | |||||
public UInt64 OtherTransferCount; | |||||
} | |||||
[StructLayout(LayoutKind.Sequential)] | |||||
struct JOBOBJECT_BASIC_LIMIT_INFORMATION | |||||
{ | |||||
public Int64 PerProcessUserTimeLimit; | |||||
public Int64 PerJobUserTimeLimit; | |||||
public UInt32 LimitFlags; | |||||
public UIntPtr MinimumWorkingSetSize; | |||||
public UIntPtr MaximumWorkingSetSize; | |||||
public UInt32 ActiveProcessLimit; | |||||
public UIntPtr Affinity; | |||||
public UInt32 PriorityClass; | |||||
public UInt32 SchedulingClass; | |||||
} | |||||
[StructLayout(LayoutKind.Sequential)] | |||||
public struct SECURITY_ATTRIBUTES | |||||
{ | |||||
public UInt32 nLength; | |||||
public IntPtr lpSecurityDescriptor; | |||||
public Int32 bInheritHandle; | |||||
} | |||||
[StructLayout(LayoutKind.Sequential)] | |||||
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION | |||||
{ | |||||
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; | |||||
public IO_COUNTERS IoInfo; | |||||
public UIntPtr ProcessMemoryLimit; | |||||
public UIntPtr JobMemoryLimit; | |||||
public UIntPtr PeakProcessMemoryUsed; | |||||
public UIntPtr PeakJobMemoryUsed; | |||||
} | |||||
public enum JobObjectInfoType | |||||
{ | |||||
AssociateCompletionPortInformation = 7, | |||||
BasicLimitInformation = 2, | |||||
BasicUIRestrictions = 4, | |||||
EndOfJobTimeInformation = 6, | |||||
ExtendedLimitInformation = 9, | |||||
SecurityLimitInformation = 5, | |||||
GroupInformation = 11 | |||||
} | |||||
#endregion | |||||
} | |||||
{ | |||||
// no managed objects to free | |||||
} | |||||
if (handle != IntPtr.Zero) | |||||
{ | |||||
CloseHandle(handle); | |||||
handle = IntPtr.Zero; | |||||
} | |||||
} | |||||
~Job() | |||||
{ | |||||
Dispose(false); | |||||
} | |||||
#endregion | |||||
#region Interop | |||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] | |||||
private static extern IntPtr CreateJobObject(IntPtr a, string lpName); | |||||
[DllImport("kernel32.dll", SetLastError = true)] | |||||
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); | |||||
[DllImport("kernel32.dll", SetLastError = true)] | |||||
private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); | |||||
[DllImport("kernel32.dll", SetLastError = true)] | |||||
[return: MarshalAs(UnmanagedType.Bool)] | |||||
private static extern bool CloseHandle(IntPtr hObject); | |||||
#endregion | |||||
} | |||||
#region Helper classes | |||||
[StructLayout(LayoutKind.Sequential)] | |||||
struct IO_COUNTERS | |||||
{ | |||||
public UInt64 ReadOperationCount; | |||||
public UInt64 WriteOperationCount; | |||||
public UInt64 OtherOperationCount; | |||||
public UInt64 ReadTransferCount; | |||||
public UInt64 WriteTransferCount; | |||||
public UInt64 OtherTransferCount; | |||||
} | |||||
[StructLayout(LayoutKind.Sequential)] | |||||
struct JOBOBJECT_BASIC_LIMIT_INFORMATION | |||||
{ | |||||
public Int64 PerProcessUserTimeLimit; | |||||
public Int64 PerJobUserTimeLimit; | |||||
public UInt32 LimitFlags; | |||||
public UIntPtr MinimumWorkingSetSize; | |||||
public UIntPtr MaximumWorkingSetSize; | |||||
public UInt32 ActiveProcessLimit; | |||||
public UIntPtr Affinity; | |||||
public UInt32 PriorityClass; | |||||
public UInt32 SchedulingClass; | |||||
} | |||||
[StructLayout(LayoutKind.Sequential)] | |||||
public struct SECURITY_ATTRIBUTES | |||||
{ | |||||
public UInt32 nLength; | |||||
public IntPtr lpSecurityDescriptor; | |||||
public Int32 bInheritHandle; | |||||
} | |||||
[StructLayout(LayoutKind.Sequential)] | |||||
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION | |||||
{ | |||||
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; | |||||
public IO_COUNTERS IoInfo; | |||||
public UIntPtr ProcessMemoryLimit; | |||||
public UIntPtr JobMemoryLimit; | |||||
public UIntPtr PeakProcessMemoryUsed; | |||||
public UIntPtr PeakJobMemoryUsed; | |||||
} | |||||
public enum JobObjectInfoType | |||||
{ | |||||
AssociateCompletionPortInformation = 7, | |||||
BasicLimitInformation = 2, | |||||
BasicUIRestrictions = 4, | |||||
EndOfJobTimeInformation = 6, | |||||
ExtendedLimitInformation = 9, | |||||
SecurityLimitInformation = 5, | |||||
GroupInformation = 11 | |||||
} | |||||
#endregion | |||||
} |
@@ -1,268 +1,268 @@ | |||||
using System; | |||||
using System.Net; | |||||
using System.Net.Sockets; | |||||
using System.Threading; | |||||
namespace Shadowsocks.Util.Sockets | |||||
{ | |||||
/* | |||||
* A wrapped socket class which support both ipv4 and ipv6 based on the | |||||
* connected remote endpoint. | |||||
* | |||||
* If the server address is host name, then it may have both ipv4 and ipv6 address | |||||
* after resolving. The main idea is we don't want to resolve and choose the address | |||||
* by ourself. Instead, Socket.ConnectAsync() do handle this thing internally by trying | |||||
* each address and returning an established socket connection. | |||||
*/ | |||||
public class WrappedSocket | |||||
{ | |||||
public EndPoint LocalEndPoint => _activeSocket?.LocalEndPoint; | |||||
// Only used during connection and close, so it won't cost too much. | |||||
private SpinLock _socketSyncLock = new SpinLock(); | |||||
private bool _disposed; | |||||
private bool Connected => _activeSocket != null; | |||||
private Socket _activeSocket; | |||||
public void BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.IsConnected); | |||||
} | |||||
var arg = new SocketAsyncEventArgs(); | |||||
arg.RemoteEndPoint = remoteEP; | |||||
arg.Completed += OnTcpConnectCompleted; | |||||
arg.UserToken = new TcpUserToken(callback, state); | |||||
using System; | |||||
using System.Net; | |||||
using System.Net.Sockets; | |||||
using System.Threading; | |||||
namespace Shadowsocks.Util.Sockets | |||||
{ | |||||
/* | |||||
* A wrapped socket class which support both ipv4 and ipv6 based on the | |||||
* connected remote endpoint. | |||||
* | |||||
* If the server address is host name, then it may have both ipv4 and ipv6 address | |||||
* after resolving. The main idea is we don't want to resolve and choose the address | |||||
* by ourself. Instead, Socket.ConnectAsync() do handle this thing internally by trying | |||||
* each address and returning an established socket connection. | |||||
*/ | |||||
public class WrappedSocket | |||||
{ | |||||
public EndPoint LocalEndPoint => _activeSocket?.LocalEndPoint; | |||||
// Only used during connection and close, so it won't cost too much. | |||||
private SpinLock _socketSyncLock = new SpinLock(); | |||||
private bool _disposed; | |||||
private bool Connected => _activeSocket != null; | |||||
private Socket _activeSocket; | |||||
public void BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.IsConnected); | |||||
} | |||||
var arg = new SocketAsyncEventArgs(); | |||||
arg.RemoteEndPoint = remoteEP; | |||||
arg.Completed += OnTcpConnectCompleted; | |||||
arg.UserToken = new TcpUserToken(callback, state); | |||||
if(!Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg)) | if(!Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg)) | ||||
{ | { | ||||
OnTcpConnectCompleted(this, arg); | OnTcpConnectCompleted(this, arg); | ||||
} | |||||
} | |||||
private class FakeAsyncResult : IAsyncResult | |||||
{ | |||||
public bool IsCompleted { get; } = true; | |||||
public WaitHandle AsyncWaitHandle { get; } = null; | |||||
public object AsyncState { get; set; } | |||||
public bool CompletedSynchronously { get; } = true; | |||||
public Exception InternalException { get; set; } = null; | |||||
} | |||||
private class TcpUserToken | |||||
{ | |||||
public AsyncCallback Callback { get; } | |||||
public object AsyncState { get; } | |||||
public TcpUserToken(AsyncCallback callback, object state) | |||||
{ | |||||
Callback = callback; | |||||
AsyncState = state; | |||||
} | |||||
} | |||||
private void OnTcpConnectCompleted(object sender, SocketAsyncEventArgs args) | |||||
{ | |||||
using (args) | |||||
{ | |||||
args.Completed -= OnTcpConnectCompleted; | |||||
var token = (TcpUserToken) args.UserToken; | |||||
if (args.SocketError != SocketError.Success) | |||||
{ | |||||
var ex = args.ConnectByNameError ?? new SocketException((int) args.SocketError); | |||||
var r = new FakeAsyncResult() | |||||
{ | |||||
AsyncState = token.AsyncState, | |||||
InternalException = ex | |||||
}; | |||||
token.Callback(r); | |||||
} | |||||
else | |||||
{ | |||||
var lockTaken = false; | |||||
if (!_socketSyncLock.IsHeldByCurrentThread) | |||||
{ | |||||
_socketSyncLock.TryEnter(ref lockTaken); | |||||
} | |||||
try | |||||
{ | |||||
if (Connected) | |||||
{ | |||||
args.ConnectSocket.FullClose(); | |||||
} | |||||
else | |||||
{ | |||||
_activeSocket = args.ConnectSocket; | |||||
if (_disposed) | |||||
{ | |||||
_activeSocket.FullClose(); | |||||
} | |||||
var r = new FakeAsyncResult() | |||||
{ | |||||
AsyncState = token.AsyncState | |||||
}; | |||||
token.Callback(r); | |||||
} | |||||
} | |||||
finally | |||||
{ | |||||
if (lockTaken) | |||||
{ | |||||
_socketSyncLock.Exit(); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
public void EndConnect(IAsyncResult asyncResult) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
var r = asyncResult as FakeAsyncResult; | |||||
if (r == null) | |||||
{ | |||||
throw new ArgumentException("Invalid asyncResult.", nameof(asyncResult)); | |||||
} | |||||
if (r.InternalException != null) | |||||
{ | |||||
throw r.InternalException; | |||||
} | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
return; | |||||
} | |||||
var lockTaken = false; | |||||
if (!_socketSyncLock.IsHeldByCurrentThread) | |||||
{ | |||||
_socketSyncLock.TryEnter(ref lockTaken); | |||||
} | |||||
try | |||||
{ | |||||
_disposed = true; | |||||
_activeSocket?.FullClose(); | |||||
} | |||||
finally | |||||
{ | |||||
if (lockTaken) | |||||
{ | |||||
_socketSyncLock.Exit(); | |||||
} | |||||
} | |||||
} | |||||
public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, | |||||
AsyncCallback callback, | |||||
object state) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.NotConnected); | |||||
} | |||||
return _activeSocket.BeginSend(buffer, offset, size, socketFlags, callback, state); | |||||
} | |||||
public int EndSend(IAsyncResult asyncResult) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.NotConnected); | |||||
} | |||||
return _activeSocket.EndSend(asyncResult); | |||||
} | |||||
public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, | |||||
AsyncCallback callback, | |||||
object state) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.NotConnected); | |||||
} | |||||
return _activeSocket.BeginReceive(buffer, offset, size, socketFlags, callback, state); | |||||
} | |||||
public int EndReceive(IAsyncResult asyncResult) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.NotConnected); | |||||
} | |||||
return _activeSocket.EndReceive(asyncResult); | |||||
} | |||||
public void Shutdown(SocketShutdown how) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
return; | |||||
} | |||||
_activeSocket.Shutdown(how); | |||||
} | |||||
public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue) | |||||
{ | |||||
SetSocketOption(optionLevel, optionName, optionValue ? 1 : 0); | |||||
} | |||||
public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int)SocketError.NotConnected); | |||||
} | |||||
_activeSocket.SetSocketOption(optionLevel, optionName, optionValue); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
private class FakeAsyncResult : IAsyncResult | |||||
{ | |||||
public bool IsCompleted { get; } = true; | |||||
public WaitHandle AsyncWaitHandle { get; } = null; | |||||
public object AsyncState { get; set; } | |||||
public bool CompletedSynchronously { get; } = true; | |||||
public Exception InternalException { get; set; } = null; | |||||
} | |||||
private class TcpUserToken | |||||
{ | |||||
public AsyncCallback Callback { get; } | |||||
public object AsyncState { get; } | |||||
public TcpUserToken(AsyncCallback callback, object state) | |||||
{ | |||||
Callback = callback; | |||||
AsyncState = state; | |||||
} | |||||
} | |||||
private void OnTcpConnectCompleted(object sender, SocketAsyncEventArgs args) | |||||
{ | |||||
using (args) | |||||
{ | |||||
args.Completed -= OnTcpConnectCompleted; | |||||
var token = (TcpUserToken) args.UserToken; | |||||
if (args.SocketError != SocketError.Success) | |||||
{ | |||||
var ex = args.ConnectByNameError ?? new SocketException((int) args.SocketError); | |||||
var r = new FakeAsyncResult() | |||||
{ | |||||
AsyncState = token.AsyncState, | |||||
InternalException = ex | |||||
}; | |||||
token.Callback(r); | |||||
} | |||||
else | |||||
{ | |||||
var lockTaken = false; | |||||
if (!_socketSyncLock.IsHeldByCurrentThread) | |||||
{ | |||||
_socketSyncLock.TryEnter(ref lockTaken); | |||||
} | |||||
try | |||||
{ | |||||
if (Connected) | |||||
{ | |||||
args.ConnectSocket.FullClose(); | |||||
} | |||||
else | |||||
{ | |||||
_activeSocket = args.ConnectSocket; | |||||
if (_disposed) | |||||
{ | |||||
_activeSocket.FullClose(); | |||||
} | |||||
var r = new FakeAsyncResult() | |||||
{ | |||||
AsyncState = token.AsyncState | |||||
}; | |||||
token.Callback(r); | |||||
} | |||||
} | |||||
finally | |||||
{ | |||||
if (lockTaken) | |||||
{ | |||||
_socketSyncLock.Exit(); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
public void EndConnect(IAsyncResult asyncResult) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
var r = asyncResult as FakeAsyncResult; | |||||
if (r == null) | |||||
{ | |||||
throw new ArgumentException("Invalid asyncResult.", nameof(asyncResult)); | |||||
} | |||||
if (r.InternalException != null) | |||||
{ | |||||
throw r.InternalException; | |||||
} | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
return; | |||||
} | |||||
var lockTaken = false; | |||||
if (!_socketSyncLock.IsHeldByCurrentThread) | |||||
{ | |||||
_socketSyncLock.TryEnter(ref lockTaken); | |||||
} | |||||
try | |||||
{ | |||||
_disposed = true; | |||||
_activeSocket?.FullClose(); | |||||
} | |||||
finally | |||||
{ | |||||
if (lockTaken) | |||||
{ | |||||
_socketSyncLock.Exit(); | |||||
} | |||||
} | |||||
} | |||||
public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, | |||||
AsyncCallback callback, | |||||
object state) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.NotConnected); | |||||
} | |||||
return _activeSocket.BeginSend(buffer, offset, size, socketFlags, callback, state); | |||||
} | |||||
public int EndSend(IAsyncResult asyncResult) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.NotConnected); | |||||
} | |||||
return _activeSocket.EndSend(asyncResult); | |||||
} | |||||
public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, | |||||
AsyncCallback callback, | |||||
object state) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.NotConnected); | |||||
} | |||||
return _activeSocket.BeginReceive(buffer, offset, size, socketFlags, callback, state); | |||||
} | |||||
public int EndReceive(IAsyncResult asyncResult) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int) SocketError.NotConnected); | |||||
} | |||||
return _activeSocket.EndReceive(asyncResult); | |||||
} | |||||
public void Shutdown(SocketShutdown how) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
return; | |||||
} | |||||
_activeSocket.Shutdown(how); | |||||
} | |||||
public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue) | |||||
{ | |||||
SetSocketOption(optionLevel, optionName, optionValue ? 1 : 0); | |||||
} | |||||
public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue) | |||||
{ | |||||
if (_disposed) | |||||
{ | |||||
throw new ObjectDisposedException(GetType().FullName); | |||||
} | |||||
if (!Connected) | |||||
{ | |||||
throw new SocketException((int)SocketError.NotConnected); | |||||
} | |||||
_activeSocket.SetSocketOption(optionLevel, optionName, optionValue); | |||||
} | |||||
} | |||||
} |
@@ -1,33 +1,33 @@ | |||||
namespace Shadowsocks.View | |||||
{ | |||||
partial class ConfigForm | |||||
{ | |||||
/// <summary> | |||||
/// Required designer variable. | |||||
/// </summary> | |||||
private System.ComponentModel.IContainer components = null; | |||||
/// <summary> | |||||
/// Clean up any resources being used. | |||||
/// </summary> | |||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |||||
protected override void Dispose(bool disposing) | |||||
{ | |||||
if (disposing && (components != null)) | |||||
{ | |||||
components.Dispose(); | |||||
} | |||||
base.Dispose(disposing); | |||||
} | |||||
#region Windows Form Designer generated code | |||||
/// <summary> | |||||
/// Required method for Designer support - do not modify | |||||
/// the contents of this method with the code editor. | |||||
/// </summary> | |||||
private void InitializeComponent() | |||||
{ | |||||
namespace Shadowsocks.View | |||||
{ | |||||
partial class ConfigForm | |||||
{ | |||||
/// <summary> | |||||
/// Required designer variable. | |||||
/// </summary> | |||||
private System.ComponentModel.IContainer components = null; | |||||
/// <summary> | |||||
/// Clean up any resources being used. | |||||
/// </summary> | |||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |||||
protected override void Dispose(bool disposing) | |||||
{ | |||||
if (disposing && (components != null)) | |||||
{ | |||||
components.Dispose(); | |||||
} | |||||
base.Dispose(disposing); | |||||
} | |||||
#region Windows Form Designer generated code | |||||
/// <summary> | |||||
/// Required method for Designer support - do not modify | |||||
/// the contents of this method with the code editor. | |||||
/// </summary> | |||||
private void InitializeComponent() | |||||
{ | |||||
this.components = new System.ComponentModel.Container(); | this.components = new System.ComponentModel.Container(); | ||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); | this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); | ||||
this.PluginOptionsLabel = new System.Windows.Forms.Label(); | this.PluginOptionsLabel = new System.Windows.Forms.Label(); | ||||
@@ -672,51 +672,51 @@ | |||||
this.ResumeLayout(false); | this.ResumeLayout(false); | ||||
this.PerformLayout(); | this.PerformLayout(); | ||||
} | |||||
#endregion | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; | |||||
private System.Windows.Forms.Label IPLabel; | |||||
private System.Windows.Forms.Label ServerPortLabel; | |||||
private System.Windows.Forms.Label PasswordLabel; | |||||
private System.Windows.Forms.TextBox IPTextBox; | |||||
private System.Windows.Forms.TextBox ServerPortTextBox; | |||||
private System.Windows.Forms.Label EncryptionLabel; | |||||
private System.Windows.Forms.ComboBox EncryptionSelect; | |||||
private System.Windows.Forms.Panel panel2; | |||||
private System.Windows.Forms.Button OKButton; | |||||
private System.Windows.Forms.Button MyCancelButton; | |||||
private System.Windows.Forms.Button ApplyButton; | |||||
private System.Windows.Forms.Button DeleteButton; | |||||
private System.Windows.Forms.Button AddButton; | |||||
private System.Windows.Forms.GroupBox ServerGroupBox; | |||||
private System.Windows.Forms.ListBox ServersListBox; | |||||
private System.Windows.Forms.TextBox RemarksTextBox; | |||||
private System.Windows.Forms.Label RemarksLabel; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; | |||||
private System.Windows.Forms.TextBox ProxyPortTextBox; | |||||
private System.Windows.Forms.Label ProxyPortLabel; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel6; | |||||
private System.Windows.Forms.Button MoveDownButton; | |||||
private System.Windows.Forms.Button MoveUpButton; | |||||
private System.Windows.Forms.Button DuplicateButton; | |||||
private System.Windows.Forms.Label TimeoutLabel; | |||||
private System.Windows.Forms.TextBox TimeoutTextBox; | |||||
private System.Windows.Forms.Label PluginOptionsLabel; | |||||
private System.Windows.Forms.TextBox PluginTextBox; | |||||
private System.Windows.Forms.Label PluginLabel; | |||||
private System.Windows.Forms.TextBox PluginOptionsTextBox; | |||||
private System.Windows.Forms.CheckBox ShowPasswdCheckBox; | |||||
private System.Windows.Forms.TextBox PasswordTextBox; | |||||
private System.Windows.Forms.TextBox PluginArgumentsTextBox; | |||||
private System.Windows.Forms.Label PluginArgumentsLabel; | |||||
private System.Windows.Forms.ToolTip toolTip1; | |||||
private System.Windows.Forms.CheckBox PortableModeCheckBox; | |||||
private System.Windows.Forms.CheckBox NeedPluginArgCheckBox; | |||||
} | |||||
} | |||||
} | |||||
#endregion | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; | |||||
private System.Windows.Forms.Label IPLabel; | |||||
private System.Windows.Forms.Label ServerPortLabel; | |||||
private System.Windows.Forms.Label PasswordLabel; | |||||
private System.Windows.Forms.TextBox IPTextBox; | |||||
private System.Windows.Forms.TextBox ServerPortTextBox; | |||||
private System.Windows.Forms.Label EncryptionLabel; | |||||
private System.Windows.Forms.ComboBox EncryptionSelect; | |||||
private System.Windows.Forms.Panel panel2; | |||||
private System.Windows.Forms.Button OKButton; | |||||
private System.Windows.Forms.Button MyCancelButton; | |||||
private System.Windows.Forms.Button ApplyButton; | |||||
private System.Windows.Forms.Button DeleteButton; | |||||
private System.Windows.Forms.Button AddButton; | |||||
private System.Windows.Forms.GroupBox ServerGroupBox; | |||||
private System.Windows.Forms.ListBox ServersListBox; | |||||
private System.Windows.Forms.TextBox RemarksTextBox; | |||||
private System.Windows.Forms.Label RemarksLabel; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; | |||||
private System.Windows.Forms.TextBox ProxyPortTextBox; | |||||
private System.Windows.Forms.Label ProxyPortLabel; | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel6; | |||||
private System.Windows.Forms.Button MoveDownButton; | |||||
private System.Windows.Forms.Button MoveUpButton; | |||||
private System.Windows.Forms.Button DuplicateButton; | |||||
private System.Windows.Forms.Label TimeoutLabel; | |||||
private System.Windows.Forms.TextBox TimeoutTextBox; | |||||
private System.Windows.Forms.Label PluginOptionsLabel; | |||||
private System.Windows.Forms.TextBox PluginTextBox; | |||||
private System.Windows.Forms.Label PluginLabel; | |||||
private System.Windows.Forms.TextBox PluginOptionsTextBox; | |||||
private System.Windows.Forms.CheckBox ShowPasswdCheckBox; | |||||
private System.Windows.Forms.TextBox PasswordTextBox; | |||||
private System.Windows.Forms.TextBox PluginArgumentsTextBox; | |||||
private System.Windows.Forms.Label PluginArgumentsLabel; | |||||
private System.Windows.Forms.ToolTip toolTip1; | |||||
private System.Windows.Forms.CheckBox PortableModeCheckBox; | |||||
private System.Windows.Forms.CheckBox NeedPluginArgCheckBox; | |||||
} | |||||
} | |||||
@@ -36,7 +36,7 @@ namespace Shadowsocks.View | |||||
private ContextMenu contextMenu1; | private ContextMenu contextMenu1; | ||||
private MenuItem disableItem; | private MenuItem disableItem; | ||||
private MenuItem AutoStartupItem; | private MenuItem AutoStartupItem; | ||||
private MenuItem ProtocolHandlerItem; | |||||
private MenuItem ProtocolHandlerItem; | |||||
private MenuItem ShareOverLANItem; | private MenuItem ShareOverLANItem; | ||||
private MenuItem SeperatorItem; | private MenuItem SeperatorItem; | ||||
private MenuItem ConfigItem; | private MenuItem ConfigItem; | ||||
@@ -316,7 +316,7 @@ namespace Shadowsocks.View | |||||
this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)), | this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)), | ||||
new MenuItem("-"), | new MenuItem("-"), | ||||
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)), | this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)), | ||||
this.ProtocolHandlerItem = CreateMenuItem("Associate ss:// Links", new EventHandler(this.ProtocolHandlerItem_Click)), | |||||
this.ProtocolHandlerItem = CreateMenuItem("Associate ss:// Links", new EventHandler(this.ProtocolHandlerItem_Click)), | |||||
this.ShareOverLANItem = CreateMenuItem("Allow other Devices to connect", new EventHandler(this.ShareOverLANItem_Click)), | this.ShareOverLANItem = CreateMenuItem("Allow other Devices to connect", new EventHandler(this.ShareOverLANItem_Click)), | ||||
new MenuItem("-"), | new MenuItem("-"), | ||||
this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)), | this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)), | ||||
@@ -444,7 +444,7 @@ namespace Shadowsocks.View | |||||
VerboseLoggingToggleItem.Checked = config.isVerboseLogging; | VerboseLoggingToggleItem.Checked = config.isVerboseLogging; | ||||
ShowPluginOutputToggleItem.Checked = config.showPluginOutput; | ShowPluginOutputToggleItem.Checked = config.showPluginOutput; | ||||
AutoStartupItem.Checked = AutoStartup.Check(); | AutoStartupItem.Checked = AutoStartup.Check(); | ||||
ProtocolHandlerItem.Checked = ProtocolHandler.Check(); | |||||
ProtocolHandlerItem.Checked = ProtocolHandler.Check(); | |||||
onlinePACItem.Checked = onlinePACItem.Enabled && config.useOnlinePac; | onlinePACItem.Checked = onlinePACItem.Enabled && config.useOnlinePac; | ||||
localPACItem.Checked = !onlinePACItem.Checked; | localPACItem.Checked = !onlinePACItem.Checked; | ||||
secureLocalPacUrlToggleItem.Checked = config.secureLocalPac; | secureLocalPacUrlToggleItem.Checked = config.secureLocalPac; | ||||
@@ -847,16 +847,16 @@ namespace Shadowsocks.View | |||||
{ | { | ||||
MessageBox.Show(I18N.GetString("Failed to update registry")); | MessageBox.Show(I18N.GetString("Failed to update registry")); | ||||
} | } | ||||
LoadCurrentConfiguration(); | |||||
} | |||||
private void ProtocolHandlerItem_Click(object sender, EventArgs e) | |||||
{ | |||||
ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked; | |||||
if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked)) | |||||
{ | |||||
MessageBox.Show(I18N.GetString("Failed to update registry")); | |||||
} | |||||
LoadCurrentConfiguration(); | |||||
LoadCurrentConfiguration(); | |||||
} | |||||
private void ProtocolHandlerItem_Click(object sender, EventArgs e) | |||||
{ | |||||
ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked; | |||||
if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked)) | |||||
{ | |||||
MessageBox.Show(I18N.GetString("Failed to update registry")); | |||||
} | |||||
LoadCurrentConfiguration(); | |||||
} | } | ||||
private void LocalPACItem_Click(object sender, EventArgs e) | private void LocalPACItem_Click(object sender, EventArgs e) | ||||
@@ -1,33 +1,33 @@ | |||||
namespace Shadowsocks.View | |||||
{ | |||||
partial class ProxyForm | |||||
{ | |||||
/// <summary> | |||||
/// Required designer variable. | |||||
/// </summary> | |||||
private System.ComponentModel.IContainer components = null; | |||||
/// <summary> | |||||
/// Clean up any resources being used. | |||||
/// </summary> | |||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |||||
protected override void Dispose(bool disposing) | |||||
{ | |||||
if (disposing && (components != null)) | |||||
{ | |||||
components.Dispose(); | |||||
} | |||||
base.Dispose(disposing); | |||||
} | |||||
#region Windows Form Designer generated code | |||||
/// <summary> | |||||
/// Required method for Designer support - do not modify | |||||
/// the contents of this method with the code editor. | |||||
/// </summary> | |||||
private void InitializeComponent() | |||||
{ | |||||
namespace Shadowsocks.View | |||||
{ | |||||
partial class ProxyForm | |||||
{ | |||||
/// <summary> | |||||
/// Required designer variable. | |||||
/// </summary> | |||||
private System.ComponentModel.IContainer components = null; | |||||
/// <summary> | |||||
/// Clean up any resources being used. | |||||
/// </summary> | |||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |||||
protected override void Dispose(bool disposing) | |||||
{ | |||||
if (disposing && (components != null)) | |||||
{ | |||||
components.Dispose(); | |||||
} | |||||
base.Dispose(disposing); | |||||
} | |||||
#region Windows Form Designer generated code | |||||
/// <summary> | |||||
/// Required method for Designer support - do not modify | |||||
/// the contents of this method with the code editor. | |||||
/// </summary> | |||||
private void InitializeComponent() | |||||
{ | |||||
this.MyCancelButton = new System.Windows.Forms.Button(); | this.MyCancelButton = new System.Windows.Forms.Button(); | ||||
this.OKButton = new System.Windows.Forms.Button(); | this.OKButton = new System.Windows.Forms.Button(); | ||||
this.UseProxyCheckBox = new System.Windows.Forms.CheckBox(); | this.UseProxyCheckBox = new System.Windows.Forms.CheckBox(); | ||||
@@ -307,17 +307,17 @@ | |||||
this.flowLayoutPanel1.ResumeLayout(false); | this.flowLayoutPanel1.ResumeLayout(false); | ||||
this.ResumeLayout(false); | this.ResumeLayout(false); | ||||
} | |||||
#endregion | |||||
private System.Windows.Forms.CheckBox UseProxyCheckBox; | |||||
private System.Windows.Forms.Label ProxyAddrLabel; | |||||
private System.Windows.Forms.TextBox ProxyServerTextBox; | |||||
private System.Windows.Forms.Label ProxyPortLabel; | |||||
private System.Windows.Forms.TextBox ProxyPortTextBox; | |||||
private System.Windows.Forms.Button MyCancelButton; | |||||
private System.Windows.Forms.Button OKButton; | |||||
private System.Windows.Forms.Label ProxyTypeLabel; | |||||
} | |||||
#endregion | |||||
private System.Windows.Forms.CheckBox UseProxyCheckBox; | |||||
private System.Windows.Forms.Label ProxyAddrLabel; | |||||
private System.Windows.Forms.TextBox ProxyServerTextBox; | |||||
private System.Windows.Forms.Label ProxyPortLabel; | |||||
private System.Windows.Forms.TextBox ProxyPortTextBox; | |||||
private System.Windows.Forms.Button MyCancelButton; | |||||
private System.Windows.Forms.Button OKButton; | |||||
private System.Windows.Forms.Label ProxyTypeLabel; | |||||
private System.Windows.Forms.ComboBox ProxyTypeComboBox; | private System.Windows.Forms.ComboBox ProxyTypeComboBox; | ||||
private System.Windows.Forms.TextBox ProxyTimeoutTextBox; | private System.Windows.Forms.TextBox ProxyTimeoutTextBox; | ||||
private System.Windows.Forms.Label ProxyTimeoutLabel; | private System.Windows.Forms.Label ProxyTimeoutLabel; | ||||
@@ -329,5 +329,5 @@ | |||||
private System.Windows.Forms.CheckBox UseAuthCheckBox; | private System.Windows.Forms.CheckBox UseAuthCheckBox; | ||||
private System.Windows.Forms.TextBox AuthUserTextBox; | private System.Windows.Forms.TextBox AuthUserTextBox; | ||||
private System.Windows.Forms.TextBox AuthPwdTextBox; | private System.Windows.Forms.TextBox AuthPwdTextBox; | ||||
} | |||||
} | |||||
} | } |