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.Linq;
using System.Net;
using System.Net.Sockets;
using System.Timers;
using NLog;
using Shadowsocks.Controller.Strategy;
using Shadowsocks.Encryption;
using Shadowsocks.Encryption.AEAD;
@@ -12,16 +14,22 @@ using Shadowsocks.Encryption.Exception;
using Shadowsocks.Model;
using Shadowsocks.Proxy;
using Shadowsocks.Util.Sockets;
using static Shadowsocks.Encryption.EncryptorBase;
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 Configuration _config;
private readonly Configuration _config;
public ISet<TCPHandler> Handlers { get; set; }
@@ -37,9 +45,24 @@ namespace Shadowsocks.Controller
{
if (socket.ProtocolType != ProtocolType.Tcp
|| (length < 2 || firstPacket[0] != 5))
{
return false;
}
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>();
lock (Handlers)
@@ -50,8 +73,12 @@ 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)
@@ -80,26 +107,46 @@ namespace Shadowsocks.Controller
}
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
{
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; }
@@ -109,7 +156,7 @@ namespace Shadowsocks.Controller
}
}
class AsyncSession<T> : AsyncSession
private class AsyncSession<T> : AsyncSession
{
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 _proxyTimeout;
@@ -143,10 +190,9 @@ namespace Shadowsocks.Controller
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 Server _server;
@@ -170,16 +216,16 @@ namespace Shadowsocks.Controller
private int _totalWrite = 0;
// 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)
private byte[] _connetionRecvBuffer = new byte[BufferSize];
private readonly byte[] _connetionRecvBuffer = new byte[BufferSize];
// 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)
private byte[] _connetionSendBuffer = new byte[BufferSize];
private readonly byte[] _connetionSendBuffer = new byte[BufferSize];
private bool _connectionShutdown = false;
private bool _remoteShutdown = false;
@@ -197,11 +243,11 @@ namespace Shadowsocks.Controller
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;
_config = config;
_tcprelay = tcprelay;
_config = config.proxy;
_connection = socket;
_proxyTimeout = config.proxy.proxyTimeout * 1000;
_serverTimeout = config.GetCurrentServer().timeout * 1000;
@@ -214,11 +260,13 @@ namespace Shadowsocks.Controller
Server server = _controller.GetAServer(IStrategyCallerType.TCP, (IPEndPoint)_connection.RemoteEndPoint,
_destEndPoint);
if (server == null || server.server == "")
{
throw new ArgumentException("No server configured");
}
_encryptor = EncryptorFactory.GetEncryptor(server.method, server.password);
this._server = server;
_server = server;
/* prepare address buffer length for AEAD */
Logger.Trace($"_addrBufLength={_addrBufLength}");
@@ -235,20 +283,31 @@ namespace Shadowsocks.Controller
private void CheckClose()
{
if (_connectionShutdown && _remoteShutdown)
{
Close();
}
}
private void ErrorClose(Exception e)
{
Logger.LogUsefulException(e);
Close();
}
public void Close()
{
lock (_closeConnLock)
{
if (_closed) return;
if (_closed)
{
return;
}
_closed = true;
}
lock (_tcprelay.Handlers)
{
_tcprelay.Handlers.Remove(this);
}
OnClosed?.Invoke(this, new SSRelayEventArgs(_server));
try
{
_connection.Shutdown(SocketShutdown.Both);
@@ -263,7 +322,7 @@ namespace Shadowsocks.Controller
{
try
{
var remote = _currentRemoteSession.Remote;
IProxy remote = _currentRemoteSession.Remote;
remote.Shutdown(SocketShutdown.Both);
remote.Close();
}
@@ -284,7 +343,11 @@ namespace Shadowsocks.Controller
private void HandshakeReceive()
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
int bytesRead = _firstPacketLength;
@@ -301,18 +364,23 @@ namespace Shadowsocks.Controller
HandshakeSendCallback, null);
}
else
{
Close();
}
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void HandshakeSendCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
_connection.EndSend(ar);
@@ -324,27 +392,30 @@ namespace Shadowsocks.Controller
// +-----+-----+-------+------+----------+----------+
// 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.
// 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,
HandshakeReceive2Callback, null);
AddressReceiveCallback, null);
}
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
{
int bytesRead = _connection.EndReceive(ar);
if (bytesRead >= 5)
{
_command = _connetionRecvBuffer[1];
switch(_command)
switch (_command)
{
case CMD_CONNECT:
@@ -355,7 +426,7 @@ namespace Shadowsocks.Controller
// +----+-----+-------+------+----------+----------+
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
_connection.BeginSend(response, 0, response.Length, SocketFlags.None,
ResponseCallback, null);
ConnectResponseCallback, null);
break;
case CMD_UDP_ASSOC:
ReadAddress(HandleUDPAssociate);
@@ -376,12 +447,11 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void ResponseCallback(IAsyncResult ar)
private void ConnectResponseCallback(IAsyncResult ar)
{
try
{
@@ -391,8 +461,7 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -431,15 +500,19 @@ namespace Shadowsocks.Controller
private void OnAddressFullyRead(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
int bytesRead = _connection.EndReceive(ar);
var states = (object[])ar.AsyncState;
object[] states = (object[])ar.AsyncState;
int bytesRemain = (int)states[0];
var onSuccess = (Action)states[1];
Action onSuccess = (Action)states[1];
if (bytesRead >= bytesRemain)
{
@@ -472,7 +545,7 @@ namespace Shadowsocks.Controller
break;
}
Logger.Debug($"connect to {dstAddr}:{dstPort}");
Logger.Debug($"connect to {dstAddr}:{dstPort}");
_destEndPoint = SocketUtil.GetEndPoint(dstAddr, dstPort);
@@ -486,8 +559,7 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -515,7 +587,11 @@ namespace Shadowsocks.Controller
private void ReadAll(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
if (ar.AsyncState != null)
@@ -533,13 +609,14 @@ namespace Shadowsocks.Controller
ReadAll, null);
}
else
{
Close();
}
}
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -584,9 +661,9 @@ namespace Shadowsocks.Controller
serverEP = pluginEP;
remote = new DirectConnect();
}
else if (_config.proxy.useProxy)
else if (_config.useProxy)
{
switch (_config.proxy.proxyType)
switch (_config.proxyType)
{
case ProxyConfig.PROXY_SOCKS5:
remote = new Socks5Proxy();
@@ -597,14 +674,14 @@ namespace Shadowsocks.Controller
default:
throw new NotSupportedException("Unknown forward proxy.");
}
proxyEP = SocketUtil.GetEndPoint(_config.proxy.proxyServer, _config.proxy.proxyPort);
proxyEP = SocketUtil.GetEndPoint(_config.proxyServer, _config.proxyPort);
}
else
{
remote = new DirectConnect();
}
var session = new AsyncSession(remote);
AsyncSession session = new AsyncSession(remote);
lock (_closeConnLock)
{
if (_closed)
@@ -632,14 +709,13 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void ProxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{
var timer = (ProxyTimer)sender;
ProxyTimer timer = (ProxyTimer)sender;
timer.Elapsed -= ProxyConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
@@ -649,7 +725,7 @@ namespace Shadowsocks.Controller
{
return;
}
var proxy = timer.Session.Remote;
IProxy proxy = timer.Session.Remote;
Logger.Info($"Proxy {proxy.ProxyEndPoint} timed out");
proxy.Close();
@@ -664,15 +740,15 @@ namespace Shadowsocks.Controller
}
try
{
var session = (AsyncSession<ProxyTimer>)ar.AsyncState;
AsyncSession<ProxyTimer> session = (AsyncSession<ProxyTimer>)ar.AsyncState;
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.Enabled = false;
timer.Dispose();
var remote = session.Remote;
IProxy remote = session.Remote;
// Complete the connection.
remote.EndConnectProxy(ar);
@@ -694,9 +770,9 @@ namespace Shadowsocks.Controller
_destConnected = false;
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.
@@ -708,14 +784,13 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void DestConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{
var timer = (ServerTimer)sender;
ServerTimer timer = (ServerTimer)sender;
timer.Elapsed -= DestConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
@@ -725,10 +800,9 @@ namespace Shadowsocks.Controller
return;
}
var session = timer.Session;
AsyncSession session = timer.Session;
Server server = timer.Server;
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.SetFailure(server);
OnFailed?.Invoke(this, new SSRelayEventArgs(_server));
Logger.Info($"{server.FriendlyName()} timed out");
session.Remote.Close();
Close();
@@ -736,17 +810,21 @@ namespace Shadowsocks.Controller
private void ConnectCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
var session = (AsyncSession<ServerTimer>)ar.AsyncState;
AsyncSession<ServerTimer> session = (AsyncSession<ServerTimer>)ar.AsyncState;
ServerTimer timer = session.State;
_server = timer.Server;
timer.Elapsed -= DestConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
var remote = session.Remote;
IProxy remote = session.Remote;
// Complete the connection.
remote.EndConnectDest(ar);
@@ -754,10 +832,9 @@ namespace Shadowsocks.Controller
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);
}
@@ -768,11 +845,9 @@ namespace Shadowsocks.Controller
{
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);
if (available > 0)
{
var size = _connection.Receive(_connetionRecvBuffer, _firstPacketLength, available,
int size = _connection.Receive(_connetionRecvBuffer, _firstPacketLength, available,
SocketFlags.None);
_firstPacketLength += size;
@@ -790,7 +865,11 @@ namespace Shadowsocks.Controller
private void StartPipe(AsyncSession session)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
_startReceivingTime = DateTime.Now;
@@ -803,20 +882,24 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void PipeRemoteReceiveCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
var session = (AsyncSession)ar.AsyncState;
AsyncSession session = (AsyncSession)ar.AsyncState;
int bytesRead = session.Remote.EndReceive(ar);
_totalRead += bytesRead;
_tcprelay.UpdateInboundCounter(_server, bytesRead);
OnInbound?.Invoke(this, new SSTransmitEventArgs(_server, bytesRead));
if (bytesRead > 0)
{
lastActivity = DateTime.Now;
@@ -845,8 +928,6 @@ namespace Shadowsocks.Controller
Logger.Trace($"start sending {bytesToSend}");
_connection.BeginSend(_remoteSendBuffer, 0, bytesToSend, SocketFlags.None,
PipeConnectionSendCallback, new object[] { session, bytesToSend });
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.UpdateLastRead(_server);
}
else
{
@@ -857,20 +938,23 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
private void PipeConnectionReceiveCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
try
{
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)
{
@@ -885,8 +969,7 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -907,22 +990,25 @@ namespace Shadowsocks.Controller
return;
}
}
_tcprelay.UpdateOutboundCounter(_server, bytesToSend);
OnOutbound?.Invoke(this, new SSTransmitEventArgs(_server, bytesToSend));
_startSendingTime = DateTime.Now;
session.Remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None,
PipeRemoteSendCallback, new object[] { session, bytesToSend });
IStrategy strategy = _controller.GetCurrentStrategy();
strategy?.UpdateLastWrite(_server);
}
private void PipeRemoteSendCallback(IAsyncResult ar)
{
if (_closed) return;
if (_closed)
{
return;
}
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);
if (bytesSent > 0)
@@ -944,8 +1030,7 @@ namespace Shadowsocks.Controller
}
catch (Exception e)
{
Logger.LogUsefulException(e);
Close();
ErrorClose(e);
}
}
@@ -954,11 +1039,11 @@ namespace Shadowsocks.Controller
{
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)
{
Logger.Info("reconstruct _remoteSendBuffer to re-send");
@@ -972,8 +1057,7 @@ namespace Shadowsocks.Controller
}
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);
}
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))
{
MessageBox.Show(I18N.GetString("Successfully imported from {0}", ssURL));
return true;
}
}
else
{
MessageBox.Show(I18N.GetString("Failed to import. Please check if the link is valid."));
}
}
return false;
}
}
}
return false;
}
public bool AddServerBySSURL(string ssURL)
{
try
@@ -490,29 +490,32 @@ namespace Shadowsocks.Controller
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)
{
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)
{
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)
{
availabilityStatistics.UpdateOutboundCounter(server, n);
availabilityStatistics.UpdateOutboundCounter(args.server, args.length);
}
}
@@ -556,6 +559,11 @@ namespace Shadowsocks.Controller
privoxyRunner.Start(_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);
List<Listener.IService> services = new List<Listener.IService>
{


Loading…
Cancel
Save