@@ -1,10 +1,10 @@ | |||||
using Shadowsocks.Model; | |||||
using System; | |||||
using System; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Net; | using System.Net; | ||||
using System.Net.NetworkInformation; | using System.Net.NetworkInformation; | ||||
using System.Net.Sockets; | using System.Net.Sockets; | ||||
using System.Text; | |||||
using Shadowsocks.Model; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
@@ -79,9 +79,7 @@ namespace Shadowsocks.Controller | |||||
// Start an asynchronous socket to listen for connections. | // Start an asynchronous socket to listen for connections. | ||||
Logging.Info("Shadowsocks started"); | Logging.Info("Shadowsocks started"); | ||||
_tcpSocket.BeginAccept( | |||||
new AsyncCallback(AcceptCallback), | |||||
_tcpSocket); | |||||
_tcpSocket.BeginAccept(new AsyncCallback(AcceptCallback), _tcpSocket); | |||||
UDPState udpState = new UDPState(); | UDPState udpState = new UDPState(); | ||||
_udpSocket.BeginReceiveFrom(udpState.buffer, 0, udpState.buffer.Length, 0, ref udpState.remoteEndPoint, new AsyncCallback(RecvFromCallback), udpState); | _udpSocket.BeginReceiveFrom(udpState.buffer, 0, udpState.buffer.Length, 0, ref udpState.remoteEndPoint, new AsyncCallback(RecvFromCallback), udpState); | ||||
} | } | ||||
@@ -1,8 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Net; | using System.Net; | ||||
using System.Net.Sockets; | using System.Net.Sockets; | ||||
using System.Text; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
@@ -1,31 +1,30 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Text; | |||||
using System.Net.Sockets; | |||||
using System.Net; | using System.Net; | ||||
using System.Net.Sockets; | |||||
using System.Timers; | |||||
using Shadowsocks.Controller.Strategy; | |||||
using Shadowsocks.Encryption; | using Shadowsocks.Encryption; | ||||
using Shadowsocks.Model; | using Shadowsocks.Model; | ||||
using Shadowsocks.Controller.Strategy; | |||||
using System.Timers; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
class TCPRelay : Listener.Service | class TCPRelay : Listener.Service | ||||
{ | { | ||||
private ShadowsocksController _controller; | private ShadowsocksController _controller; | ||||
private DateTime _lastSweepTime; | private DateTime _lastSweepTime; | ||||
public ISet<Handler> Handlers | |||||
public ISet<TCPHandler> Handlers | |||||
{ | { | ||||
get; set; | get; set; | ||||
} | } | ||||
public TCPRelay(ShadowsocksController controller) | public TCPRelay(ShadowsocksController controller) | ||||
{ | { | ||||
this._controller = controller; | |||||
this.Handlers = new HashSet<Handler>(); | |||||
this._lastSweepTime = DateTime.Now; | |||||
_controller = controller; | |||||
Handlers = new HashSet<TCPHandler>(); | |||||
_lastSweepTime = DateTime.Now; | |||||
} | } | ||||
public bool Handle(byte[] firstPacket, int length, Socket socket, object state) | public bool Handle(byte[] firstPacket, int length, Socket socket, object state) | ||||
@@ -39,22 +38,21 @@ namespace Shadowsocks.Controller | |||||
return false; | return false; | ||||
} | } | ||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); | socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); | ||||
Handler handler = new Handler(); | |||||
TCPHandler handler = new TCPHandler(this); | |||||
handler.connection = socket; | handler.connection = socket; | ||||
handler.controller = _controller; | handler.controller = _controller; | ||||
handler.relay = this; | handler.relay = this; | ||||
handler.Start(firstPacket, length); | handler.Start(firstPacket, length); | ||||
IList<Handler> handlersToClose = new List<Handler>(); | |||||
lock (this.Handlers) | |||||
IList<TCPHandler> handlersToClose = new List<TCPHandler>(); | |||||
lock (Handlers) | |||||
{ | { | ||||
this.Handlers.Add(handler); | |||||
Logging.Debug($"TCP connections: {Handlers.Count}"); | |||||
Handlers.Add(handler); | |||||
DateTime now = DateTime.Now; | DateTime now = DateTime.Now; | ||||
if (now - _lastSweepTime > TimeSpan.FromSeconds(1)) | if (now - _lastSweepTime > TimeSpan.FromSeconds(1)) | ||||
{ | { | ||||
_lastSweepTime = now; | _lastSweepTime = now; | ||||
foreach (Handler handler1 in this.Handlers) | |||||
foreach (TCPHandler handler1 in Handlers) | |||||
{ | { | ||||
if (now - handler1.lastActivity > TimeSpan.FromSeconds(900)) | if (now - handler1.lastActivity > TimeSpan.FromSeconds(900)) | ||||
{ | { | ||||
@@ -63,18 +61,28 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
} | } | ||||
} | } | ||||
foreach (Handler handler1 in handlersToClose) | |||||
foreach (TCPHandler handler1 in handlersToClose) | |||||
{ | { | ||||
Logging.Debug("Closing timed out TCP connection."); | Logging.Debug("Closing timed out TCP connection."); | ||||
handler1.Close(); | handler1.Close(); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
public void UpdateInboundCounter(long n) | |||||
{ | |||||
_controller.UpdateInboundCounter(n); | |||||
} | |||||
public void UpdateOutboundCounter(long n) | |||||
{ | |||||
_controller.UpdateOutboundCounter(n); | |||||
} | |||||
} | } | ||||
class Handler | |||||
class TCPHandler | |||||
{ | { | ||||
//public Encryptor encryptor; | |||||
// public Encryptor encryptor; | |||||
public IEncryptor encryptor; | public IEncryptor encryptor; | ||||
public Server server; | public Server server; | ||||
// Client socket. | // Client socket. | ||||
@@ -85,6 +93,7 @@ namespace Shadowsocks.Controller | |||||
public DateTime lastActivity; | public DateTime lastActivity; | ||||
private const int maxRetry = 4; | |||||
private int retryCount = 0; | private int retryCount = 0; | ||||
private bool connected; | private bool connected; | ||||
@@ -117,6 +126,12 @@ namespace Shadowsocks.Controller | |||||
private object decryptionLock = new object(); | private object decryptionLock = new object(); | ||||
private DateTime _startConnectTime; | private DateTime _startConnectTime; | ||||
private TCPRelay tcprelay; // TODO: tcprelay ?= relay | |||||
public TCPHandler(TCPRelay tcprelay) | |||||
{ | |||||
this.tcprelay = tcprelay; | |||||
} | |||||
public void CreateRemote() | public void CreateRemote() | ||||
{ | { | ||||
@@ -125,23 +140,23 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
throw new ArgumentException("No server configured"); | throw new ArgumentException("No server configured"); | ||||
} | } | ||||
this.encryptor = EncryptorFactory.GetEncryptor(server.method, server.password, server.auth, false); | |||||
encryptor = EncryptorFactory.GetEncryptor(server.method, server.password, server.auth, false); | |||||
this.server = server; | this.server = server; | ||||
} | } | ||||
public void Start(byte[] firstPacket, int length) | public void Start(byte[] firstPacket, int length) | ||||
{ | { | ||||
this._firstPacket = firstPacket; | |||||
this._firstPacketLength = length; | |||||
this.HandshakeReceive(); | |||||
this.lastActivity = DateTime.Now; | |||||
_firstPacket = firstPacket; | |||||
_firstPacketLength = length; | |||||
HandshakeReceive(); | |||||
lastActivity = DateTime.Now; | |||||
} | } | ||||
private void CheckClose() | private void CheckClose() | ||||
{ | { | ||||
if (connectionShutdown && remoteShutdown) | if (connectionShutdown && remoteShutdown) | ||||
{ | { | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -149,7 +164,6 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
lock (relay.Handlers) | lock (relay.Handlers) | ||||
{ | { | ||||
Logging.Debug($"TCP connections: {relay.Handlers.Count}"); | |||||
relay.Handlers.Remove(this); | relay.Handlers.Remove(this); | ||||
} | } | ||||
lock (this) | lock (this) | ||||
@@ -215,18 +229,17 @@ namespace Shadowsocks.Controller | |||||
response = new byte[] { 0, 91 }; | response = new byte[] { 0, 91 }; | ||||
Logging.Error("socks 5 protocol error"); | Logging.Error("socks 5 protocol error"); | ||||
} | } | ||||
Logging.Debug($"======Send Local Port, size:" + response.Length); | |||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null); | connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -240,21 +253,19 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
connection.EndSend(ar); | connection.EndSend(ar); | ||||
// +----+-----+-------+------+----------+----------+ | |||||
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | | |||||
// +----+-----+-------+------+----------+----------+ | |||||
// | 1 | 1 | X'00' | 1 | Variable | 2 | | |||||
// +----+-----+-------+------+----------+----------+ | |||||
// +-----+-----+-------+------+----------+----------+ | |||||
// | VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | | |||||
// +-----+-----+-------+------+----------+----------+ | |||||
// | 1 | 1 | X'00' | 1 | Variable | 2 | | |||||
// +-----+-----+-------+------+----------+----------+ | |||||
// Skip first 3 bytes | // Skip first 3 bytes | ||||
// TODO validate | // TODO validate | ||||
Logging.Debug($"======Receive Local Port, size:" + 3); | |||||
connection.BeginReceive(connetionRecvBuffer, 0, 3, 0, | |||||
new AsyncCallback(handshakeReceive2Callback), null); | |||||
connection.BeginReceive(connetionRecvBuffer, 0, 3, 0, new AsyncCallback(handshakeReceive2Callback), null); | |||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -274,7 +285,6 @@ namespace Shadowsocks.Controller | |||||
if (command == 1) | if (command == 1) | ||||
{ | { | ||||
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 }; | byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 }; | ||||
Logging.Debug($"======Send Local Port, size:" + response.Length); | |||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ResponseCallback), null); | connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ResponseCallback), null); | ||||
} | } | ||||
else if (command == 3) | else if (command == 3) | ||||
@@ -284,14 +294,14 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
Logging.Error("failed to recv data in handshakeReceive2Callback"); | |||||
this.Close(); | |||||
Logging.Debug("failed to recv data in Shadowsocks.Controller.TCPHandler.handshakeReceive2Callback()"); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -313,7 +323,6 @@ namespace Shadowsocks.Controller | |||||
address.CopyTo(response, 4); | address.CopyTo(response, 4); | ||||
response[response.Length - 1] = (byte)(port & 0xFF); | response[response.Length - 1] = (byte)(port & 0xFF); | ||||
response[response.Length - 2] = (byte)((port >> 8) & 0xFF); | response[response.Length - 2] = (byte)((port >> 8) & 0xFF); | ||||
Logging.Debug($"======Send Local Port, size:" + response.Length); | |||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ReadAll), true); | connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ReadAll), true); | ||||
} | } | ||||
@@ -328,29 +337,27 @@ namespace Shadowsocks.Controller | |||||
if (ar.AsyncState != null) | if (ar.AsyncState != null) | ||||
{ | { | ||||
connection.EndSend(ar); | connection.EndSend(ar); | ||||
Logging.Debug($"======Receive Local Port, size:" + RecvSize); | |||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(ReadAll), null); | |||||
Logging.Debug(remote, RecvSize, "TCP Relay"); | |||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(ReadAll), null); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
int bytesRead = connection.EndReceive(ar); | int bytesRead = connection.EndReceive(ar); | ||||
if (bytesRead > 0) | if (bytesRead > 0) | ||||
{ | { | ||||
Logging.Debug($"======Receive Local Port, size:" + RecvSize); | |||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(ReadAll), null); | |||||
Logging.Debug(remote, RecvSize, "TCP Relay"); | |||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(ReadAll), null); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -366,15 +373,16 @@ namespace Shadowsocks.Controller | |||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
// inner class | |||||
private class ServerTimer : Timer | private class ServerTimer : Timer | ||||
{ | { | ||||
public Server Server; | public Server Server; | ||||
public ServerTimer(int p) :base(p) | |||||
public ServerTimer(int p) : base(p) | |||||
{ | { | ||||
} | } | ||||
} | } | ||||
@@ -408,14 +416,12 @@ namespace Shadowsocks.Controller | |||||
connected = false; | connected = false; | ||||
// Connect to the remote endpoint. | // Connect to the remote endpoint. | ||||
Logging.Debug($"++++++Connect Server Port"); | |||||
remote.BeginConnect(remoteEP, | |||||
new AsyncCallback(ConnectCallback), connectTimer); | |||||
remote.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), connectTimer); | |||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -438,15 +444,15 @@ namespace Shadowsocks.Controller | |||||
private void RetryConnect() | private void RetryConnect() | ||||
{ | { | ||||
if (retryCount < 4) | |||||
if (retryCount < maxRetry) | |||||
{ | { | ||||
Logging.Debug("Connection failed, retrying"); | |||||
Logging.Debug($"Connection failed, retry ({retryCount})"); | |||||
StartConnect(); | StartConnect(); | ||||
retryCount++; | retryCount++; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -507,17 +513,13 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
try | try | ||||
{ | { | ||||
Logging.Debug($"++++++Receive Server Port, size:" + RecvSize); | |||||
remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(PipeRemoteReceiveCallback), null); | |||||
Logging.Debug($"======Receive Local Port, size:"+ RecvSize); | |||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(PipeConnectionReceiveCallback), null); | |||||
remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeRemoteReceiveCallback), null); | |||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeConnectionReceiveCallback), null); | |||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -531,10 +533,11 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
int bytesRead = remote.EndReceive(ar); | int bytesRead = remote.EndReceive(ar); | ||||
totalRead += bytesRead; | totalRead += bytesRead; | ||||
tcprelay.UpdateInboundCounter(bytesRead); | |||||
if (bytesRead > 0) | if (bytesRead > 0) | ||||
{ | { | ||||
this.lastActivity = DateTime.Now; | |||||
lastActivity = DateTime.Now; | |||||
int bytesToSend; | int bytesToSend; | ||||
lock (decryptionLock) | lock (decryptionLock) | ||||
{ | { | ||||
@@ -544,13 +547,13 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
encryptor.Decrypt(remoteRecvBuffer, bytesRead, remoteSendBuffer, out bytesToSend); | encryptor.Decrypt(remoteRecvBuffer, bytesRead, remoteSendBuffer, out bytesToSend); | ||||
} | } | ||||
Logging.Debug($"======Send Local Port, size:" + bytesToSend); | |||||
Logging.Debug(remote, bytesToSend, "TCP Relay", "@PipeRemoteReceiveCallback() (download)"); | |||||
connection.BeginSend(remoteSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeConnectionSendCallback), null); | connection.BeginSend(remoteSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeConnectionSendCallback), null); | ||||
IStrategy strategy = controller.GetCurrentStrategy(); | IStrategy strategy = controller.GetCurrentStrategy(); | ||||
if (strategy != null) | if (strategy != null) | ||||
{ | { | ||||
strategy.UpdateLastRead(this.server); | |||||
strategy.UpdateLastRead(server); | |||||
} | } | ||||
} | } | ||||
else | else | ||||
@@ -559,18 +562,18 @@ namespace Shadowsocks.Controller | |||||
connectionShutdown = true; | connectionShutdown = true; | ||||
CheckClose(); | CheckClose(); | ||||
if (totalRead == 0) | |||||
{ | |||||
// closed before anything received, reports as failure | |||||
// disable this feature | |||||
// controller.GetCurrentStrategy().SetFailure(this.server); | |||||
} | |||||
//if (totalRead == 0) | |||||
//{ | |||||
// // closed before anything received, reports as failure | |||||
// // disable this feature | |||||
// controller.GetCurrentStrategy().SetFailure(this.server); | |||||
//} | |||||
} | } | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -584,6 +587,7 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
int bytesRead = connection.EndReceive(ar); | int bytesRead = connection.EndReceive(ar); | ||||
totalWrite += bytesRead; | totalWrite += bytesRead; | ||||
tcprelay.UpdateOutboundCounter(bytesRead); | |||||
if (bytesRead > 0) | if (bytesRead > 0) | ||||
{ | { | ||||
@@ -596,13 +600,13 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend); | encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend); | ||||
} | } | ||||
Logging.Debug($"++++++Send Server Port, size:" + bytesToSend); | |||||
Logging.Debug(remote, bytesToSend, "TCP Relay", "@PipeConnectionReceiveCallback() (upload)"); | |||||
remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeRemoteSendCallback), null); | remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeRemoteSendCallback), null); | ||||
IStrategy strategy = controller.GetCurrentStrategy(); | IStrategy strategy = controller.GetCurrentStrategy(); | ||||
if (strategy != null) | if (strategy != null) | ||||
{ | { | ||||
strategy.UpdateLastWrite(this.server); | |||||
strategy.UpdateLastWrite(server); | |||||
} | } | ||||
} | } | ||||
else | else | ||||
@@ -615,7 +619,7 @@ namespace Shadowsocks.Controller | |||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -628,14 +632,12 @@ namespace Shadowsocks.Controller | |||||
try | try | ||||
{ | { | ||||
remote.EndSend(ar); | remote.EndSend(ar); | ||||
Logging.Debug($"======Receive Local Port, size:" + RecvSize); | |||||
connection.BeginReceive(this.connetionRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(PipeConnectionReceiveCallback), null); | |||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeConnectionReceiveCallback), null); | |||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
@@ -648,14 +650,12 @@ namespace Shadowsocks.Controller | |||||
try | try | ||||
{ | { | ||||
connection.EndSend(ar); | connection.EndSend(ar); | ||||
Logging.Debug($"++++++Receive Server Port, size:" + RecvSize); | |||||
remote.BeginReceive(this.remoteRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(PipeRemoteReceiveCallback), null); | |||||
remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeRemoteReceiveCallback), null); | |||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
Logging.LogUsefulException(e); | Logging.LogUsefulException(e); | ||||
this.Close(); | |||||
Close(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -1,12 +1,12 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Text; | |||||
using Shadowsocks.Encryption; | |||||
using Shadowsocks.Model; | |||||
using System.Net.Sockets; | |||||
using System.Net; | using System.Net; | ||||
using System.Net.Sockets; | |||||
using System.Runtime.CompilerServices; | using System.Runtime.CompilerServices; | ||||
using Shadowsocks.Controller.Strategy; | using Shadowsocks.Controller.Strategy; | ||||
using Shadowsocks.Encryption; | |||||
using Shadowsocks.Model; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
@@ -14,6 +14,10 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
private ShadowsocksController _controller; | private ShadowsocksController _controller; | ||||
private LRUCache<IPEndPoint, UDPHandler> _cache; | private LRUCache<IPEndPoint, UDPHandler> _cache; | ||||
public long outbound = 0; | |||||
public long inbound = 0; | |||||
public UDPRelay(ShadowsocksController controller) | public UDPRelay(ShadowsocksController controller) | ||||
{ | { | ||||
this._controller = controller; | this._controller = controller; | ||||
@@ -70,8 +74,8 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
_remoteEndPoint = new IPEndPoint(ipAddress, server.server_port); | _remoteEndPoint = new IPEndPoint(ipAddress, server.server_port); | ||||
_remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); | _remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); | ||||
} | } | ||||
public void Send(byte[] data, int length) | public void Send(byte[] data, int length) | ||||
{ | { | ||||
IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password, _server.auth, true); | IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password, _server.auth, true); | ||||
@@ -80,15 +84,17 @@ namespace Shadowsocks.Controller | |||||
byte[] dataOut = new byte[length - 3 + 16 + IVEncryptor.ONETIMEAUTH_BYTES]; | byte[] dataOut = new byte[length - 3 + 16 + IVEncryptor.ONETIMEAUTH_BYTES]; | ||||
int outlen; | int outlen; | ||||
encryptor.Encrypt(dataIn, length - 3, dataOut, out outlen); | encryptor.Encrypt(dataIn, length - 3, dataOut, out outlen); | ||||
Logging.Debug($"++++++Send Server Port, size:" + outlen); | |||||
Logging.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay"); | |||||
_remote.SendTo(dataOut, outlen, SocketFlags.None, _remoteEndPoint); | _remote.SendTo(dataOut, outlen, SocketFlags.None, _remoteEndPoint); | ||||
} | } | ||||
public void Receive() | public void Receive() | ||||
{ | { | ||||
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); | EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); | ||||
Logging.Debug($"++++++Receive Server Port, size:" + _buffer.Length); | Logging.Debug($"++++++Receive Server Port, size:" + _buffer.Length); | ||||
_remote.BeginReceiveFrom(_buffer, 0, _buffer.Length, 0, ref remoteEndPoint, new AsyncCallback(RecvFromCallback), null); | _remote.BeginReceiveFrom(_buffer, 0, _buffer.Length, 0, ref remoteEndPoint, new AsyncCallback(RecvFromCallback), null); | ||||
} | } | ||||
public void RecvFromCallback(IAsyncResult ar) | public void RecvFromCallback(IAsyncResult ar) | ||||
{ | { | ||||
try | try | ||||
@@ -105,7 +111,7 @@ namespace Shadowsocks.Controller | |||||
byte[] sendBuf = new byte[outlen + 3]; | byte[] sendBuf = new byte[outlen + 3]; | ||||
Array.Copy(dataOut, 0, sendBuf, 3, outlen); | Array.Copy(dataOut, 0, sendBuf, 3, outlen); | ||||
Logging.Debug($"======Send Local Port, size:" + (outlen + 3)); | |||||
Logging.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay"); | |||||
_local.SendTo(sendBuf, outlen + 3, 0, _localEndPoint); | _local.SendTo(sendBuf, outlen + 3, 0, _localEndPoint); | ||||
Receive(); | Receive(); | ||||
} | } | ||||
@@ -121,6 +127,7 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
} | } | ||||
} | } | ||||
public void Close() | public void Close() | ||||
{ | { | ||||
try | try | ||||
@@ -142,7 +149,6 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
} | } | ||||
// cc by-sa 3.0 http://stackoverflow.com/a/3719378/1124054 | // cc by-sa 3.0 http://stackoverflow.com/a/3719378/1124054 | ||||
class LRUCache<K, V> where V : UDPRelay.UDPHandler | class LRUCache<K, V> where V : UDPRelay.UDPHandler | ||||
{ | { | ||||
@@ -1,14 +1,15 @@ | |||||
using System.IO; | |||||
using Shadowsocks.Model; | |||||
using System; | |||||
using System; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.IO; | |||||
using System.Net; | |||||
using System.Net.Sockets; | |||||
using System.Text; | using System.Text; | ||||
using System.Threading; | using System.Threading; | ||||
using System.Net.Sockets; | |||||
using Shadowsocks.Controller.Strategy; | using Shadowsocks.Controller.Strategy; | ||||
using System.Net; | |||||
using Shadowsocks.Util; | |||||
using Shadowsocks.Model; | |||||
using Shadowsocks.Properties; | using Shadowsocks.Properties; | ||||
using Shadowsocks.Util; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
@@ -30,6 +31,9 @@ namespace Shadowsocks.Controller | |||||
public AvailabilityStatistics availabilityStatistics { get; private set; } | public AvailabilityStatistics availabilityStatistics { get; private set; } | ||||
public StatisticsStrategyConfiguration StatisticsConfiguration { get; private set; } | public StatisticsStrategyConfiguration StatisticsConfiguration { get; private set; } | ||||
public long inboundCounter = 0; | |||||
public long outboundCounter = 0; | |||||
private bool stopped = false; | private bool stopped = false; | ||||
private bool _systemProxyIsDirty = false; | private bool _systemProxyIsDirty = false; | ||||
@@ -62,7 +66,6 @@ namespace Shadowsocks.Controller | |||||
StartReleasingMemory(); | StartReleasingMemory(); | ||||
} | } | ||||
public void Start() | public void Start() | ||||
{ | { | ||||
Reload(); | Reload(); | ||||
@@ -302,6 +305,16 @@ namespace Shadowsocks.Controller | |||||
Configuration.Save(_config); | Configuration.Save(_config); | ||||
} | } | ||||
public void UpdateInboundCounter(long n) | |||||
{ | |||||
inboundCounter += n; | |||||
} | |||||
public void UpdateOutboundCounter(long n) | |||||
{ | |||||
outboundCounter += n; | |||||
} | |||||
protected void Reload() | protected void Reload() | ||||
{ | { | ||||
// some logic in configuration updated the config when saving, we need to read it again | // some logic in configuration updated the config when saving, we need to read it again | ||||
@@ -1,10 +1,8 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using System.IO; | using System.IO; | ||||
using System.IO.Compression; | using System.IO.Compression; | ||||
using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
using System.Text; | |||||
using System.Windows.Forms; | using System.Windows.Forms; | ||||
using Shadowsocks.Controller; | using Shadowsocks.Controller; | ||||
@@ -85,6 +83,33 @@ namespace Shadowsocks.Util | |||||
} | } | ||||
} | } | ||||
public static string FormatBandwide(long n) | |||||
{ | |||||
float f = n; | |||||
string unit = "B"; | |||||
if (f > 1024) | |||||
{ | |||||
f = f / 1024; | |||||
unit = "KiB"; | |||||
} | |||||
if (f > 1024) | |||||
{ | |||||
f = f / 1024; | |||||
unit = "MiB"; | |||||
} | |||||
if (f > 1024) | |||||
{ | |||||
f = f / 1024; | |||||
unit = "GiB"; | |||||
} | |||||
if (f > 1024) | |||||
{ | |||||
f = f / 1024; | |||||
unit = "TiB"; | |||||
} | |||||
return $"{f:.##}{unit}"; | |||||
} | |||||
[DllImport("kernel32.dll")] | [DllImport("kernel32.dll")] | ||||
[return: MarshalAs(UnmanagedType.Bool)] | [return: MarshalAs(UnmanagedType.Bool)] | ||||
private static extern bool SetProcessWorkingSetSize(IntPtr process, | private static extern bool SetProcessWorkingSetSize(IntPtr process, | ||||
@@ -57,13 +57,13 @@ | |||||
this.LogMessageTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | this.LogMessageTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | ||||
this.LogMessageTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); | this.LogMessageTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); | ||||
this.LogMessageTextBox.ForeColor = System.Drawing.Color.White; | this.LogMessageTextBox.ForeColor = System.Drawing.Color.White; | ||||
this.LogMessageTextBox.Location = new System.Drawing.Point(3, 38); | |||||
this.LogMessageTextBox.Location = new System.Drawing.Point(3, 40); | |||||
this.LogMessageTextBox.MaxLength = 2147483647; | this.LogMessageTextBox.MaxLength = 2147483647; | ||||
this.LogMessageTextBox.Multiline = true; | this.LogMessageTextBox.Multiline = true; | ||||
this.LogMessageTextBox.Name = "LogMessageTextBox"; | this.LogMessageTextBox.Name = "LogMessageTextBox"; | ||||
this.LogMessageTextBox.ReadOnly = true; | this.LogMessageTextBox.ReadOnly = true; | ||||
this.LogMessageTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both; | this.LogMessageTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both; | ||||
this.LogMessageTextBox.Size = new System.Drawing.Size(378, 99); | |||||
this.LogMessageTextBox.Size = new System.Drawing.Size(378, 131); | |||||
this.LogMessageTextBox.TabIndex = 0; | this.LogMessageTextBox.TabIndex = 0; | ||||
// | // | ||||
// MainMenu | // MainMenu | ||||
@@ -141,12 +141,12 @@ | |||||
// | // | ||||
// TopMostCheckBox | // TopMostCheckBox | ||||
// | // | ||||
this.TopMostCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | |||||
this.TopMostCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | |||||
| System.Windows.Forms.AnchorStyles.Left))); | | System.Windows.Forms.AnchorStyles.Left))); | ||||
this.TopMostCheckBox.AutoSize = true; | this.TopMostCheckBox.AutoSize = true; | ||||
this.TopMostCheckBox.Location = new System.Drawing.Point(249, 3); | |||||
this.TopMostCheckBox.Location = new System.Drawing.Point(247, 3); | |||||
this.TopMostCheckBox.Name = "TopMostCheckBox"; | this.TopMostCheckBox.Name = "TopMostCheckBox"; | ||||
this.TopMostCheckBox.Size = new System.Drawing.Size(72, 23); | |||||
this.TopMostCheckBox.Size = new System.Drawing.Size(71, 25); | |||||
this.TopMostCheckBox.TabIndex = 3; | this.TopMostCheckBox.TabIndex = 3; | ||||
this.TopMostCheckBox.Text = "&Top Most"; | this.TopMostCheckBox.Text = "&Top Most"; | ||||
this.TopMostCheckBox.UseVisualStyleBackColor = true; | this.TopMostCheckBox.UseVisualStyleBackColor = true; | ||||
@@ -157,7 +157,7 @@ | |||||
this.ChangeFontButton.AutoSize = true; | this.ChangeFontButton.AutoSize = true; | ||||
this.ChangeFontButton.Location = new System.Drawing.Point(84, 3); | this.ChangeFontButton.Location = new System.Drawing.Point(84, 3); | ||||
this.ChangeFontButton.Name = "ChangeFontButton"; | this.ChangeFontButton.Name = "ChangeFontButton"; | ||||
this.ChangeFontButton.Size = new System.Drawing.Size(75, 23); | |||||
this.ChangeFontButton.Size = new System.Drawing.Size(75, 25); | |||||
this.ChangeFontButton.TabIndex = 2; | this.ChangeFontButton.TabIndex = 2; | ||||
this.ChangeFontButton.Text = "&Font"; | this.ChangeFontButton.Text = "&Font"; | ||||
this.ChangeFontButton.UseVisualStyleBackColor = true; | this.ChangeFontButton.UseVisualStyleBackColor = true; | ||||
@@ -168,7 +168,7 @@ | |||||
this.CleanLogsButton.AutoSize = true; | this.CleanLogsButton.AutoSize = true; | ||||
this.CleanLogsButton.Location = new System.Drawing.Point(3, 3); | this.CleanLogsButton.Location = new System.Drawing.Point(3, 3); | ||||
this.CleanLogsButton.Name = "CleanLogsButton"; | this.CleanLogsButton.Name = "CleanLogsButton"; | ||||
this.CleanLogsButton.Size = new System.Drawing.Size(75, 23); | |||||
this.CleanLogsButton.Size = new System.Drawing.Size(75, 25); | |||||
this.CleanLogsButton.TabIndex = 1; | this.CleanLogsButton.TabIndex = 1; | ||||
this.CleanLogsButton.Text = "&Clean Logs"; | this.CleanLogsButton.Text = "&Clean Logs"; | ||||
this.CleanLogsButton.UseVisualStyleBackColor = true; | this.CleanLogsButton.UseVisualStyleBackColor = true; | ||||
@@ -176,12 +176,12 @@ | |||||
// | // | ||||
// WrapTextCheckBox | // WrapTextCheckBox | ||||
// | // | ||||
this.WrapTextCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | |||||
this.WrapTextCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | |||||
| System.Windows.Forms.AnchorStyles.Left))); | | System.Windows.Forms.AnchorStyles.Left))); | ||||
this.WrapTextCheckBox.AutoSize = true; | this.WrapTextCheckBox.AutoSize = true; | ||||
this.WrapTextCheckBox.Location = new System.Drawing.Point(165, 3); | this.WrapTextCheckBox.Location = new System.Drawing.Point(165, 3); | ||||
this.WrapTextCheckBox.Name = "WrapTextCheckBox"; | this.WrapTextCheckBox.Name = "WrapTextCheckBox"; | ||||
this.WrapTextCheckBox.Size = new System.Drawing.Size(78, 23); | |||||
this.WrapTextCheckBox.Size = new System.Drawing.Size(76, 25); | |||||
this.WrapTextCheckBox.TabIndex = 0; | this.WrapTextCheckBox.TabIndex = 0; | ||||
this.WrapTextCheckBox.Text = "&Wrap Text"; | this.WrapTextCheckBox.Text = "&Wrap Text"; | ||||
this.WrapTextCheckBox.UseVisualStyleBackColor = true; | this.WrapTextCheckBox.UseVisualStyleBackColor = true; | ||||
@@ -199,7 +199,7 @@ | |||||
this.tableLayoutPanel1.RowCount = 2; | this.tableLayoutPanel1.RowCount = 2; | ||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | ||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | ||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(384, 140); | |||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(384, 174); | |||||
this.tableLayoutPanel1.TabIndex = 2; | this.tableLayoutPanel1.TabIndex = 2; | ||||
// | // | ||||
// ToolbarFlowLayoutPanel | // ToolbarFlowLayoutPanel | ||||
@@ -212,17 +212,17 @@ | |||||
this.ToolbarFlowLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; | this.ToolbarFlowLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; | ||||
this.ToolbarFlowLayoutPanel.Location = new System.Drawing.Point(3, 3); | this.ToolbarFlowLayoutPanel.Location = new System.Drawing.Point(3, 3); | ||||
this.ToolbarFlowLayoutPanel.Name = "ToolbarFlowLayoutPanel"; | this.ToolbarFlowLayoutPanel.Name = "ToolbarFlowLayoutPanel"; | ||||
this.ToolbarFlowLayoutPanel.Size = new System.Drawing.Size(378, 29); | |||||
this.ToolbarFlowLayoutPanel.Size = new System.Drawing.Size(378, 31); | |||||
this.ToolbarFlowLayoutPanel.TabIndex = 2; | this.ToolbarFlowLayoutPanel.TabIndex = 2; | ||||
// | // | ||||
// LogForm | // LogForm | ||||
// | // | ||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); | |||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); | |||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; | ||||
this.ClientSize = new System.Drawing.Size(384, 140); | |||||
this.ClientSize = new System.Drawing.Size(384, 174); | |||||
this.Controls.Add(this.tableLayoutPanel1); | this.Controls.Add(this.tableLayoutPanel1); | ||||
this.Menu = this.MainMenu; | this.Menu = this.MainMenu; | ||||
this.MinimumSize = new System.Drawing.Size(400, 200); | |||||
this.MinimumSize = new System.Drawing.Size(400, 213); | |||||
this.Name = "LogForm"; | this.Name = "LogForm"; | ||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; | ||||
this.Text = "Log Viewer"; | this.Text = "Log Viewer"; | ||||
@@ -1,16 +1,12 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.ComponentModel; | |||||
using System.Data; | |||||
using System.Drawing; | using System.Drawing; | ||||
using System.IO; | using System.IO; | ||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Windows.Forms; | using System.Windows.Forms; | ||||
using Shadowsocks.Controller; | using Shadowsocks.Controller; | ||||
using Shadowsocks.Properties; | using Shadowsocks.Properties; | ||||
using Shadowsocks.Model; | using Shadowsocks.Model; | ||||
using Shadowsocks.Util; | |||||
namespace Shadowsocks.View | namespace Shadowsocks.View | ||||
{ | { | ||||
@@ -112,11 +108,14 @@ namespace Shadowsocks.View | |||||
lastOffset = reader.BaseStream.Position; | lastOffset = reader.BaseStream.Position; | ||||
} | } | ||||
this.Text = $"Log Viewer [in: {Utils.FormatBandwide(controller.inboundCounter)}, out: {Utils.FormatBandwide(controller.outboundCounter)}]"; | |||||
} | } | ||||
private void LogForm_Load(object sender, EventArgs e) | private void LogForm_Load(object sender, EventArgs e) | ||||
{ | { | ||||
InitContent(); | InitContent(); | ||||
timer = new Timer(); | timer = new Timer(); | ||||
timer.Interval = 300; | timer.Interval = 300; | ||||
timer.Tick += Timer_Tick; | timer.Tick += Timer_Tick; | ||||
@@ -117,7 +117,31 @@ | |||||
<resheader name="writer"> | <resheader name="writer"> | ||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
</resheader> | </resheader> | ||||
<metadata name="LogMessageTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||||
<value>True</value> | |||||
</metadata> | |||||
<metadata name="MainMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> | <metadata name="MainMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> | ||||
<value>17, 17</value> | <value>17, 17</value> | ||||
</metadata> | </metadata> | ||||
<metadata name="TopMostCheckBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||||
<value>True</value> | |||||
</metadata> | |||||
<metadata name="ChangeFontButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||||
<value>True</value> | |||||
</metadata> | |||||
<metadata name="CleanLogsButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||||
<value>True</value> | |||||
</metadata> | |||||
<metadata name="WrapTextCheckBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||||
<value>True</value> | |||||
</metadata> | |||||
<metadata name="tableLayoutPanel1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||||
<value>True</value> | |||||
</metadata> | |||||
<metadata name="ToolbarFlowLayoutPanel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||||
<value>True</value> | |||||
</metadata> | |||||
<metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||||
<value>True</value> | |||||
</metadata> | |||||
</root> | </root> |