Browse Source

Merge pull request #3 from clowwindy/master

Merge with upstream
pull/146/head
Sharuru 10 years ago
parent
commit
6485362a8c
23 changed files with 810 additions and 294 deletions
  1. +3
    -2
      .gitignore
  2. +8
    -3
      CHANGES
  3. +2
    -0
      README.md
  4. +9
    -0
      shadowsocks-csharp.sln
  5. +62
    -48
      shadowsocks-csharp/Controller/Local.cs
  6. +34
    -0
      shadowsocks-csharp/Controller/Logging.cs
  7. +44
    -19
      shadowsocks-csharp/Controller/PACServer.cs
  8. +8
    -7
      shadowsocks-csharp/Controller/PolipoRunner.cs
  9. +56
    -24
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  10. +151
    -0
      shadowsocks-csharp/Controller/UpdateChecker.cs
  11. +1
    -1
      shadowsocks-csharp/Data/polipo_config.txt
  12. +144
    -106
      shadowsocks-csharp/Encrypt/PolarSSLEncryptor.cs
  13. +1
    -0
      shadowsocks-csharp/Model/Configuration.cs
  14. +2
    -15
      shadowsocks-csharp/Program.cs
  15. +1
    -1
      shadowsocks-csharp/Properties/AssemblyInfo.cs
  16. +1
    -1
      shadowsocks-csharp/Properties/Resources.Designer.cs
  17. +27
    -8
      shadowsocks-csharp/View/ConfigForm.Designer.cs
  18. +77
    -37
      shadowsocks-csharp/View/ConfigForm.cs
  19. +37
    -22
      shadowsocks-csharp/View/QRCodeForm.cs
  20. +3
    -0
      shadowsocks-csharp/shadowsocks-csharp.csproj
  21. +36
    -0
      test/Properties/AssemblyInfo.cs
  22. +22
    -0
      test/UnitTest.cs
  23. +81
    -0
      test/test.csproj

+ 3
- 2
.gitignore View File

@@ -1,6 +1,7 @@
Backup/
shadowsocks-csharp/bin/
shadowsocks-csharp/obj/
bin/
obj/
shadowsocks-csharp/shadowsocks-csharp.csproj.user
TestResults
*.suo


+ 8
- 3
CHANGES View File

@@ -1,12 +1,17 @@
2.0.4
2.0.5 2014-11-09
- Fix QRCode size
- Share over LAN option
- Log to temp path instead

2.0.4 2014-11-09
- Try to fix data corruption
- Remove all configuration except x86

2.0.3
2.0.3 2014-11-08
- Support QRCode generation
- Fix compatibility issues with some Chrome version

2.0.2
2.0.2 2014-11-08
- Add remarks
- Fix error when polipo is killed



+ 2
- 0
README.md View File

@@ -3,6 +3,8 @@ Shadowsocks for Windows

[![Build Status]][Appveyor]

Currently beta. Please file an issue if you find any bugs.

### Features

1. Native Windows UI


+ 9
- 0
shadowsocks-csharp.sln View File

@@ -3,6 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2012 for Windows Desktop
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shadowsocks-csharp", "shadowsocks-csharp\shadowsocks-csharp.csproj", "{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{45913187-0685-4903-B250-DCEF0479CD86}"
ProjectSection(ProjectDependencies) = postProject
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062} = {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@@ -14,6 +19,10 @@ Global
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Deploy.0 = Debug|x86
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.ActiveCfg = Release|x86
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.Build.0 = Release|x86
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.ActiveCfg = Debug|x86
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.Build.0 = Debug|x86
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.ActiveCfg = Release|x86
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE


+ 62
- 48
shadowsocks-csharp/Controller/Local.cs View File

@@ -11,12 +11,14 @@ namespace Shadowsocks.Controller
class Local
{
private Server config;
private Server _server;
private bool _shareOverLAN;
//private Encryptor encryptor;
Socket _listener;
public Local(Server config)
public Local(Configuration config)
{
this.config = config;
this._server = config.GetCurrentServer();
_shareOverLAN = config.shareOverLan;
//this.encryptor = new Encryptor(config.method, config.password);
}
@@ -25,9 +27,17 @@ namespace Shadowsocks.Controller
try
{
// Create a TCP/IP socket.
_listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndPoint = new IPEndPoint(0, config.local_port);
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
IPEndPoint localEndPoint = null;
if (_shareOverLAN)
{
localEndPoint = new IPEndPoint(IPAddress.Any, _server.local_port);
}
else
{
localEndPoint = new IPEndPoint(IPAddress.Loopback, _server.local_port);
}
// Bind the socket to the local endpoint and listen for incoming connections.
_listener.Bind(localEndPoint);
@@ -58,37 +68,20 @@ namespace Shadowsocks.Controller
{
try
{
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
//if (!listener.Connected)
//{
// return;
//}
Socket conn = listener.EndAccept(ar);
conn.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Create the state object.
Handler handler = new Handler();
handler.connection = conn;
//if (encryptor.method == "table")
//{
// handler.encryptor = encryptor;
//}
//else
//{
// handler.encryptor = new Encryptor(config.method, config.password);
//}
handler.encryptor = EncryptorFactory.GetEncryptor(config.method, config.password);
handler.config = config;
handler.encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password);
handler.config = _server;
handler.Start();
//handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
// new AsyncCallback(ReadCallback), state);
}
catch
{
@@ -119,6 +112,9 @@ namespace Shadowsocks.Controller
public byte[] connetionSendBuffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
private bool connectionShutdown = false;
private bool remoteShutdown = false;
private bool closed = false;
public void Start()
@@ -138,6 +134,7 @@ namespace Shadowsocks.Controller
remote = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
remote.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
// Connect to the remote endpoint.
remote.BeginConnect(remoteEP,
@@ -150,18 +147,30 @@ namespace Shadowsocks.Controller
}
}
private void CheckClose()
{
if (connectionShutdown && remoteShutdown)
{
this.Close();
}
}
public void Close()
{
if (closed)
lock (this)
{
return;
if (closed)
{
return;
}
closed = true;
}
closed = true;
if (connection != null)
{
try
{
connection.Shutdown(SocketShutdown.Send);
connection.Shutdown(SocketShutdown.Both);
connection.Close();
}
catch (Exception e)
{
@@ -172,7 +181,8 @@ namespace Shadowsocks.Controller
{
try
{
remote.Shutdown(SocketShutdown.Send);
remote.Shutdown(SocketShutdown.Both);
remote.Close();
}
catch (SocketException e)
{
@@ -229,7 +239,7 @@ namespace Shadowsocks.Controller
// reject socks 4
response = new byte[]{ 0, 91 };
}
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(handshakeSendCallback), null);
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null);
}
else
{
@@ -243,7 +253,7 @@ namespace Shadowsocks.Controller
}
}
private void handshakeSendCallback(IAsyncResult ar)
private void HandshakeSendCallback(IAsyncResult ar)
{
try
{
@@ -275,7 +285,7 @@ namespace Shadowsocks.Controller
if (bytesRead > 0)
{
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(startPipe), null);
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(StartPipe), null);
}
else
{
@@ -290,15 +300,15 @@ namespace Shadowsocks.Controller
}
private void startPipe(IAsyncResult ar)
private void StartPipe(IAsyncResult ar)
{
try
{
connection.EndReceive(ar);
remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0,
new AsyncCallback(pipeRemoteReceiveCallback), null);
new AsyncCallback(PipeRemoteReceiveCallback), null);
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0,
new AsyncCallback(pipeConnectionReceiveCallback), null);
new AsyncCallback(PipeConnectionReceiveCallback), null);
}
catch (Exception e)
{
@@ -307,7 +317,7 @@ namespace Shadowsocks.Controller
}
}
private void pipeRemoteReceiveCallback(IAsyncResult ar)
private void PipeRemoteReceiveCallback(IAsyncResult ar)
{
try
@@ -318,12 +328,14 @@ namespace Shadowsocks.Controller
{
int bytesToSend;
encryptor.Decrypt(remoteRecvBuffer, bytesRead, remoteSendBuffer, out bytesToSend);
connection.BeginSend(remoteSendBuffer, 0, bytesToSend, 0, new AsyncCallback(pipeConnectionSendCallback), null);
connection.BeginSend(remoteSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeConnectionSendCallback), null);
}
else
{
Console.WriteLine("bytesRead: " + bytesRead.ToString());
this.Close();
//Console.WriteLine("bytesRead: " + bytesRead.ToString());
connection.Shutdown(SocketShutdown.Send);
connectionShutdown = true;
CheckClose();
}
}
catch (Exception e)
@@ -333,7 +345,7 @@ namespace Shadowsocks.Controller
}
}
private void pipeConnectionReceiveCallback(IAsyncResult ar)
private void PipeConnectionReceiveCallback(IAsyncResult ar)
{
try
@@ -344,11 +356,13 @@ namespace Shadowsocks.Controller
{
int bytesToSend;
encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend);
remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(pipeRemoteSendCallback), null);
remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeRemoteSendCallback), null);
}
else
{
this.Close();
remote.Shutdown(SocketShutdown.Send);
remoteShutdown = true;
CheckClose();
}
}
catch (Exception e)
@@ -358,13 +372,13 @@ namespace Shadowsocks.Controller
}
}
private void pipeRemoteSendCallback(IAsyncResult ar)
private void PipeRemoteSendCallback(IAsyncResult ar)
{
try
{
remote.EndSend(ar);
connection.BeginReceive(this.connetionRecvBuffer, 0, RecvSize, 0,
new AsyncCallback(pipeConnectionReceiveCallback), null);
new AsyncCallback(PipeConnectionReceiveCallback), null);
}
catch (Exception e)
{
@@ -373,13 +387,13 @@ namespace Shadowsocks.Controller
}
}
private void pipeConnectionSendCallback(IAsyncResult ar)
private void PipeConnectionSendCallback(IAsyncResult ar)
{
try
{
connection.EndSend(ar);
remote.BeginReceive(this.remoteRecvBuffer, 0, RecvSize, 0,
new AsyncCallback(pipeRemoteReceiveCallback), null);
new AsyncCallback(PipeRemoteReceiveCallback), null);
}
catch (Exception e)
{


+ 34
- 0
shadowsocks-csharp/Controller/Logging.cs View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Shadowsocks.Controller
{
public class Logging
{
public static string LogFile;
public static bool OpenLogFile()
{
try
{
string temppath = Path.GetTempPath();
LogFile = Path.Combine(temppath, "shadowsocks.log");
FileStream fs = new FileStream(LogFile, FileMode.Append);
TextWriter tmp = Console.Out;
StreamWriter sw = new StreamWriter(fs);
sw.AutoFlush = true;
Console.SetOut(sw);
Console.SetError(sw);
return true;
}
catch (IOException e)
{
Console.WriteLine(e.ToString());
return false;
}
}
}
}

+ 44
- 19
shadowsocks-csharp/Controller/PACServer.cs View File

@@ -1,4 +1,5 @@
using Shadowsocks.Properties;
using Shadowsocks.Model;
using Shadowsocks.Properties;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -12,28 +13,51 @@ namespace Shadowsocks.Controller
{
class PACServer
{
private static int PORT = 8090;
private static string PAC_FILE = "pac.txt";
Socket listener;
Socket _listener;
FileSystemWatcher watcher;
public event EventHandler PACFileChanged;
public void Start()
public void Start(Configuration configuration)
{
// Create a TCP/IP socket.
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndPoint = new IPEndPoint(0, 8090);
// Bind the socket to the local endpoint and listen for incoming connections.
listener.Bind(localEndPoint);
listener.Listen(100);
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
WatchPacFile();
try
{
// Create a TCP/IP socket.
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
IPEndPoint localEndPoint = null;
if (configuration.shareOverLan)
{
localEndPoint = new IPEndPoint(IPAddress.Any, PORT);
}
else
{
localEndPoint = new IPEndPoint(IPAddress.Loopback, PORT);
}
// Bind the socket to the local endpoint and listen for incoming connections.
_listener.Bind(localEndPoint);
_listener.Listen(100);
_listener.BeginAccept(
new AsyncCallback(AcceptCallback),
_listener);
WatchPacFile();
}
catch (SocketException)
{
_listener.Close();
throw;
}
}
public void Stop()
{
_listener.Close();
_listener = null;
}
public string TouchPACFile()
@@ -55,10 +79,10 @@ namespace Shadowsocks.Controller
try
{
Socket listener = (Socket)ar.AsyncState;
Socket conn = listener.EndAccept(ar);
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
Socket conn = listener.EndAccept(ar);
conn.BeginReceive(new byte[1024], 0, 1024, 0,
new AsyncCallback(ReceiveCallback), conn);
@@ -92,7 +116,6 @@ namespace Shadowsocks.Controller
return System.Text.Encoding.UTF8.GetString(buffer, 0, n);
}
}
WatchPacFile();
}
private void ReceiveCallback(IAsyncResult ar)
@@ -104,7 +127,9 @@ namespace Shadowsocks.Controller
string pac = GetPACContent();
string proxy = "PROXY 127.0.0.1:8123;";
IPEndPoint localEndPoint = (IPEndPoint)conn.LocalEndPoint;
string proxy = "PROXY " + localEndPoint.Address + ":8123;";
pac = pac.Replace("__PROXY__", proxy);


+ 8
- 7
shadowsocks-csharp/Controller/PolipoRunner.cs View File

@@ -13,8 +13,9 @@ namespace Shadowsocks.Controller
{
private Process _process;
public void Start(Server config)
public void Start(Configuration configuration)
{
Server server = configuration.GetCurrentServer();
if (_process == null)
{
Process[] existingPolipo = Process.GetProcessesByName("ss_polipo");
@@ -31,8 +32,9 @@ namespace Shadowsocks.Controller
}
}
string temppath = Path.GetTempPath();
string polipoConfig = Resources.polipo_config;
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", config.local_port.ToString());
string polipoConfig = Resources.polipo_config;
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", server.local_port.ToString());
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1");
FileManager.ByteArrayToFile(temppath + "/polipo.conf", System.Text.Encoding.UTF8.GetBytes(polipoConfig));
FileManager.UncompressFile(temppath + "/ss_polipo.exe", Resources.polipo_exe);
@@ -41,11 +43,10 @@ namespace Shadowsocks.Controller
_process.StartInfo.FileName = temppath + "/ss_polipo.exe";
_process.StartInfo.Arguments = "-c \"" + temppath + "/polipo.conf\"";
_process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
_process.StartInfo.UseShellExecute = false;
_process.StartInfo.UseShellExecute = true;
_process.StartInfo.CreateNoWindow = true;
_process.StartInfo.RedirectStandardOutput = true;
_process.StartInfo.RedirectStandardError = true;
//process.StandardOutput
//_process.StartInfo.RedirectStandardOutput = true;
//_process.StartInfo.RedirectStandardError = true;
_process.Start();
}
}


+ 56
- 24
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -1,7 +1,9 @@
using Shadowsocks.Model;
using System.IO;
using Shadowsocks.Model;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Shadowsocks.Controller
{
@@ -25,6 +27,7 @@ namespace Shadowsocks.Controller
public event EventHandler ConfigChanged;
public event EventHandler EnableStatusChanged;
public event EventHandler ShareOverLANStatusChanged;
// when user clicked Edit PAC, and PAC file has already created
public event EventHandler<PathEventArgs> PACFileReadyToOpen;
@@ -33,14 +36,14 @@ namespace Shadowsocks.Controller
{
_config = Configuration.Load();
polipoRunner = new PolipoRunner();
polipoRunner.Start(_config.GetCurrentServer());
local = new Local(_config.GetCurrentServer());
polipoRunner.Start(_config);
local = new Local(_config);
try
{
local.Start();
pacServer = new PACServer();
pacServer.PACFileChanged += pacServer_PACFileChanged;
pacServer.Start();
pacServer.Start(_config);
}
catch (Exception e)
{
@@ -50,25 +53,6 @@ namespace Shadowsocks.Controller
UpdateSystemProxy();
}
public void SaveConfig(Configuration newConfig)
{
Configuration.Save(newConfig);
// some logic in configuration updated the config when saving, we need to read it again
_config = Configuration.Load();
local.Stop();
polipoRunner.Stop();
polipoRunner.Start(_config.GetCurrentServer());
local = new Local(_config.GetCurrentServer());
local.Start();
if (ConfigChanged != null)
{
ConfigChanged(this, new EventArgs());
}
}
public Server GetCurrentServer()
{
return _config.GetCurrentServer();
@@ -80,6 +64,11 @@ namespace Shadowsocks.Controller
return Configuration.Load();
}
public void SaveServers(List<Server> servers)
{
_config.configs = servers;
SaveConfig(_config);
}
public void ToggleEnable(bool enabled)
{
@@ -92,6 +81,22 @@ namespace Shadowsocks.Controller
}
}
public void ToggleShareOverLAN(bool enabled)
{
_config.shareOverLan = enabled;
SaveConfig(_config);
if (ShareOverLANStatusChanged != null)
{
ShareOverLANStatusChanged(this, new EventArgs());
}
}
public void SelectServerIndex(int index)
{
_config.index = index;
SaveConfig(_config);
}
public void Stop()
{
if (stopped)
@@ -124,6 +129,34 @@ namespace Shadowsocks.Controller
return "ss://" + base64;
}
protected void SaveConfig(Configuration newConfig)
{
Configuration.Save(newConfig);
// some logic in configuration updated the config when saving, we need to read it again
_config = Configuration.Load();
pacServer.Stop();
local.Stop();
// don't put polipoRunner.Start() before pacServer.Stop()
// or bind will fail when switching bind address from 0.0.0.0 to 127.0.0.1
// though UseShellExecute is set to true now
// http://stackoverflow.com/questions/10235093/socket-doesnt-close-after-application-exits-if-a-launched-process-is-open
polipoRunner.Stop();
polipoRunner.Start(_config);
local = new Local(_config);
local.Start();
pacServer.Start(_config);
if (ConfigChanged != null)
{
ConfigChanged(this, new EventArgs());
}
}
private void UpdateSystemProxy()
{
if (_config.enabled)
@@ -140,6 +173,5 @@ namespace Shadowsocks.Controller
{
UpdateSystemProxy();
}
}
}

+ 151
- 0
shadowsocks-csharp/Controller/UpdateChecker.cs View File

@@ -0,0 +1,151 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
namespace Shadowsocks.Controller
{
public class UpdateChecker
{
private const string UpdateURL = "https://sourceforge.net/api/file/index/project-id/1817190/path/dist/mtime/desc/limit/10/rss";
public string LatestVersionNumber;
public string LatestVersionURL;
public event EventHandler NewVersionFound;
public void CheckUpdate()
{
// TODO test failures
WebClient http = new WebClient();
http.DownloadStringCompleted += http_DownloadStringCompleted;
http.DownloadStringAsync(new Uri(UpdateURL));
}
public static int CompareVersion(string l, string r)
{
var ls = l.Split('.');
var rs = r.Split('.');
for (int i = 0; i < Math.Max(ls.Length, rs.Length); i++)
{
int lp = (i < ls.Length) ? int.Parse(ls[i]) : 0;
int rp = (i < rs.Length) ? int.Parse(rs[i]) : 0;
if (lp != rp)
{
return lp - rp;
}
}
return 0;
}
public class VersionComparer : IComparer<string>
{
// Calls CaseInsensitiveComparer.Compare with the parameters reversed.
public int Compare(string x, string y)
{
return CompareVersion(ParseVersionFromURL(x), ParseVersionFromURL(y));
}
}
private static string ParseVersionFromURL(string url)
{
Match match = Regex.Match(url, @".*Shadowsocks-win.*?-([\d\.]+)\.\w+", RegexOptions.IgnoreCase);
if (match.Success)
{
if (match.Groups.Count == 2)
{
return match.Groups[1].Value;
}
}
return null;
}
private void SortVersions(List<string> versions)
{
versions.Sort(new VersionComparer());
}
private bool IsNewVersion(string url)
{
// check dotnet 4.0
AssemblyName[] references = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
Version dotNetVersion = Environment.Version;
foreach (AssemblyName reference in references)
{
if (reference.Name == "mscorlib")
{
dotNetVersion = reference.Version;
}
}
if (dotNetVersion.Major >= 4)
{
if (url.IndexOf("dotnet4.0") < 0)
{
return false;
}
}
else
{
if (url.IndexOf("dotnet4.0") >= 0)
{
return false;
}
}
string version = ParseVersionFromURL(url);
if (version == null)
{
return false;
}
string currentVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
return CompareVersion(version, currentVersion) > 0;
}
private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
string response = e.Result;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(response);
XmlNodeList elements = xmlDoc.GetElementsByTagName("media:content");
List<string> versions = new List<string>();
foreach (XmlNode el in elements)
{
foreach (XmlAttribute attr in el.Attributes)
{
if (attr.Name == "url")
{
if (IsNewVersion(attr.Value))
{
versions.Add(attr.Value);
}
}
}
}
if (versions.Count == 0)
{
return;
}
// sort versions
SortVersions(versions);
LatestVersionURL = versions[versions.Count - 1];
LatestVersionNumber = ParseVersionFromURL(LatestVersionURL);
if (NewVersionFound != null)
{
NewVersionFound(this, new EventArgs());
}
}
catch (Exception ex)
{
Console.Write(ex.ToString());
return;
}
}
}
}

+ 1
- 1
shadowsocks-csharp/Data/polipo_config.txt View File

@@ -1,4 +1,4 @@
proxyAddress = "127.0.0.1"
proxyAddress = "__POLIPO_BIND_IP__"

socksParentProxy = "127.0.0.1:__SOCKS_PORT__"
socksProxyType = socks5


+ 144
- 106
shadowsocks-csharp/Encrypt/PolarSSLEncryptor.cs View File

@@ -103,56 +103,59 @@ namespace Shadowsocks.Encrypt
private void InitCipher(ref byte[] ctx, byte[] iv, bool isCipher)
{
ctx = new byte[_cipherInfo[3]];
byte[] realkey;
if (_method == "rc4-md5")
lock (ctx)
{
byte[] temp = new byte[keyLen + ivLen];
realkey = new byte[keyLen];
Array.Copy(_key, 0, temp, 0, keyLen);
Array.Copy(iv, 0, temp, keyLen, ivLen);
realkey = MD5.Create().ComputeHash(temp);
}
else
{
realkey = _key;
}
if (_cipher == CIPHER_AES)
{
PolarSSL.aes_init(ctx);
// PolarSSL takes key length by bit
// since we'll use CFB mode, here we both do enc, not dec
PolarSSL.aes_setkey_enc(ctx, realkey, keyLen * 8);
if (isCipher)
byte[] realkey;
if (_method == "rc4-md5")
{
_encryptIV = new byte[ivLen];
Array.Copy(iv, _encryptIV, ivLen);
byte[] temp = new byte[keyLen + ivLen];
realkey = new byte[keyLen];
Array.Copy(_key, 0, temp, 0, keyLen);
Array.Copy(iv, 0, temp, keyLen, ivLen);
realkey = MD5.Create().ComputeHash(temp);
}
else
{
_decryptIV = new byte[ivLen];
Array.Copy(iv, _decryptIV, ivLen);
realkey = _key;
}
}
else if (_cipher == CIPHER_BF)
{
PolarSSL.blowfish_init(ctx);
// PolarSSL takes key length by bit
PolarSSL.blowfish_setkey(ctx, realkey, keyLen * 8);
if (isCipher)
if (_cipher == CIPHER_AES)
{
_encryptIV = new byte[ivLen];
Array.Copy(iv, _encryptIV, ivLen);
PolarSSL.aes_init(ctx);
// PolarSSL takes key length by bit
// since we'll use CFB mode, here we both do enc, not dec
PolarSSL.aes_setkey_enc(ctx, realkey, keyLen * 8);
if (isCipher)
{
_encryptIV = new byte[ivLen];
Array.Copy(iv, _encryptIV, ivLen);
}
else
{
_decryptIV = new byte[ivLen];
Array.Copy(iv, _decryptIV, ivLen);
}
}
else
else if (_cipher == CIPHER_BF)
{
_decryptIV = new byte[ivLen];
Array.Copy(iv, _decryptIV, ivLen);
PolarSSL.blowfish_init(ctx);
// PolarSSL takes key length by bit
PolarSSL.blowfish_setkey(ctx, realkey, keyLen * 8);
if (isCipher)
{
_encryptIV = new byte[ivLen];
Array.Copy(iv, _encryptIV, ivLen);
}
else
{
_decryptIV = new byte[ivLen];
Array.Copy(iv, _decryptIV, ivLen);
}
}
else if (_cipher == CIPHER_RC4)
{
PolarSSL.arc4_init(ctx);
PolarSSL.arc4_setup(ctx, realkey, keyLen);
}
}
else if (_cipher == CIPHER_RC4)
{
PolarSSL.arc4_init(ctx);
PolarSSL.arc4_setup(ctx, realkey, keyLen);
}
}
@@ -170,36 +173,50 @@ namespace Shadowsocks.Encrypt
lock (tempbuf)
{
// C# could be multi-threaded
lock (_encryptCtx)
{
if (_disposed)
{
throw new ObjectDisposedException(this.ToString());
}
switch (_cipher)
{
case CIPHER_AES:
PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, tempbuf);
break;
case CIPHER_BF:
PolarSSL.blowfish_crypt_cfb64(_encryptCtx, PolarSSL.BLOWFISH_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, tempbuf);
break;
case CIPHER_RC4:
PolarSSL.arc4_crypt(_encryptCtx, length, buf, tempbuf);
break;
}
outlength = length + ivLen;
Buffer.BlockCopy(tempbuf, 0, outbuf, ivLen, outlength);
}
}
}
else
{
outlength = length;
lock (_encryptCtx)
{
if (_disposed)
{
throw new ObjectDisposedException(this.ToString());
}
switch (_cipher)
{
case CIPHER_AES:
PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, tempbuf);
PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, outbuf);
break;
case CIPHER_BF:
PolarSSL.blowfish_crypt_cfb64(_encryptCtx, PolarSSL.BLOWFISH_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, tempbuf);
PolarSSL.blowfish_crypt_cfb64(_encryptCtx, PolarSSL.BLOWFISH_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, outbuf);
break;
case CIPHER_RC4:
PolarSSL.arc4_crypt(_encryptCtx, length, buf, tempbuf);
PolarSSL.arc4_crypt(_encryptCtx, length, buf, outbuf);
break;
}
outlength = length + ivLen;
Buffer.BlockCopy(tempbuf, 0, outbuf, ivLen, outlength);
}
}
else
{
outlength = length;
switch (_cipher)
{
case CIPHER_AES:
PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, outbuf);
break;
case CIPHER_BF:
PolarSSL.blowfish_crypt_cfb64(_encryptCtx, PolarSSL.BLOWFISH_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, outbuf);
break;
case CIPHER_RC4:
PolarSSL.arc4_crypt(_encryptCtx, length, buf, outbuf);
break;
}
}
}
@@ -214,36 +231,50 @@ namespace Shadowsocks.Encrypt
{
// C# could be multi-threaded
Buffer.BlockCopy(buf, ivLen, tempbuf, 0, length - ivLen);
lock (_decryptCtx)
{
if (_disposed)
{
throw new ObjectDisposedException(this.ToString());
}
switch (_cipher)
{
case CIPHER_AES:
PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length - ivLen, ref _decryptIVOffset, _decryptIV, tempbuf, outbuf);
break;
case CIPHER_BF:
PolarSSL.blowfish_crypt_cfb64(_decryptCtx, PolarSSL.BLOWFISH_DECRYPT, length - ivLen, ref _decryptIVOffset, _decryptIV, tempbuf, outbuf);
break;
case CIPHER_RC4:
PolarSSL.arc4_crypt(_decryptCtx, length - ivLen, tempbuf, outbuf);
break;
}
}
}
}
else
{
outlength = length;
lock (_decryptCtx)
{
if (_disposed)
{
throw new ObjectDisposedException(this.ToString());
}
switch (_cipher)
{
case CIPHER_AES:
PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length - ivLen, ref _decryptIVOffset, _decryptIV, tempbuf, outbuf);
PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length, ref _decryptIVOffset, _decryptIV, buf, outbuf);
break;
case CIPHER_BF:
PolarSSL.blowfish_crypt_cfb64(_decryptCtx, PolarSSL.BLOWFISH_DECRYPT, length - ivLen, ref _decryptIVOffset, _decryptIV, tempbuf, outbuf);
PolarSSL.blowfish_crypt_cfb64(_decryptCtx, PolarSSL.BLOWFISH_DECRYPT, length, ref _decryptIVOffset, _decryptIV, buf, outbuf);
break;
case CIPHER_RC4:
PolarSSL.arc4_crypt(_decryptCtx, length - ivLen, tempbuf, outbuf);
PolarSSL.arc4_crypt(_decryptCtx, length, buf, outbuf);
break;
}
}
}
else
{
outlength = length;
switch (_cipher)
{
case CIPHER_AES:
PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length, ref _decryptIVOffset, _decryptIV, buf, outbuf);
break;
case CIPHER_BF:
PolarSSL.blowfish_crypt_cfb64(_decryptCtx, PolarSSL.BLOWFISH_DECRYPT, length, ref _decryptIVOffset, _decryptIV, buf, outbuf);
break;
case CIPHER_RC4:
PolarSSL.arc4_crypt(_decryptCtx, length, buf, outbuf);
break;
}
}
}
#region IDisposable
@@ -262,46 +293,53 @@ namespace Shadowsocks.Encrypt
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
lock (this)
{
if (disposing)
if (_disposed)
{
return;
}
_disposed = true;
}
if (disposing)
{
if (_encryptCtx != null)
{
switch (_cipher)
lock (_encryptCtx)
{
case CIPHER_AES:
PolarSSL.aes_free(_encryptCtx);
break;
case CIPHER_BF:
PolarSSL.blowfish_free(_encryptCtx);
break;
case CIPHER_RC4:
PolarSSL.arc4_free(_encryptCtx);
break;
switch (_cipher)
{
case CIPHER_AES:
PolarSSL.aes_free(_encryptCtx);
break;
case CIPHER_BF:
PolarSSL.blowfish_free(_encryptCtx);
break;
case CIPHER_RC4:
PolarSSL.arc4_free(_encryptCtx);
break;
}
}
}
if (_decryptCtx != null)
{
switch (_cipher)
lock (_decryptCtx)
{
case CIPHER_AES:
PolarSSL.aes_free(_decryptCtx);
break;
case CIPHER_BF:
PolarSSL.blowfish_free(_decryptCtx);
break;
case CIPHER_RC4:
PolarSSL.arc4_free(_decryptCtx);
break;
switch (_cipher)
{
case CIPHER_AES:
PolarSSL.aes_free(_decryptCtx);
break;
case CIPHER_BF:
PolarSSL.blowfish_free(_decryptCtx);
break;
case CIPHER_RC4:
PolarSSL.arc4_free(_decryptCtx);
break;
}
}
}
_encryptCtx = null;
_decryptCtx = null;
_disposed = true;
}
}
#endregion


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

@@ -15,6 +15,7 @@ namespace Shadowsocks.Model
public List<Server> configs;
public int index;
public bool enabled;
public bool shareOverLan;
public bool isDefault;
private static string CONFIG_FILE = "gui-config.json";


+ 2
- 15
shadowsocks-csharp/Program.cs View File

@@ -23,7 +23,7 @@ namespace Shadowsocks
[STAThread]
static void Main()
{
using (Mutex mutex = new Mutex(false, "Global\\" + Assembly.GetExecutingAssembly().GetType().GUID.ToString()))
using (Mutex mutex = new Mutex(false, "Global\\" + "71981632-A427-497F-AB91-241CD227EC1F"))
{
if (!mutex.WaitOne(0, false))
{
@@ -47,26 +47,13 @@ namespace Shadowsocks
}
LoadLibrary(dllPath);
try
{
FileStream fs = new FileStream("shadowsocks.log", FileMode.Append);
TextWriter tmp = Console.Out;
StreamWriter sw = new StreamWriter(fs);
sw.AutoFlush = true;
Console.SetOut(sw);
Console.SetError(sw);
}
catch (IOException e)
{
Console.WriteLine(e.ToString());
}
Logging.OpenLogFile();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ShadowsocksController controller = new ShadowsocksController();
// TODO run without a main form to save RAM
Application.Run(new ConfigForm(controller));
}
}
}


+ 1
- 1
shadowsocks-csharp/Properties/AssemblyInfo.cs View File

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.0.4")]
[assembly: AssemblyVersion("2.0.6")]
// [assembly: AssemblyFileVersion("2.0.0")]

+ 1
- 1
shadowsocks-csharp/Properties/Resources.Designer.cs View File

@@ -71,7 +71,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized string similar to proxyAddress = &quot;127.0.0.1&quot;
/// Looks up a localized string similar to proxyAddress = &quot;__POLIPO_BIND_IP__&quot;
///
///socksParentProxy = &quot;127.0.0.1:__SOCKS_PORT__&quot;
///socksProxyType = socks5


+ 27
- 8
shadowsocks-csharp/View/ConfigForm.Designer.cs View File

@@ -50,12 +50,14 @@
this.panel1 = new System.Windows.Forms.Panel();
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
this.enableItem = new System.Windows.Forms.MenuItem();
this.ShareOverLANItem = new System.Windows.Forms.MenuItem();
this.ServersItem = new System.Windows.Forms.MenuItem();
this.SeperatorItem = new System.Windows.Forms.MenuItem();
this.ConfigItem = new System.Windows.Forms.MenuItem();
this.menuItem4 = new System.Windows.Forms.MenuItem();
this.editPACFileItem = new System.Windows.Forms.MenuItem();
this.QRCodeItem = new System.Windows.Forms.MenuItem();
this.ShowLogItem = new System.Windows.Forms.MenuItem();
this.aboutItem = new System.Windows.Forms.MenuItem();
this.menuItem3 = new System.Windows.Forms.MenuItem();
this.quitItem = new System.Windows.Forms.MenuItem();
@@ -285,10 +287,12 @@
//
this.contextMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.enableItem,
this.ShareOverLANItem,
this.ServersItem,
this.menuItem4,
this.editPACFileItem,
this.QRCodeItem,
this.ShowLogItem,
this.aboutItem,
this.menuItem3,
this.quitItem});
@@ -299,9 +303,15 @@
this.enableItem.Text = "&Enable";
this.enableItem.Click += new System.EventHandler(this.EnableItem_Click);
//
// ShareOverLANItem
//
this.ShareOverLANItem.Index = 1;
this.ShareOverLANItem.Text = "Share over LAN";
this.ShareOverLANItem.Click += new System.EventHandler(this.ShareOverLANItem_Click);
//
// ServersItem
//
this.ServersItem.Index = 1;
this.ServersItem.Index = 2;
this.ServersItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.SeperatorItem,
this.ConfigItem});
@@ -320,35 +330,41 @@
//
// menuItem4
//
this.menuItem4.Index = 2;
this.menuItem4.Index = 3;
this.menuItem4.Text = "-";
//
// editPACFileItem
//
this.editPACFileItem.Index = 3;
this.editPACFileItem.Index = 4;
this.editPACFileItem.Text = "Edit &PAC File...";
this.editPACFileItem.Click += new System.EventHandler(this.EditPACFileItem_Click);
//
// QRCodeItem
//
this.QRCodeItem.Index = 4;
this.QRCodeItem.Index = 5;
this.QRCodeItem.Text = "Show &QRCode...";
this.QRCodeItem.Click += new System.EventHandler(this.QRCodeItem_Click);
//
// ShowLogItem
//
this.ShowLogItem.Index = 6;
this.ShowLogItem.Text = "Show Logs...";
this.ShowLogItem.Click += new System.EventHandler(this.ShowLogItem_Click);
//
// aboutItem
//
this.aboutItem.Index = 5;
this.aboutItem.Index = 7;
this.aboutItem.Text = "About...";
this.aboutItem.Click += new System.EventHandler(this.AboutItem_Click);
//
// menuItem3
//
this.menuItem3.Index = 6;
this.menuItem3.Index = 8;
this.menuItem3.Text = "-";
//
// quitItem
//
this.quitItem.Index = 7;
this.quitItem.Index = 9;
this.quitItem.Text = "&Quit";
this.quitItem.Click += new System.EventHandler(this.Quit_Click);
//
@@ -418,9 +434,10 @@
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ConfigForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Shadowsocks";
this.Text = "Edit Servers";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ConfigForm_FormClosed);
this.Load += new System.EventHandler(this.ConfigForm_Load);
this.Shown += new System.EventHandler(this.ConfigForm_Shown);
@@ -471,6 +488,8 @@
private System.Windows.Forms.TextBox RemarksTextBox;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.MenuItem QRCodeItem;
private System.Windows.Forms.MenuItem ShowLogItem;
private System.Windows.Forms.MenuItem ShareOverLANItem;
}
}

+ 77
- 37
shadowsocks-csharp/View/ConfigForm.cs View File

@@ -13,11 +13,12 @@ namespace Shadowsocks.View
public partial class ConfigForm : Form
{
private ShadowsocksController controller;
private UpdateChecker updateChecker;
// this is a copy of configuration that we are working on
private Configuration modifiedConfiguration;
private int oldSelectedIndex = -1;
private bool isFirstRun;
private Configuration _modifiedConfiguration;
private int _oldSelectedIndex = -1;
private bool _isFirstRun;
public ConfigForm(ShadowsocksController controller)
{
@@ -28,6 +29,10 @@ namespace Shadowsocks.View
controller.EnableStatusChanged += controller_EnableStatusChanged;
controller.ConfigChanged += controller_ConfigChanged;
controller.PACFileReadyToOpen += controller_PACFileReadyToOpen;
controller.ShareOverLANStatusChanged += controller_ShareOverLANStatusChanged;
this.updateChecker = new UpdateChecker();
updateChecker.NewVersionFound += updateChecker_NewVersionFound;
LoadCurrentConfiguration();
}
@@ -42,6 +47,11 @@ namespace Shadowsocks.View
enableItem.Checked = controller.GetConfiguration().enabled;
}
void controller_ShareOverLANStatusChanged(object sender, EventArgs e)
{
ShareOverLANItem.Checked = controller.GetConfiguration().shareOverLan;
}
void controller_PACFileReadyToOpen(object sender, ShadowsocksController.PathEventArgs e)
{
string argument = @"/select, " + e.Path;
@@ -49,6 +59,21 @@ namespace Shadowsocks.View
System.Diagnostics.Process.Start("explorer.exe", argument);
}
void updateChecker_NewVersionFound(object sender, EventArgs e)
{
notifyIcon1.BalloonTipTitle = "Shadowsocks " + updateChecker.LatestVersionNumber + " Update Found";
notifyIcon1.BalloonTipText = "Click here to download";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.BalloonTipClicked += notifyIcon1_BalloonTipClicked;
notifyIcon1.ShowBalloonTip(5000);
_isFirstRun = false;
}
void notifyIcon1_BalloonTipClicked(object sender, EventArgs e)
{
Process.Start(updateChecker.LatestVersionURL);
}
private void ShowWindow()
{
@@ -61,7 +86,7 @@ namespace Shadowsocks.View
{
try
{
if (oldSelectedIndex == -1 || oldSelectedIndex >= modifiedConfiguration.configs.Count)
if (_oldSelectedIndex == -1 || _oldSelectedIndex >= _modifiedConfiguration.configs.Count)
{
return true;
}
@@ -75,7 +100,8 @@ namespace Shadowsocks.View
remarks = RemarksTextBox.Text
};
Configuration.CheckServer(server);
modifiedConfiguration.configs[oldSelectedIndex] = server;
_modifiedConfiguration.configs[_oldSelectedIndex] = server;
return true;
}
catch (FormatException)
@@ -91,15 +117,15 @@ namespace Shadowsocks.View
private void LoadSelectedServer()
{
if (ServersListBox.SelectedIndex >= 0 && ServersListBox.SelectedIndex < modifiedConfiguration.configs.Count)
if (ServersListBox.SelectedIndex >= 0 && ServersListBox.SelectedIndex < _modifiedConfiguration.configs.Count)
{
Server server = modifiedConfiguration.configs[ServersListBox.SelectedIndex];
Server server = _modifiedConfiguration.configs[ServersListBox.SelectedIndex];
IPTextBox.Text = server.server;
ServerPortTextBox.Text = server.server_port.ToString();
PasswordTextBox.Text = server.password;
ProxyPortTextBox.Text = server.local_port.ToString();
EncryptionSelect.Text = server.method == null ? "aes-256-cfb" : server.method;
EncryptionSelect.Text = server.method ?? "aes-256-cfb";
RemarksTextBox.Text = server.remarks;
ServerGroupBox.Visible = true;
//IPTextBox.Focus();
@@ -113,7 +139,7 @@ namespace Shadowsocks.View
private void LoadConfiguration(Configuration configuration)
{
ServersListBox.Items.Clear();
foreach (Server server in modifiedConfiguration.configs)
foreach (Server server in _modifiedConfiguration.configs)
{
ServersListBox.Items.Add(string.IsNullOrEmpty(server.server) ? "New server" : string.IsNullOrEmpty(server.remarks)? server.server + ":" + server.server_port : server.server + ":" + server.server_port + " (" + server.remarks + ")");
}
@@ -121,14 +147,15 @@ namespace Shadowsocks.View
private void LoadCurrentConfiguration()
{
modifiedConfiguration = controller.GetConfiguration();
LoadConfiguration(modifiedConfiguration);
oldSelectedIndex = modifiedConfiguration.index;
ServersListBox.SelectedIndex = modifiedConfiguration.index;
_modifiedConfiguration = controller.GetConfiguration();
LoadConfiguration(_modifiedConfiguration);
_oldSelectedIndex = _modifiedConfiguration.index;
ServersListBox.SelectedIndex = _modifiedConfiguration.index;
LoadSelectedServer();
UpdateServersMenu();
enableItem.Checked = modifiedConfiguration.enabled;
enableItem.Checked = _modifiedConfiguration.enabled;
ShareOverLANItem.Checked = _modifiedConfiguration.shareOverLan;
}
private void UpdateServersMenu()
@@ -167,13 +194,14 @@ namespace Shadowsocks.View
}
else
{
isFirstRun = true;
_isFirstRun = true;
}
updateChecker.CheckUpdate();
}
private void ServersListBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (oldSelectedIndex == ServersListBox.SelectedIndex)
if (_oldSelectedIndex == ServersListBox.SelectedIndex)
{
// we are moving back to oldSelectedIndex or doing a force move
return;
@@ -181,11 +209,11 @@ namespace Shadowsocks.View
if (!SaveOldSelectedServer())
{
// why this won't cause stack overflow?
ServersListBox.SelectedIndex = oldSelectedIndex;
ServersListBox.SelectedIndex = _oldSelectedIndex;
return;
}
LoadSelectedServer();
oldSelectedIndex = ServersListBox.SelectedIndex;
_oldSelectedIndex = ServersListBox.SelectedIndex;
}
private void AddButton_Click(object sender, EventArgs e)
@@ -195,27 +223,27 @@ namespace Shadowsocks.View
return;
}
Server server = Configuration.GetDefaultServer();
modifiedConfiguration.configs.Add(server);
LoadConfiguration(modifiedConfiguration);
ServersListBox.SelectedIndex = modifiedConfiguration.configs.Count - 1;
oldSelectedIndex = ServersListBox.SelectedIndex;
_modifiedConfiguration.configs.Add(server);
LoadConfiguration(_modifiedConfiguration);
ServersListBox.SelectedIndex = _modifiedConfiguration.configs.Count - 1;
_oldSelectedIndex = ServersListBox.SelectedIndex;
}
private void DeleteButton_Click(object sender, EventArgs e)
{
oldSelectedIndex = ServersListBox.SelectedIndex;
if (oldSelectedIndex >= 0 && oldSelectedIndex < modifiedConfiguration.configs.Count)
_oldSelectedIndex = ServersListBox.SelectedIndex;
if (_oldSelectedIndex >= 0 && _oldSelectedIndex < _modifiedConfiguration.configs.Count)
{
modifiedConfiguration.configs.RemoveAt(oldSelectedIndex);
_modifiedConfiguration.configs.RemoveAt(_oldSelectedIndex);
}
if (oldSelectedIndex >= modifiedConfiguration.configs.Count)
if (_oldSelectedIndex >= _modifiedConfiguration.configs.Count)
{
// can be -1
oldSelectedIndex = modifiedConfiguration.configs.Count - 1;
_oldSelectedIndex = _modifiedConfiguration.configs.Count - 1;
}
ServersListBox.SelectedIndex = oldSelectedIndex;
LoadConfiguration(modifiedConfiguration);
ServersListBox.SelectedIndex = oldSelectedIndex;
ServersListBox.SelectedIndex = _oldSelectedIndex;
LoadConfiguration(_modifiedConfiguration);
ServersListBox.SelectedIndex = _oldSelectedIndex;
LoadSelectedServer();
}
@@ -231,12 +259,13 @@ namespace Shadowsocks.View
private void ShowFirstTimeBalloon()
{
if (isFirstRun)
if (_isFirstRun)
{
notifyIcon1.BalloonTipTitle = "Shadowsocks is here";
notifyIcon1.BalloonTipText = "You can turn on/off Shadowsocks in the context menu";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.ShowBalloonTip(0);
isFirstRun = false;
_isFirstRun = false;
}
}
@@ -246,12 +275,12 @@ namespace Shadowsocks.View
{
return;
}
if (modifiedConfiguration.configs.Count == 0)
if (_modifiedConfiguration.configs.Count == 0)
{
MessageBox.Show("Please add at least one server");
return;
}
controller.SaveConfig(modifiedConfiguration);
controller.SaveServers(_modifiedConfiguration.configs);
this.Hide();
ShowFirstTimeBalloon();
}
@@ -285,6 +314,12 @@ namespace Shadowsocks.View
controller.ToggleEnable(enableItem.Checked);
}
private void ShareOverLANItem_Click(object sender, EventArgs e)
{
ShareOverLANItem.Checked = !ShareOverLANItem.Checked;
controller.ToggleShareOverLAN(ShareOverLANItem.Checked);
}
private void EditPACFileItem_Click(object sender, EventArgs e)
{
controller.TouchPACFile();
@@ -293,9 +328,14 @@ namespace Shadowsocks.View
private void AServerItem_Click(object sender, EventArgs e)
{
MenuItem item = (MenuItem)sender;
Configuration configuration = controller.GetConfiguration();
configuration.index = (int)item.Tag;
controller.SaveConfig(configuration);
controller.SelectServerIndex((int)item.Tag);
}
private void ShowLogItem_Click(object sender, EventArgs e)
{
string argument = Logging.LogFile;
System.Diagnostics.Process.Start("notepad.exe", argument);
}
private void ConfigForm_Shown(object sender, EventArgs e)


+ 37
- 22
shadowsocks-csharp/View/QRCodeForm.cs View File

@@ -25,35 +25,50 @@ namespace Shadowsocks.View
private void GenQR(string ssconfig)
{
string qrText = ssconfig;
QRCode4CS.QRCode qrCoded = new QRCode4CS.QRCode(6, QRErrorCorrectLevel.H);
qrCoded.AddData(qrText);
qrCoded.Make();
int blockSize = 5;
Bitmap drawArea = new Bitmap((qrCoded.GetModuleCount() * blockSize), (qrCoded.GetModuleCount() * blockSize));
for (int row = 0; row < qrCoded.GetModuleCount(); row++)
QRCode4CS.Options options = new QRCode4CS.Options();
options.Text = qrText;
QRCode4CS.QRCode qrCoded = null;
bool success = false;
foreach (var level in new QRErrorCorrectLevel[]{QRErrorCorrectLevel.H, QRErrorCorrectLevel.Q, QRErrorCorrectLevel.M, QRErrorCorrectLevel.L})
{
for (int col = 0; col < qrCoded.GetModuleCount(); col++)
for (int i = 3; i < 10; i++)
{
bool isDark = qrCoded.IsDark(row, col);
if (isDark)
try
{
for (int y = 0; y < blockSize; y++)
{
int myCol = (blockSize * (col - 1)) + (y + blockSize);
for (int x = 0; x < blockSize; x++)
{
drawArea.SetPixel((blockSize * (row - 1)) + (x + blockSize), myCol, Color.Black);
}
}
options.TypeNumber = i;
options.CorrectLevel = level;
qrCoded = new QRCode4CS.QRCode(options);
qrCoded.Make();
success = true;
break;
}
catch
{
qrCoded = null;
continue;
}
else
}
if (success)
break;
}
if (qrCoded == null)
{
return;
}
int blockSize = Math.Max(200 / qrCoded.GetModuleCount(), 1);
Bitmap drawArea = new Bitmap((qrCoded.GetModuleCount() * blockSize), (qrCoded.GetModuleCount() * blockSize));
using (Graphics g = Graphics.FromImage(drawArea))
{
g.Clear(Color.White);
using (Brush b = new SolidBrush(Color.Black))
{
for (int row = 0; row < qrCoded.GetModuleCount(); row++)
{
for (int y = 0; y < blockSize; y++)
for (int col = 0; col < qrCoded.GetModuleCount(); col++)
{
int myCol = (blockSize * (col - 1)) + (y + blockSize);
for (int x = 0; x < blockSize; x++)
if (qrCoded.IsDark(row, col))
{
drawArea.SetPixel((blockSize * (row - 1)) + (x + blockSize), myCol, Color.White);
g.FillRectangle(b, blockSize * row, blockSize * col, blockSize, blockSize);
}
}
}


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

@@ -63,11 +63,14 @@
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
<Compile Include="3rd\QRCodeCS.cs" />
<Compile Include="3rd\SimpleJson.cs" />
<Compile Include="Controller\FileManager.cs" />
<Compile Include="Controller\Logging.cs" />
<Compile Include="Controller\UpdateChecker.cs" />
<Compile Include="Encrypt\EncryptorBase.cs" />
<Compile Include="Encrypt\EncryptorFactory.cs" />
<Compile Include="Encrypt\PolarSSL.cs" />


+ 36
- 0
test/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("test")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f74e87ac-7e3a-444b-a1d9-8b91a674c60f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

+ 22
- 0
test/UnitTest.cs View File

@@ -0,0 +1,22 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shadowsocks.Controller;
namespace test
{
[TestClass]
public class UnitTest
{
[TestMethod]
public void TestCompareVersion()
{
Assert.IsTrue(UpdateChecker.CompareVersion("2.3.1.0", "2.3.1") == 0);
Assert.IsTrue(UpdateChecker.CompareVersion("1.2", "1.3") < 0);
Assert.IsTrue(UpdateChecker.CompareVersion("1.3", "1.2") > 0);
Assert.IsTrue(UpdateChecker.CompareVersion("1.3", "1.3") == 0);
Assert.IsTrue(UpdateChecker.CompareVersion("1.2.1", "1.2") > 0);
Assert.IsTrue(UpdateChecker.CompareVersion("2.3.1", "2.4") < 0);
Assert.IsTrue(UpdateChecker.CompareVersion("1.3.2", "1.3.1") > 0);
}
}
}

+ 81
- 0
test/test.csproj View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{45913187-0685-4903-B250-DCEF0479CD86}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>test</RootNamespace>
<AssemblyName>test</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<OutputPath>bin\x86\Debug\</OutputPath>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="UnitTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\shadowsocks-csharp\shadowsocks-csharp.csproj">
<Project>{8c02d2f7-7cdb-4d55-9f25-cd03ef4aa062}</Project>
<Name>shadowsocks-csharp</Name>
</ProjectReference>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Loading…
Cancel
Save