diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index 9c162780..00edc00f 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -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 Handlers - { - get; set; - } + public ISet Handlers { get; set; } - public TCPRelay(ShadowsocksController controller) + public TCPRelay(ShadowsocksController controller, Configuration conf) { _controller = controller; + _config = conf; Handlers = new HashSet(); _lastSweepTime = DateTime.Now; } public bool Handle(byte[] firstPacket, int length, Socket socket, object state) { - if (socket.ProtocolType != ProtocolType.Tcp) - { - return false; - } - if (length < 2 || firstPacket[0] != 5) - { + if (socket.ProtocolType != ProtocolType.Tcp + || (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 handlersToClose = new List(); @@ -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; - - // 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 bool connectionShutdown = false; - private bool remoteShutdown = false; - private bool closed = false; - - private object encryptionLock = new object(); - private object decryptionLock = new object(); + + private int _totalRead = 0; + private int _totalWrite = 0; + + 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 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) + try { - if (closed) - { - return; - } - closed = true; + connection?.Shutdown(SocketShutdown.Both); + connection?.Close(); } - if (connection != null) + catch (Exception e) { - try - { - connection.Shutdown(SocketShutdown.Both); - connection.Close(); - } - catch (Exception e) - { - Logging.LogUsefulException(e); - } + Logging.LogUsefulException(e); } - if (remote != null) + try { - try - { - remote.Shutdown(SocketShutdown.Both); - remote.Close(); - } - catch (Exception e) - { - Logging.LogUsefulException(e); - } + remote?.Shutdown(SocketShutdown.Both); + remote?.Close(); } - lock (encryptionLock) + catch (Exception e) { - lock (decryptionLock) + 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 atyp = _connetionRecvBuffer[0]; + string dst_addr; + int dst_port; + switch (atyp) + { + 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; + } int bytesToSend; - lock (encryptionLock) + lock (_encryptionLock) { - if (closed) - { - return; - } - encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend); + if (_closed) return; + encryptor.Encrypt(_connetionRecvBuffer, bytesRead, _connetionSendBuffer, out bytesToSend); } - Logging.Debug(remote, bytesToSend, "TCP Relay", "@PipeConnectionReceiveCallback() (upload)"); - tcprelay.UpdateOutboundCounter(server, 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) { diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 8023f51f..9cd2a77a 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -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 services = new List(); services.Add(tcpRelay); diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index 8d25b904..3f371457 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -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=启动时检查更新 diff --git a/shadowsocks-csharp/Model/Configuration.cs b/shadowsocks-csharp/Model/Configuration.cs index 10a42124..91c95871 100755 --- a/shadowsocks-csharp/Model/Configuration.cs +++ b/shadowsocks-csharp/Model/Configuration.cs @@ -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"; diff --git a/shadowsocks-csharp/Util/Util.cs b/shadowsocks-csharp/Util/Util.cs index 207e5289..44ae5e8f 100755 --- a/shadowsocks-csharp/Util/Util.cs +++ b/shadowsocks-csharp/Util/Util.cs @@ -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) { diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 3a5e5367..42f0fa48 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -48,6 +48,7 @@ namespace Shadowsocks.View private MenuItem editGFWUserRuleItem; private MenuItem editOnlinePACItem; private MenuItem autoCheckUpdatesToggleItem; + private MenuItem VerboseLoggingToggleItem; private ConfigForm configForm; private List logForms = new List(); 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);