Browse Source

Merge branch 'dev_proxy' of https://github.com/Noisyfox/shadowsocks-windows into Noisyfox-dev_proxy

tags/3.2
Syrone Wong 8 years ago
parent
commit
dc591413ce
12 changed files with 1091 additions and 23 deletions
  1. +125
    -22
      shadowsocks-csharp/Controller/Service/TCPRelay.cs
  2. +14
    -0
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  3. +8
    -0
      shadowsocks-csharp/Data/cn.txt
  4. +4
    -1
      shadowsocks-csharp/Model/Configuration.cs
  5. +96
    -0
      shadowsocks-csharp/Proxy/DirectConnect.cs
  6. +38
    -0
      shadowsocks-csharp/Proxy/IProxy.cs
  7. +312
    -0
      shadowsocks-csharp/Proxy/Socks5Proxy.cs
  8. +28
    -0
      shadowsocks-csharp/View/MenuViewController.cs
  9. +218
    -0
      shadowsocks-csharp/View/ProxyForm.Designer.cs
  10. +116
    -0
      shadowsocks-csharp/View/ProxyForm.cs
  11. +120
    -0
      shadowsocks-csharp/View/ProxyForm.resx
  12. +12
    -0
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 125
- 22
shadowsocks-csharp/Controller/Service/TCPRelay.cs View File

@@ -8,6 +8,7 @@ using System.Timers;
using Shadowsocks.Controller.Strategy;
using Shadowsocks.Encryption;
using Shadowsocks.Model;
using Shadowsocks.Proxy;
namespace Shadowsocks.Controller
{
@@ -87,16 +88,17 @@ namespace Shadowsocks.Controller
public IEncryptor encryptor;
public Server server;
// Client socket.
public Socket remote;
public IProxy remote;
public Socket connection;
public ShadowsocksController controller;
public TCPRelay tcprelay;
public DateTime lastActivity;
private const int _maxRetry = 4;
private const int MaxRetry = 4;
private int _retryCount = 0;
private bool _connected;
private bool _proxyConnected;
private bool _destConnected;
private byte _command;
private byte[] _firstPacket;
@@ -126,8 +128,8 @@ namespace Shadowsocks.Controller
public TCPHandler(TCPRelay tcprelay, Configuration config)
{
_tcprelay = tcprelay;
_config = config;
this._tcprelay = tcprelay;
this._config = config;
}
public void CreateRemote()
@@ -300,7 +302,7 @@ namespace Shadowsocks.Controller
if (ar.AsyncState != null)
{
connection.EndSend(ar);
Logging.Debug(remote, RecvSize, "TCP Relay");
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
}
else
@@ -308,7 +310,7 @@ namespace Shadowsocks.Controller
int bytesRead = connection.EndReceive(ar);
if (bytesRead > 0)
{
Logging.Debug(remote, RecvSize, "TCP Relay");
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
}
else
@@ -337,6 +339,16 @@ namespace Shadowsocks.Controller
}
// inner class
private class ProxyTimer : Timer
{
public EndPoint DestEndPoint;
public Server Server;
public ProxyTimer(int p) : base(p)
{
}
}
private class ServerTimer : Timer
{
public Server Server;
@@ -357,32 +369,118 @@ namespace Shadowsocks.Controller
IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server);
ipAddress = ipHostInfo.AddressList[0];
}
IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port);
IPEndPoint destEP = new IPEndPoint(ipAddress, server.server_port);
// Setting up proxy
IPEndPoint proxyEP;
if (_config.useProxy)
{
parsed = IPAddress.TryParse(_config.proxyServer, out ipAddress);
if (!parsed)
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(_config.proxyServer);
ipAddress = ipHostInfo.AddressList[0];
}
remote = new Socks5Proxy();
proxyEP = new IPEndPoint(ipAddress, _config.proxyPort);
}
else
{
remote = new DirectConnect();
proxyEP = destEP;
}
remote = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
ProxyTimer proxyTimer = new ProxyTimer(3000);
proxyTimer.AutoReset = false;
proxyTimer.Elapsed += proxyConnectTimer_Elapsed;
proxyTimer.Enabled = true;
proxyTimer.DestEndPoint = destEP;
proxyTimer.Server = server;
_proxyConnected = false;
// Connect to the proxy server.
remote.BeginConnectProxy(proxyEP, new AsyncCallback(ProxyConnectCallback), proxyTimer);
}
catch (Exception e)
{
Logging.LogUsefulException(e);
Close();
}
}
private void proxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_proxyConnected || _destConnected)
{
return;
}
var ep = ((ProxyTimer)sender).DestEndPoint;
Logging.Info($"Proxy {ep} timed out");
remote.Close();
RetryConnect();
}
private void ProxyConnectCallback(IAsyncResult ar)
{
Server server = null;
if (_closed)
{
return;
}
try
{
ProxyTimer timer = (ProxyTimer)ar.AsyncState;
var destEP = timer.DestEndPoint;
server = timer.Server;
timer.Elapsed -= proxyConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
// Complete the connection.
remote.EndConnectProxy(ar);
_proxyConnected = true;
if (_config.isVerboseLogging)
{
if (!(remote is DirectConnect))
{
Logging.Info($"Socket connected to proxy {remote.ProxyEndPoint}");
}
}
_startConnectTime = DateTime.Now;
ServerTimer connectTimer = new ServerTimer(3000);
connectTimer.AutoReset = false;
connectTimer.Elapsed += connectTimer_Elapsed;
connectTimer.Elapsed += destConnectTimer_Elapsed;
connectTimer.Enabled = true;
connectTimer.Server = server;
_connected = false;
_destConnected = false;
// Connect to the remote endpoint.
remote.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), connectTimer);
remote.BeginConnectDest(destEP, new AsyncCallback(ConnectCallback), connectTimer);
}
catch (ArgumentException)
{
}
catch (Exception e)
{
Logging.LogUsefulException(e);
Close();
RetryConnect();
}
}
private void connectTimer_Elapsed(object sender, ElapsedEventArgs e)
private void destConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_connected) return;
if (_destConnected)
{
return;
}
Server server = ((ServerTimer)sender).Server;
IStrategy strategy = controller.GetCurrentStrategy();
strategy?.SetFailure(server);
@@ -393,7 +491,7 @@ namespace Shadowsocks.Controller
private void RetryConnect()
{
if (_retryCount < _maxRetry)
if (_retryCount < MaxRetry)
{
Logging.Debug($"Connection failed, retry ({_retryCount})");
StartConnect();
@@ -409,15 +507,20 @@ namespace Shadowsocks.Controller
try
{
ServerTimer timer = (ServerTimer)ar.AsyncState;
Server server = timer.Server;
timer.Elapsed -= connectTimer_Elapsed;
server = timer.Server;
timer.Elapsed -= destConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
// Complete the connection.
remote.EndConnect(ar);
remote.EndConnectDest(ar);
_destConnected = true;
_connected = true;
if (_config.isVerboseLogging)
{
Logging.Info($"Socket connected to ss server {remote.DestEndPoint}");
}
var latency = DateTime.Now - _startConnectTime;
IStrategy strategy = controller.GetCurrentStrategy();


+ 14
- 0
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -213,6 +213,20 @@ namespace Shadowsocks.Controller
}
}
public void DisableProxy()
{
_config.useProxy = false;
SaveConfig(_config);
}
public void EnableProxy(string proxy, int port)
{
_config.useProxy = true;
_config.proxyServer = proxy;
_config.proxyPort = port;
SaveConfig(_config);
}
public void ToggleVerboseLogging(bool enabled)
{
_config.isVerboseLogging = enabled;


+ 8
- 0
shadowsocks-csharp/Data/cn.txt View File

@@ -12,6 +12,7 @@ Servers=服务器
Edit Servers...=编辑服务器...
Statistics Config...=统计配置...
Start on Boot=开机启动
Proxy...=代理设置...
Allow Clients from LAN=允许来自局域网的连接
Local PAC=使用本地 PAC
Online PAC=使用在线 PAC
@@ -51,6 +52,13 @@ New server=未配置的服务器
Move &Up=上移(&U)
Move D&own=下移(&O)

# Proxy Form

Edit Proxy=代理设置
Use Proxy=使用代理
Proxy Addr=代理地址
Proxy Port=代理端口

# Log Form

&File=文件(&F)


+ 4
- 1
shadowsocks-csharp/Model/Configuration.cs View File

@@ -26,6 +26,9 @@ namespace Shadowsocks.Model
public bool autoCheckUpdate;
public bool isVerboseLogging;
public LogViewerConfig logViewer;
public bool useProxy;
public string proxyServer;
public int proxyPort;
private static string CONFIG_FILE = "gui-config.json";
@@ -129,7 +132,7 @@ namespace Shadowsocks.Model
throw new ArgumentException(I18N.GetString("Password can not be blank"));
}
private static void CheckServer(string server)
public static void CheckServer(string server)
{
if (server.IsNullOrEmpty())
throw new ArgumentException(I18N.GetString("Server IP can not be blank"));


+ 96
- 0
shadowsocks-csharp/Proxy/DirectConnect.cs View File

@@ -0,0 +1,96 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Shadowsocks.Proxy
{
public class DirectConnect : IProxy
{
private class FakeAsyncResult : IAsyncResult
{
public FakeAsyncResult(object state)
{
AsyncState = state;
}

public bool IsCompleted { get; } = true;
public WaitHandle AsyncWaitHandle { get; } = null;
public object AsyncState { get; }
public bool CompletedSynchronously { get; } = true;
}

private Socket _remote;

public EndPoint LocalEndPoint => _remote.LocalEndPoint;

public EndPoint ProxyEndPoint { get; private set; }

public EndPoint DestEndPoint { get; private set; }


public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state)
{
// do nothing
ProxyEndPoint = remoteEP;

var r = new FakeAsyncResult(state);
callback?.Invoke(r);
}

public void EndConnectProxy(IAsyncResult asyncResult)
{
// do nothing
}

public void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state)
{
if (_remote == null)
{
_remote = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
}

DestEndPoint = remoteEP;

_remote.BeginConnect(remoteEP, callback, state);
}

public void EndConnectDest(IAsyncResult asyncResult)
{
_remote.EndConnect(asyncResult);
}

public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state)
{
_remote.BeginSend(buffer, offset, size, socketFlags, callback, state);
}

public int EndSend(IAsyncResult asyncResult)
{
return _remote.EndSend(asyncResult);
}

public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state)
{
_remote.BeginReceive(buffer, offset, size, socketFlags, callback, state);
}

public int EndReceive(IAsyncResult asyncResult)
{
return _remote.EndReceive(asyncResult);
}

public void Shutdown(SocketShutdown how)
{
_remote?.Shutdown(how);
}

public void Close()
{
_remote?.Close();
}
}
}

+ 38
- 0
shadowsocks-csharp/Proxy/IProxy.cs View File

@@ -0,0 +1,38 @@
using System;
using System.Net;
using System.Net.Sockets;

namespace Shadowsocks.Proxy
{

public interface IProxy
{
EndPoint LocalEndPoint { get; }

EndPoint ProxyEndPoint { get; }

EndPoint DestEndPoint { get; }

void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state);

void EndConnectProxy(IAsyncResult asyncResult);

void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state);

void EndConnectDest(IAsyncResult asyncResult);

void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state);

int EndSend(IAsyncResult asyncResult);

void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state);

int EndReceive(IAsyncResult asyncResult);

void Shutdown(SocketShutdown how);

void Close();
}
}

+ 312
- 0
shadowsocks-csharp/Proxy/Socks5Proxy.cs View File

@@ -0,0 +1,312 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Shadowsocks.Controller;

namespace Shadowsocks.Proxy
{
public class Socks5Proxy : IProxy
{
private class FakeAsyncResult : IAsyncResult
{
public readonly Socks5State innerState;

private readonly IAsyncResult r;

public FakeAsyncResult(IAsyncResult orig, Socks5State state)
{
r = orig;
innerState = state;
}

public bool IsCompleted => r.IsCompleted;
public WaitHandle AsyncWaitHandle => r.AsyncWaitHandle;
public object AsyncState => innerState.AsyncState;
public bool CompletedSynchronously => r.CompletedSynchronously;
}

private class Socks5State
{
public AsyncCallback Callback { get; set; }

public object AsyncState { get; set; }

public int BytesToRead;

public Exception ex { get; set; }
}

private Socket _remote;

private const int Socks5PktMaxSize = 4 + 16 + 2;
private readonly byte[] _receiveBuffer = new byte[Socks5PktMaxSize];

public EndPoint LocalEndPoint => _remote.LocalEndPoint;
public EndPoint ProxyEndPoint { get; private set; }
public EndPoint DestEndPoint { get; private set; }

public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state)
{
_remote = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);

var st = new Socks5State();
st.Callback = callback;
st.AsyncState = state;

ProxyEndPoint = remoteEP;

_remote.BeginConnect(remoteEP, ConnectCallback, st);
}

public void EndConnectProxy(IAsyncResult asyncResult)
{
var state = ((FakeAsyncResult)asyncResult).innerState;

if (state.ex != null)
{
throw state.ex;
}
}

public void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state)
{
var ep = remoteEP as IPEndPoint;
if (ep == null)
{
throw new Exception(I18N.GetString("Proxy request faild"));
}

byte[] request = null;
byte atyp = 0;
switch (ep.AddressFamily)
{
case AddressFamily.InterNetwork:
request = new byte[4 + 4 + 2];
atyp = 1;
break;
case AddressFamily.InterNetworkV6:
request = new byte[4 + 16 + 2];
atyp = 4;
break;
}
if (request == null)
{
throw new Exception(I18N.GetString("Proxy request faild"));
}

// 构造request包
var addr = ep.Address.GetAddressBytes();
request[0] = 5;
request[1] = 1;
request[2] = 0;
request[3] = atyp;
Array.Copy(addr, 0, request, 4, request.Length - 4 - 2);
request[request.Length - 2] = (byte) ((ep.Port >> 8) & 0xff);
request[request.Length - 1] = (byte) (ep.Port & 0xff);

var st = new Socks5State();
st.Callback = callback;
st.AsyncState = state;

DestEndPoint = remoteEP;

_remote.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st);

}

public void EndConnectDest(IAsyncResult asyncResult)
{
var state = ((FakeAsyncResult)asyncResult).innerState;

if (state.ex != null)
{
throw state.ex;
}
}

public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state)
{
_remote.BeginSend(buffer, offset, size, socketFlags, callback, state);
}

public int EndSend(IAsyncResult asyncResult)
{
return _remote.EndSend(asyncResult);
}

public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
object state)
{
_remote.BeginReceive(buffer, offset, size, socketFlags, callback, state);
}

public int EndReceive(IAsyncResult asyncResult)
{
return _remote.EndReceive(asyncResult);
}

public void Shutdown(SocketShutdown how)
{
_remote?.Shutdown(how);
}

public void Close()
{
_remote?.Close();
}

private void ConnectCallback(IAsyncResult ar)
{
var state = (Socks5State) ar.AsyncState;
try
{
_remote.EndConnect(ar);

byte[] handshake = {5, 1, 0};
_remote.BeginSend(handshake, 0, handshake.Length, 0, Socks5HandshakeSendCallback, state);
}
catch (Exception ex)
{
state.ex = ex;
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}
}

private void Socks5HandshakeSendCallback(IAsyncResult ar)
{
var state = (Socks5State)ar.AsyncState;
try
{
_remote.EndSend(ar);

_remote.BeginReceive(_receiveBuffer, 0, 2, 0, Socks5HandshakeReceiveCallback, state);
}
catch (Exception ex)
{
state.ex = ex;
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}
}

private void Socks5HandshakeReceiveCallback(IAsyncResult ar)
{
Exception ex = null;
var state = (Socks5State)ar.AsyncState;
try
{
var bytesRead = _remote.EndReceive(ar);
if (bytesRead >= 2)
{
if (_receiveBuffer[0] != 5 || _receiveBuffer[1] != 0)
{
ex = new Exception(I18N.GetString("Proxy handshake faild"));
}
}
else
{
ex = new Exception(I18N.GetString("Proxy handshake faild"));
}
}
catch (Exception ex2)
{
ex = ex2;
}
state.ex = ex;
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}


private void Socks5RequestSendCallback(IAsyncResult ar)
{
var state = (Socks5State)ar.AsyncState;
try
{
_remote.EndSend(ar);

_remote.BeginReceive(_receiveBuffer, 0, 4, 0, Socks5ReplyReceiveCallback, state);
}
catch (Exception ex)
{
state.ex = ex;
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}
}

private void Socks5ReplyReceiveCallback(IAsyncResult ar)
{
var state = (Socks5State)ar.AsyncState;
try
{
var bytesRead = _remote.EndReceive(ar);
if (bytesRead >= 4)
{
if (_receiveBuffer[0] == 5 && _receiveBuffer[1] == 0)
{
// 跳过剩下的reply
switch (_receiveBuffer[3]) // atyp
{
case 1:
state.BytesToRead = 4 + 2;
_remote.BeginReceive(_receiveBuffer, 0, 4 + 2, 0, Socks5ReplyReceiveCallback2, state);
break;
case 4:
state.BytesToRead = 16 + 2;
_remote.BeginReceive(_receiveBuffer, 0, 16 + 2, 0, Socks5ReplyReceiveCallback2, state);
break;
default:
state.ex = new Exception(I18N.GetString("Proxy request faild"));
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
break;
}
}
else
{
state.ex = new Exception(I18N.GetString("Proxy request faild"));
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}
}
else
{
state.ex = new Exception(I18N.GetString("Proxy request faild"));
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}
}
catch (Exception ex)
{
state.ex = ex;
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}
}


private void Socks5ReplyReceiveCallback2(IAsyncResult ar)
{
Exception ex = null;
var state = (Socks5State)ar.AsyncState;
try
{
var bytesRead = _remote.EndReceive(ar);
var bytesNeedSkip = state.BytesToRead;

if (bytesRead < bytesNeedSkip)
{
ex = new Exception(I18N.GetString("Proxy request faild"));
}
}
catch (Exception ex2)
{
ex = ex2;
}

state.ex = ex;
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}
}
}

+ 28
- 0
shadowsocks-csharp/View/MenuViewController.cs View File

@@ -48,8 +48,10 @@ namespace Shadowsocks.View
private MenuItem editGFWUserRuleItem;
private MenuItem editOnlinePACItem;
private MenuItem autoCheckUpdatesToggleItem;
private MenuItem proxyItem;
private MenuItem VerboseLoggingToggleItem;
private ConfigForm configForm;
private ProxyForm proxyForm;
private List<LogForm> logForms = new List<LogForm>();
private bool logFormsVisible = false;
private string _urlToOpen;
@@ -262,6 +264,7 @@ namespace Shadowsocks.View
this.editGFWUserRuleItem = CreateMenuItem("Edit User Rule for GFWList...", new EventHandler(this.EditUserRuleFileForGFWListItem_Click)),
this.editOnlinePACItem = CreateMenuItem("Edit Online PAC URL...", new EventHandler(this.UpdateOnlinePACURLItem_Click)),
}),
this.proxyItem = CreateMenuItem("Proxy...", new EventHandler(this.proxyItem_Click)),
new MenuItem("-"),
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
@@ -434,6 +437,20 @@ namespace Shadowsocks.View
}
}
private void ShowProxyForm()
{
if (proxyForm != null)
{
proxyForm.Activate();
}
else
{
proxyForm = new ProxyForm(controller);
proxyForm.Show();
proxyForm.FormClosed += proxyForm_FormClosed;
}
}
private void ShowLogForms()
{
if (logForms.Count == 0)
@@ -472,6 +489,12 @@ namespace Shadowsocks.View
}
}
void proxyForm_FormClosed(object sender, FormClosedEventArgs e)
{
proxyForm = null;
Utils.ReleaseMemory(true);
}
private void Config_Click(object sender, EventArgs e)
{
ShowConfigForm();
@@ -783,5 +806,10 @@ namespace Shadowsocks.View
{
updateChecker.CheckUpdate(controller.GetConfigurationCopy());
}
private void proxyItem_Click(object sender, EventArgs e)
{
ShowProxyForm();
}
}
}

+ 218
- 0
shadowsocks-csharp/View/ProxyForm.Designer.cs View File

@@ -0,0 +1,218 @@
namespace Shadowsocks.View
{
partial class ProxyForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.MyCancelButton = new System.Windows.Forms.Button();
this.OKButton = new System.Windows.Forms.Button();
this.UseProxyCheckBox = new System.Windows.Forms.CheckBox();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.ProxyAddrLabel = new System.Windows.Forms.Label();
this.ProxyServerTextBox = new System.Windows.Forms.TextBox();
this.ProxyPortLable = new System.Windows.Forms.Label();
this.ProxyPortTextBox = new System.Windows.Forms.TextBox();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.AutoSize = true;
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 1);
this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
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(395, 87);
this.tableLayoutPanel1.TabIndex = 0;
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.AutoSize = true;
this.tableLayoutPanel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel3.ColumnCount = 2;
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0);
this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right;
this.tableLayoutPanel3.Location = new System.Drawing.Point(236, 58);
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 1;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.Size = new System.Drawing.Size(159, 26);
this.tableLayoutPanel3.TabIndex = 9;
//
// MyCancelButton
//
this.MyCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.MyCancelButton.Dock = System.Windows.Forms.DockStyle.Right;
this.MyCancelButton.Location = new System.Drawing.Point(84, 3);
this.MyCancelButton.Margin = new System.Windows.Forms.Padding(3, 3, 0, 0);
this.MyCancelButton.Name = "MyCancelButton";
this.MyCancelButton.Size = new System.Drawing.Size(75, 23);
this.MyCancelButton.TabIndex = 13;
this.MyCancelButton.Text = "Cancel";
this.MyCancelButton.UseVisualStyleBackColor = true;
this.MyCancelButton.Click += new System.EventHandler(this.CancelButton_Click);
//
// OKButton
//
this.OKButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.OKButton.Dock = System.Windows.Forms.DockStyle.Right;
this.OKButton.Location = new System.Drawing.Point(3, 3);
this.OKButton.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.OKButton.Name = "OKButton";
this.OKButton.Size = new System.Drawing.Size(75, 23);
this.OKButton.TabIndex = 12;
this.OKButton.Text = "OK";
this.OKButton.UseVisualStyleBackColor = true;
this.OKButton.Click += new System.EventHandler(this.OKButton_Click);
//
// UseProxyCheckBox
//
this.UseProxyCheckBox.AutoSize = true;
this.UseProxyCheckBox.Location = new System.Drawing.Point(3, 3);
this.UseProxyCheckBox.Name = "UseProxyCheckBox";
this.UseProxyCheckBox.Size = new System.Drawing.Size(78, 16);
this.UseProxyCheckBox.TabIndex = 0;
this.UseProxyCheckBox.Text = "Use Proxy";
this.UseProxyCheckBox.UseVisualStyleBackColor = true;
this.UseProxyCheckBox.CheckedChanged += new System.EventHandler(this.UseProxyCheckBox_CheckedChanged);
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.AutoSize = true;
this.tableLayoutPanel2.ColumnCount = 4;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.Controls.Add(this.ProxyAddrLabel, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.ProxyServerTextBox, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.ProxyPortLable, 2, 0);
this.tableLayoutPanel2.Controls.Add(this.ProxyPortTextBox, 3, 0);
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 25);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 1;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(389, 27);
this.tableLayoutPanel2.TabIndex = 1;
//
// ProxyAddrLabel
//
this.ProxyAddrLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.ProxyAddrLabel.AutoSize = true;
this.ProxyAddrLabel.Location = new System.Drawing.Point(3, 7);
this.ProxyAddrLabel.Name = "ProxyAddrLabel";
this.ProxyAddrLabel.Size = new System.Drawing.Size(65, 12);
this.ProxyAddrLabel.TabIndex = 0;
this.ProxyAddrLabel.Text = "Proxy Addr";
//
// ProxyServerTextBox
//
this.ProxyServerTextBox.Location = new System.Drawing.Point(74, 3);
this.ProxyServerTextBox.MaxLength = 512;
this.ProxyServerTextBox.Name = "ProxyServerTextBox";
this.ProxyServerTextBox.Size = new System.Drawing.Size(135, 21);
this.ProxyServerTextBox.TabIndex = 1;
this.ProxyServerTextBox.WordWrap = false;
//
// ProxyPortLable
//
this.ProxyPortLable.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.ProxyPortLable.AutoSize = true;
this.ProxyPortLable.Location = new System.Drawing.Point(215, 7);
this.ProxyPortLable.Name = "ProxyPortLable";
this.ProxyPortLable.Size = new System.Drawing.Size(65, 12);
this.ProxyPortLable.TabIndex = 2;
this.ProxyPortLable.Text = "Proxy Port";
//
// ProxyPortTextBox
//
this.ProxyPortTextBox.Location = new System.Drawing.Point(286, 3);
this.ProxyPortTextBox.MaxLength = 10;
this.ProxyPortTextBox.Name = "ProxyPortTextBox";
this.ProxyPortTextBox.Size = new System.Drawing.Size(100, 21);
this.ProxyPortTextBox.TabIndex = 3;
this.ProxyPortTextBox.WordWrap = false;
//
// ProxyForm
//
this.AcceptButton = this.OKButton;
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.CancelButton = this.MyCancelButton;
this.ClientSize = new System.Drawing.Size(441, 149);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ProxyForm";
this.Padding = new System.Windows.Forms.Padding(12, 12, 12, 9);
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Edit Proxy";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ProxyForm_FormClosed);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.tableLayoutPanel3.ResumeLayout(false);
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.CheckBox UseProxyCheckBox;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.Label ProxyAddrLabel;
private System.Windows.Forms.TextBox ProxyServerTextBox;
private System.Windows.Forms.Label ProxyPortLable;
private System.Windows.Forms.TextBox ProxyPortTextBox;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.Button MyCancelButton;
private System.Windows.Forms.Button OKButton;
}
}

+ 116
- 0
shadowsocks-csharp/View/ProxyForm.cs View File

@@ -0,0 +1,116 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using Shadowsocks.Controller;
using Shadowsocks.Model;
using Shadowsocks.Properties;

namespace Shadowsocks.View
{
public partial class ProxyForm : Form
{
private ShadowsocksController controller;

// this is a copy of configuration that we are working on
private Configuration _modifiedConfiguration;

public ProxyForm(ShadowsocksController controller)
{
this.Font = System.Drawing.SystemFonts.MessageBoxFont;
InitializeComponent();

UpdateTexts();
this.Icon = Icon.FromHandle(Resources.ssw128.GetHicon());

this.controller = controller;
controller.ConfigChanged += controller_ConfigChanged;

UpdateEnabled();
LoadCurrentConfiguration();
}

private void UpdateTexts()
{
UseProxyCheckBox.Text = I18N.GetString("Use Proxy");
ProxyAddrLabel.Text = I18N.GetString("Proxy Addr");
ProxyPortLable.Text = I18N.GetString("Proxy Port");
OKButton.Text = I18N.GetString("OK");
MyCancelButton.Text = I18N.GetString("Cancel");
this.Text = I18N.GetString("Edit Proxy");
}

private void controller_ConfigChanged(object sender, EventArgs e)
{
LoadCurrentConfiguration();
}

private void LoadCurrentConfiguration()
{
_modifiedConfiguration = controller.GetConfigurationCopy();

UseProxyCheckBox.Checked = _modifiedConfiguration.useProxy;
ProxyServerTextBox.Text = _modifiedConfiguration.proxyServer;
ProxyPortTextBox.Text = _modifiedConfiguration.proxyPort.ToString();
}

private void OKButton_Click(object sender, EventArgs e)
{
if (UseProxyCheckBox.Checked)
{
try
{
var proxy = ProxyServerTextBox.Text;
var port = int.Parse(ProxyPortTextBox.Text);
Configuration.CheckServer(proxy);
Configuration.CheckPort(port);

controller.EnableProxy(proxy, port);
}
catch (FormatException)
{
MessageBox.Show(I18N.GetString("Illegal port number format"));
return;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
else
{
controller.DisableProxy();
}
this.Close();
}

private void CancelButton_Click(object sender, EventArgs e)
{
this.Close();
}

private void ProxyForm_FormClosed(object sender, FormClosedEventArgs e)
{
controller.ConfigChanged -= controller_ConfigChanged;
}

private void UseProxyCheckBox_CheckedChanged(object sender, EventArgs e)
{
UpdateEnabled();
}

private void UpdateEnabled()
{
if (UseProxyCheckBox.Checked)
{
ProxyServerTextBox.Enabled = true;
ProxyPortTextBox.Enabled = true;
}
else
{
ProxyServerTextBox.Enabled = false;
ProxyPortTextBox.Enabled = false;
}
}
}
}

+ 120
- 0
shadowsocks-csharp/View/ProxyForm.resx View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

+ 12
- 0
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -138,6 +138,8 @@
<Compile Include="3rd\zxing\ResultPoint.cs" />
<Compile Include="3rd\zxing\ResultPointCallback.cs" />
<Compile Include="3rd\zxing\WriterException.cs" />
<Compile Include="Proxy\DirectConnect.cs" />
<Compile Include="Proxy\IProxy.cs" />
<Compile Include="Controller\Service\AvailabilityStatistics.cs" />
<Compile Include="Controller\Strategy\HighAvailabilityStrategy.cs" />
<Compile Include="Controller\Strategy\StatisticsStrategy.cs" />
@@ -173,6 +175,7 @@
<Compile Include="Controller\Strategy\BalancingStrategy.cs" />
<Compile Include="Controller\Strategy\StrategyManager.cs" />
<Compile Include="Controller\Strategy\IStrategy.cs" />
<Compile Include="Proxy\Socks5Proxy.cs" />
<Compile Include="StringEx.cs" />
<Compile Include="Util\Util.cs" />
<Compile Include="View\ConfigForm.cs">
@@ -200,6 +203,12 @@
<DependentUpon>LogForm.cs</DependentUpon>
</Compile>
<Compile Include="View\MenuViewController.cs" />
<Compile Include="View\ProxyForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="View\ProxyForm.Designer.cs">
<DependentUpon>ProxyForm.cs</DependentUpon>
</Compile>
<Compile Include="View\QRCodeForm.cs">
<SubType>Form</SubType>
</Compile>
@@ -230,6 +239,9 @@
<EmbeddedResource Include="View\LogForm.resx">
<DependentUpon>LogForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="View\ProxyForm.resx">
<DependentUpon>ProxyForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="View\QRCodeForm.resx">
<DependentUpon>QRCodeForm.cs</DependentUpon>
</EmbeddedResource>


Loading…
Cancel
Save