@@ -1035,13 +1035,13 @@ namespace SimpleJson | |||||
protected static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable anArray, StringBuilder builder) | protected static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable anArray, StringBuilder builder) | ||||
{ | { | ||||
builder.Append("["); | |||||
builder.Append("[\r\n "); | |||||
bool first = true; | bool first = true; | ||||
foreach (object value in anArray) | foreach (object value in anArray) | ||||
{ | { | ||||
if (!first) | if (!first) | ||||
builder.Append(","); | |||||
builder.Append(",\r\n "); | |||||
if (!SerializeValue(jsonSerializerStrategy, value, builder)) | if (!SerializeValue(jsonSerializerStrategy, value, builder)) | ||||
return false; | return false; | ||||
@@ -1049,7 +1049,7 @@ namespace SimpleJson | |||||
first = false; | first = false; | ||||
} | } | ||||
builder.Append("]"); | |||||
builder.Append("\r\n]"); | |||||
return true; | return true; | ||||
} | } | ||||
@@ -3,88 +3,70 @@ using System.Collections.Generic; | |||||
using System.Text; | using System.Text; | ||||
using System.Net; | using System.Net; | ||||
using System.IO; | using System.IO; | ||||
using Shadowsocks.Properties; | |||||
using System.IO.Compression; | |||||
using System.Text.RegularExpressions; | |||||
using SimpleJson; | |||||
using Shadowsocks.Util; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
public class GfwListUpdater | |||||
public class GFWListUpdater | |||||
{ | { | ||||
private const string GFWLIST_URL = "https://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt"; | private const string GFWLIST_URL = "https://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt"; | ||||
public IWebProxy proxy = null; | |||||
private static string PAC_FILE = PACServer.PAC_FILE; | |||||
public class GfwListDownloadCompletedArgs : EventArgs | |||||
{ | |||||
public string Content; | |||||
} | |||||
public event EventHandler<GfwListDownloadCompletedArgs> DownloadCompleted; | |||||
public event EventHandler UpdateCompleted; | |||||
public event ErrorEventHandler Error; | public event ErrorEventHandler Error; | ||||
public void Download() | |||||
{ | |||||
WebClient http = new WebClient(); | |||||
http.Proxy = proxy; | |||||
http.DownloadStringCompleted += http_DownloadStringCompleted; | |||||
http.DownloadStringAsync(new Uri(GFWLIST_URL)); | |||||
} | |||||
protected void ReportError(Exception e) | |||||
{ | |||||
if (Error != null) | |||||
{ | |||||
Error(this, new ErrorEventArgs(e)); | |||||
} | |||||
} | |||||
private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) | private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) | ||||
{ | { | ||||
try | try | ||||
{ | { | ||||
string response = e.Result; | |||||
if (DownloadCompleted != null) | |||||
string[] lines = ParseResult(e.Result); | |||||
JsonArray rules = new JsonArray(); | |||||
rules.AddRange(lines); | |||||
string abpContent = Utils.UnGzip(Resources.abp_js); | |||||
abpContent = abpContent.Replace("__RULES__", rules.ToString()); | |||||
File.WriteAllText(PAC_FILE, abpContent, Encoding.UTF8); | |||||
if (UpdateCompleted != null) | |||||
{ | { | ||||
DownloadCompleted(this, new GfwListDownloadCompletedArgs | |||||
{ | |||||
Content = response | |||||
}); | |||||
UpdateCompleted(this, new EventArgs()); | |||||
} | } | ||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
ReportError(ex); | |||||
if (Error != null) | |||||
{ | |||||
Error(this, new ErrorEventArgs(ex)); | |||||
} | |||||
} | } | ||||
} | } | ||||
public class Parser | |||||
{ | |||||
private string _Content; | |||||
public string Content | |||||
{ | |||||
get { return _Content; } | |||||
} | |||||
public Parser(string response) | |||||
{ | |||||
byte[] bytes = Convert.FromBase64String(response); | |||||
this._Content = Encoding.ASCII.GetString(bytes); | |||||
} | |||||
public void UpdatePACFromGFWList() | |||||
{ | |||||
WebClient http = new WebClient(); | |||||
http.DownloadStringCompleted += http_DownloadStringCompleted; | |||||
http.DownloadStringAsync(new Uri(GFWLIST_URL)); | |||||
} | |||||
public string[] GetValidLines() | |||||
public string[] ParseResult(string response) | |||||
{ | |||||
byte[] bytes = Convert.FromBase64String(response); | |||||
string content = Encoding.ASCII.GetString(bytes); | |||||
string[] lines = content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); | |||||
List<string> valid_lines = new List<string>(lines.Length); | |||||
foreach (string line in lines) | |||||
{ | { | ||||
string[] lines = Content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); | |||||
List<string> valid_lines = new List<string>(lines.Length); | |||||
foreach (string line in lines) | |||||
{ | |||||
if (line.StartsWith("!") || line.StartsWith("[")) | |||||
continue; | |||||
valid_lines.Add(line); | |||||
} | |||||
return valid_lines.ToArray(); | |||||
if (line.StartsWith("!") || line.StartsWith("[")) | |||||
continue; | |||||
valid_lines.Add(line); | |||||
} | } | ||||
return valid_lines.ToArray(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,5 +1,6 @@ | |||||
using Shadowsocks.Model; | using Shadowsocks.Model; | ||||
using Shadowsocks.Properties; | using Shadowsocks.Properties; | ||||
using Shadowsocks.Util; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
@@ -8,14 +9,13 @@ using System.IO.Compression; | |||||
using System.Net; | using System.Net; | ||||
using System.Net.Sockets; | using System.Net.Sockets; | ||||
using System.Text; | using System.Text; | ||||
using System.Text.RegularExpressions; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
class PACServer | class PACServer | ||||
{ | { | ||||
private static int PORT = 8093; | private static int PORT = 8093; | ||||
private static string PAC_FILE = "pac.txt"; | |||||
public static string PAC_FILE = "pac.txt"; | |||||
private static Configuration config; | private static Configuration config; | ||||
Socket _listener; | Socket _listener; | ||||
@@ -23,10 +23,6 @@ namespace Shadowsocks.Controller | |||||
public event EventHandler PACFileChanged; | public event EventHandler PACFileChanged; | ||||
public event EventHandler UpdatePACFromGFWListCompleted; | |||||
public event ErrorEventHandler UpdatePACFromGFWListError; | |||||
public void Start(Configuration configuration) | public void Start(Configuration configuration) | ||||
{ | { | ||||
try | try | ||||
@@ -135,19 +131,7 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
byte[] pacGZ = Resources.proxy_pac_txt; | |||||
byte[] buffer = new byte[1024]; // builtin pac gzip size: maximum 100K | |||||
MemoryStream sb = new MemoryStream(); | |||||
int n; | |||||
using (GZipStream input = new GZipStream(new MemoryStream(pacGZ), | |||||
CompressionMode.Decompress, false)) | |||||
{ | |||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0) | |||||
{ | |||||
sb.Write(buffer, 0, n); | |||||
} | |||||
return System.Text.Encoding.UTF8.GetString(sb.ToArray()); | |||||
} | |||||
return Utils.UnGzip(Resources.proxy_pac_txt); | |||||
} | } | ||||
} | } | ||||
@@ -180,7 +164,7 @@ Connection: Close | |||||
", System.Text.Encoding.UTF8.GetBytes(pac).Length) + pac; | ", System.Text.Encoding.UTF8.GetBytes(pac).Length) + pac; | ||||
byte[] response = System.Text.Encoding.UTF8.GetBytes(text); | byte[] response = System.Text.Encoding.UTF8.GetBytes(text); | ||||
conn.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), conn); | conn.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), conn); | ||||
Util.Util.ReleaseMemory(); | |||||
Util.Utils.ReleaseMemory(); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -247,117 +231,5 @@ Connection: Close | |||||
//} | //} | ||||
return proxy; | return proxy; | ||||
} | } | ||||
public void UpdatePACFromGFWList() | |||||
{ | |||||
GfwListUpdater gfwlist = new GfwListUpdater(); | |||||
gfwlist.DownloadCompleted += gfwlist_DownloadCompleted; | |||||
gfwlist.Error += gfwlist_Error; | |||||
gfwlist.proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123); /* use polipo proxy*/ | |||||
gfwlist.Download(); | |||||
} | |||||
private void gfwlist_DownloadCompleted(object sender, GfwListUpdater.GfwListDownloadCompletedArgs e) | |||||
{ | |||||
GfwListUpdater.Parser parser = new GfwListUpdater.Parser(e.Content); | |||||
string[] lines = parser.GetValidLines(); | |||||
StringBuilder rules = new StringBuilder(lines.Length * 16); | |||||
SerializeRules(lines, rules); | |||||
string abpContent = GetAbpContent(); | |||||
abpContent = abpContent.Replace("__RULES__", rules.ToString()); | |||||
File.WriteAllText(PAC_FILE, abpContent, Encoding.UTF8); | |||||
if (UpdatePACFromGFWListCompleted != null) | |||||
{ | |||||
UpdatePACFromGFWListCompleted(this, new EventArgs()); | |||||
} | |||||
} | |||||
private void gfwlist_Error(object sender, ErrorEventArgs e) | |||||
{ | |||||
if (UpdatePACFromGFWListError != null) | |||||
{ | |||||
UpdatePACFromGFWListError(this, e); | |||||
} | |||||
} | |||||
private string GetAbpContent() | |||||
{ | |||||
string content; | |||||
if (File.Exists(PAC_FILE)) | |||||
{ | |||||
content = File.ReadAllText(PAC_FILE, Encoding.UTF8); | |||||
Regex regex = new Regex("var\\s+rules\\s*=\\s*(\\[(\\s*\"[^\"]*\"\\s*,)*(\\s*\"[^\"]*\")\\s*\\])", RegexOptions.Singleline); | |||||
Match m = regex.Match(content); | |||||
if (m.Success) | |||||
{ | |||||
content = regex.Replace(content, "var rules = __RULES__"); | |||||
return content; | |||||
} | |||||
} | |||||
byte[] abpGZ = Resources.abp_js; | |||||
byte[] buffer = new byte[1024]; // builtin pac gzip size: maximum 100K | |||||
int n; | |||||
using (MemoryStream sb = new MemoryStream()) | |||||
{ | |||||
using (GZipStream input = new GZipStream(new MemoryStream(abpGZ), | |||||
CompressionMode.Decompress, false)) | |||||
{ | |||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0) | |||||
{ | |||||
sb.Write(buffer, 0, n); | |||||
} | |||||
} | |||||
content = System.Text.Encoding.UTF8.GetString(sb.ToArray()); | |||||
} | |||||
return content; | |||||
} | |||||
private static void SerializeRules(string[] rules, StringBuilder builder) | |||||
{ | |||||
builder.Append("[\n"); | |||||
bool first = true; | |||||
foreach (string rule in rules) | |||||
{ | |||||
if (!first) | |||||
builder.Append(",\n"); | |||||
SerializeString(rule, builder); | |||||
first = false; | |||||
} | |||||
builder.Append("\n]"); | |||||
} | |||||
private static void SerializeString(string aString, StringBuilder builder) | |||||
{ | |||||
builder.Append("\t\""); | |||||
char[] charArray = aString.ToCharArray(); | |||||
for (int i = 0; i < charArray.Length; i++) | |||||
{ | |||||
char c = charArray[i]; | |||||
if (c == '"') | |||||
builder.Append("\\\""); | |||||
else if (c == '\\') | |||||
builder.Append("\\\\"); | |||||
else if (c == '\b') | |||||
builder.Append("\\b"); | |||||
else if (c == '\f') | |||||
builder.Append("\\f"); | |||||
else if (c == '\n') | |||||
builder.Append("\\n"); | |||||
else if (c == '\r') | |||||
builder.Append("\\r"); | |||||
else if (c == '\t') | |||||
builder.Append("\\t"); | |||||
else | |||||
builder.Append(c); | |||||
} | |||||
builder.Append("\""); | |||||
} | |||||
} | } | ||||
} | } |
@@ -21,6 +21,7 @@ namespace Shadowsocks.Controller | |||||
private PACServer pacServer; | private PACServer pacServer; | ||||
private Configuration _config; | private Configuration _config; | ||||
private PolipoRunner polipoRunner; | private PolipoRunner polipoRunner; | ||||
private GFWListUpdater gfwListUpdater; | |||||
private bool stopped = false; | private bool stopped = false; | ||||
private bool _systemProxyIsDirty = false; | private bool _systemProxyIsDirty = false; | ||||
@@ -157,13 +158,9 @@ namespace Shadowsocks.Controller | |||||
public void UpdatePACFromGFWList() | public void UpdatePACFromGFWList() | ||||
{ | { | ||||
if (pacServer != null) | |||||
if (gfwListUpdater != null) | |||||
{ | { | ||||
pacServer.UpdatePACFromGFWList(); | |||||
} | |||||
else if (UpdatePACFromGFWListError != null) | |||||
{ | |||||
UpdatePACFromGFWListError(this, new ErrorEventArgs(new Exception("The PACServer is not run."))); | |||||
gfwListUpdater.UpdatePACFromGFWList(); | |||||
} | } | ||||
} | } | ||||
@@ -180,8 +177,12 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
pacServer = new PACServer(); | pacServer = new PACServer(); | ||||
pacServer.PACFileChanged += pacServer_PACFileChanged; | pacServer.PACFileChanged += pacServer_PACFileChanged; | ||||
pacServer.UpdatePACFromGFWListCompleted += pacServer_UpdatePACFromGFWListCompleted; | |||||
pacServer.UpdatePACFromGFWListError += pacServer_UpdatePACFromGFWListError; | |||||
} | |||||
if (gfwListUpdater == null) | |||||
{ | |||||
gfwListUpdater = new GFWListUpdater(); | |||||
gfwListUpdater.UpdateCompleted += pacServer_PACUpdateCompleted; | |||||
gfwListUpdater.Error += pacServer_PACUpdateError; | |||||
} | } | ||||
pacServer.Stop(); | pacServer.Stop(); | ||||
@@ -226,7 +227,7 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
UpdateSystemProxy(); | UpdateSystemProxy(); | ||||
Util.Util.ReleaseMemory(); | |||||
Util.Utils.ReleaseMemory(); | |||||
} | } | ||||
@@ -260,13 +261,13 @@ namespace Shadowsocks.Controller | |||||
UpdateSystemProxy(); | UpdateSystemProxy(); | ||||
} | } | ||||
private void pacServer_UpdatePACFromGFWListCompleted(object sender, EventArgs e) | |||||
private void pacServer_PACUpdateCompleted(object sender, EventArgs e) | |||||
{ | { | ||||
if (UpdatePACFromGFWListCompleted != null) | if (UpdatePACFromGFWListCompleted != null) | ||||
UpdatePACFromGFWListCompleted(this, e); | UpdatePACFromGFWListCompleted(this, e); | ||||
} | } | ||||
private void pacServer_UpdatePACFromGFWListError(object sender, ErrorEventArgs e) | |||||
private void pacServer_PACUpdateError(object sender, ErrorEventArgs e) | |||||
{ | { | ||||
if (UpdatePACFromGFWListError != null) | if (UpdatePACFromGFWListError != null) | ||||
UpdatePACFromGFWListError(this, e); | UpdatePACFromGFWListError(this, e); | ||||
@@ -283,7 +284,7 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
while (true) | while (true) | ||||
{ | { | ||||
Util.Util.ReleaseMemory(); | |||||
Util.Utils.ReleaseMemory(); | |||||
Thread.Sleep(30 * 1000); | Thread.Sleep(30 * 1000); | ||||
} | } | ||||
} | } | ||||
@@ -39,6 +39,6 @@ Shadowsocks is here=Shadowsocks 在这里 | |||||
You can turn on/off Shadowsocks in the context menu=可以在右键菜单中开关 Shadowsocks | You can turn on/off Shadowsocks in the context menu=可以在右键菜单中开关 Shadowsocks | ||||
Enabled=已启用代理 | Enabled=已启用代理 | ||||
Disabled=已禁用代理 | Disabled=已禁用代理 | ||||
Update PAC File via GFWList...=从 GFWList 更新 PAC 文件... | |||||
Update PAC from GFWList=从 GFWList 更新 PAC | |||||
Failed to update PAC file =更新 PAC 文件失败 | Failed to update PAC file =更新 PAC 文件失败 | ||||
PAC updated=更新 PAC 成功 | PAC updated=更新 PAC 成功 |
@@ -18,7 +18,7 @@ namespace Shadowsocks | |||||
[STAThread] | [STAThread] | ||||
static void Main() | static void Main() | ||||
{ | { | ||||
Util.Util.ReleaseMemory(); | |||||
Util.Utils.ReleaseMemory(); | |||||
using (Mutex mutex = new Mutex(false, "Global\\" + "71981632-A427-497F-AB91-241CD227EC1F")) | using (Mutex mutex = new Mutex(false, "Global\\" + "71981632-A427-497F-AB91-241CD227EC1F")) | ||||
{ | { | ||||
Application.EnableVisualStyles(); | Application.EnableVisualStyles(); | ||||
@@ -1,12 +1,14 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using System.IO; | |||||
using System.IO.Compression; | |||||
using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
using System.Text; | using System.Text; | ||||
namespace Shadowsocks.Util | namespace Shadowsocks.Util | ||||
{ | { | ||||
public class Util | |||||
public class Utils | |||||
{ | { | ||||
public static void ReleaseMemory() | public static void ReleaseMemory() | ||||
{ | { | ||||
@@ -22,6 +24,24 @@ namespace Shadowsocks.Util | |||||
(UIntPtr)0xFFFFFFFF, (UIntPtr)0xFFFFFFFF); | (UIntPtr)0xFFFFFFFF, (UIntPtr)0xFFFFFFFF); | ||||
} | } | ||||
public static string UnGzip(byte[] buf) | |||||
{ | |||||
byte[] buffer = new byte[1024]; | |||||
int n; | |||||
using (MemoryStream sb = new MemoryStream()) | |||||
{ | |||||
using (GZipStream input = new GZipStream(new MemoryStream(buf), | |||||
CompressionMode.Decompress, false)) | |||||
{ | |||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0) | |||||
{ | |||||
sb.Write(buffer, 0, n); | |||||
} | |||||
} | |||||
return System.Text.Encoding.UTF8.GetString(sb.ToArray()); | |||||
} | |||||
} | |||||
[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, | ||||
@@ -141,7 +141,7 @@ namespace Shadowsocks.View | |||||
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("Share over LAN", new EventHandler(this.ShareOverLANItem_Click)), | this.ShareOverLANItem = CreateMenuItem("Share over LAN", new EventHandler(this.ShareOverLANItem_Click)), | ||||
CreateMenuItem("Edit PAC File...", new EventHandler(this.EditPACFileItem_Click)), | CreateMenuItem("Edit PAC File...", new EventHandler(this.EditPACFileItem_Click)), | ||||
CreateMenuItem("Update PAC File via gfwlist...", new EventHandler(this.UpdatePACFromGFWListItem_Click)), | |||||
CreateMenuItem("Update PAC from GFWList", new EventHandler(this.UpdatePACFromGFWListItem_Click)), | |||||
new MenuItem("-"), | new MenuItem("-"), | ||||
CreateMenuItem("Show QRCode...", new EventHandler(this.QRCodeItem_Click)), | CreateMenuItem("Show QRCode...", new EventHandler(this.QRCodeItem_Click)), | ||||
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)), | CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)), | ||||
@@ -265,7 +265,7 @@ namespace Shadowsocks.View | |||||
void configForm_FormClosed(object sender, FormClosedEventArgs e) | void configForm_FormClosed(object sender, FormClosedEventArgs e) | ||||
{ | { | ||||
configForm = null; | configForm = null; | ||||
Util.Util.ReleaseMemory(); | |||||
Util.Utils.ReleaseMemory(); | |||||
ShowFirstTimeBalloon(); | ShowFirstTimeBalloon(); | ||||
} | } | ||||
@@ -86,7 +86,7 @@ | |||||
<Compile Include="3rd\zxing\Version.cs" /> | <Compile Include="3rd\zxing\Version.cs" /> | ||||
<Compile Include="Controller\AutoStartup.cs" /> | <Compile Include="Controller\AutoStartup.cs" /> | ||||
<Compile Include="Controller\FileManager.cs" /> | <Compile Include="Controller\FileManager.cs" /> | ||||
<Compile Include="Controller\GfwListUpdater.cs" /> | |||||
<Compile Include="Controller\GFWListUpdater.cs" /> | |||||
<Compile Include="Controller\I18N.cs" /> | <Compile Include="Controller\I18N.cs" /> | ||||
<Compile Include="Controller\Logging.cs" /> | <Compile Include="Controller\Logging.cs" /> | ||||
<Compile Include="Controller\UpdateChecker.cs" /> | <Compile Include="Controller\UpdateChecker.cs" /> | ||||