| @@ -1035,13 +1035,13 @@ namespace SimpleJson | |||
| protected static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable anArray, StringBuilder builder) | |||
| { | |||
| builder.Append("["); | |||
| builder.Append("[\r\n "); | |||
| bool first = true; | |||
| foreach (object value in anArray) | |||
| { | |||
| if (!first) | |||
| builder.Append(","); | |||
| builder.Append(",\r\n "); | |||
| if (!SerializeValue(jsonSerializerStrategy, value, builder)) | |||
| return false; | |||
| @@ -1049,7 +1049,7 @@ namespace SimpleJson | |||
| first = false; | |||
| } | |||
| builder.Append("]"); | |||
| builder.Append("\r\n]"); | |||
| return true; | |||
| } | |||
| @@ -3,88 +3,70 @@ using System.Collections.Generic; | |||
| using System.Text; | |||
| using System.Net; | |||
| using System.IO; | |||
| using Shadowsocks.Properties; | |||
| using System.IO.Compression; | |||
| using System.Text.RegularExpressions; | |||
| using SimpleJson; | |||
| using Shadowsocks.Util; | |||
| namespace Shadowsocks.Controller | |||
| { | |||
| public class GfwListUpdater | |||
| public class GFWListUpdater | |||
| { | |||
| 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 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) | |||
| { | |||
| 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) | |||
| { | |||
| 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.Properties; | |||
| using Shadowsocks.Util; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Diagnostics; | |||
| @@ -8,14 +9,13 @@ using System.IO.Compression; | |||
| using System.Net; | |||
| using System.Net.Sockets; | |||
| using System.Text; | |||
| using System.Text.RegularExpressions; | |||
| namespace Shadowsocks.Controller | |||
| { | |||
| class PACServer | |||
| { | |||
| private static int PORT = 8093; | |||
| private static string PAC_FILE = "pac.txt"; | |||
| public static string PAC_FILE = "pac.txt"; | |||
| private static Configuration config; | |||
| Socket _listener; | |||
| @@ -23,10 +23,6 @@ namespace Shadowsocks.Controller | |||
| public event EventHandler PACFileChanged; | |||
| public event EventHandler UpdatePACFromGFWListCompleted; | |||
| public event ErrorEventHandler UpdatePACFromGFWListError; | |||
| public void Start(Configuration configuration) | |||
| { | |||
| try | |||
| @@ -135,19 +131,7 @@ namespace Shadowsocks.Controller | |||
| } | |||
| 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; | |||
| byte[] response = System.Text.Encoding.UTF8.GetBytes(text); | |||
| conn.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), conn); | |||
| Util.Util.ReleaseMemory(); | |||
| Util.Utils.ReleaseMemory(); | |||
| } | |||
| else | |||
| { | |||
| @@ -247,117 +231,5 @@ Connection: Close | |||
| //} | |||
| 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 Configuration _config; | |||
| private PolipoRunner polipoRunner; | |||
| private GFWListUpdater gfwListUpdater; | |||
| private bool stopped = false; | |||
| private bool _systemProxyIsDirty = false; | |||
| @@ -157,13 +158,9 @@ namespace Shadowsocks.Controller | |||
| 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.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(); | |||
| @@ -226,7 +227,7 @@ namespace Shadowsocks.Controller | |||
| } | |||
| UpdateSystemProxy(); | |||
| Util.Util.ReleaseMemory(); | |||
| Util.Utils.ReleaseMemory(); | |||
| } | |||
| @@ -260,13 +261,13 @@ namespace Shadowsocks.Controller | |||
| UpdateSystemProxy(); | |||
| } | |||
| private void pacServer_UpdatePACFromGFWListCompleted(object sender, EventArgs e) | |||
| private void pacServer_PACUpdateCompleted(object sender, EventArgs e) | |||
| { | |||
| if (UpdatePACFromGFWListCompleted != null) | |||
| UpdatePACFromGFWListCompleted(this, e); | |||
| } | |||
| private void pacServer_UpdatePACFromGFWListError(object sender, ErrorEventArgs e) | |||
| private void pacServer_PACUpdateError(object sender, ErrorEventArgs e) | |||
| { | |||
| if (UpdatePACFromGFWListError != null) | |||
| UpdatePACFromGFWListError(this, e); | |||
| @@ -283,7 +284,7 @@ namespace Shadowsocks.Controller | |||
| { | |||
| while (true) | |||
| { | |||
| Util.Util.ReleaseMemory(); | |||
| Util.Utils.ReleaseMemory(); | |||
| Thread.Sleep(30 * 1000); | |||
| } | |||
| } | |||
| @@ -39,6 +39,6 @@ Shadowsocks is here=Shadowsocks 在这里 | |||
| You can turn on/off Shadowsocks in the context menu=可以在右键菜单中开关 Shadowsocks | |||
| Enabled=已启用代理 | |||
| Disabled=已禁用代理 | |||
| Update PAC File via GFWList...=从 GFWList 更新 PAC 文件... | |||
| Update PAC from GFWList=从 GFWList 更新 PAC | |||
| Failed to update PAC file =更新 PAC 文件失败 | |||
| PAC updated=更新 PAC 成功 | |||
| @@ -18,7 +18,7 @@ namespace Shadowsocks | |||
| [STAThread] | |||
| static void Main() | |||
| { | |||
| Util.Util.ReleaseMemory(); | |||
| Util.Utils.ReleaseMemory(); | |||
| using (Mutex mutex = new Mutex(false, "Global\\" + "71981632-A427-497F-AB91-241CD227EC1F")) | |||
| { | |||
| Application.EnableVisualStyles(); | |||
| @@ -1,12 +1,14 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Diagnostics; | |||
| using System.IO; | |||
| using System.IO.Compression; | |||
| using System.Runtime.InteropServices; | |||
| using System.Text; | |||
| namespace Shadowsocks.Util | |||
| { | |||
| public class Util | |||
| public class Utils | |||
| { | |||
| public static void ReleaseMemory() | |||
| { | |||
| @@ -22,6 +24,24 @@ namespace Shadowsocks.Util | |||
| (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")] | |||
| [return: MarshalAs(UnmanagedType.Bool)] | |||
| 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.ShareOverLANItem = CreateMenuItem("Share over LAN", new EventHandler(this.ShareOverLANItem_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("-"), | |||
| CreateMenuItem("Show QRCode...", new EventHandler(this.QRCodeItem_Click)), | |||
| CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)), | |||
| @@ -265,7 +265,7 @@ namespace Shadowsocks.View | |||
| void configForm_FormClosed(object sender, FormClosedEventArgs e) | |||
| { | |||
| configForm = null; | |||
| Util.Util.ReleaseMemory(); | |||
| Util.Utils.ReleaseMemory(); | |||
| ShowFirstTimeBalloon(); | |||
| } | |||
| @@ -86,7 +86,7 @@ | |||
| <Compile Include="3rd\zxing\Version.cs" /> | |||
| <Compile Include="Controller\AutoStartup.cs" /> | |||
| <Compile Include="Controller\FileManager.cs" /> | |||
| <Compile Include="Controller\GfwListUpdater.cs" /> | |||
| <Compile Include="Controller\GFWListUpdater.cs" /> | |||
| <Compile Include="Controller\I18N.cs" /> | |||
| <Compile Include="Controller\Logging.cs" /> | |||
| <Compile Include="Controller\UpdateChecker.cs" /> | |||