@@ -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" /> | |||