Compare commits

...
18 Commits
Author SHA1 Message Date
Syrone Wong f910400449 Update CHANGES and bump version
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-10-03 18:58:45 +08:00
Syrone Wong 3ba5c491d2 Update libsscrypto
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-10-03 18:56:00 +08:00
Syrone Wong 13ebb5ef01 Fix RegistryKey dispose
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-10-01 06:53:43 +08:00
Syrone Wong c46149a375 Fix hotkey dispose
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-30 15:15:48 +08:00
Syrone Wong 6e8d6d3d21 Adjust garbage collection
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-30 15:15:39 +08:00
破娃酱 c7adac5fb0 Remove lock in SodiumEncryptor (#754)
- Use separate encrypt/decrypt buffer when creating instances
- Revert 3bc77d212a
2016-09-29 19:03:43 -05:00
Syrone Wong 41eb43b54e Drop retry connect
Shadowsocks don't need to reconnect, which is the software's
responsibility to retry.

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-29 16:39:58 +08:00
Syrone Wong 46d95e7411 Get rid of lock(this)
- Use readonly object as lock

Info from stackoverflow:

If I want to be sure that it will be locked for all threads inside my
application:
The lock object has to be static, if it locks access to static state.
Otherwise it has to be instance, because there's no need to lock state of
one class instance, and prevent other threads to work with another class
instance at the same time.

everyone says that the object has to be "readonly" I didn't found the
reason
Well, it doesn't have to be. This is just a best practice, which helps you
to avoid errors.

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-29 16:39:58 +08:00
Syrone Wong d5f24df128 Don't suppress exceptions
It is better to log them.

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-29 16:38:54 +08:00
Syrone Wong a0fd003099 Close connection in the caller if exception is caught
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-29 16:38:24 +08:00
Syrone Wong 4bd9fd8a6b Replace treewide polipo with privoxy
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-28 16:35:51 +08:00
Syrone Wong 1dc992e806 Refine encryption
introduce a constructor to store inner method name

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-28 10:46:19 +08:00
Noisyfox 4acae9de9b Fix a bug that the callback will be invoked twice if http proxy request failed. (#751) 2016-09-24 23:52:04 -05:00
Noisyfox 35fc73b58b Add HTTP proxy support in forward proxy (#745)
* Add HTTP proxy support in forward proxy

Signed-off-by: noisyfox <timemanager.rick@gmail.com>

* Typo

* Throw exception if forward proxy not supported.
2016-09-24 23:37:24 -05:00
Syrone Wong 156b3acd9b Misc
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-22 09:45:08 +08:00
Syrone Wong 8cf582803d Fix #740
>_<

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-22 08:40:22 +08:00
Syrone Wong c8d070fb09 Free unmanaged memory
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-21 20:01:52 +08:00
Syrone Wong c671c7c32d Add easter egg
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-09-21 20:00:55 +08:00
29 changed files with 766 additions and 212 deletions
+4
View File
@@ -1,3 +1,7 @@
3.3.2 2016-10-03
- Add HTTP forward proxy support
- Bug fixes and improvements
3.3.1 2016-09-20
- Add global hotkey support
- Bug fixes and improvements
@@ -39,6 +39,9 @@ namespace Shadowsocks.Controller
// connection receive buffer
private byte[] connetionRecvBuffer = new byte[RecvSize];
// instance-based lock
private readonly object _Lock = new object();
public void Start(byte[] firstPacket, int length, Socket socket, int targetPort)
{
this._firstPacket = firstPacket;
@@ -220,7 +223,7 @@ namespace Shadowsocks.Controller
public void Close()
{
lock (this)
lock (_Lock)
{
if (_closed)
{
@@ -16,21 +16,21 @@ using Shadowsocks.Util.ProcessManagement;
namespace Shadowsocks.Controller
{
class PolipoRunner
class PrivoxyRunner
{
private static int Uid;
private static string UniqueConfigFile;
private static Job PolipoJob;
private static Job PrivoxyJob;
private Process _process;
private int _runningPort;
static PolipoRunner()
static PrivoxyRunner()
{
try
{
Uid = Application.StartupPath.GetHashCode(); // Currently we use ss's StartupPath to identify different polipo instance.
Uid = Application.StartupPath.GetHashCode(); // Currently we use ss's StartupPath to identify different Privoxy instance.
UniqueConfigFile = $"privoxy_{Uid}.conf";
PolipoJob = new Job();
PrivoxyJob = new Job();
FileManager.UncompressFile(Utils.GetTempPath("ss_privoxy.exe"), Resources.privoxy_exe);
FileManager.UncompressFile(Utils.GetTempPath("mgwz.dll"), Resources.mgwz_dll);
@@ -54,17 +54,17 @@ namespace Shadowsocks.Controller
Server server = configuration.GetCurrentServer();
if (_process == null)
{
Process[] existingPolipo = Process.GetProcessesByName("ss_privoxy");
foreach (Process p in existingPolipo.Where(IsChildProcess))
Process[] existingPrivoxy = Process.GetProcessesByName("ss_privoxy");
foreach (Process p in existingPrivoxy.Where(IsChildProcess))
{
KillProcess(p);
}
string polipoConfig = Resources.privoxy_conf;
string privoxyConfig = Resources.privoxy_conf;
_runningPort = this.GetFreePort();
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString());
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_PORT__", _runningPort.ToString());
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1");
FileManager.ByteArrayToFile(Utils.GetTempPath(UniqueConfigFile), Encoding.UTF8.GetBytes(polipoConfig));
privoxyConfig = privoxyConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString());
privoxyConfig = privoxyConfig.Replace("__PRIVOXY_BIND_PORT__", _runningPort.ToString());
privoxyConfig = privoxyConfig.Replace("__PRIVOXY_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1");
FileManager.ByteArrayToFile(Utils.GetTempPath(UniqueConfigFile), Encoding.UTF8.GetBytes(privoxyConfig));
_process = new Process();
// Configure the process using the StartInfo properties.
@@ -80,7 +80,7 @@ namespace Shadowsocks.Controller
* Add this process to job obj associated with this ss process, so that
* when ss exit unexpectedly, this process will be forced killed by system.
*/
PolipoJob.AddProcess(_process.Handle);
PrivoxyJob.AddProcess(_process.Handle);
}
RefreshTrayArea();
}
@@ -139,8 +139,6 @@ namespace Shadowsocks.Controller
private AsyncSession _currentRemoteSession;
private const int MaxRetry = 4;
private int _retryCount = 0;
private bool _proxyConnected;
private bool _destConnected;
@@ -160,8 +158,10 @@ namespace Shadowsocks.Controller
private bool _remoteShutdown = false;
private bool _closed = false;
private object _encryptionLock = new object();
private object _decryptionLock = new object();
// instance-based lock without static
private readonly object _encryptionLock = new object();
private readonly object _decryptionLock = new object();
private readonly object _closeConnLock = new object();
private DateTime _startConnectTime;
private DateTime _startReceivingTime;
@@ -207,7 +207,7 @@ namespace Shadowsocks.Controller
public void Close()
{
lock (this)
lock (_closeConnLock)
{
if (_closed) return;
_closed = true;
@@ -218,8 +218,8 @@ namespace Shadowsocks.Controller
}
try
{
_connection?.Shutdown(SocketShutdown.Both);
_connection?.Close();
_connection.Shutdown(SocketShutdown.Both);
_connection.Close();
}
catch (Exception e)
{
@@ -227,9 +227,9 @@ namespace Shadowsocks.Controller
}
try
{
var remote = _currentRemoteSession?.Remote;
remote?.Shutdown(SocketShutdown.Both);
remote?.Close();
var remote = _currentRemoteSession.Remote;
remote.Shutdown(SocketShutdown.Both);
remote.Close();
}
catch (Exception e)
{
@@ -259,7 +259,7 @@ namespace Shadowsocks.Controller
response = new byte[] { 0, 91 };
Logging.Error("socks 5 protocol error");
}
_connection?.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(HandshakeSendCallback), null);
_connection.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(HandshakeSendCallback), null);
}
else
Close();
@@ -378,7 +378,7 @@ namespace Shadowsocks.Controller
{
try
{
_connection?.EndSend(ar);
_connection.EndSend(ar);
StartConnect();
}
catch (Exception e)
@@ -420,7 +420,17 @@ namespace Shadowsocks.Controller
EndPoint proxyEP;
if (_config.proxy.useProxy)
{
remote = new Socks5Proxy();
switch (_config.proxy.proxyType)
{
case ProxyConfig.PROXY_SOCKS5:
remote = new Socks5Proxy();
break;
case ProxyConfig.PROXY_HTTP:
remote = new HttpProxy();
break;
default:
throw new NotSupportedException("Unknown forward proxy.");
}
proxyEP = SocketUtil.GetEndPoint(_config.proxy.proxyServer, _config.proxy.proxyPort);
}
else
@@ -469,7 +479,7 @@ namespace Shadowsocks.Controller
Logging.Info($"Proxy {proxy.ProxyEndPoint} timed out");
proxy.Close();
RetryConnect();
Close();
}
private void ProxyConnectCallback(IAsyncResult ar)
@@ -522,7 +532,7 @@ namespace Shadowsocks.Controller
catch (Exception e)
{
Logging.LogUsefulException(e);
RetryConnect();
Close();
}
}
@@ -544,19 +554,7 @@ namespace Shadowsocks.Controller
strategy?.SetFailure(server);
Logging.Info($"{server.FriendlyName()} timed out");
session.Remote.Close();
RetryConnect();
}
private void RetryConnect()
{
if (_retryCount < MaxRetry)
{
Logging.Debug($"Connection failed, retry ({_retryCount})");
StartConnect();
_retryCount++;
}
else
Close();
Close();
}
private void ConnectCallback(IAsyncResult ar)
@@ -573,7 +571,7 @@ namespace Shadowsocks.Controller
var remote = session.Remote;
// Complete the connection.
remote?.EndConnectDest(ar);
remote.EndConnectDest(ar);
_destConnected = true;
@@ -600,7 +598,7 @@ namespace Shadowsocks.Controller
strategy?.SetFailure(_server);
}
Logging.LogUsefulException(e);
RetryConnect();
Close();
}
}
@@ -611,7 +609,7 @@ namespace Shadowsocks.Controller
{
_startReceivingTime = DateTime.Now;
session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session);
_connection?.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback),
_connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback),
new AsyncSession<bool>(session, true) /* to tell the callback this is the first time reading packet, and we haven't found the header yet. */);
}
catch (Exception e)
@@ -636,7 +634,6 @@ namespace Shadowsocks.Controller
int bytesToSend;
lock (_decryptionLock)
{
if (_closed) return;
_encryptor.Decrypt(_remoteRecvBuffer, bytesRead, _remoteSendBuffer, out bytesToSend);
}
_connection.BeginSend(_remoteSendBuffer, 0, bytesToSend, SocketFlags.None, new AsyncCallback(PipeConnectionSendCallback), session);
@@ -662,7 +659,6 @@ namespace Shadowsocks.Controller
if (_closed) return;
try
{
if(_connection == null) return;
int bytesRead = _connection.EndReceive(ar);
_totalWrite += bytesRead;
@@ -710,7 +706,6 @@ namespace Shadowsocks.Controller
int bytesToSend;
lock (_encryptionLock)
{
if (_closed) return;
_encryptor.Encrypt(_connetionRecvBuffer, bytesRead, _connetionSendBuffer, out bytesToSend);
}
_tcprelay.UpdateOutboundCounter(_server, bytesToSend);
@@ -740,7 +735,7 @@ namespace Shadowsocks.Controller
{
var session = (AsyncSession)ar.AsyncState;
session.Remote.EndSend(ar);
_connection?.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback), session);
_connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback), session);
}
catch (Exception e)
{
@@ -751,11 +746,10 @@ namespace Shadowsocks.Controller
private void PipeConnectionSendCallback(IAsyncResult ar)
{
if (_closed) return;
try
{
var session = (AsyncSession)ar.AsyncState;
_connection?.EndSend(ar);
_connection.EndSend(ar);
session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session);
}
catch (Exception e)
@@ -23,7 +23,7 @@ namespace Shadowsocks.Controller
public string LatestVersionLocalName;
public event EventHandler CheckUpdateCompleted;
public const string Version = "3.3.1";
public const string Version = "3.3.2";
private class CheckUpdateTimer : System.Timers.Timer
{
@@ -28,7 +28,7 @@ namespace Shadowsocks.Controller
private PACServer _pacServer;
private Configuration _config;
private StrategyManager _strategyManager;
private PolipoRunner polipoRunner;
private PrivoxyRunner privoxyRunner;
private GFWListUpdater gfwListUpdater;
public AvailabilityStatistics availabilityStatistics = AvailabilityStatistics.Instance;
public StatisticsStrategyConfiguration StatisticsConfiguration { get; private set; }
@@ -221,9 +221,10 @@ namespace Shadowsocks.Controller
SaveConfig(_config);
}
public void EnableProxy(string proxy, int port)
public void EnableProxy(int type, string proxy, int port)
{
_config.proxy.useProxy = true;
_config.proxy.proxyType = type;
_config.proxy.proxyServer = proxy;
_config.proxy.proxyPort = port;
SaveConfig(_config);
@@ -263,9 +264,9 @@ namespace Shadowsocks.Controller
{
_listener.Stop();
}
if (polipoRunner != null)
if (privoxyRunner != null)
{
polipoRunner.Stop();
privoxyRunner.Stop();
}
if (_config.enabled)
{
@@ -416,9 +417,9 @@ namespace Shadowsocks.Controller
_config = Configuration.Load();
StatisticsConfiguration = StatisticsStrategyConfiguration.Load();
if (polipoRunner == null)
if (privoxyRunner == null)
{
polipoRunner = new PolipoRunner();
privoxyRunner = new PrivoxyRunner();
}
if (_pacServer == null)
{
@@ -440,11 +441,11 @@ namespace Shadowsocks.Controller
{
_listener.Stop();
}
// don't put polipoRunner.Start() before pacServer.Stop()
// don't put PrivoxyRunner.Start() before pacServer.Stop()
// or bind will fail when switching bind address from 0.0.0.0 to 127.0.0.1
// though UseShellExecute is set to true now
// http://stackoverflow.com/questions/10235093/socket-doesnt-close-after-application-exits-if-a-launched-process-is-open
polipoRunner.Stop();
privoxyRunner.Stop();
try
{
var strategy = GetCurrentStrategy();
@@ -453,7 +454,7 @@ namespace Shadowsocks.Controller
strategy.ReloadServers();
}
polipoRunner.Start(_config);
privoxyRunner.Start(_config);
TCPRelay tcpRelay = new TCPRelay(this, _config);
UDPRelay udpRelay = new UDPRelay(this);
@@ -461,7 +462,7 @@ namespace Shadowsocks.Controller
services.Add(tcpRelay);
services.Add(udpRelay);
services.Add(_pacServer);
services.Add(new PortForwarder(polipoRunner.RunningPort));
services.Add(new PortForwarder(privoxyRunner.RunningPort));
_listener = new Listener(services);
_listener.Start(_config);
}
@@ -39,8 +39,10 @@ namespace Shadowsocks.Controller
{
if (runKey != null)
{
try { runKey.Close(); }
catch (Exception e)
try {
runKey.Close();
runKey.Dispose();
} catch (Exception e)
{ Logging.LogUsefulException(e); }
}
}
@@ -84,8 +86,10 @@ namespace Shadowsocks.Controller
{
if (runKey != null)
{
try { runKey.Close(); }
catch (Exception e)
try {
runKey.Close();
runKey.Dispose();
} catch (Exception e)
{ Logging.LogUsefulException(e); }
}
}
@@ -84,8 +84,10 @@ namespace Shadowsocks.Controller
MessageBox.Show( I18N.GetString( "Failed to update registry" ) );
} finally {
if ( registry != null ) {
try { registry.Close(); }
catch (Exception e)
try {
registry.Close();
registry.Dispose();
} catch (Exception e)
{ Logging.LogUsefulException(e); }
}
}
@@ -119,8 +121,10 @@ namespace Shadowsocks.Controller
Logging.LogUsefulException( e );
} finally {
if ( registry != null ) {
try { registry.Close(); }
catch (Exception e)
try {
registry.Close();
registry.Dispose();
} catch (Exception e)
{ Logging.LogUsefulException(e); }
}
}
@@ -165,8 +169,10 @@ namespace Shadowsocks.Controller
} finally {
if (registry != null)
{
try { registry.Close(); }
catch (Exception e)
try {
registry.Close();
registry.Dispose();
} catch (Exception e)
{ Logging.LogUsefulException(e); }
}
}
+2 -1
View File
@@ -12,7 +12,7 @@ Servers=服务器
Edit Servers...=编辑服务器...
Statistics Config...=统计配置...
Start on Boot=开机启动
SOCKS5 Proxy...=SOCKS5代理设置...
Forward Proxy...=正向代理设置...
Allow Clients from LAN=允许来自局域网的连接
Local PAC=使用本地 PAC
Online PAC=使用在线 PAC
@@ -58,6 +58,7 @@ Move D&own=下移(&O)
Edit Proxy=代理设置
Use Proxy=使用代理
Proxy Type=代理类型
Proxy Addr=代理地址
Proxy Port=代理端口
Binary file not shown.
+1 -1
View File
@@ -1,4 +1,4 @@
listen-address __POLIPO_BIND_IP__:__POLIPO_BIND_PORT__
listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__
show-on-task-bar 0
activity-animation 0
forward-socks5 / 127.0.0.1:__SOCKS_PORT__ .
+2 -1
View File
@@ -12,7 +12,7 @@ Servers=伺服器
Edit Servers...=編輯伺服器...
Statistics Config...=統計配置...
Start on Boot=開機啟動
SOCKS5 Proxy...=SOCKS5代理設置...
Forward Proxy...=正向代理設置...
Allow Clients from LAN=允許來自區域網路的連接
Local PAC=使用本地 PAC
Online PAC=使用在線 PAC
@@ -58,6 +58,7 @@ Move D&own=下移(&O)
Edit Proxy=代理設置
Use Proxy=使用代理
Proxy Type=代理類別
Proxy Addr=代理位址
Proxy Port=代理連接埠
+19 -9
View File
@@ -4,17 +4,27 @@ namespace Shadowsocks.Encryption
{
public struct EncryptorInfo
{
public string name;
public int key_size;
public int iv_size;
public int type;
public int KeySize;
public int IvSize;
public int Type;
public string InnerLibName;
public EncryptorInfo(string name, int key_size, int iv_size, int type)
// For those who make use of internal crypto method name
// e.g. mbed TLS
public EncryptorInfo(string innerLibName, int keySize, int ivSize, int type)
{
this.name = name;
this.key_size = key_size;
this.iv_size = iv_size;
this.type = type;
this.KeySize = keySize;
this.IvSize = ivSize;
this.Type = type;
this.InnerLibName = innerLibName;
}
public EncryptorInfo(int keySize, int ivSize, int type)
{
this.KeySize = keySize;
this.IvSize = ivSize;
this.Type = type;
this.InnerLibName = string.Empty;
}
}
+8 -8
View File
@@ -25,9 +25,9 @@ namespace Shadowsocks.Encryption
protected bool _encryptIVSent;
protected string _method;
protected int _cipher;
// cipher name in MbedTLS, useless when using LibSodium
protected string _cipherMbedName;
protected EncryptorInfo _cipherInfo;
// internal name in the crypto library
protected string _innerLibName;
protected EncryptorInfo CipherInfo;
protected byte[] _key;
protected int keyLen;
protected int ivLen;
@@ -46,15 +46,15 @@ namespace Shadowsocks.Encryption
_method = method;
string k = method + ":" + password;
ciphers = getCiphers();
_cipherInfo = ciphers[_method];
_cipherMbedName = _cipherInfo.name;
_cipher = _cipherInfo.type;
CipherInfo = ciphers[_method];
_innerLibName = CipherInfo.InnerLibName;
_cipher = CipherInfo.Type;
if (_cipher == 0)
{
throw new Exception("method not found");
}
keyLen = _cipherInfo.key_size;
ivLen = _cipherInfo.iv_size;
keyLen = CipherInfo.KeySize;
ivLen = CipherInfo.IvSize;
_key = CachedKeys.GetOrAdd(k, (nk) =>
{
byte[] passbuf = Encoding.UTF8.GetBytes(password);
@@ -70,7 +70,7 @@ namespace Shadowsocks.Encryption
realkey = _key;
}
MbedTLS.cipher_init(ctx);
if (MbedTLS.cipher_setup( ctx, MbedTLS.cipher_info_from_string( _cipherMbedName ) ) != 0 )
if (MbedTLS.cipher_setup( ctx, MbedTLS.cipher_info_from_string( _innerLibName ) ) != 0 )
throw new Exception("Cannot initialize mbed TLS cipher context");
/*
* MbedTLS takes key length by bit
@@ -105,8 +105,12 @@ namespace Shadowsocks.Encryption
}
#region IDisposable
private bool _disposed;
// instance based lock
private readonly object _lock = new object();
public override void Dispose()
{
Dispose(true);
@@ -120,31 +124,32 @@ namespace Shadowsocks.Encryption
protected virtual void Dispose(bool disposing)
{
lock (this)
lock (_lock)
{
if (_disposed)
{
return;
}
if (_disposed) return;
_disposed = true;
}
if (disposing)
{
if (_encryptCtx != IntPtr.Zero)
{
MbedTLS.cipher_free(_encryptCtx);
Marshal.FreeHGlobal(_encryptCtx);
_encryptCtx = IntPtr.Zero;
}
if (_decryptCtx != IntPtr.Zero)
{
MbedTLS.cipher_free(_decryptCtx);
Marshal.FreeHGlobal(_decryptCtx);
_decryptCtx = IntPtr.Zero;
}
// free managed objects
}
// free unmanaged objects
if (_encryptCtx != IntPtr.Zero)
{
MbedTLS.cipher_free(_encryptCtx);
Marshal.FreeHGlobal(_encryptCtx);
_encryptCtx = IntPtr.Zero;
}
if (_decryptCtx != IntPtr.Zero)
{
MbedTLS.cipher_free(_decryptCtx);
Marshal.FreeHGlobal(_decryptCtx);
_decryptCtx = IntPtr.Zero;
}
}
#endregion
}
}
@@ -12,22 +12,24 @@ namespace Shadowsocks.Encryption
const int SODIUM_BLOCK_SIZE = 64;
static byte[] sodiumBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE];
protected int _encryptBytesRemaining;
protected int _decryptBytesRemaining;
protected ulong _encryptIC;
protected ulong _decryptIC;
protected byte[] _encryptBuf;
protected byte[] _decryptBuf;
public SodiumEncryptor(string method, string password, bool onetimeauth, bool isudp)
: base(method, password, onetimeauth, isudp)
{
_encryptBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE];
_decryptBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE];
}
private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> {
{ "salsa20", new EncryptorInfo("salsa20", 32, 8, CIPHER_SALSA20) },
{ "chacha20", new EncryptorInfo("chacha20", 32, 8, CIPHER_CHACHA20) },
{ "chacha20-ietf", new EncryptorInfo("chacha20-ietf", 32, 12, CIPHER_CHACHA20_IETF) }
{ "salsa20", new EncryptorInfo(32, 8, CIPHER_SALSA20) },
{ "chacha20", new EncryptorInfo(32, 8, CIPHER_CHACHA20) },
{ "chacha20-ietf", new EncryptorInfo(32, 12, CIPHER_CHACHA20_IETF) }
};
protected override Dictionary<string, EncryptorInfo> getCiphers()
@@ -45,54 +47,52 @@ namespace Shadowsocks.Encryption
// TODO write a unidirection cipher so we don't have to if if if
int bytesRemaining;
ulong ic;
byte[] sodiumBuf;
byte[] iv;
// I'm tired. just add a big lock
// let's optimize for RAM instead of CPU
lock(sodiumBuf)
if (isCipher)
{
if (isCipher)
{
bytesRemaining = _encryptBytesRemaining;
ic = _encryptIC;
iv = _encryptIV;
}
else
{
bytesRemaining = _decryptBytesRemaining;
ic = _decryptIC;
iv = _decryptIV;
}
int padding = bytesRemaining;
Buffer.BlockCopy(buf, 0, sodiumBuf, padding, length);
bytesRemaining = _encryptBytesRemaining;
ic = _encryptIC;
sodiumBuf = _encryptBuf;
iv = _encryptIV;
}
else
{
bytesRemaining = _decryptBytesRemaining;
ic = _decryptIC;
sodiumBuf = _decryptBuf;
iv = _decryptIV;
}
int padding = bytesRemaining;
Buffer.BlockCopy(buf, 0, sodiumBuf, padding, length);
switch (_cipher)
{
case CIPHER_SALSA20:
Sodium.crypto_stream_salsa20_xor_ic(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, ic, _key);
break;
case CIPHER_CHACHA20:
Sodium.crypto_stream_chacha20_xor_ic(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, ic, _key);
break;
case CIPHER_CHACHA20_IETF:
Sodium.crypto_stream_chacha20_ietf_xor_ic(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, (uint)ic, _key);
break;
}
Buffer.BlockCopy(sodiumBuf, padding, outbuf, 0, length);
padding += length;
ic += (ulong)padding / SODIUM_BLOCK_SIZE;
bytesRemaining = padding % SODIUM_BLOCK_SIZE;
switch (_cipher)
{
case CIPHER_SALSA20:
Sodium.crypto_stream_salsa20_xor_ic(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, ic, _key);
break;
case CIPHER_CHACHA20:
Sodium.crypto_stream_chacha20_xor_ic(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, ic, _key);
break;
case CIPHER_CHACHA20_IETF:
Sodium.crypto_stream_chacha20_ietf_xor_ic(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, (uint)ic, _key);
break;
}
Buffer.BlockCopy(sodiumBuf, padding, outbuf, 0, length);
padding += length;
ic += (ulong)padding / SODIUM_BLOCK_SIZE;
bytesRemaining = padding % SODIUM_BLOCK_SIZE;
if (isCipher)
{
_encryptBytesRemaining = bytesRemaining;
_encryptIC = ic;
}
else
{
_decryptBytesRemaining = bytesRemaining;
_decryptIC = ic;
}
if (isCipher)
{
_encryptBytesRemaining = bytesRemaining;
_encryptIC = ic;
}
else
{
_decryptBytesRemaining = bytesRemaining;
_decryptIC = ic;
}
}
@@ -63,6 +63,11 @@ namespace Shadowsocks.Model
config.proxy = new ProxyConfig();
if (config.hotkey == null)
config.hotkey = new HotkeyConfig();
if (config.proxy.proxyType < ProxyConfig.PROXY_SOCKS5 || config.proxy.proxyType > ProxyConfig.PROXY_HTTP)
{
config.proxy.proxyType = ProxyConfig.PROXY_SOCKS5;
}
return config;
}
catch (Exception e)
+6 -4
View File
@@ -1,20 +1,22 @@
using Shadowsocks.View;
using System;
using System.Drawing;
using System.Windows.Forms;
using System;
namespace Shadowsocks.Model
{
[Serializable]
public class ProxyConfig
{
public const int PROXY_SOCKS5 = 0;
public const int PROXY_HTTP = 1;
public bool useProxy;
public int proxyType;
public string proxyServer;
public int proxyPort;
public ProxyConfig()
{
useProxy = false;
proxyType = PROXY_SOCKS5;
proxyServer = "";
proxyPort = 0;
}
+4 -4
View File
@@ -67,7 +67,7 @@ namespace Shadowsocks.Proxy
public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state)
{
_remote?.BeginSend(buffer, offset, size, socketFlags, callback, state);
_remote.BeginSend(buffer, offset, size, socketFlags, callback, state);
}
public int EndSend(IAsyncResult asyncResult)
@@ -78,7 +78,7 @@ namespace Shadowsocks.Proxy
public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state)
{
_remote?.BeginReceive(buffer, offset, size, socketFlags, callback, state);
_remote.BeginReceive(buffer, offset, size, socketFlags, callback, state);
}
public int EndReceive(IAsyncResult asyncResult)
@@ -88,12 +88,12 @@ namespace Shadowsocks.Proxy
public void Shutdown(SocketShutdown how)
{
_remote?.Shutdown(how);
_remote.Shutdown(how);
}
public void Close()
{
_remote?.Dispose();
_remote.Dispose();
}
}
}
+201
View File
@@ -0,0 +1,201 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Shadowsocks.Controller;
using Shadowsocks.Util.Sockets;
namespace Shadowsocks.Proxy
{
public class HttpProxy : IProxy
{
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/51.0.2704.103 Safari/537.36" + HTTP_CRLF +
"" + HTTP_CRLF; // End with an empty line
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state)
{
DestEndPoint = destEndPoint;
string request = string.Format(HTTP_CONNECT_TEMPLATE, destEndPoint);
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}) (.+)$");
private int _respondLineCount = 0;
private bool _established = false;
private bool OnLineRead(string line, object state)
{
Logging.Debug(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;
}
}
}
+6 -6
View File
@@ -39,7 +39,7 @@ namespace Shadowsocks.Proxy
public Exception ex { get; set; }
}
private WrappedSocket _remote = new WrappedSocket();
private readonly WrappedSocket _remote = new WrappedSocket();
private const int Socks5PktMaxSize = 4 + 16 + 2;
private readonly byte[] _receiveBuffer = new byte[Socks5PktMaxSize];
@@ -124,7 +124,7 @@ namespace Shadowsocks.Proxy
st.Callback = callback;
st.AsyncState = state;
_remote?.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st);
_remote.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st);
}
public void EndConnectDest(IAsyncResult asyncResult)
@@ -140,7 +140,7 @@ namespace Shadowsocks.Proxy
public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state)
{
_remote?.BeginSend(buffer, offset, size, socketFlags, callback, state);
_remote.BeginSend(buffer, offset, size, socketFlags, callback, state);
}
public int EndSend(IAsyncResult asyncResult)
@@ -151,7 +151,7 @@ namespace Shadowsocks.Proxy
public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state)
{
_remote?.BeginReceive(buffer, offset, size, socketFlags, callback, state);
_remote.BeginReceive(buffer, offset, size, socketFlags, callback, state);
}
public int EndReceive(IAsyncResult asyncResult)
@@ -161,12 +161,12 @@ namespace Shadowsocks.Proxy
public void Shutdown(SocketShutdown how)
{
_remote?.Shutdown(how);
_remote.Shutdown(how);
}
public void Close()
{
_remote?.Dispose();
_remote.Dispose();
}
+7 -2
View File
@@ -22,7 +22,11 @@ namespace Shadowsocks.Util
_hotKeyManager.KeyPressed += HotKeyManagerPressed;
}
public static void Destroy() => _hotKeyManager.Dispose();
public static void Destroy()
{
_hotKeyManager.KeyPressed -= HotKeyManagerPressed;
_hotKeyManager.Dispose();
}
private static void HotKeyManagerPressed(object sender, KeyPressedEventArgs e)
{
@@ -79,7 +83,8 @@ namespace Shadowsocks.Util
}
}
public static HotKey Str2HotKey( string s ) {
public static HotKey Str2HotKey(string s)
{
try
{
if (s.IsNullOrEmpty()) return null;
@@ -12,25 +12,25 @@ namespace Shadowsocks.Util.ProcessManagement
public class Job : IDisposable
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr CreateJobObject(IntPtr a, string lpName);
[DllImport("kernel32.dll")]
static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);
private static extern IntPtr CreateJobObject(IntPtr a, string lpName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
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)]
static extern bool CloseHandle(IntPtr hObject);
private static extern bool CloseHandle(IntPtr hObject);
private IntPtr handle;
private IntPtr handle = IntPtr.Zero;
private bool disposed;
public Job()
{
handle = CreateJobObject(IntPtr.Zero, null);
var extendedInfoPtr = IntPtr.Zero;
var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
{
LimitFlags = 0x2000
@@ -41,12 +41,25 @@ namespace Shadowsocks.Util.ProcessManagement
BasicLimitInformation = info
};
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
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()));
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 void Dispose()
@@ -57,19 +70,26 @@ namespace Shadowsocks.Util.ProcessManagement
private void Dispose(bool disposing)
{
if (disposed)
return;
if (disposed) return;
disposed = true;
if (disposing) { }
Close();
disposed = true;
}
public void Close()
private void Close()
{
CloseHandle(handle);
handle = IntPtr.Zero;
if (handle != IntPtr.Zero)
{
CloseHandle(handle);
handle = IntPtr.Zero;
}
}
~Job()
{
Dispose(false);
}
public bool AddProcess(IntPtr processHandle)
@@ -78,8 +98,7 @@ namespace Shadowsocks.Util.ProcessManagement
if (!succ)
{
var err = Marshal.GetLastWin32Error();
Logging.Error("Failed to call AssignProcessToJobObject! GetLastError=" + err);
Logging.Error("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error());
}
return succ;
@@ -0,0 +1,231 @@
using System;
using System.Text;
namespace Shadowsocks.Util.Sockets
{
public class LineReader
{
private readonly WrappedSocket _socket;
private readonly Func<string, object, bool> _onLineRead;
private readonly Action<Exception, object> _onException;
private readonly Action<byte[], int, int, object> _onFinish;
private readonly Encoding _encoding;
// private readonly string _delimiter;
private readonly byte[] _delimiterBytes;
private readonly int[] _delimiterSearchCharTable;
private readonly int[] _delimiterSearchOffsetTable;
private readonly object _state;
private readonly byte[] _lineBuffer;
private int _bufferIndex;
public LineReader(WrappedSocket socket, Func<string, object, bool> onLineRead, Action<Exception, object> onException,
Action<byte[], int, int, object> onFinish, Encoding encoding, string delimiter, int maxLineBytes, object state)
{
if (socket == null)
{
throw new ArgumentNullException(nameof(socket));
}
if (onLineRead == null)
{
throw new ArgumentNullException(nameof(onLineRead));
}
if (encoding == null)
{
throw new ArgumentNullException(nameof(encoding));
}
if (delimiter == null)
{
throw new ArgumentNullException(nameof(delimiter));
}
_socket = socket;
_onLineRead = onLineRead;
_onException = onException;
_onFinish = onFinish;
_encoding = encoding;
// _delimiter = delimiter;
_state = state;
// decode delimiter
_delimiterBytes = encoding.GetBytes(delimiter);
if (_delimiterBytes.Length == 0)
{
throw new ArgumentException("Too short!", nameof(delimiter));
}
if (maxLineBytes < _delimiterBytes.Length)
{
throw new ArgumentException("Too small!", nameof(maxLineBytes));
}
_delimiterSearchCharTable = MakeCharTable(_delimiterBytes);
_delimiterSearchOffsetTable = MakeOffsetTable(_delimiterBytes);
_lineBuffer = new byte[maxLineBytes];
// start reading
socket.BeginReceive(_lineBuffer, 0, maxLineBytes, 0, ReceiveCallback, 0);
}
private void ReceiveCallback(IAsyncResult ar)
{
int length = (int)ar.AsyncState;
try
{
var bytesRead = _socket.EndReceive(ar);
if (bytesRead == 0)
{
OnFinish(length);
return;
}
length += bytesRead;
int i;
while ((i = IndexOf(_lineBuffer, _bufferIndex, length, _delimiterBytes, _delimiterSearchOffsetTable,
_delimiterSearchCharTable)) != -1)
{
var decodeLen = i - _bufferIndex;
string line = _encoding.GetString(_lineBuffer, _bufferIndex, decodeLen);
_bufferIndex = i + _delimiterBytes.Length;
length -= decodeLen;
length -= _delimiterBytes.Length;
var stop = _onLineRead(line, _state);
if (stop)
{
OnFinish(length);
return;
}
}
if (length == _lineBuffer.Length)
{
OnException(new IndexOutOfRangeException("LineBuffer full! Try increace maxLineBytes!"));
OnFinish(length);
return;
}
if (_bufferIndex > 0)
{
Buffer.BlockCopy(_lineBuffer, _bufferIndex, _lineBuffer, 0, length);
_bufferIndex = 0;
}
_socket.BeginReceive(_lineBuffer, length, _lineBuffer.Length - length, 0, ReceiveCallback, length);
}
catch (Exception ex)
{
OnException(ex);
OnFinish(length);
}
}
private void OnException(Exception ex)
{
_onException?.Invoke(ex, _state);
}
private void OnFinish(int length)
{
_onFinish?.Invoke(_lineBuffer, _bufferIndex, length, _state);
}
#region Boyer-Moore string search
public static int IndexOf(byte[] haystack, int index, int length, byte[] needle, int[] offsetTable, int[] charTable)
{
var end = index + length;
for (int i = needle.Length - 1 + index, j; i < end;)
{
for (j = needle.Length - 1; needle[j] == haystack[i]; --i, --j)
{
if (j == 0)
{
return i;
}
}
// i += needle.length - j; // For naive method
i += Math.Max(offsetTable[needle.Length - 1 - j], charTable[haystack[i]]);
}
return -1;
}
/**
* Makes the jump table based on the mismatched character information.
*/
private static int[] MakeCharTable(byte[] needle)
{
const int ALPHABET_SIZE = 256;
int[] table = new int[ALPHABET_SIZE];
for (int i = 0; i < table.Length; ++i)
{
table[i] = needle.Length;
}
for (int i = 0; i < needle.Length - 1; ++i)
{
table[needle[i]] = needle.Length - 1 - i;
}
return table;
}
/**
* Makes the jump table based on the scan offset which mismatch occurs.
*/
private static int[] MakeOffsetTable(byte[] needle)
{
int[] table = new int[needle.Length];
int lastPrefixPosition = needle.Length;
for (int i = needle.Length - 1; i >= 0; --i)
{
if (IsPrefix(needle, i + 1))
{
lastPrefixPosition = i + 1;
}
table[needle.Length - 1 - i] = lastPrefixPosition - i + needle.Length - 1;
}
for (int i = 0; i < needle.Length - 1; ++i)
{
int slen = SuffixLength(needle, i);
table[slen] = needle.Length - 1 - i + slen;
}
return table;
}
/**
* Is needle[p:end] a prefix of needle?
*/
private static bool IsPrefix(byte[] needle, int p)
{
for (int i = p, j = 0; i < needle.Length; ++i, ++j)
{
if (needle[i] != needle[j])
{
return false;
}
}
return true;
}
/**
* Returns the maximum length of the substring ends at p and is a suffix.
*/
private static int SuffixLength(byte[] needle, int p)
{
int len = 0;
for (int i = p, j = needle.Length - 1;
i >= 0 && needle[i] == needle[j]; --i, --j)
{
len += 1;
}
return len;
}
#endregion
}
}
+5 -2
View File
@@ -34,6 +34,9 @@ namespace Shadowsocks.View
const int BACK_OFFSET = 65536;
ShadowsocksController controller;
// global traffic update lock, make it static
private static readonly object _lock = new object();
#region chart
long lastMaxSpeed;
ShadowsocksController.QueueLast<TrafficInfo> traffic = new ShadowsocksController.QueueLast<TrafficInfo>();
@@ -71,7 +74,7 @@ namespace Shadowsocks.View
long maxSpeed = 0;
long lastInbound, lastOutbound;
lock (this)
lock (_lock)
{
if (traffic.Count == 0)
return;
@@ -120,7 +123,7 @@ namespace Shadowsocks.View
private void controller_TrafficChanged(object sender, EventArgs e)
{
lock (this)
lock (_lock)
{
traffic = new ShadowsocksController.QueueLast<TrafficInfo>();
foreach (var trafficPerSecond in controller.traffic)
@@ -271,7 +271,7 @@ namespace Shadowsocks.View
this.editGFWUserRuleItem = CreateMenuItem("Edit User Rule for GFWList...", new EventHandler(this.EditUserRuleFileForGFWListItem_Click)),
this.editOnlinePACItem = CreateMenuItem("Edit Online PAC URL...", new EventHandler(this.UpdateOnlinePACURLItem_Click)),
}),
this.proxyItem = CreateMenuItem("SOCKS5 Proxy...", new EventHandler(this.proxyItem_Click)),
this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)),
new MenuItem("-"),
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
@@ -501,12 +501,14 @@ namespace Shadowsocks.View
void logForm_FormClosed(object sender, FormClosedEventArgs e)
{
logForm.Dispose();
logForm = null;
Utils.ReleaseMemory(true);
}
void configForm_FormClosed(object sender, FormClosedEventArgs e)
{
configForm.Dispose();
configForm = null;
Utils.ReleaseMemory(true);
if (_isFirstRun)
@@ -519,12 +521,14 @@ namespace Shadowsocks.View
void proxyForm_FormClosed(object sender, FormClosedEventArgs e)
{
proxyForm.Dispose();
proxyForm = null;
Utils.ReleaseMemory(true);
}
void hotkeySettingsForm_FormClosed(object sender, FormClosedEventArgs e)
{
hotkeySettingsForm.Dispose();
hotkeySettingsForm = null;
Utils.ReleaseMemory(true);
}
@@ -564,11 +568,7 @@ namespace Shadowsocks.View
private void notifyIcon1_Click(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// TODO: show something interesting
}
else if (e.Button == MouseButtons.Middle)
if ( e.Button == MouseButtons.Middle )
{
ShowLogForm();
}
+58 -7
View File
@@ -38,9 +38,13 @@
this.ProxyServerTextBox = new System.Windows.Forms.TextBox();
this.ProxyPortLable = new System.Windows.Forms.Label();
this.ProxyPortTextBox = new System.Windows.Forms.TextBox();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.ProxyTypeLabel = new System.Windows.Forms.Label();
this.ProxyTypeComboBox = new System.Windows.Forms.ComboBox();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
@@ -49,16 +53,18 @@
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 0, 1);
this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowCount = 4;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(395, 87);
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(395, 123);
this.tableLayoutPanel1.TabIndex = 0;
//
// tableLayoutPanel3
@@ -72,7 +78,7 @@
this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0);
this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right;
this.tableLayoutPanel3.Location = new System.Drawing.Point(236, 58);
this.tableLayoutPanel3.Location = new System.Drawing.Point(236, 94);
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 1;
@@ -129,10 +135,11 @@
this.tableLayoutPanel2.Controls.Add(this.ProxyServerTextBox, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.ProxyPortLable, 2, 0);
this.tableLayoutPanel2.Controls.Add(this.ProxyPortTextBox, 3, 0);
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 25);
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 61);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 1;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(389, 27);
this.tableLayoutPanel2.TabIndex = 1;
//
@@ -174,6 +181,45 @@
this.ProxyPortTextBox.TabIndex = 3;
this.ProxyPortTextBox.WordWrap = false;
//
// tableLayoutPanel4
//
this.tableLayoutPanel4.AutoSize = true;
this.tableLayoutPanel4.ColumnCount = 2;
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeLabel, 0, 0);
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeComboBox, 1, 0);
this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 25);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 1;
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.Size = new System.Drawing.Size(198, 30);
this.tableLayoutPanel4.TabIndex = 10;
//
// ProxyTypeLabel
//
this.ProxyTypeLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.ProxyTypeLabel.AutoSize = true;
this.ProxyTypeLabel.Location = new System.Drawing.Point(3, 9);
this.ProxyTypeLabel.Name = "ProxyTypeLabel";
this.ProxyTypeLabel.Size = new System.Drawing.Size(65, 12);
this.ProxyTypeLabel.TabIndex = 1;
this.ProxyTypeLabel.Text = "Proxy Type";
//
// ProxyTypeComboBox
//
this.ProxyTypeComboBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.ProxyTypeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.ProxyTypeComboBox.FormattingEnabled = true;
this.ProxyTypeComboBox.Items.AddRange(new object[] {
"SOCKS5",
"HTTP"});
this.ProxyTypeComboBox.Location = new System.Drawing.Point(74, 5);
this.ProxyTypeComboBox.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5);
this.ProxyTypeComboBox.Name = "ProxyTypeComboBox";
this.ProxyTypeComboBox.Size = new System.Drawing.Size(121, 20);
this.ProxyTypeComboBox.TabIndex = 2;
//
// ProxyForm
//
this.AcceptButton = this.OKButton;
@@ -182,7 +228,7 @@
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.CancelButton = this.MyCancelButton;
this.ClientSize = new System.Drawing.Size(441, 149);
this.ClientSize = new System.Drawing.Size(441, 165);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
@@ -197,6 +243,8 @@
this.tableLayoutPanel3.ResumeLayout(false);
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.tableLayoutPanel4.ResumeLayout(false);
this.tableLayoutPanel4.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@@ -214,5 +262,8 @@
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.Button MyCancelButton;
private System.Windows.Forms.Button OKButton;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
private System.Windows.Forms.Label ProxyTypeLabel;
private System.Windows.Forms.ComboBox ProxyTypeComboBox;
}
}
+7 -1
View File
@@ -32,6 +32,7 @@ namespace Shadowsocks.View
private void UpdateTexts()
{
UseProxyCheckBox.Text = I18N.GetString("Use Proxy");
ProxyTypeLabel.Text = I18N.GetString("Proxy Type");
ProxyAddrLabel.Text = I18N.GetString("Proxy Addr");
ProxyPortLable.Text = I18N.GetString("Proxy Port");
OKButton.Text = I18N.GetString("OK");
@@ -50,6 +51,7 @@ namespace Shadowsocks.View
UseProxyCheckBox.Checked = _modifiedConfiguration.useProxy;
ProxyServerTextBox.Text = _modifiedConfiguration.proxyServer;
ProxyPortTextBox.Text = _modifiedConfiguration.proxyPort.ToString();
ProxyTypeComboBox.SelectedIndex = _modifiedConfiguration.proxyType;
}
private void OKButton_Click(object sender, EventArgs e)
@@ -58,12 +60,13 @@ namespace Shadowsocks.View
{
try
{
var type = ProxyTypeComboBox.SelectedIndex;
var proxy = ProxyServerTextBox.Text;
var port = int.Parse(ProxyPortTextBox.Text);
Configuration.CheckServer(proxy);
Configuration.CheckPort(port);
controller.EnableProxy(proxy, port);
controller.EnableProxy(type, proxy, port);
}
catch (FormatException)
{
@@ -82,6 +85,7 @@ namespace Shadowsocks.View
}
_modifiedConfiguration.useProxy = UseProxyCheckBox.Checked;
_modifiedConfiguration.proxyType = ProxyTypeComboBox.SelectedIndex;
_modifiedConfiguration.proxyServer = ProxyServerTextBox.Text;
var tmpProxyPort = 0;
int.TryParse(ProxyPortTextBox.Text, out tmpProxyPort);
@@ -112,6 +116,7 @@ namespace Shadowsocks.View
{
ProxyServerTextBox.Enabled = true;
ProxyPortTextBox.Enabled = true;
ProxyTypeComboBox.Enabled = true;
}
else
{
@@ -119,6 +124,7 @@ namespace Shadowsocks.View
ProxyPortTextBox.Clear();
ProxyServerTextBox.Enabled = false;
ProxyPortTextBox.Enabled = false;
ProxyTypeComboBox.Enabled = false;
}
}
}
+3 -1
View File
@@ -146,6 +146,7 @@
<Compile Include="Model\HotKeyConfig.cs" />
<Compile Include="Model\ProxyConfig.cs" />
<Compile Include="Proxy\DirectConnect.cs" />
<Compile Include="Proxy\HttpProxy.cs" />
<Compile Include="Proxy\IProxy.cs" />
<Compile Include="Controller\Service\AvailabilityStatistics.cs" />
<Compile Include="Controller\Strategy\HighAvailabilityStrategy.cs" />
@@ -186,6 +187,7 @@
<Compile Include="Util\Hotkeys.cs" />
<Compile Include="Util\ProcessManagement\Job.cs" />
<Compile Include="Util\ProcessManagement\ThreadUtil.cs" />
<Compile Include="Util\Sockets\LineReader.cs" />
<Compile Include="Util\Sockets\SocketUtil.cs" />
<Compile Include="Util\Sockets\WrappedSocket.cs" />
<Compile Include="Util\Util.cs" />
@@ -196,7 +198,7 @@
<DependentUpon>ConfigForm.cs</DependentUpon>
</Compile>
<Compile Include="Controller\Service\TCPRelay.cs" />
<Compile Include="Controller\Service\PolipoRunner.cs" />
<Compile Include="Controller\Service\PrivoxyRunner.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Controller\ShadowsocksController.cs" />