Browse Source

Merge pull request #2872 from studentmain/decouple-statistic

Decouple statistic and TCPRelay
tags/4.2.0.0
Allen Zhu GitHub 5 years ago
parent
commit
607ae65567
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 235 additions and 143 deletions
  1. +207
    -123
      shadowsocks-csharp/Controller/Service/TCPRelay.cs
  2. +28
    -20
      shadowsocks-csharp/Controller/ShadowsocksController.cs

+ 207
- 123
shadowsocks-csharp/Controller/Service/TCPRelay.cs View File

@@ -1,10 +1,12 @@
using NLog;
using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Timers; using System.Timers;
using NLog;
using Shadowsocks.Controller.Strategy; using Shadowsocks.Controller.Strategy;
using Shadowsocks.Encryption; using Shadowsocks.Encryption;
using Shadowsocks.Encryption.AEAD; using Shadowsocks.Encryption.AEAD;
@@ -12,16 +14,22 @@ using Shadowsocks.Encryption.Exception;
using Shadowsocks.Model; using Shadowsocks.Model;
using Shadowsocks.Proxy; using Shadowsocks.Proxy;
using Shadowsocks.Util.Sockets; using Shadowsocks.Util.Sockets;
using static Shadowsocks.Encryption.EncryptorBase; using static Shadowsocks.Encryption.EncryptorBase;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
class TCPRelay : Listener.Service
internal class TCPRelay : Listener.Service
{ {
private static Logger logger = LogManager.GetCurrentClassLogger();
private ShadowsocksController _controller;
public event EventHandler<SSTCPConnectedEventArgs> OnConnected;
public event EventHandler<SSTransmitEventArgs> OnInbound;
public event EventHandler<SSTransmitEventArgs> OnOutbound;
public event EventHandler<SSRelayEventArgs> OnFailed;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
private readonly ShadowsocksController _controller;
private DateTime _lastSweepTime; private DateTime _lastSweepTime;
private Configuration _config;
private readonly Configuration _config;
public ISet<TCPHandler> Handlers { get; set; } public ISet<TCPHandler> Handlers { get; set; }
@@ -37,9 +45,24 @@ namespace Shadowsocks.Controller
{ {
if (socket.ProtocolType != ProtocolType.Tcp if (socket.ProtocolType != ProtocolType.Tcp
|| (length < 2 || firstPacket[0] != 5)) || (length < 2 || firstPacket[0] != 5))
{
return false; return false;
}
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
TCPHandler handler = new TCPHandler(_controller, _config, this, socket);
TCPHandler handler = new TCPHandler(_controller, _config, socket);
handler.OnConnected += OnConnected;
handler.OnInbound += OnInbound;
handler.OnOutbound += OnOutbound;
handler.OnFailed += OnFailed;
handler.OnClosed += (h, arg) =>
{
lock (Handlers)
{
Handlers.Remove(handler);
}
};
IList<TCPHandler> handlersToClose = new List<TCPHandler>(); IList<TCPHandler> handlersToClose = new List<TCPHandler>();
lock (Handlers) lock (Handlers)
@@ -50,8 +73,12 @@ namespace Shadowsocks.Controller
{ {
_lastSweepTime = now; _lastSweepTime = now;
foreach (TCPHandler handler1 in Handlers) foreach (TCPHandler handler1 in Handlers)
{
if (now - handler1.lastActivity > TimeSpan.FromSeconds(900)) if (now - handler1.lastActivity > TimeSpan.FromSeconds(900))
{
handlersToClose.Add(handler1); handlersToClose.Add(handler1);
}
}
} }
} }
foreach (TCPHandler handler1 in handlersToClose) foreach (TCPHandler handler1 in handlersToClose)
@@ -80,26 +107,46 @@ namespace Shadowsocks.Controller
} }
handlersToClose.ForEach(h => h.Close()); handlersToClose.ForEach(h => h.Close());
} }
}
public void UpdateInboundCounter(Server server, long n)
public class SSRelayEventArgs : EventArgs
{
public readonly Server server;
public SSRelayEventArgs(Server server)
{ {
_controller.UpdateInboundCounter(server, n);
this.server = server;
} }
}
public void UpdateOutboundCounter(Server server, long n)
public class SSTransmitEventArgs : SSRelayEventArgs
{
public readonly long length;
public SSTransmitEventArgs(Server server, long length) : base(server)
{ {
_controller.UpdateOutboundCounter(server, n);
this.length = length;
} }
}
public class SSTCPConnectedEventArgs : SSRelayEventArgs
{
public readonly TimeSpan latency;
public void UpdateLatency(Server server, TimeSpan latency)
public SSTCPConnectedEventArgs(Server server, TimeSpan latency) : base(server)
{ {
_controller.UpdateLatency(server, latency);
this.latency = latency;
} }
} }
internal class TCPHandler internal class TCPHandler
{ {
class AsyncSession
public event EventHandler<SSTCPConnectedEventArgs> OnConnected;
public event EventHandler<SSTransmitEventArgs> OnInbound;
public event EventHandler<SSTransmitEventArgs> OnOutbound;
public event EventHandler<SSRelayEventArgs> OnClosed;
public event EventHandler<SSRelayEventArgs> OnFailed;
private class AsyncSession
{ {
public IProxy Remote { get; } public IProxy Remote { get; }
@@ -109,7 +156,7 @@ namespace Shadowsocks.Controller
} }
} }
class AsyncSession<T> : AsyncSession
private class AsyncSession<T> : AsyncSession
{ {
public T State { get; set; } public T State { get; set; }
@@ -124,7 +171,7 @@ namespace Shadowsocks.Controller
} }
} }
private static Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly int _serverTimeout; private readonly int _serverTimeout;
private readonly int _proxyTimeout; private readonly int _proxyTimeout;
@@ -143,10 +190,9 @@ namespace Shadowsocks.Controller
public DateTime lastActivity; public DateTime lastActivity;
private ShadowsocksController _controller;
private Configuration _config;
private TCPRelay _tcprelay;
private Socket _connection;
private readonly ShadowsocksController _controller;
private readonly ProxyConfig _config;
private readonly Socket _connection;
private IEncryptor _encryptor; private IEncryptor _encryptor;
private Server _server; private Server _server;
@@ -170,16 +216,16 @@ namespace Shadowsocks.Controller
private int _totalWrite = 0; private int _totalWrite = 0;
// remote -> local proxy (ciphertext, before decrypt) // remote -> local proxy (ciphertext, before decrypt)
private byte[] _remoteRecvBuffer = new byte[BufferSize];
private readonly byte[] _remoteRecvBuffer = new byte[BufferSize];
// client -> local proxy (plaintext, before encrypt) // client -> local proxy (plaintext, before encrypt)
private byte[] _connetionRecvBuffer = new byte[BufferSize];
private readonly byte[] _connetionRecvBuffer = new byte[BufferSize];
// local proxy -> remote (plaintext, after decrypt) // local proxy -> remote (plaintext, after decrypt)
private byte[] _remoteSendBuffer = new byte[BufferSize];
private readonly byte[] _remoteSendBuffer = new byte[BufferSize];
// local proxy -> client (ciphertext, before decrypt) // local proxy -> client (ciphertext, before decrypt)
private byte[] _connetionSendBuffer = new byte[BufferSize];
private readonly byte[] _connetionSendBuffer = new byte[BufferSize];
private bool _connectionShutdown = false; private bool _connectionShutdown = false;
private bool _remoteShutdown = false; private bool _remoteShutdown = false;
@@ -197,11 +243,11 @@ namespace Shadowsocks.Controller
private EndPoint _destEndPoint = null; private EndPoint _destEndPoint = null;
public TCPHandler(ShadowsocksController controller, Configuration config, TCPRelay tcprelay, Socket socket)
// TODO: decouple controller
public TCPHandler(ShadowsocksController controller, Configuration config, Socket socket)
{ {
_controller = controller; _controller = controller;
_config = config;
_tcprelay = tcprelay;
_config = config.proxy;
_connection = socket; _connection = socket;
_proxyTimeout = config.proxy.proxyTimeout * 1000; _proxyTimeout = config.proxy.proxyTimeout * 1000;
_serverTimeout = config.GetCurrentServer().timeout * 1000; _serverTimeout = config.GetCurrentServer().timeout * 1000;
@@ -214,11 +260,13 @@ namespace Shadowsocks.Controller
Server server = _controller.GetAServer(IStrategyCallerType.TCP, (IPEndPoint)_connection.RemoteEndPoint, Server server = _controller.GetAServer(IStrategyCallerType.TCP, (IPEndPoint)_connection.RemoteEndPoint,
_destEndPoint); _destEndPoint);
if (server == null || server.server == "") if (server == null || server.server == "")
{
throw new ArgumentException("No server configured"); throw new ArgumentException("No server configured");
}
_encryptor = EncryptorFactory.GetEncryptor(server.method, server.password); _encryptor = EncryptorFactory.GetEncryptor(server.method, server.password);
this._server = server;
_server = server;
/* prepare address buffer length for AEAD */ /* prepare address buffer length for AEAD */
Logger.Trace($"_addrBufLength={_addrBufLength}"); Logger.Trace($"_addrBufLength={_addrBufLength}");
@@ -235,20 +283,31 @@ namespace Shadowsocks.Controller
private void CheckClose() private void CheckClose()
{ {
if (_connectionShutdown && _remoteShutdown) if (_connectionShutdown && _remoteShutdown)
{
Close(); Close();
}
}
private void ErrorClose(Exception e)
{
Logger.LogUsefulException(e);
Close();
} }
public void Close() public void Close()
{ {
lock (_closeConnLock) lock (_closeConnLock)
{ {
if (_closed) return;
if (_closed)
{
return;
}
_closed = true; _closed = true;
} }
lock (_tcprelay.Handlers)
{
_tcprelay.Handlers.Remove(this);
}
OnClosed?.Invoke(this, new SSRelayEventArgs(_server));
try try
{ {
_connection.Shutdown(SocketShutdown.Both); _connection.Shutdown(SocketShutdown.Both);
@@ -263,7 +322,7 @@ namespace Shadowsocks.Controller
{ {
try try
{ {
var remote = _currentRemoteSession.Remote;
IProxy remote = _currentRemoteSession.Remote;
remote.Shutdown(SocketShutdown.Both); remote.Shutdown(SocketShutdown.Both);
remote.Close(); remote.Close();
} }
@@ -284,7 +343,11 @@ namespace Shadowsocks.Controller
private void HandshakeReceive() private void HandshakeReceive()
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
int bytesRead = _firstPacketLength; int bytesRead = _firstPacketLength;
@@ -301,18 +364,23 @@ namespace Shadowsocks.Controller
HandshakeSendCallback, null); HandshakeSendCallback, null);
} }
else else
{
Close(); Close();
}
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
private void HandshakeSendCallback(IAsyncResult ar) private void HandshakeSendCallback(IAsyncResult ar)
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
_connection.EndSend(ar); _connection.EndSend(ar);
@@ -324,27 +392,30 @@ namespace Shadowsocks.Controller
// +-----+-----+-------+------+----------+----------+ // +-----+-----+-------+------+----------+----------+
// Skip first 3 bytes, and read 2 more bytes to analysis the address. // Skip first 3 bytes, and read 2 more bytes to analysis the address.
// 2 more bytes is designed if address is domain then we don't need to read once more to get the addr length. // 2 more bytes is designed if address is domain then we don't need to read once more to get the addr length.
// TODO validate
// validate is unnecessary, we did it in first packet, but we can do it in future version
_connection.BeginReceive(_connetionRecvBuffer, 0, 3 + ADDR_ATYP_LEN + 1, SocketFlags.None, _connection.BeginReceive(_connetionRecvBuffer, 0, 3 + ADDR_ATYP_LEN + 1, SocketFlags.None,
HandshakeReceive2Callback, null);
AddressReceiveCallback, null);
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
private void HandshakeReceive2Callback(IAsyncResult ar)
private void AddressReceiveCallback(IAsyncResult ar)
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
int bytesRead = _connection.EndReceive(ar); int bytesRead = _connection.EndReceive(ar);
if (bytesRead >= 5) if (bytesRead >= 5)
{ {
_command = _connetionRecvBuffer[1]; _command = _connetionRecvBuffer[1];
switch(_command)
switch (_command)
{ {
case CMD_CONNECT: case CMD_CONNECT:
@@ -355,7 +426,7 @@ namespace Shadowsocks.Controller
// +----+-----+-------+------+----------+----------+ // +----+-----+-------+------+----------+----------+
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 }; byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
_connection.BeginSend(response, 0, response.Length, SocketFlags.None, _connection.BeginSend(response, 0, response.Length, SocketFlags.None,
ResponseCallback, null);
ConnectResponseCallback, null);
break; break;
case CMD_UDP_ASSOC: case CMD_UDP_ASSOC:
ReadAddress(HandleUDPAssociate); ReadAddress(HandleUDPAssociate);
@@ -376,12 +447,11 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
private void ResponseCallback(IAsyncResult ar)
private void ConnectResponseCallback(IAsyncResult ar)
{ {
try try
{ {
@@ -391,8 +461,7 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
@@ -431,15 +500,19 @@ namespace Shadowsocks.Controller
private void OnAddressFullyRead(IAsyncResult ar) private void OnAddressFullyRead(IAsyncResult ar)
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
int bytesRead = _connection.EndReceive(ar); int bytesRead = _connection.EndReceive(ar);
var states = (object[])ar.AsyncState;
object[] states = (object[])ar.AsyncState;
int bytesRemain = (int)states[0]; int bytesRemain = (int)states[0];
var onSuccess = (Action)states[1];
Action onSuccess = (Action)states[1];
if (bytesRead >= bytesRemain) if (bytesRead >= bytesRemain)
{ {
@@ -472,7 +545,7 @@ namespace Shadowsocks.Controller
break; break;
} }
Logger.Debug($"connect to {dstAddr}:{dstPort}");
Logger.Debug($"connect to {dstAddr}:{dstPort}");
_destEndPoint = SocketUtil.GetEndPoint(dstAddr, dstPort); _destEndPoint = SocketUtil.GetEndPoint(dstAddr, dstPort);
@@ -486,8 +559,7 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
@@ -515,7 +587,11 @@ namespace Shadowsocks.Controller
private void ReadAll(IAsyncResult ar) private void ReadAll(IAsyncResult ar)
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
if (ar.AsyncState != null) if (ar.AsyncState != null)
@@ -533,13 +609,14 @@ namespace Shadowsocks.Controller
ReadAll, null); ReadAll, null);
} }
else else
{
Close(); Close();
}
} }
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
@@ -584,9 +661,9 @@ namespace Shadowsocks.Controller
serverEP = pluginEP; serverEP = pluginEP;
remote = new DirectConnect(); remote = new DirectConnect();
} }
else if (_config.proxy.useProxy)
else if (_config.useProxy)
{ {
switch (_config.proxy.proxyType)
switch (_config.proxyType)
{ {
case ProxyConfig.PROXY_SOCKS5: case ProxyConfig.PROXY_SOCKS5:
remote = new Socks5Proxy(); remote = new Socks5Proxy();
@@ -597,14 +674,14 @@ namespace Shadowsocks.Controller
default: default:
throw new NotSupportedException("Unknown forward proxy."); throw new NotSupportedException("Unknown forward proxy.");
} }
proxyEP = SocketUtil.GetEndPoint(_config.proxy.proxyServer, _config.proxy.proxyPort);
proxyEP = SocketUtil.GetEndPoint(_config.proxyServer, _config.proxyPort);
} }
else else
{ {
remote = new DirectConnect(); remote = new DirectConnect();
} }
var session = new AsyncSession(remote);
AsyncSession session = new AsyncSession(remote);
lock (_closeConnLock) lock (_closeConnLock)
{ {
if (_closed) if (_closed)
@@ -632,14 +709,13 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
private void ProxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e) private void ProxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{ {
var timer = (ProxyTimer)sender;
ProxyTimer timer = (ProxyTimer)sender;
timer.Elapsed -= ProxyConnectTimer_Elapsed; timer.Elapsed -= ProxyConnectTimer_Elapsed;
timer.Enabled = false; timer.Enabled = false;
timer.Dispose(); timer.Dispose();
@@ -649,7 +725,7 @@ namespace Shadowsocks.Controller
{ {
return; return;
} }
var proxy = timer.Session.Remote;
IProxy proxy = timer.Session.Remote;
Logger.Info($"Proxy {proxy.ProxyEndPoint} timed out"); Logger.Info($"Proxy {proxy.ProxyEndPoint} timed out");
proxy.Close(); proxy.Close();
@@ -664,15 +740,15 @@ namespace Shadowsocks.Controller
} }
try try
{ {
var session = (AsyncSession<ProxyTimer>)ar.AsyncState;
AsyncSession<ProxyTimer> session = (AsyncSession<ProxyTimer>)ar.AsyncState;
ProxyTimer timer = session.State; ProxyTimer timer = session.State;
var destEndPoint = timer.DestEndPoint;
var server = timer.Server;
EndPoint destEndPoint = timer.DestEndPoint;
Server server = timer.Server;
timer.Elapsed -= ProxyConnectTimer_Elapsed; timer.Elapsed -= ProxyConnectTimer_Elapsed;
timer.Enabled = false; timer.Enabled = false;
timer.Dispose(); timer.Dispose();
var remote = session.Remote;
IProxy remote = session.Remote;
// Complete the connection. // Complete the connection.
remote.EndConnectProxy(ar); remote.EndConnectProxy(ar);
@@ -694,9 +770,9 @@ namespace Shadowsocks.Controller
_destConnected = false; _destConnected = false;
NetworkCredential auth = null; NetworkCredential auth = null;
if (_config.proxy.useAuth)
if (_config.useAuth)
{ {
auth = new NetworkCredential(_config.proxy.authUser, _config.proxy.authPwd);
auth = new NetworkCredential(_config.authUser, _config.authPwd);
} }
// Connect to the remote endpoint. // Connect to the remote endpoint.
@@ -708,14 +784,13 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
private void DestConnectTimer_Elapsed(object sender, ElapsedEventArgs e) private void DestConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{ {
var timer = (ServerTimer)sender;
ServerTimer timer = (ServerTimer)sender;
timer.Elapsed -= DestConnectTimer_Elapsed; timer.Elapsed -= DestConnectTimer_Elapsed;
timer.Enabled = false; timer.Enabled = false;
timer.Dispose(); timer.Dispose();
@@ -725,10 +800,9 @@ namespace Shadowsocks.Controller
return; return;
} }
var session = timer.Session;
AsyncSession session = timer.Session;
Server server = timer.Server; Server server = timer.Server;
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.SetFailure(server);
OnFailed?.Invoke(this, new SSRelayEventArgs(_server));
Logger.Info($"{server.FriendlyName()} timed out"); Logger.Info($"{server.FriendlyName()} timed out");
session.Remote.Close(); session.Remote.Close();
Close(); Close();
@@ -736,17 +810,21 @@ namespace Shadowsocks.Controller
private void ConnectCallback(IAsyncResult ar) private void ConnectCallback(IAsyncResult ar)
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
var session = (AsyncSession<ServerTimer>)ar.AsyncState;
AsyncSession<ServerTimer> session = (AsyncSession<ServerTimer>)ar.AsyncState;
ServerTimer timer = session.State; ServerTimer timer = session.State;
_server = timer.Server; _server = timer.Server;
timer.Elapsed -= DestConnectTimer_Elapsed; timer.Elapsed -= DestConnectTimer_Elapsed;
timer.Enabled = false; timer.Enabled = false;
timer.Dispose(); timer.Dispose();
var remote = session.Remote;
IProxy remote = session.Remote;
// Complete the connection. // Complete the connection.
remote.EndConnectDest(ar); remote.EndConnectDest(ar);
@@ -754,10 +832,9 @@ namespace Shadowsocks.Controller
Logger.Debug($"Socket connected to ss server: {_server.FriendlyName()}"); Logger.Debug($"Socket connected to ss server: {_server.FriendlyName()}");
var latency = DateTime.Now - _startConnectTime;
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.UpdateLatency(_server, latency);
_tcprelay.UpdateLatency(_server, latency);
TimeSpan latency = DateTime.Now - _startConnectTime;
OnConnected?.Invoke(this, new SSTCPConnectedEventArgs(_server, latency));
StartPipe(session); StartPipe(session);
} }
@@ -768,11 +845,9 @@ namespace Shadowsocks.Controller
{ {
if (_server != null) if (_server != null)
{ {
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.SetFailure(_server);
OnFailed?.Invoke(this, new SSRelayEventArgs(_server));
} }
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
@@ -781,7 +856,7 @@ namespace Shadowsocks.Controller
int available = Math.Min(_connection.Available, RecvSize - _firstPacketLength); int available = Math.Min(_connection.Available, RecvSize - _firstPacketLength);
if (available > 0) if (available > 0)
{ {
var size = _connection.Receive(_connetionRecvBuffer, _firstPacketLength, available,
int size = _connection.Receive(_connetionRecvBuffer, _firstPacketLength, available,
SocketFlags.None); SocketFlags.None);
_firstPacketLength += size; _firstPacketLength += size;
@@ -790,7 +865,11 @@ namespace Shadowsocks.Controller
private void StartPipe(AsyncSession session) private void StartPipe(AsyncSession session)
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
_startReceivingTime = DateTime.Now; _startReceivingTime = DateTime.Now;
@@ -803,20 +882,24 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
private void PipeRemoteReceiveCallback(IAsyncResult ar) private void PipeRemoteReceiveCallback(IAsyncResult ar)
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
var session = (AsyncSession)ar.AsyncState;
AsyncSession session = (AsyncSession)ar.AsyncState;
int bytesRead = session.Remote.EndReceive(ar); int bytesRead = session.Remote.EndReceive(ar);
_totalRead += bytesRead; _totalRead += bytesRead;
_tcprelay.UpdateInboundCounter(_server, bytesRead);
OnInbound?.Invoke(this, new SSTransmitEventArgs(_server, bytesRead));
if (bytesRead > 0) if (bytesRead > 0)
{ {
lastActivity = DateTime.Now; lastActivity = DateTime.Now;
@@ -845,8 +928,6 @@ namespace Shadowsocks.Controller
Logger.Trace($"start sending {bytesToSend}"); Logger.Trace($"start sending {bytesToSend}");
_connection.BeginSend(_remoteSendBuffer, 0, bytesToSend, SocketFlags.None, _connection.BeginSend(_remoteSendBuffer, 0, bytesToSend, SocketFlags.None,
PipeConnectionSendCallback, new object[] { session, bytesToSend }); PipeConnectionSendCallback, new object[] { session, bytesToSend });
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.UpdateLastRead(_server);
} }
else else
{ {
@@ -857,20 +938,23 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
private void PipeConnectionReceiveCallback(IAsyncResult ar) private void PipeConnectionReceiveCallback(IAsyncResult ar)
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
int bytesRead = _connection.EndReceive(ar); int bytesRead = _connection.EndReceive(ar);
var session = (AsyncSession)ar.AsyncState;
var remote = session.Remote;
AsyncSession session = (AsyncSession)ar.AsyncState;
IProxy remote = session.Remote;
if (bytesRead > 0) if (bytesRead > 0)
{ {
@@ -885,8 +969,7 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
@@ -907,22 +990,25 @@ namespace Shadowsocks.Controller
return; return;
} }
} }
_tcprelay.UpdateOutboundCounter(_server, bytesToSend);
OnOutbound?.Invoke(this, new SSTransmitEventArgs(_server, bytesToSend));
_startSendingTime = DateTime.Now; _startSendingTime = DateTime.Now;
session.Remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None, session.Remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None,
PipeRemoteSendCallback, new object[] { session, bytesToSend }); PipeRemoteSendCallback, new object[] { session, bytesToSend });
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.UpdateLastWrite(_server);
} }
private void PipeRemoteSendCallback(IAsyncResult ar) private void PipeRemoteSendCallback(IAsyncResult ar)
{ {
if (_closed) return;
if (_closed)
{
return;
}
try try
{ {
var container = (object[])ar.AsyncState;
var session = (AsyncSession)container[0];
var bytesShouldSend = (int)container[1];
object[] container = (object[])ar.AsyncState;
AsyncSession session = (AsyncSession)container[0];
int bytesShouldSend = (int)container[1];
int bytesSent = session.Remote.EndSend(ar); int bytesSent = session.Remote.EndSend(ar);
if (bytesSent > 0) if (bytesSent > 0)
@@ -944,8 +1030,7 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
@@ -954,11 +1039,11 @@ namespace Shadowsocks.Controller
{ {
try try
{ {
var container = (object[])ar.AsyncState;
var session = (AsyncSession)container[0];
var bytesShouldSend = (int)container[1];
var bytesSent = _connection.EndSend(ar);
var bytesRemaining = bytesShouldSend - bytesSent;
object[] container = (object[])ar.AsyncState;
AsyncSession session = (AsyncSession)container[0];
int bytesShouldSend = (int)container[1];
int bytesSent = _connection.EndSend(ar);
int bytesRemaining = bytesShouldSend - bytesSent;
if (bytesRemaining > 0) if (bytesRemaining > 0)
{ {
Logger.Info("reconstruct _remoteSendBuffer to re-send"); Logger.Info("reconstruct _remoteSendBuffer to re-send");
@@ -972,8 +1057,7 @@ namespace Shadowsocks.Controller
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
} }
} }
} }

+ 28
- 20
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -218,25 +218,25 @@ namespace Shadowsocks.Controller
StatisticsStrategyConfiguration.Save(configuration); StatisticsStrategyConfiguration.Save(configuration);
} }
public bool AskAddServerBySSURL(string ssURL)
{
var dr = MessageBox.Show(I18N.GetString("Import from URL: {0} ?", ssURL), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo);
if (dr == DialogResult.Yes)
{
public bool AskAddServerBySSURL(string ssURL)
{
var dr = MessageBox.Show(I18N.GetString("Import from URL: {0} ?", ssURL), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo);
if (dr == DialogResult.Yes)
{
if (AddServerBySSURL(ssURL)) if (AddServerBySSURL(ssURL))
{ {
MessageBox.Show(I18N.GetString("Successfully imported from {0}", ssURL)); MessageBox.Show(I18N.GetString("Successfully imported from {0}", ssURL));
return true; return true;
}
}
else else
{ {
MessageBox.Show(I18N.GetString("Failed to import. Please check if the link is valid.")); MessageBox.Show(I18N.GetString("Failed to import. Please check if the link is valid."));
}
}
return false;
}
}
}
return false;
}
public bool AddServerBySSURL(string ssURL) public bool AddServerBySSURL(string ssURL)
{ {
try try
@@ -490,29 +490,32 @@ namespace Shadowsocks.Controller
ConfigChanged?.Invoke(this, new EventArgs()); ConfigChanged?.Invoke(this, new EventArgs());
} }
public void UpdateLatency(Server server, TimeSpan latency)
public void UpdateLatency(object sender, SSTCPConnectedEventArgs args)
{ {
GetCurrentStrategy()?.UpdateLatency(args.server, args.latency);
if (_config.availabilityStatistics) if (_config.availabilityStatistics)
{ {
availabilityStatistics.UpdateLatency(server, (int)latency.TotalMilliseconds);
availabilityStatistics.UpdateLatency(args.server, (int)args.latency.TotalMilliseconds);
} }
} }
public void UpdateInboundCounter(Server server, long n)
public void UpdateInboundCounter(object sender, SSTransmitEventArgs args)
{ {
Interlocked.Add(ref _inboundCounter, n);
GetCurrentStrategy()?.UpdateLastRead(args.server);
Interlocked.Add(ref _inboundCounter, args.length);
if (_config.availabilityStatistics) if (_config.availabilityStatistics)
{ {
availabilityStatistics.UpdateInboundCounter(server, n);
availabilityStatistics.UpdateInboundCounter(args.server, args.length);
} }
} }
public void UpdateOutboundCounter(Server server, long n)
public void UpdateOutboundCounter(object sender, SSTransmitEventArgs args)
{ {
Interlocked.Add(ref _outboundCounter, n);
GetCurrentStrategy()?.UpdateLastWrite(args.server);
Interlocked.Add(ref _outboundCounter, args.length);
if (_config.availabilityStatistics) if (_config.availabilityStatistics)
{ {
availabilityStatistics.UpdateOutboundCounter(server, n);
availabilityStatistics.UpdateOutboundCounter(args.server, args.length);
} }
} }
@@ -556,6 +559,11 @@ namespace Shadowsocks.Controller
privoxyRunner.Start(_config); privoxyRunner.Start(_config);
TCPRelay tcpRelay = new TCPRelay(this, _config); TCPRelay tcpRelay = new TCPRelay(this, _config);
tcpRelay.OnConnected += UpdateLatency;
tcpRelay.OnInbound += UpdateInboundCounter;
tcpRelay.OnOutbound += UpdateOutboundCounter;
tcpRelay.OnFailed += (o, e) => GetCurrentStrategy()?.SetFailure(e.server);
UDPRelay udpRelay = new UDPRelay(this); UDPRelay udpRelay = new UDPRelay(this);
List<Listener.IService> services = new List<Listener.IService> List<Listener.IService> services = new List<Listener.IService>
{ {


Loading…
Cancel
Save