* Add HTTP proxy support in forward proxy Signed-off-by: noisyfox <timemanager.rick@gmail.com> * Typo * Throw exception if forward proxy not supported.tags/3.3.2
@@ -420,7 +420,17 @@ namespace Shadowsocks.Controller | |||||
EndPoint proxyEP; | EndPoint proxyEP; | ||||
if (_config.proxy.useProxy) | if (_config.proxy.useProxy) | ||||
{ | { | ||||
remote = new Socks5Proxy(); | |||||
switch (_config.proxy.proxyType) | |||||
{ | |||||
case ProxyConfig.PROXY_SOCKS5: | |||||
remote = new Socks5Proxy(); | |||||
break; | |||||
case ProxyConfig.PROXY_HTTP: | |||||
remote = new HttpProxy(); | |||||
break; | |||||
default: | |||||
throw new NotSupportedException("Unknown forward proxy."); | |||||
} | |||||
proxyEP = SocketUtil.GetEndPoint(_config.proxy.proxyServer, _config.proxy.proxyPort); | proxyEP = SocketUtil.GetEndPoint(_config.proxy.proxyServer, _config.proxy.proxyPort); | ||||
} | } | ||||
else | else | ||||
@@ -221,9 +221,10 @@ namespace Shadowsocks.Controller | |||||
SaveConfig(_config); | SaveConfig(_config); | ||||
} | } | ||||
public void EnableProxy(string proxy, int port) | |||||
public void EnableProxy(int type, string proxy, int port) | |||||
{ | { | ||||
_config.proxy.useProxy = true; | _config.proxy.useProxy = true; | ||||
_config.proxy.proxyType = type; | |||||
_config.proxy.proxyServer = proxy; | _config.proxy.proxyServer = proxy; | ||||
_config.proxy.proxyPort = port; | _config.proxy.proxyPort = port; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
@@ -12,7 +12,7 @@ Servers=服务器 | |||||
Edit Servers...=编辑服务器... | Edit Servers...=编辑服务器... | ||||
Statistics Config...=统计配置... | Statistics Config...=统计配置... | ||||
Start on Boot=开机启动 | Start on Boot=开机启动 | ||||
SOCKS5 Proxy...=SOCKS5代理设置... | |||||
Forward Proxy...=正向代理设置... | |||||
Allow Clients from LAN=允许来自局域网的连接 | Allow Clients from LAN=允许来自局域网的连接 | ||||
Local PAC=使用本地 PAC | Local PAC=使用本地 PAC | ||||
Online PAC=使用在线 PAC | Online PAC=使用在线 PAC | ||||
@@ -58,6 +58,7 @@ Move D&own=下移(&O) | |||||
Edit Proxy=代理设置 | Edit Proxy=代理设置 | ||||
Use Proxy=使用代理 | Use Proxy=使用代理 | ||||
Proxy Type=代理类型 | |||||
Proxy Addr=代理地址 | Proxy Addr=代理地址 | ||||
Proxy Port=代理端口 | Proxy Port=代理端口 | ||||
@@ -12,7 +12,7 @@ Servers=伺服器 | |||||
Edit Servers...=編輯伺服器... | Edit Servers...=編輯伺服器... | ||||
Statistics Config...=統計配置... | Statistics Config...=統計配置... | ||||
Start on Boot=開機啟動 | Start on Boot=開機啟動 | ||||
SOCKS5 Proxy...=SOCKS5代理設置... | |||||
Forward Proxy...=正向代理設置... | |||||
Allow Clients from LAN=允許來自區域網路的連接 | Allow Clients from LAN=允許來自區域網路的連接 | ||||
Local PAC=使用本地 PAC | Local PAC=使用本地 PAC | ||||
Online PAC=使用在線 PAC | Online PAC=使用在線 PAC | ||||
@@ -58,6 +58,7 @@ Move D&own=下移(&O) | |||||
Edit Proxy=代理設置 | Edit Proxy=代理設置 | ||||
Use Proxy=使用代理 | Use Proxy=使用代理 | ||||
Proxy Type=代理類別 | |||||
Proxy Addr=代理位址 | Proxy Addr=代理位址 | ||||
Proxy Port=代理連接埠 | Proxy Port=代理連接埠 | ||||
@@ -63,6 +63,11 @@ namespace Shadowsocks.Model | |||||
config.proxy = new ProxyConfig(); | config.proxy = new ProxyConfig(); | ||||
if (config.hotkey == null) | if (config.hotkey == null) | ||||
config.hotkey = new HotkeyConfig(); | config.hotkey = new HotkeyConfig(); | ||||
if (config.proxy.proxyType < ProxyConfig.PROXY_SOCKS5 || config.proxy.proxyType > ProxyConfig.PROXY_HTTP) | |||||
{ | |||||
config.proxy.proxyType = ProxyConfig.PROXY_SOCKS5; | |||||
} | |||||
return config; | return config; | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
@@ -1,20 +1,22 @@ | |||||
using Shadowsocks.View; | |||||
using System; | |||||
using System.Drawing; | |||||
using System.Windows.Forms; | |||||
using System; | |||||
namespace Shadowsocks.Model | namespace Shadowsocks.Model | ||||
{ | { | ||||
[Serializable] | [Serializable] | ||||
public class ProxyConfig | public class ProxyConfig | ||||
{ | { | ||||
public const int PROXY_SOCKS5 = 0; | |||||
public const int PROXY_HTTP = 1; | |||||
public bool useProxy; | public bool useProxy; | ||||
public int proxyType; | |||||
public string proxyServer; | public string proxyServer; | ||||
public int proxyPort; | public int proxyPort; | ||||
public ProxyConfig() | public ProxyConfig() | ||||
{ | { | ||||
useProxy = false; | useProxy = false; | ||||
proxyType = PROXY_SOCKS5; | |||||
proxyServer = ""; | proxyServer = ""; | ||||
proxyPort = 0; | proxyPort = 0; | ||||
} | } | ||||
@@ -0,0 +1,199 @@ | |||||
using System; | |||||
using System.Net; | |||||
using System.Net.Sockets; | |||||
using System.Text; | |||||
using System.Text.RegularExpressions; | |||||
using System.Threading; | |||||
using Shadowsocks.Controller; | |||||
using Shadowsocks.Util.Sockets; | |||||
namespace Shadowsocks.Proxy | |||||
{ | |||||
public class HttpProxy : IProxy | |||||
{ | |||||
private class FakeAsyncResult : IAsyncResult | |||||
{ | |||||
public readonly HttpState innerState; | |||||
private readonly IAsyncResult r; | |||||
public FakeAsyncResult(IAsyncResult orig, HttpState 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 HttpState | |||||
{ | |||||
public AsyncCallback Callback { get; set; } | |||||
public object AsyncState { get; set; } | |||||
public int BytesToRead; | |||||
public Exception ex { get; set; } | |||||
} | |||||
public EndPoint LocalEndPoint => _remote.LocalEndPoint; | |||||
public EndPoint ProxyEndPoint { get; private set; } | |||||
public EndPoint DestEndPoint { get; private set; } | |||||
private readonly WrappedSocket _remote = new WrappedSocket(); | |||||
public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) | |||||
{ | |||||
ProxyEndPoint = remoteEP; | |||||
_remote.BeginConnect(remoteEP, callback, state); | |||||
} | |||||
public void EndConnectProxy(IAsyncResult asyncResult) | |||||
{ | |||||
_remote.EndConnect(asyncResult); | |||||
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); | |||||
} | |||||
private const string HTTP_CRLF = "\r\n"; | |||||
private const string HTTP_CONNECT_TEMPLATE = | |||||
"CONNECT {0} HTTP/1.1" + HTTP_CRLF + | |||||
"Host: {0}" + HTTP_CRLF + | |||||
"Proxy-Connection: keep-alive" + HTTP_CRLF + | |||||
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" + HTTP_CRLF + | |||||
"" + HTTP_CRLF; // End with an empty line | |||||
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state) | |||||
{ | |||||
DestEndPoint = destEndPoint; | |||||
string request = string.Format(HTTP_CONNECT_TEMPLATE, destEndPoint); | |||||
var b = Encoding.UTF8.GetBytes(request); | |||||
var st = new HttpState(); | |||||
st.Callback = callback; | |||||
st.AsyncState = state; | |||||
_remote.BeginSend(b, 0, b.Length, 0, HttpRequestSendCallback, 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.Dispose(); | |||||
} | |||||
private void HttpRequestSendCallback(IAsyncResult ar) | |||||
{ | |||||
var state = (HttpState) ar.AsyncState; | |||||
try | |||||
{ | |||||
_remote.EndSend(ar); | |||||
// start line read | |||||
new LineReader(_remote, OnLineRead, OnException, OnFinish, Encoding.UTF8, HTTP_CRLF, 1024, new FakeAsyncResult(ar, state)); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
state.ex = ex; | |||||
state.Callback?.Invoke(new FakeAsyncResult(ar, state)); | |||||
} | |||||
} | |||||
private void OnFinish(byte[] lastBytes, int index, int length, object state) | |||||
{ | |||||
// TODO: save last bytes | |||||
var st = (FakeAsyncResult)state; | |||||
if (!_established) | |||||
{ | |||||
st.innerState.ex = new Exception(I18N.GetString("Proxy request failed")); | |||||
} | |||||
st.innerState.Callback?.Invoke(st); | |||||
} | |||||
private void OnException(Exception ex, object state) | |||||
{ | |||||
var st = (FakeAsyncResult) state; | |||||
st.innerState.ex = ex; | |||||
st.innerState.Callback?.Invoke(st); | |||||
} | |||||
private static readonly Regex HttpRespondHeaderRegex = new Regex(@"^(HTTP/1\.\d) (\d{3}) (.+)$"); | |||||
private int _respondLineCount = 0; | |||||
private bool _established = false; | |||||
private bool OnLineRead(string line, object state) | |||||
{ | |||||
Logging.Debug(line); | |||||
if (_respondLineCount == 0) | |||||
{ | |||||
var m = HttpRespondHeaderRegex.Match(line); | |||||
if (m.Success) | |||||
{ | |||||
var resultCode = m.Groups[2].Value; | |||||
if ("200" != resultCode) | |||||
{ | |||||
return true; | |||||
} | |||||
_established = true; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
if (line.IsNullOrEmpty()) | |||||
{ | |||||
return true; | |||||
} | |||||
} | |||||
_respondLineCount++; | |||||
return false; | |||||
} | |||||
} | |||||
} |
@@ -39,7 +39,7 @@ namespace Shadowsocks.Proxy | |||||
public Exception ex { get; set; } | public Exception ex { get; set; } | ||||
} | } | ||||
private WrappedSocket _remote = new WrappedSocket(); | |||||
private readonly WrappedSocket _remote = new WrappedSocket(); | |||||
private const int Socks5PktMaxSize = 4 + 16 + 2; | private const int Socks5PktMaxSize = 4 + 16 + 2; | ||||
private readonly byte[] _receiveBuffer = new byte[Socks5PktMaxSize]; | private readonly byte[] _receiveBuffer = new byte[Socks5PktMaxSize]; | ||||
@@ -124,7 +124,7 @@ namespace Shadowsocks.Proxy | |||||
st.Callback = callback; | st.Callback = callback; | ||||
st.AsyncState = state; | st.AsyncState = state; | ||||
_remote?.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st); | |||||
_remote.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st); | |||||
} | } | ||||
public void EndConnectDest(IAsyncResult asyncResult) | public void EndConnectDest(IAsyncResult asyncResult) | ||||
@@ -140,7 +140,7 @@ namespace Shadowsocks.Proxy | |||||
public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, | public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, | ||||
object state) | object state) | ||||
{ | { | ||||
_remote?.BeginSend(buffer, offset, size, socketFlags, callback, state); | |||||
_remote.BeginSend(buffer, offset, size, socketFlags, callback, state); | |||||
} | } | ||||
public int EndSend(IAsyncResult asyncResult) | public int EndSend(IAsyncResult asyncResult) | ||||
@@ -151,7 +151,7 @@ namespace Shadowsocks.Proxy | |||||
public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, | public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, | ||||
object state) | object state) | ||||
{ | { | ||||
_remote?.BeginReceive(buffer, offset, size, socketFlags, callback, state); | |||||
_remote.BeginReceive(buffer, offset, size, socketFlags, callback, state); | |||||
} | } | ||||
public int EndReceive(IAsyncResult asyncResult) | public int EndReceive(IAsyncResult asyncResult) | ||||
@@ -161,12 +161,12 @@ namespace Shadowsocks.Proxy | |||||
public void Shutdown(SocketShutdown how) | public void Shutdown(SocketShutdown how) | ||||
{ | { | ||||
_remote?.Shutdown(how); | |||||
_remote.Shutdown(how); | |||||
} | } | ||||
public void Close() | public void Close() | ||||
{ | { | ||||
_remote?.Dispose(); | |||||
_remote.Dispose(); | |||||
} | } | ||||
@@ -0,0 +1,231 @@ | |||||
using System; | |||||
using System.Text; | |||||
namespace Shadowsocks.Util.Sockets | |||||
{ | |||||
public class LineReader | |||||
{ | |||||
private readonly WrappedSocket _socket; | |||||
private readonly Func<string, object, bool> _onLineRead; | |||||
private readonly Action<Exception, object> _onException; | |||||
private readonly Action<byte[], int, int, object> _onFinish; | |||||
private readonly Encoding _encoding; | |||||
// private readonly string _delimiter; | |||||
private readonly byte[] _delimiterBytes; | |||||
private readonly int[] _delimiterSearchCharTable; | |||||
private readonly int[] _delimiterSearchOffsetTable; | |||||
private readonly object _state; | |||||
private readonly byte[] _lineBuffer; | |||||
private int _bufferIndex; | |||||
public LineReader(WrappedSocket socket, Func<string, object, bool> onLineRead, Action<Exception, object> onException, | |||||
Action<byte[], int, int, object> onFinish, Encoding encoding, string delimiter, int maxLineBytes, object state) | |||||
{ | |||||
if (socket == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(socket)); | |||||
} | |||||
if (onLineRead == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(onLineRead)); | |||||
} | |||||
if (encoding == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(encoding)); | |||||
} | |||||
if (delimiter == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(delimiter)); | |||||
} | |||||
_socket = socket; | |||||
_onLineRead = onLineRead; | |||||
_onException = onException; | |||||
_onFinish = onFinish; | |||||
_encoding = encoding; | |||||
// _delimiter = delimiter; | |||||
_state = state; | |||||
// decode delimiter | |||||
_delimiterBytes = encoding.GetBytes(delimiter); | |||||
if (_delimiterBytes.Length == 0) | |||||
{ | |||||
throw new ArgumentException("Too short!", nameof(delimiter)); | |||||
} | |||||
if (maxLineBytes < _delimiterBytes.Length) | |||||
{ | |||||
throw new ArgumentException("Too small!", nameof(maxLineBytes)); | |||||
} | |||||
_delimiterSearchCharTable = MakeCharTable(_delimiterBytes); | |||||
_delimiterSearchOffsetTable = MakeOffsetTable(_delimiterBytes); | |||||
_lineBuffer = new byte[maxLineBytes]; | |||||
// start reading | |||||
socket.BeginReceive(_lineBuffer, 0, maxLineBytes, 0, ReceiveCallback, 0); | |||||
} | |||||
private void ReceiveCallback(IAsyncResult ar) | |||||
{ | |||||
int length = (int)ar.AsyncState; | |||||
try | |||||
{ | |||||
var bytesRead = _socket.EndReceive(ar); | |||||
if (bytesRead == 0) | |||||
{ | |||||
OnFinish(length); | |||||
return; | |||||
} | |||||
length += bytesRead; | |||||
int i; | |||||
while ((i = IndexOf(_lineBuffer, _bufferIndex, length, _delimiterBytes, _delimiterSearchOffsetTable, | |||||
_delimiterSearchCharTable)) != -1) | |||||
{ | |||||
var decodeLen = i - _bufferIndex; | |||||
string line = _encoding.GetString(_lineBuffer, _bufferIndex, decodeLen); | |||||
_bufferIndex = i + _delimiterBytes.Length; | |||||
length -= decodeLen; | |||||
length -= _delimiterBytes.Length; | |||||
var stop = _onLineRead(line, _state); | |||||
if (stop) | |||||
{ | |||||
OnFinish(length); | |||||
return; | |||||
} | |||||
} | |||||
if (length == _lineBuffer.Length) | |||||
{ | |||||
OnException(new IndexOutOfRangeException("LineBuffer full! Try increace maxLineBytes!")); | |||||
OnFinish(length); | |||||
return; | |||||
} | |||||
if (_bufferIndex > 0) | |||||
{ | |||||
Buffer.BlockCopy(_lineBuffer, _bufferIndex, _lineBuffer, 0, length); | |||||
_bufferIndex = 0; | |||||
} | |||||
_socket.BeginReceive(_lineBuffer, length, _lineBuffer.Length - length, 0, ReceiveCallback, length); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
OnException(ex); | |||||
OnFinish(length); | |||||
} | |||||
} | |||||
private void OnException(Exception ex) | |||||
{ | |||||
_onException?.Invoke(ex, _state); | |||||
} | |||||
private void OnFinish(int length) | |||||
{ | |||||
_onFinish?.Invoke(_lineBuffer, _bufferIndex, length, _state); | |||||
} | |||||
#region Boyer-Moore string search | |||||
public static int IndexOf(byte[] haystack, int index, int length, byte[] needle, int[] offsetTable, int[] charTable) | |||||
{ | |||||
var end = index + length; | |||||
for (int i = needle.Length - 1 + index, j; i < end;) | |||||
{ | |||||
for (j = needle.Length - 1; needle[j] == haystack[i]; --i, --j) | |||||
{ | |||||
if (j == 0) | |||||
{ | |||||
return i; | |||||
} | |||||
} | |||||
// i += needle.length - j; // For naive method | |||||
i += Math.Max(offsetTable[needle.Length - 1 - j], charTable[haystack[i]]); | |||||
} | |||||
return -1; | |||||
} | |||||
/** | |||||
* Makes the jump table based on the mismatched character information. | |||||
*/ | |||||
private static int[] MakeCharTable(byte[] needle) | |||||
{ | |||||
const int ALPHABET_SIZE = 256; | |||||
int[] table = new int[ALPHABET_SIZE]; | |||||
for (int i = 0; i < table.Length; ++i) | |||||
{ | |||||
table[i] = needle.Length; | |||||
} | |||||
for (int i = 0; i < needle.Length - 1; ++i) | |||||
{ | |||||
table[needle[i]] = needle.Length - 1 - i; | |||||
} | |||||
return table; | |||||
} | |||||
/** | |||||
* Makes the jump table based on the scan offset which mismatch occurs. | |||||
*/ | |||||
private static int[] MakeOffsetTable(byte[] needle) | |||||
{ | |||||
int[] table = new int[needle.Length]; | |||||
int lastPrefixPosition = needle.Length; | |||||
for (int i = needle.Length - 1; i >= 0; --i) | |||||
{ | |||||
if (IsPrefix(needle, i + 1)) | |||||
{ | |||||
lastPrefixPosition = i + 1; | |||||
} | |||||
table[needle.Length - 1 - i] = lastPrefixPosition - i + needle.Length - 1; | |||||
} | |||||
for (int i = 0; i < needle.Length - 1; ++i) | |||||
{ | |||||
int slen = SuffixLength(needle, i); | |||||
table[slen] = needle.Length - 1 - i + slen; | |||||
} | |||||
return table; | |||||
} | |||||
/** | |||||
* Is needle[p:end] a prefix of needle? | |||||
*/ | |||||
private static bool IsPrefix(byte[] needle, int p) | |||||
{ | |||||
for (int i = p, j = 0; i < needle.Length; ++i, ++j) | |||||
{ | |||||
if (needle[i] != needle[j]) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Returns the maximum length of the substring ends at p and is a suffix. | |||||
*/ | |||||
private static int SuffixLength(byte[] needle, int p) | |||||
{ | |||||
int len = 0; | |||||
for (int i = p, j = needle.Length - 1; | |||||
i >= 0 && needle[i] == needle[j]; --i, --j) | |||||
{ | |||||
len += 1; | |||||
} | |||||
return len; | |||||
} | |||||
#endregion | |||||
} | |||||
} |
@@ -271,7 +271,7 @@ namespace Shadowsocks.View | |||||
this.editGFWUserRuleItem = CreateMenuItem("Edit User Rule for GFWList...", new EventHandler(this.EditUserRuleFileForGFWListItem_Click)), | 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.editOnlinePACItem = CreateMenuItem("Edit Online PAC URL...", new EventHandler(this.UpdateOnlinePACURLItem_Click)), | ||||
}), | }), | ||||
this.proxyItem = CreateMenuItem("SOCKS5 Proxy...", new EventHandler(this.proxyItem_Click)), | |||||
this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)), | |||||
new MenuItem("-"), | new MenuItem("-"), | ||||
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)), | this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)), | ||||
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)), | this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)), | ||||
@@ -38,9 +38,13 @@ | |||||
this.ProxyServerTextBox = new System.Windows.Forms.TextBox(); | this.ProxyServerTextBox = new System.Windows.Forms.TextBox(); | ||||
this.ProxyPortLable = new System.Windows.Forms.Label(); | this.ProxyPortLable = new System.Windows.Forms.Label(); | ||||
this.ProxyPortTextBox = new System.Windows.Forms.TextBox(); | this.ProxyPortTextBox = new System.Windows.Forms.TextBox(); | ||||
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); | |||||
this.ProxyTypeLabel = new System.Windows.Forms.Label(); | |||||
this.ProxyTypeComboBox = new System.Windows.Forms.ComboBox(); | |||||
this.tableLayoutPanel1.SuspendLayout(); | this.tableLayoutPanel1.SuspendLayout(); | ||||
this.tableLayoutPanel3.SuspendLayout(); | this.tableLayoutPanel3.SuspendLayout(); | ||||
this.tableLayoutPanel2.SuspendLayout(); | this.tableLayoutPanel2.SuspendLayout(); | ||||
this.tableLayoutPanel4.SuspendLayout(); | |||||
this.SuspendLayout(); | this.SuspendLayout(); | ||||
// | // | ||||
// tableLayoutPanel1 | // tableLayoutPanel1 | ||||
@@ -49,16 +53,18 @@ | |||||
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; | this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; | ||||
this.tableLayoutPanel1.ColumnCount = 1; | this.tableLayoutPanel1.ColumnCount = 1; | ||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); | ||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 2); | |||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 3); | |||||
this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0); | this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0); | ||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 1); | |||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 2); | |||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 0, 1); | |||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15); | this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15); | ||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1"; | this.tableLayoutPanel1.Name = "tableLayoutPanel1"; | ||||
this.tableLayoutPanel1.RowCount = 3; | |||||
this.tableLayoutPanel1.RowCount = 4; | |||||
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.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.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(395, 123); | |||||
this.tableLayoutPanel1.TabIndex = 0; | this.tableLayoutPanel1.TabIndex = 0; | ||||
// | // | ||||
// tableLayoutPanel3 | // tableLayoutPanel3 | ||||
@@ -72,7 +78,7 @@ | |||||
this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0); | this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0); | ||||
this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0); | this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0); | ||||
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right; | this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right; | ||||
this.tableLayoutPanel3.Location = new System.Drawing.Point(236, 58); | |||||
this.tableLayoutPanel3.Location = new System.Drawing.Point(236, 94); | |||||
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3); | this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3); | ||||
this.tableLayoutPanel3.Name = "tableLayoutPanel3"; | this.tableLayoutPanel3.Name = "tableLayoutPanel3"; | ||||
this.tableLayoutPanel3.RowCount = 1; | this.tableLayoutPanel3.RowCount = 1; | ||||
@@ -129,10 +135,11 @@ | |||||
this.tableLayoutPanel2.Controls.Add(this.ProxyServerTextBox, 1, 0); | this.tableLayoutPanel2.Controls.Add(this.ProxyServerTextBox, 1, 0); | ||||
this.tableLayoutPanel2.Controls.Add(this.ProxyPortLable, 2, 0); | this.tableLayoutPanel2.Controls.Add(this.ProxyPortLable, 2, 0); | ||||
this.tableLayoutPanel2.Controls.Add(this.ProxyPortTextBox, 3, 0); | this.tableLayoutPanel2.Controls.Add(this.ProxyPortTextBox, 3, 0); | ||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 25); | |||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 61); | |||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2"; | this.tableLayoutPanel2.Name = "tableLayoutPanel2"; | ||||
this.tableLayoutPanel2.RowCount = 1; | this.tableLayoutPanel2.RowCount = 1; | ||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); | ||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); | |||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(389, 27); | this.tableLayoutPanel2.Size = new System.Drawing.Size(389, 27); | ||||
this.tableLayoutPanel2.TabIndex = 1; | this.tableLayoutPanel2.TabIndex = 1; | ||||
// | // | ||||
@@ -174,6 +181,45 @@ | |||||
this.ProxyPortTextBox.TabIndex = 3; | this.ProxyPortTextBox.TabIndex = 3; | ||||
this.ProxyPortTextBox.WordWrap = false; | this.ProxyPortTextBox.WordWrap = false; | ||||
// | // | ||||
// tableLayoutPanel4 | |||||
// | |||||
this.tableLayoutPanel4.AutoSize = true; | |||||
this.tableLayoutPanel4.ColumnCount = 2; | |||||
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); | |||||
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); | |||||
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeLabel, 0, 0); | |||||
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeComboBox, 1, 0); | |||||
this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 25); | |||||
this.tableLayoutPanel4.Name = "tableLayoutPanel4"; | |||||
this.tableLayoutPanel4.RowCount = 1; | |||||
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||||
this.tableLayoutPanel4.Size = new System.Drawing.Size(198, 30); | |||||
this.tableLayoutPanel4.TabIndex = 10; | |||||
// | |||||
// ProxyTypeLabel | |||||
// | |||||
this.ProxyTypeLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; | |||||
this.ProxyTypeLabel.AutoSize = true; | |||||
this.ProxyTypeLabel.Location = new System.Drawing.Point(3, 9); | |||||
this.ProxyTypeLabel.Name = "ProxyTypeLabel"; | |||||
this.ProxyTypeLabel.Size = new System.Drawing.Size(65, 12); | |||||
this.ProxyTypeLabel.TabIndex = 1; | |||||
this.ProxyTypeLabel.Text = "Proxy Type"; | |||||
// | |||||
// ProxyTypeComboBox | |||||
// | |||||
this.ProxyTypeComboBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||||
this.ProxyTypeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; | |||||
this.ProxyTypeComboBox.FormattingEnabled = true; | |||||
this.ProxyTypeComboBox.Items.AddRange(new object[] { | |||||
"SOCKS5", | |||||
"HTTP"}); | |||||
this.ProxyTypeComboBox.Location = new System.Drawing.Point(74, 5); | |||||
this.ProxyTypeComboBox.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5); | |||||
this.ProxyTypeComboBox.Name = "ProxyTypeComboBox"; | |||||
this.ProxyTypeComboBox.Size = new System.Drawing.Size(121, 20); | |||||
this.ProxyTypeComboBox.TabIndex = 2; | |||||
// | |||||
// ProxyForm | // ProxyForm | ||||
// | // | ||||
this.AcceptButton = this.OKButton; | this.AcceptButton = this.OKButton; | ||||
@@ -182,7 +228,7 @@ | |||||
this.AutoSize = true; | this.AutoSize = true; | ||||
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; | this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; | ||||
this.CancelButton = this.MyCancelButton; | this.CancelButton = this.MyCancelButton; | ||||
this.ClientSize = new System.Drawing.Size(441, 149); | |||||
this.ClientSize = new System.Drawing.Size(441, 165); | |||||
this.Controls.Add(this.tableLayoutPanel1); | this.Controls.Add(this.tableLayoutPanel1); | ||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; | ||||
this.MaximizeBox = false; | this.MaximizeBox = false; | ||||
@@ -197,6 +243,8 @@ | |||||
this.tableLayoutPanel3.ResumeLayout(false); | this.tableLayoutPanel3.ResumeLayout(false); | ||||
this.tableLayoutPanel2.ResumeLayout(false); | this.tableLayoutPanel2.ResumeLayout(false); | ||||
this.tableLayoutPanel2.PerformLayout(); | this.tableLayoutPanel2.PerformLayout(); | ||||
this.tableLayoutPanel4.ResumeLayout(false); | |||||
this.tableLayoutPanel4.PerformLayout(); | |||||
this.ResumeLayout(false); | this.ResumeLayout(false); | ||||
this.PerformLayout(); | this.PerformLayout(); | ||||
@@ -214,5 +262,8 @@ | |||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; | ||||
private System.Windows.Forms.Button MyCancelButton; | private System.Windows.Forms.Button MyCancelButton; | ||||
private System.Windows.Forms.Button OKButton; | private System.Windows.Forms.Button OKButton; | ||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; | |||||
private System.Windows.Forms.Label ProxyTypeLabel; | |||||
private System.Windows.Forms.ComboBox ProxyTypeComboBox; | |||||
} | } | ||||
} | } |
@@ -32,6 +32,7 @@ namespace Shadowsocks.View | |||||
private void UpdateTexts() | private void UpdateTexts() | ||||
{ | { | ||||
UseProxyCheckBox.Text = I18N.GetString("Use Proxy"); | UseProxyCheckBox.Text = I18N.GetString("Use Proxy"); | ||||
ProxyTypeLabel.Text = I18N.GetString("Proxy Type"); | |||||
ProxyAddrLabel.Text = I18N.GetString("Proxy Addr"); | ProxyAddrLabel.Text = I18N.GetString("Proxy Addr"); | ||||
ProxyPortLable.Text = I18N.GetString("Proxy Port"); | ProxyPortLable.Text = I18N.GetString("Proxy Port"); | ||||
OKButton.Text = I18N.GetString("OK"); | OKButton.Text = I18N.GetString("OK"); | ||||
@@ -50,6 +51,7 @@ namespace Shadowsocks.View | |||||
UseProxyCheckBox.Checked = _modifiedConfiguration.useProxy; | UseProxyCheckBox.Checked = _modifiedConfiguration.useProxy; | ||||
ProxyServerTextBox.Text = _modifiedConfiguration.proxyServer; | ProxyServerTextBox.Text = _modifiedConfiguration.proxyServer; | ||||
ProxyPortTextBox.Text = _modifiedConfiguration.proxyPort.ToString(); | ProxyPortTextBox.Text = _modifiedConfiguration.proxyPort.ToString(); | ||||
ProxyTypeComboBox.SelectedIndex = _modifiedConfiguration.proxyType; | |||||
} | } | ||||
private void OKButton_Click(object sender, EventArgs e) | private void OKButton_Click(object sender, EventArgs e) | ||||
@@ -58,12 +60,13 @@ namespace Shadowsocks.View | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
var type = ProxyTypeComboBox.SelectedIndex; | |||||
var proxy = ProxyServerTextBox.Text; | var proxy = ProxyServerTextBox.Text; | ||||
var port = int.Parse(ProxyPortTextBox.Text); | var port = int.Parse(ProxyPortTextBox.Text); | ||||
Configuration.CheckServer(proxy); | Configuration.CheckServer(proxy); | ||||
Configuration.CheckPort(port); | Configuration.CheckPort(port); | ||||
controller.EnableProxy(proxy, port); | |||||
controller.EnableProxy(type, proxy, port); | |||||
} | } | ||||
catch (FormatException) | catch (FormatException) | ||||
{ | { | ||||
@@ -82,6 +85,7 @@ namespace Shadowsocks.View | |||||
} | } | ||||
_modifiedConfiguration.useProxy = UseProxyCheckBox.Checked; | _modifiedConfiguration.useProxy = UseProxyCheckBox.Checked; | ||||
_modifiedConfiguration.proxyType = ProxyTypeComboBox.SelectedIndex; | |||||
_modifiedConfiguration.proxyServer = ProxyServerTextBox.Text; | _modifiedConfiguration.proxyServer = ProxyServerTextBox.Text; | ||||
var tmpProxyPort = 0; | var tmpProxyPort = 0; | ||||
int.TryParse(ProxyPortTextBox.Text, out tmpProxyPort); | int.TryParse(ProxyPortTextBox.Text, out tmpProxyPort); | ||||
@@ -112,6 +116,7 @@ namespace Shadowsocks.View | |||||
{ | { | ||||
ProxyServerTextBox.Enabled = true; | ProxyServerTextBox.Enabled = true; | ||||
ProxyPortTextBox.Enabled = true; | ProxyPortTextBox.Enabled = true; | ||||
ProxyTypeComboBox.Enabled = true; | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -119,6 +124,7 @@ namespace Shadowsocks.View | |||||
ProxyPortTextBox.Clear(); | ProxyPortTextBox.Clear(); | ||||
ProxyServerTextBox.Enabled = false; | ProxyServerTextBox.Enabled = false; | ||||
ProxyPortTextBox.Enabled = false; | ProxyPortTextBox.Enabled = false; | ||||
ProxyTypeComboBox.Enabled = false; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -146,6 +146,7 @@ | |||||
<Compile Include="Model\HotKeyConfig.cs" /> | <Compile Include="Model\HotKeyConfig.cs" /> | ||||
<Compile Include="Model\ProxyConfig.cs" /> | <Compile Include="Model\ProxyConfig.cs" /> | ||||
<Compile Include="Proxy\DirectConnect.cs" /> | <Compile Include="Proxy\DirectConnect.cs" /> | ||||
<Compile Include="Proxy\HttpProxy.cs" /> | |||||
<Compile Include="Proxy\IProxy.cs" /> | <Compile Include="Proxy\IProxy.cs" /> | ||||
<Compile Include="Controller\Service\AvailabilityStatistics.cs" /> | <Compile Include="Controller\Service\AvailabilityStatistics.cs" /> | ||||
<Compile Include="Controller\Strategy\HighAvailabilityStrategy.cs" /> | <Compile Include="Controller\Strategy\HighAvailabilityStrategy.cs" /> | ||||
@@ -186,6 +187,7 @@ | |||||
<Compile Include="Util\Hotkeys.cs" /> | <Compile Include="Util\Hotkeys.cs" /> | ||||
<Compile Include="Util\ProcessManagement\Job.cs" /> | <Compile Include="Util\ProcessManagement\Job.cs" /> | ||||
<Compile Include="Util\ProcessManagement\ThreadUtil.cs" /> | <Compile Include="Util\ProcessManagement\ThreadUtil.cs" /> | ||||
<Compile Include="Util\Sockets\LineReader.cs" /> | |||||
<Compile Include="Util\Sockets\SocketUtil.cs" /> | <Compile Include="Util\Sockets\SocketUtil.cs" /> | ||||
<Compile Include="Util\Sockets\WrappedSocket.cs" /> | <Compile Include="Util\Sockets\WrappedSocket.cs" /> | ||||
<Compile Include="Util\Util.cs" /> | <Compile Include="Util\Util.cs" /> | ||||