@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Timers;
|
||||
@@ -14,34 +15,28 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
private ShadowsocksController _controller;
|
||||
private DateTime _lastSweepTime;
|
||||
private Configuration _config;
|
||||
|
||||
public ISet<TCPHandler> Handlers
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public ISet<TCPHandler> Handlers { get; set; }
|
||||
|
||||
public TCPRelay(ShadowsocksController controller)
|
||||
public TCPRelay(ShadowsocksController controller, Configuration conf)
|
||||
{
|
||||
_controller = controller;
|
||||
_config = conf;
|
||||
Handlers = new HashSet<TCPHandler>();
|
||||
_lastSweepTime = DateTime.Now;
|
||||
}
|
||||
|
||||
public bool Handle(byte[] firstPacket, int length, Socket socket, object state)
|
||||
{
|
||||
if (socket.ProtocolType != ProtocolType.Tcp)
|
||||
{
|
||||
if (socket.ProtocolType != ProtocolType.Tcp
|
||||
|| (length < 2 || firstPacket[0] != 5))
|
||||
return false;
|
||||
}
|
||||
if (length < 2 || firstPacket[0] != 5)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||||
TCPHandler handler = new TCPHandler(this);
|
||||
TCPHandler handler = new TCPHandler(this, _config);
|
||||
handler.connection = socket;
|
||||
handler.controller = _controller;
|
||||
handler.relay = this;
|
||||
handler.tcprelay = this;
|
||||
|
||||
handler.Start(firstPacket, length);
|
||||
IList<TCPHandler> handlersToClose = new List<TCPHandler>();
|
||||
@@ -53,12 +48,8 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
_lastSweepTime = now;
|
||||
foreach (TCPHandler handler1 in Handlers)
|
||||
{
|
||||
if (now - handler1.lastActivity > TimeSpan.FromSeconds(900))
|
||||
{
|
||||
handlersToClose.Add(handler1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (TCPHandler handler1 in handlersToClose)
|
||||
@@ -87,6 +78,11 @@ namespace Shadowsocks.Controller
|
||||
|
||||
class TCPHandler
|
||||
{
|
||||
// Size of receive buffer.
|
||||
public static readonly int RecvSize = 8192;
|
||||
public static readonly int RecvReserveSize = IVEncryptor.ONETIMEAUTH_BYTES + IVEncryptor.AUTH_BYTES; // reserve for one-time auth
|
||||
public static readonly int BufferSize = RecvSize + RecvReserveSize + 32;
|
||||
|
||||
// public Encryptor encryptor;
|
||||
public IEncryptor encryptor;
|
||||
public Server server;
|
||||
@@ -94,60 +90,51 @@ namespace Shadowsocks.Controller
|
||||
public Socket remote;
|
||||
public Socket connection;
|
||||
public ShadowsocksController controller;
|
||||
public TCPRelay relay;
|
||||
public TCPRelay tcprelay;
|
||||
|
||||
public DateTime lastActivity;
|
||||
|
||||
private const int maxRetry = 4;
|
||||
private int retryCount = 0;
|
||||
private bool connected;
|
||||
private const int _maxRetry = 4;
|
||||
private int _retryCount = 0;
|
||||
private bool _connected;
|
||||
|
||||
private byte command;
|
||||
private byte _command;
|
||||
private byte[] _firstPacket;
|
||||
private int _firstPacketLength;
|
||||
// Size of receive buffer.
|
||||
public const int RecvSize = 8192;
|
||||
public const int RecvReserveSize = IVEncryptor.ONETIMEAUTH_BYTES + IVEncryptor.AUTH_BYTES; // reserve for one-time auth
|
||||
public const int BufferSize = RecvSize + RecvReserveSize + 32;
|
||||
|
||||
private int totalRead = 0;
|
||||
private int totalWrite = 0;
|
||||
private int _totalRead = 0;
|
||||
private int _totalWrite = 0;
|
||||
|
||||
// remote receive buffer
|
||||
private byte[] remoteRecvBuffer = new byte[BufferSize];
|
||||
// remote send buffer
|
||||
private byte[] remoteSendBuffer = new byte[BufferSize];
|
||||
// connection receive buffer
|
||||
private byte[] connetionRecvBuffer = new byte[BufferSize];
|
||||
// connection send buffer
|
||||
private byte[] connetionSendBuffer = new byte[BufferSize];
|
||||
// Received data string.
|
||||
private byte[] _remoteRecvBuffer = new byte[BufferSize];
|
||||
private byte[] _remoteSendBuffer = new byte[BufferSize];
|
||||
private byte[] _connetionRecvBuffer = new byte[BufferSize];
|
||||
private byte[] _connetionSendBuffer = new byte[BufferSize];
|
||||
|
||||
private bool connectionShutdown = false;
|
||||
private bool remoteShutdown = false;
|
||||
private bool closed = false;
|
||||
private bool _connectionShutdown = false;
|
||||
private bool _remoteShutdown = false;
|
||||
private bool _closed = false;
|
||||
|
||||
private object encryptionLock = new object();
|
||||
private object decryptionLock = new object();
|
||||
private object _encryptionLock = new object();
|
||||
private object _decryptionLock = new object();
|
||||
|
||||
private DateTime _startConnectTime;
|
||||
private DateTime _startReceivingTime;
|
||||
private DateTime _startSendingTime;
|
||||
private int _bytesToSend;
|
||||
private TCPRelay tcprelay; // TODO: tcprelay ?= relay
|
||||
private TCPRelay _tcprelay; // TODO: is _tcprelay equals tcprelay declared above?
|
||||
private Configuration _config;
|
||||
|
||||
public TCPHandler(TCPRelay tcprelay)
|
||||
public TCPHandler(TCPRelay tcprelay, Configuration config)
|
||||
{
|
||||
this.tcprelay = tcprelay;
|
||||
_tcprelay = tcprelay;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public void CreateRemote()
|
||||
{
|
||||
Server server = controller.GetAServer(IStrategyCallerType.TCP, (IPEndPoint)connection.RemoteEndPoint);
|
||||
if (server == null || server.server == "")
|
||||
{
|
||||
throw new ArgumentException("No server configured");
|
||||
}
|
||||
encryptor = EncryptorFactory.GetEncryptor(server.method, server.password, server.auth, false);
|
||||
this.server = server;
|
||||
}
|
||||
@@ -162,72 +149,53 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void CheckClose()
|
||||
{
|
||||
if (connectionShutdown && remoteShutdown)
|
||||
{
|
||||
if (_connectionShutdown && _remoteShutdown)
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
lock (relay.Handlers)
|
||||
lock (tcprelay.Handlers)
|
||||
{
|
||||
relay.Handlers.Remove(this);
|
||||
tcprelay.Handlers.Remove(this);
|
||||
}
|
||||
lock (this)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
lock (this) {
|
||||
if (_closed) return;
|
||||
_closed = true;
|
||||
}
|
||||
if (connection != null)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
connection.Shutdown(SocketShutdown.Both);
|
||||
connection.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
connection?.Shutdown(SocketShutdown.Both);
|
||||
connection?.Close();
|
||||
}
|
||||
if (remote != null)
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
remote.Shutdown(SocketShutdown.Both);
|
||||
remote.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
lock (encryptionLock)
|
||||
try
|
||||
{
|
||||
lock (decryptionLock)
|
||||
remote?.Shutdown(SocketShutdown.Both);
|
||||
remote?.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
lock (_encryptionLock)
|
||||
{
|
||||
lock (_decryptionLock)
|
||||
{
|
||||
if (encryptor != null)
|
||||
{
|
||||
((IDisposable)encryptor).Dispose();
|
||||
}
|
||||
encryptor?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandshakeReceive()
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
int bytesRead = _firstPacketLength;
|
||||
|
||||
if (bytesRead > 1)
|
||||
{
|
||||
byte[] response = { 5, 0 };
|
||||
@@ -237,12 +205,10 @@ namespace Shadowsocks.Controller
|
||||
response = new byte[] { 0, 91 };
|
||||
Logging.Error("socks 5 protocol error");
|
||||
}
|
||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null);
|
||||
connection.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(HandshakeSendCallback), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -253,10 +219,7 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void HandshakeSendCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
connection.EndSend(ar);
|
||||
@@ -268,7 +231,7 @@ namespace Shadowsocks.Controller
|
||||
// +-----+-----+-------+------+----------+----------+
|
||||
// Skip first 3 bytes
|
||||
// TODO validate
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, 3, 0, new AsyncCallback(handshakeReceive2Callback), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, 3, SocketFlags.None, new AsyncCallback(handshakeReceive2Callback), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -279,26 +242,20 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void handshakeReceive2Callback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
int bytesRead = connection.EndReceive(ar);
|
||||
|
||||
if (bytesRead >= 3)
|
||||
{
|
||||
command = connetionRecvBuffer[1];
|
||||
if (command == 1)
|
||||
_command = _connetionRecvBuffer[1];
|
||||
if (_command == 1)
|
||||
{
|
||||
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
|
||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ResponseCallback), null);
|
||||
connection.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(ResponseCallback), null);
|
||||
}
|
||||
else if (command == 3)
|
||||
{
|
||||
else if (_command == 3)
|
||||
HandleUDPAssociate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -320,33 +277,31 @@ namespace Shadowsocks.Controller
|
||||
int port = endPoint.Port;
|
||||
byte[] response = new byte[4 + address.Length + 2];
|
||||
response[0] = 5;
|
||||
if (endPoint.AddressFamily == AddressFamily.InterNetwork)
|
||||
switch (endPoint.AddressFamily)
|
||||
{
|
||||
response[3] = 1;
|
||||
}
|
||||
else if (endPoint.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
response[3] = 4;
|
||||
case AddressFamily.InterNetwork:
|
||||
response[3] = 1;
|
||||
break;
|
||||
case AddressFamily.InterNetworkV6:
|
||||
response[3] = 4;
|
||||
break;
|
||||
}
|
||||
address.CopyTo(response, 4);
|
||||
response[response.Length - 1] = (byte)(port & 0xFF);
|
||||
response[response.Length - 2] = (byte)((port >> 8) & 0xFF);
|
||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ReadAll), true);
|
||||
connection.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(ReadAll), true);
|
||||
}
|
||||
|
||||
private void ReadAll(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
if (ar.AsyncState != null)
|
||||
{
|
||||
connection.EndSend(ar);
|
||||
Logging.Debug(remote, RecvSize, "TCP Relay");
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(ReadAll), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -354,12 +309,10 @@ namespace Shadowsocks.Controller
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
Logging.Debug(remote, RecvSize, "TCP Relay");
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(ReadAll), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -374,10 +327,8 @@ namespace Shadowsocks.Controller
|
||||
try
|
||||
{
|
||||
connection.EndSend(ar);
|
||||
|
||||
StartConnect();
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
@@ -389,10 +340,7 @@ namespace Shadowsocks.Controller
|
||||
private class ServerTimer : Timer
|
||||
{
|
||||
public Server Server;
|
||||
|
||||
public ServerTimer(int p) : base(p)
|
||||
{
|
||||
}
|
||||
public ServerTimer(int p) : base(p) { }
|
||||
}
|
||||
|
||||
private void StartConnect()
|
||||
@@ -411,8 +359,7 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port);
|
||||
|
||||
remote = new Socket(ipAddress.AddressFamily,
|
||||
SocketType.Stream, ProtocolType.Tcp);
|
||||
remote = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||||
|
||||
_startConnectTime = DateTime.Now;
|
||||
@@ -422,7 +369,7 @@ namespace Shadowsocks.Controller
|
||||
connectTimer.Enabled = true;
|
||||
connectTimer.Server = server;
|
||||
|
||||
connected = false;
|
||||
_connected = false;
|
||||
// Connect to the remote endpoint.
|
||||
remote.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), connectTimer);
|
||||
}
|
||||
@@ -435,16 +382,10 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void connectTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_connected) return;
|
||||
Server server = ((ServerTimer)sender).Server;
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
if (strategy != null)
|
||||
{
|
||||
strategy.SetFailure(server);
|
||||
}
|
||||
strategy?.SetFailure(server);
|
||||
Logging.Info($"{server.FriendlyName()} timed out");
|
||||
remote.Close();
|
||||
RetryConnect();
|
||||
@@ -452,29 +393,23 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void RetryConnect()
|
||||
{
|
||||
if (retryCount < maxRetry)
|
||||
if (_retryCount < _maxRetry)
|
||||
{
|
||||
Logging.Debug($"Connection failed, retry ({retryCount})");
|
||||
Logging.Debug($"Connection failed, retry ({_retryCount})");
|
||||
StartConnect();
|
||||
retryCount++;
|
||||
_retryCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectCallback(IAsyncResult ar)
|
||||
{
|
||||
Server server = null;
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
ServerTimer timer = (ServerTimer)ar.AsyncState;
|
||||
server = timer.Server;
|
||||
Server server = timer.Server;
|
||||
timer.Elapsed -= connectTimer_Elapsed;
|
||||
timer.Enabled = false;
|
||||
timer.Dispose();
|
||||
@@ -482,14 +417,12 @@ namespace Shadowsocks.Controller
|
||||
// Complete the connection.
|
||||
remote.EndConnect(ar);
|
||||
|
||||
connected = true;
|
||||
|
||||
Logging.Debug($"Socket connected to {remote.RemoteEndPoint}");
|
||||
_connected = true;
|
||||
|
||||
var latency = DateTime.Now - _startConnectTime;
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
strategy?.UpdateLatency(server, latency);
|
||||
tcprelay.UpdateLatency(server, latency);
|
||||
_tcprelay.UpdateLatency(server, latency);
|
||||
|
||||
StartPipe();
|
||||
}
|
||||
@@ -501,10 +434,7 @@ namespace Shadowsocks.Controller
|
||||
if (server != null)
|
||||
{
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
if (strategy != null)
|
||||
{
|
||||
strategy.SetFailure(server);
|
||||
}
|
||||
strategy?.SetFailure(server);
|
||||
}
|
||||
Logging.LogUsefulException(e);
|
||||
RetryConnect();
|
||||
@@ -513,15 +443,12 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void StartPipe()
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
_startReceivingTime = DateTime.Now;
|
||||
remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -532,49 +459,30 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void PipeRemoteReceiveCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
int bytesRead = remote.EndReceive(ar);
|
||||
totalRead += bytesRead;
|
||||
tcprelay.UpdateInboundCounter(server, bytesRead);
|
||||
|
||||
_totalRead += bytesRead;
|
||||
_tcprelay.UpdateInboundCounter(server, bytesRead);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
lastActivity = DateTime.Now;
|
||||
int bytesToSend;
|
||||
lock (decryptionLock)
|
||||
lock (_decryptionLock)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
encryptor.Decrypt(remoteRecvBuffer, bytesRead, remoteSendBuffer, out bytesToSend);
|
||||
if (_closed) return;
|
||||
encryptor.Decrypt(_remoteRecvBuffer, bytesRead, _remoteSendBuffer, out bytesToSend);
|
||||
}
|
||||
Logging.Debug(remote, bytesToSend, "TCP Relay", "@PipeRemoteReceiveCallback() (download)");
|
||||
connection.BeginSend(remoteSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeConnectionSendCallback), null);
|
||||
|
||||
connection.BeginSend(_remoteSendBuffer, 0, bytesToSend, SocketFlags.None, new AsyncCallback(PipeConnectionSendCallback), null);
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
if (strategy != null)
|
||||
{
|
||||
strategy.UpdateLastRead(server);
|
||||
}
|
||||
strategy?.UpdateLastRead(server);
|
||||
}
|
||||
else
|
||||
{
|
||||
connection.Shutdown(SocketShutdown.Send);
|
||||
connectionShutdown = true;
|
||||
_connectionShutdown = true;
|
||||
CheckClose();
|
||||
|
||||
//if (totalRead == 0)
|
||||
//{
|
||||
// // closed before anything received, reports as failure
|
||||
// // disable this feature
|
||||
// controller.GetCurrentStrategy().SetFailure(this.server);
|
||||
//}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -586,39 +494,58 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void PipeConnectionReceiveCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
int bytesRead = connection.EndReceive(ar);
|
||||
totalWrite += bytesRead;
|
||||
|
||||
_totalWrite += bytesRead;
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
int bytesToSend;
|
||||
lock (encryptionLock)
|
||||
int atyp = _connetionRecvBuffer[0];
|
||||
string dst_addr;
|
||||
int dst_port;
|
||||
switch (atyp)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend);
|
||||
case 1: // IPv4 address, 4 bytes
|
||||
dst_addr = new IPAddress(_connetionRecvBuffer.Skip(1).Take(4).ToArray()).ToString();
|
||||
dst_port = (_connetionRecvBuffer[5] << 8) + _connetionRecvBuffer[6];
|
||||
if ( _config.isVerboseLogging ) {
|
||||
Logging.Info( $"connect to {dst_addr}:{dst_port}" );
|
||||
}
|
||||
break;
|
||||
case 3: // domain name, length + str
|
||||
int len = _connetionRecvBuffer[1];
|
||||
dst_addr = System.Text.Encoding.UTF8.GetString(_connetionRecvBuffer, 2, len);
|
||||
dst_port = (_connetionRecvBuffer[len + 2] << 8) + _connetionRecvBuffer[len + 3];
|
||||
if ( _config.isVerboseLogging ) {
|
||||
Logging.Info( $"connect to {dst_addr}:{dst_port}" );
|
||||
}
|
||||
break;
|
||||
case 4: // IPv6 address, 16 bytes
|
||||
dst_addr = new IPAddress(_connetionRecvBuffer.Skip(1).Take(16).ToArray()).ToString();
|
||||
dst_port = (_connetionRecvBuffer[17] << 8) + _connetionRecvBuffer[18];
|
||||
if ( _config.isVerboseLogging ) {
|
||||
Logging.Info( $"connect to [{dst_addr}]:{dst_port}" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
Logging.Debug(remote, bytesToSend, "TCP Relay", "@PipeConnectionReceiveCallback() (upload)");
|
||||
tcprelay.UpdateOutboundCounter(server, bytesToSend);
|
||||
int bytesToSend;
|
||||
lock (_encryptionLock)
|
||||
{
|
||||
if (_closed) return;
|
||||
encryptor.Encrypt(_connetionRecvBuffer, bytesRead, _connetionSendBuffer, out bytesToSend);
|
||||
}
|
||||
_tcprelay.UpdateOutboundCounter(server, bytesToSend);
|
||||
_startSendingTime = DateTime.Now;
|
||||
_bytesToSend = bytesToSend;
|
||||
remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeRemoteSendCallback), null);
|
||||
|
||||
remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None, new AsyncCallback(PipeRemoteSendCallback), null);
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
strategy?.UpdateLastWrite(server);
|
||||
}
|
||||
else
|
||||
{
|
||||
remote.Shutdown(SocketShutdown.Send);
|
||||
remoteShutdown = true;
|
||||
_remoteShutdown = true;
|
||||
CheckClose();
|
||||
}
|
||||
}
|
||||
@@ -631,14 +558,11 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void PipeRemoteSendCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
remote.EndSend(ar);
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -649,14 +573,11 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void PipeConnectionSendCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
connection.EndSend(ar);
|
||||
remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace Shadowsocks.Controller
|
||||
public event EventHandler EnableStatusChanged;
|
||||
public event EventHandler EnableGlobalChanged;
|
||||
public event EventHandler ShareOverLANStatusChanged;
|
||||
public event EventHandler VerboseLoggingStatusChanged;
|
||||
public event EventHandler TrafficChanged;
|
||||
|
||||
// when user clicked Edit PAC, and PAC file has already created
|
||||
@@ -212,6 +213,15 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleVerboseLogging(bool enabled)
|
||||
{
|
||||
_config.isVerboseLogging = enabled;
|
||||
SaveConfig(_config);
|
||||
if ( VerboseLoggingStatusChanged != null ) {
|
||||
VerboseLoggingStatusChanged(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectServerIndex(int index)
|
||||
{
|
||||
_config.index = index;
|
||||
@@ -401,7 +411,7 @@ namespace Shadowsocks.Controller
|
||||
|
||||
polipoRunner.Start(_config);
|
||||
|
||||
TCPRelay tcpRelay = new TCPRelay(this);
|
||||
TCPRelay tcpRelay = new TCPRelay(this, _config);
|
||||
UDPRelay udpRelay = new UDPRelay(this);
|
||||
List<Listener.Service> services = new List<Listener.Service>();
|
||||
services.Add(tcpRelay);
|
||||
|
||||
@@ -22,6 +22,7 @@ Show QRCode...=显示二维码...
|
||||
Scan QRCode from Screen...=扫描屏幕上的二维码...
|
||||
Availability Statistics=统计可用性
|
||||
Show Logs...=显示日志...
|
||||
Verbose Logging=详细记录日志
|
||||
Updates...=更新...
|
||||
Check for Updates...=检查更新
|
||||
Check for Updates at Startup=启动时检查更新
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Shadowsocks.Model
|
||||
public bool useOnlinePac;
|
||||
public bool availabilityStatistics;
|
||||
public bool autoCheckUpdate;
|
||||
public bool isVerboseLogging;
|
||||
public LogViewerConfig logViewer;
|
||||
|
||||
private static string CONFIG_FILE = "gui-config.json";
|
||||
|
||||
@@ -76,7 +76,8 @@ namespace Shadowsocks.Util
|
||||
//
|
||||
// just kidding
|
||||
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle,
|
||||
(UIntPtr)0xFFFFFFFF, (UIntPtr)0xFFFFFFFF);
|
||||
(UIntPtr)0xFFFFFFFF,
|
||||
(UIntPtr)0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +88,8 @@ namespace Shadowsocks.Util
|
||||
using (MemoryStream sb = new MemoryStream())
|
||||
{
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(buf),
|
||||
CompressionMode.Decompress, false))
|
||||
CompressionMode.Decompress,
|
||||
false))
|
||||
{
|
||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace Shadowsocks.View
|
||||
private MenuItem editGFWUserRuleItem;
|
||||
private MenuItem editOnlinePACItem;
|
||||
private MenuItem autoCheckUpdatesToggleItem;
|
||||
private MenuItem VerboseLoggingToggleItem;
|
||||
private ConfigForm configForm;
|
||||
private List<LogForm> logForms = new List<LogForm>();
|
||||
private bool logFormsVisible = false;
|
||||
@@ -64,6 +65,7 @@ namespace Shadowsocks.View
|
||||
controller.PACFileReadyToOpen += controller_FileReadyToOpen;
|
||||
controller.UserRuleFileReadyToOpen += controller_FileReadyToOpen;
|
||||
controller.ShareOverLANStatusChanged += controller_ShareOverLANStatusChanged;
|
||||
controller.VerboseLoggingStatusChanged += controller_VerboseLoggingStatusChanged;
|
||||
controller.EnableGlobalChanged += controller_EnableGlobalChanged;
|
||||
controller.Errored += controller_Errored;
|
||||
controller.UpdatePACFromGFWListCompleted += controller_UpdatePACFromGFWListCompleted;
|
||||
@@ -265,6 +267,7 @@ namespace Shadowsocks.View
|
||||
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
|
||||
new MenuItem("-"),
|
||||
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)),
|
||||
this.VerboseLoggingToggleItem = CreateMenuItem( "Verbose Logging", new EventHandler(this.VerboseLoggingToggleItem_Click) ),
|
||||
CreateMenuGroup("Updates...", new MenuItem[] {
|
||||
CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)),
|
||||
new MenuItem("-"),
|
||||
@@ -293,6 +296,10 @@ namespace Shadowsocks.View
|
||||
ShareOverLANItem.Checked = controller.GetConfigurationCopy().shareOverLan;
|
||||
}
|
||||
|
||||
void controller_VerboseLoggingStatusChanged(object sender, EventArgs e) {
|
||||
VerboseLoggingToggleItem.Checked = controller.GetConfigurationCopy().isVerboseLogging;
|
||||
}
|
||||
|
||||
void controller_EnableGlobalChanged(object sender, EventArgs e)
|
||||
{
|
||||
globalModeItem.Checked = controller.GetConfigurationCopy().global;
|
||||
@@ -369,6 +376,7 @@ namespace Shadowsocks.View
|
||||
globalModeItem.Checked = config.global;
|
||||
PACModeItem.Checked = !config.global;
|
||||
ShareOverLANItem.Checked = config.shareOverLan;
|
||||
VerboseLoggingToggleItem.Checked = config.isVerboseLogging;
|
||||
AutoStartupItem.Checked = AutoStartup.Check();
|
||||
onlinePACItem.Checked = onlinePACItem.Enabled && config.useOnlinePac;
|
||||
localPACItem.Checked = !onlinePACItem.Checked;
|
||||
@@ -576,6 +584,11 @@ namespace Shadowsocks.View
|
||||
logForms.Add(f);
|
||||
}
|
||||
|
||||
private void VerboseLoggingToggleItem_Click( object sender, EventArgs e ) {
|
||||
VerboseLoggingToggleItem.Checked = ! VerboseLoggingToggleItem.Checked;
|
||||
controller.ToggleVerboseLogging( VerboseLoggingToggleItem.Checked );
|
||||
}
|
||||
|
||||
private void StatisticsConfigItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
StatisticsStrategyConfigurationForm form = new StatisticsStrategyConfigurationForm(controller);
|
||||
|
||||
Reference in New Issue
Block a user