Merge remote-tracking branch 'upstream/master' into feature/statistics_ui
# Conflicts: # shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs # shadowsocks-csharp/Controller/Strategy/StatisticsStrategy.cs # shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs
This commit is contained in:
@@ -30,16 +30,16 @@ namespace ZXing.Common
|
||||
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || WINDOWS_PHONE80 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE)
|
||||
private const String PLATFORM_DEFAULT_ENCODING = "UTF-8";
|
||||
#else
|
||||
private static String PLATFORM_DEFAULT_ENCODING = Encoding.Default.WebName;
|
||||
private static string PLATFORM_DEFAULT_ENCODING = Encoding.Default.WebName;
|
||||
#endif
|
||||
public static String SHIFT_JIS = "SJIS";
|
||||
public static String GB2312 = "GB2312";
|
||||
private const String EUC_JP = "EUC-JP";
|
||||
private const String UTF8 = "UTF-8";
|
||||
private const String ISO88591 = "ISO-8859-1";
|
||||
public static string SHIFT_JIS = "SJIS";
|
||||
public static string GB2312 = "GB2312";
|
||||
private const string EUC_JP = "EUC-JP";
|
||||
private const string UTF8 = "UTF-8";
|
||||
private const string ISO88591 = "ISO-8859-1";
|
||||
private static readonly bool ASSUME_SHIFT_JIS =
|
||||
String.Compare(SHIFT_JIS, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase) == 0 ||
|
||||
String.Compare(EUC_JP, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase) == 0;
|
||||
string.Equals(SHIFT_JIS, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(EUC_JP, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Guesses the encoding.
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace ZXing.Common.ReedSolomon
|
||||
|
||||
internal GenericGFPoly addOrSubtract(GenericGFPoly other)
|
||||
{
|
||||
if (!field.Equals(other.field))
|
||||
if (field != other.field)
|
||||
{
|
||||
throw new ArgumentException("GenericGFPolys do not have same GenericGF field");
|
||||
}
|
||||
@@ -181,7 +181,7 @@ namespace ZXing.Common.ReedSolomon
|
||||
|
||||
internal GenericGFPoly multiply(GenericGFPoly other)
|
||||
{
|
||||
if (!field.Equals(other.field))
|
||||
if (field != other.field)
|
||||
{
|
||||
throw new ArgumentException("GenericGFPolys do not have same GenericGF field");
|
||||
}
|
||||
@@ -246,7 +246,7 @@ namespace ZXing.Common.ReedSolomon
|
||||
|
||||
internal GenericGFPoly[] divide(GenericGFPoly other)
|
||||
{
|
||||
if (!field.Equals(other.field))
|
||||
if (field != other.field)
|
||||
{
|
||||
throw new ArgumentException("GenericGFPolys do not have same GenericGF field");
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace ZXing.QrCode.Internal
|
||||
{
|
||||
encoding = DEFAULT_BYTE_MODE_ENCODING;
|
||||
}
|
||||
bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding);
|
||||
bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding, StringComparison.OrdinalIgnoreCase);
|
||||
#else
|
||||
// Silverlight supports only UTF-8 and UTF-16 out-of-the-box
|
||||
const string encoding = "UTF-8";
|
||||
@@ -514,7 +514,8 @@ namespace ZXing.QrCode.Internal
|
||||
BitArray bits,
|
||||
String encoding)
|
||||
{
|
||||
if (mode.Equals(Mode.BYTE))
|
||||
// TODO: check the purpose of this .Equals(obj)
|
||||
if (mode == Mode.BYTE)
|
||||
append8BitBytes(content, bits, encoding);
|
||||
else
|
||||
throw new WriterException("Invalid mode: " + mode);
|
||||
|
||||
@@ -10,37 +10,35 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
FileStream _FileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write);
|
||||
_FileStream.Write(content, 0, content.Length);
|
||||
_FileStream.Close();
|
||||
using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
|
||||
fs.Write(content, 0, content.Length);
|
||||
return true;
|
||||
}
|
||||
catch (Exception _Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Exception caught in process: {0}",
|
||||
_Exception.ToString());
|
||||
ex.ToString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void UncompressFile(string fileName, byte[] content)
|
||||
{
|
||||
FileStream destinationFile = File.Create(fileName);
|
||||
|
||||
// Because the uncompressed size of the file is unknown,
|
||||
// we are using an arbitrary buffer size.
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(content),
|
||||
using(var fs = File.Create(fileName))
|
||||
using (var input = new GZipStream(
|
||||
new MemoryStream(content),
|
||||
CompressionMode.Decompress, false))
|
||||
{
|
||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
destinationFile.Write(buffer, 0, n);
|
||||
fs.Write(buffer, 0, n);
|
||||
}
|
||||
}
|
||||
destinationFile.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using Shadowsocks.Properties;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
using Shadowsocks.Properties;
|
||||
|
||||
public class I18N
|
||||
{
|
||||
protected static Dictionary<string, string> Strings;
|
||||
@@ -13,19 +14,19 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
Strings = new Dictionary<string, string>();
|
||||
|
||||
if (System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag.ToLowerInvariant().StartsWith("zh"))
|
||||
if (CultureInfo.CurrentCulture.IetfLanguageTag.StartsWith("zh", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string[] lines = Regex.Split(Resources.cn, "\r\n|\r|\n");
|
||||
foreach (string line in lines)
|
||||
using (var sr = new StringReader(Resources.cn))
|
||||
{
|
||||
if (line.StartsWith("#"))
|
||||
foreach (var line in sr.NonWhiteSpaceLines())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string[] kv = Regex.Split(line, "=");
|
||||
if (kv.Length == 2)
|
||||
{
|
||||
Strings[kv[0]] = kv[1];
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
var pos = line.IndexOf('=');
|
||||
if (pos < 1)
|
||||
continue;
|
||||
Strings[line.Substring(0, pos)] = line.Substring(pos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,4 +316,4 @@ namespace Shadowsocks.Controller
|
||||
_speedMonior.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' };
|
||||
private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -39,12 +40,14 @@ namespace Shadowsocks.Controller
|
||||
if (File.Exists(PACServer.USER_RULE_FILE))
|
||||
{
|
||||
string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
|
||||
string[] rules = local.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string rule in rules)
|
||||
using (var sr = new StringReader(local))
|
||||
{
|
||||
if (rule.StartsWith("!") || rule.StartsWith("["))
|
||||
continue;
|
||||
lines.Add(rule);
|
||||
foreach (var rule in sr.NonWhiteSpaceLines())
|
||||
{
|
||||
if (rule.BeginWithAny(IgnoredLineBegins))
|
||||
continue;
|
||||
lines.Add(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
string abpContent;
|
||||
@@ -93,13 +96,15 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
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)
|
||||
List<string> valid_lines = new List<string>();
|
||||
using (var sr = new StringReader(content))
|
||||
{
|
||||
if (line.StartsWith("!") || line.StartsWith("["))
|
||||
continue;
|
||||
valid_lines.Add(line);
|
||||
foreach (var line in sr.NonWhiteSpaceLines())
|
||||
{
|
||||
if (line.BeginWithAny(IgnoredLineBegins))
|
||||
continue;
|
||||
valid_lines.Add(line);
|
||||
}
|
||||
}
|
||||
return valid_lines;
|
||||
}
|
||||
|
||||
@@ -438,6 +438,7 @@ namespace Shadowsocks.Controller
|
||||
UpdatePACFromGFWListError(this, e);
|
||||
}
|
||||
|
||||
private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' };
|
||||
private void pacServer_UserRuleFileChanged(object sender, EventArgs e)
|
||||
{
|
||||
// TODO: this is a dirty hack. (from code GListUpdater.http_DownloadStringCompleted())
|
||||
@@ -450,12 +451,14 @@ namespace Shadowsocks.Controller
|
||||
if (File.Exists(PACServer.USER_RULE_FILE))
|
||||
{
|
||||
string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
|
||||
string[] rules = local.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string rule in rules)
|
||||
using (var sr = new StringReader(local))
|
||||
{
|
||||
if (rule.StartsWith("!") || rule.StartsWith("["))
|
||||
continue;
|
||||
lines.Add(rule);
|
||||
foreach (var rule in sr.NonWhiteSpaceLines())
|
||||
{
|
||||
if (rule.BeginWithAny(IgnoredLineBegins))
|
||||
continue;
|
||||
lines.Add(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
string abpContent;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Shadowsocks.Controller.Strategy
|
||||
private Statistics _filteredStatistics;
|
||||
private AvailabilityStatistics Service => _controller.availabilityStatistics;
|
||||
private int ChoiceKeptMilliseconds
|
||||
=> (int) TimeSpan.FromMinutes(_controller.StatisticsConfiguration.ChoiceKeptMinutes).TotalMilliseconds;
|
||||
=> (int)TimeSpan.FromMinutes(_controller.StatisticsConfiguration.ChoiceKeptMinutes).TotalMilliseconds;
|
||||
|
||||
public StatisticsStrategy(ShadowsocksController controller)
|
||||
{
|
||||
@@ -93,7 +93,7 @@ namespace Shadowsocks.Controller.Strategy
|
||||
}
|
||||
).Aggregate((result1, result2) => result1.score > result2.score ? result1 : result2);
|
||||
|
||||
LogWhenEnabled($"Switch to server: {bestResult.server.FriendlyName()} by statistics: score {bestResult.score}");
|
||||
LogWhenEnabled($"Switch to server: {bestResult.server.FriendlyName()} by statistics: score {bestResult.score}");
|
||||
_currentServer = bestResult.server;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
@@ -14,7 +14,7 @@ namespace Shadowsocks.Controller
|
||||
try
|
||||
{
|
||||
string path = Application.ExecutablePath;
|
||||
runKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true);
|
||||
runKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true);
|
||||
if (enabled)
|
||||
{
|
||||
runKey.SetValue(Key, path);
|
||||
@@ -47,16 +47,16 @@ namespace Shadowsocks.Controller
|
||||
try
|
||||
{
|
||||
string path = Application.ExecutablePath;
|
||||
runKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true);
|
||||
runKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true);
|
||||
string[] runList = runKey.GetValueNames();
|
||||
foreach (string item in runList)
|
||||
{
|
||||
if (item.Equals(Key))
|
||||
if (item.Equals(Key, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
else if (item.Equals("Shadowsocks")) // Compatibility with older versions
|
||||
else if (item.Equals("Shadowsocks", StringComparison.OrdinalIgnoreCase)) // Compatibility with older versions
|
||||
{
|
||||
string value = Convert.ToString(runKey.GetValue(item));
|
||||
if (path.Equals(value, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (path.Equals(value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
runKey.DeleteValue(item);
|
||||
runKey.SetValue(Key, path);
|
||||
@@ -76,10 +76,10 @@ namespace Shadowsocks.Controller
|
||||
if (runKey != null)
|
||||
{
|
||||
try { runKey.Close(); }
|
||||
catch(Exception e)
|
||||
catch (Exception e)
|
||||
{ Logging.LogUsefulException(e); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ using Shadowsocks.Model;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
public class SystemProxy
|
||||
public static class SystemProxy
|
||||
{
|
||||
|
||||
[DllImport("wininet.dll")]
|
||||
@@ -26,19 +26,29 @@ namespace Shadowsocks.Controller
|
||||
_refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
|
||||
}
|
||||
|
||||
private static readonly DateTime UnixEpoch
|
||||
= new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
public static long ToUnixEpochMilliseconds(this DateTime dt)
|
||||
=> (long)(dt - UnixEpoch).TotalMilliseconds;
|
||||
private static string GetTimestamp(DateTime value)
|
||||
{
|
||||
return value.ToString("yyyyMMddHHmmssfff");
|
||||
}
|
||||
|
||||
public static void Update(Configuration config, bool forceDisable)
|
||||
{
|
||||
bool global = config.global;
|
||||
bool enabled = config.enabled;
|
||||
|
||||
if (forceDisable)
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
RegistryKey registry =
|
||||
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
|
||||
true);
|
||||
var registry = Registry.CurrentUser
|
||||
.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
||||
if (enabled)
|
||||
{
|
||||
if (global)
|
||||
@@ -50,10 +60,10 @@ namespace Shadowsocks.Controller
|
||||
else
|
||||
{
|
||||
string pacUrl;
|
||||
if (config.useOnlinePac && !string.IsNullOrEmpty(config.pacUrl))
|
||||
if (config.useOnlinePac && !config.pacUrl.IsNullOrEmpty())
|
||||
pacUrl = config.pacUrl;
|
||||
else
|
||||
pacUrl = "http://127.0.0.1:" + config.localPort.ToString() + "/pac?t=" + GetTimestamp(DateTime.Now);
|
||||
pacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}";
|
||||
registry.SetValue("ProxyEnable", 0);
|
||||
var readProxyServer = registry.GetValue("ProxyServer");
|
||||
registry.SetValue("ProxyServer", "");
|
||||
@@ -66,9 +76,11 @@ namespace Shadowsocks.Controller
|
||||
registry.SetValue("ProxyServer", "");
|
||||
registry.SetValue("AutoConfigURL", "");
|
||||
}
|
||||
//Set AutoDetectProxy Off
|
||||
IEAutoDetectProxy(false);
|
||||
SystemProxy.NotifyIE();
|
||||
|
||||
//Set AutoDetectProxy
|
||||
IEAutoDetectProxy(!enabled);
|
||||
|
||||
NotifyIE();
|
||||
//Must Notify IE first, or the connections do not chanage
|
||||
CopyProxySettingFromLan();
|
||||
}
|
||||
@@ -82,55 +94,66 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private static void CopyProxySettingFromLan()
|
||||
{
|
||||
RegistryKey registry =
|
||||
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections",
|
||||
true);
|
||||
var registry = Registry.CurrentUser
|
||||
.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections", true);
|
||||
var defaultValue = registry.GetValue("DefaultConnectionSettings");
|
||||
try
|
||||
{
|
||||
var connections = registry.GetValueNames();
|
||||
foreach (String each in connections)
|
||||
foreach (var each in connections)
|
||||
{
|
||||
if (!(each.Equals("DefaultConnectionSettings")
|
||||
|| each.Equals("LAN Connection")
|
||||
|| each.Equals("SavedLegacySettings")))
|
||||
switch (each.ToUpperInvariant())
|
||||
{
|
||||
//set all the connections's proxy as the lan
|
||||
registry.SetValue(each, defaultValue);
|
||||
case "DEFAULTCONNECTIONSETTINGS":
|
||||
case "LAN CONNECTION":
|
||||
case "SAVEDLEGACYSETTINGS":
|
||||
continue;
|
||||
default:
|
||||
//set all the connections's proxy as the lan
|
||||
registry.SetValue(each, defaultValue);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
SystemProxy.NotifyIE();
|
||||
} catch (IOException e) {
|
||||
NotifyIE();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String GetTimestamp(DateTime value)
|
||||
{
|
||||
return value.ToString("yyyyMMddHHmmssffff");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks or unchecks the IE Options Connection setting of "Automatically detect Proxy"
|
||||
/// </summary>
|
||||
/// <param name="set">Provide 'true' if you want to check the 'Automatically detect Proxy' check box. To uncheck, pass 'false'</param>
|
||||
private static void IEAutoDetectProxy(bool set)
|
||||
{
|
||||
RegistryKey registry =
|
||||
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections",
|
||||
true);
|
||||
byte[] defConnection = (byte[])registry.GetValue("DefaultConnectionSettings");
|
||||
byte[] savedLegacySetting = (byte[])registry.GetValue("SavedLegacySettings");
|
||||
var registry = Registry.CurrentUser
|
||||
.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections", true);
|
||||
var defConnection = (byte[])registry.GetValue("DefaultConnectionSettings");
|
||||
var savedLegacySetting = (byte[])registry.GetValue("SavedLegacySettings");
|
||||
|
||||
const int versionOffset = 4;
|
||||
const int optionsOffset = 8;
|
||||
|
||||
if (set)
|
||||
{
|
||||
defConnection[8] = Convert.ToByte(defConnection[8] & 8);
|
||||
savedLegacySetting[8] = Convert.ToByte(savedLegacySetting[8] & 8);
|
||||
defConnection[optionsOffset] = (byte)(defConnection[optionsOffset] | 8);
|
||||
savedLegacySetting[optionsOffset] = (byte)(savedLegacySetting[optionsOffset] | 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
defConnection[8] = Convert.ToByte(defConnection[8] & ~8);
|
||||
savedLegacySetting[8] = Convert.ToByte(savedLegacySetting[8] & ~8);
|
||||
defConnection[optionsOffset] = (byte)(defConnection[optionsOffset] & ~8);
|
||||
savedLegacySetting[optionsOffset] = (byte)(savedLegacySetting[optionsOffset] & ~8);
|
||||
}
|
||||
|
||||
BitConverter.GetBytes(
|
||||
unchecked(BitConverter.ToUInt32(defConnection, versionOffset) + 1))
|
||||
.CopyTo(defConnection, versionOffset);
|
||||
BitConverter.GetBytes(
|
||||
unchecked(BitConverter.ToUInt32(savedLegacySetting, versionOffset) + 1))
|
||||
.CopyTo(savedLegacySetting, versionOffset);
|
||||
|
||||
registry.SetValue("DefaultConnectionSettings", defConnection);
|
||||
registry.SetValue("SavedLegacySettings", savedLegacySetting);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Shadowsocks.Encryption
|
||||
|
||||
public static IEncryptor GetEncryptor(string method, string password, bool onetimeauth, bool isudp)
|
||||
{
|
||||
if (string.IsNullOrEmpty(method))
|
||||
if (method.IsNullOrEmpty())
|
||||
{
|
||||
method = "aes-256-cfb";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
@@ -24,7 +25,7 @@ namespace Shadowsocks.Encryption
|
||||
|
||||
protected Dictionary<string, int[]> ciphers;
|
||||
|
||||
private static readonly Dictionary<string, byte[]> CachedKeys = new Dictionary<string, byte[]>();
|
||||
private static readonly ConcurrentDictionary<string, byte[]> CachedKeys = new ConcurrentDictionary<string, byte[]>();
|
||||
protected byte[] _encryptIV;
|
||||
protected byte[] _decryptIV;
|
||||
protected bool _decryptIVReceived;
|
||||
@@ -62,22 +63,14 @@ namespace Shadowsocks.Encryption
|
||||
}
|
||||
keyLen = ciphers[_method][0];
|
||||
ivLen = ciphers[_method][1];
|
||||
if (!CachedKeys.ContainsKey(k))
|
||||
_key = CachedKeys.GetOrAdd(k, (nk) =>
|
||||
{
|
||||
lock (CachedKeys)
|
||||
{
|
||||
if (!CachedKeys.ContainsKey(k))
|
||||
{
|
||||
byte[] passbuf = Encoding.UTF8.GetBytes(password);
|
||||
_key = new byte[32];
|
||||
byte[] iv = new byte[16];
|
||||
bytesToKey(passbuf, _key);
|
||||
CachedKeys[k] = _key;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_key == null)
|
||||
_key = CachedKeys[k];
|
||||
byte[] passbuf = Encoding.UTF8.GetBytes(password);
|
||||
byte[] key = new byte[32];
|
||||
byte[] iv = new byte[16];
|
||||
bytesToKey(passbuf, key);
|
||||
return key;
|
||||
});
|
||||
}
|
||||
|
||||
protected void bytesToKey(byte[] password, byte[] key)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Weavers>
|
||||
<Costura/>
|
||||
|
||||
<Caseless StringComparison="Ordinal"/>
|
||||
<Costura/>
|
||||
</Weavers>
|
||||
@@ -124,13 +124,13 @@ namespace Shadowsocks.Model
|
||||
|
||||
private static void CheckPassword(string password)
|
||||
{
|
||||
if (string.IsNullOrEmpty(password))
|
||||
if (password.IsNullOrEmpty())
|
||||
throw new ArgumentException(I18N.GetString("Password can not be blank"));
|
||||
}
|
||||
|
||||
private static void CheckServer(string server)
|
||||
{
|
||||
if (string.IsNullOrEmpty(server))
|
||||
if (server.IsNullOrEmpty())
|
||||
throw new ArgumentException(I18N.GetString("Server IP can not be blank"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ namespace Shadowsocks.Model
|
||||
|
||||
public string FriendlyName()
|
||||
{
|
||||
if (string.IsNullOrEmpty(server))
|
||||
if (server.IsNullOrEmpty())
|
||||
{
|
||||
return I18N.GetString("New server");
|
||||
}
|
||||
if (string.IsNullOrEmpty(remarks))
|
||||
if (remarks.IsNullOrEmpty())
|
||||
{
|
||||
return server + ":" + server_port;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
static partial class StringEx
|
||||
{
|
||||
#pragma warning disable 1591
|
||||
|
||||
public static StringComparison GlobalDefaultComparison { get; set; } = StringComparison.Ordinal;
|
||||
|
||||
[ThreadStatic]
|
||||
private static StringComparison? _DefaultComparison;
|
||||
public static StringComparison DefaultComparison
|
||||
{
|
||||
get { return _DefaultComparison ?? GlobalDefaultComparison; }
|
||||
set { _DefaultComparison = value; }
|
||||
}
|
||||
|
||||
#region basic String methods
|
||||
|
||||
public static bool IsNullOrEmpty(this string value)
|
||||
=> string.IsNullOrEmpty(value);
|
||||
|
||||
public static bool IsNullOrWhiteSpace(this string value)
|
||||
=> string.IsNullOrWhiteSpace(value);
|
||||
|
||||
public static bool IsWhiteSpace(this string value)
|
||||
{
|
||||
foreach(var c in value)
|
||||
{
|
||||
if (char.IsWhiteSpace(c)) continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !PCL
|
||||
public static string IsInterned(this string value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
|
||||
return string.IsInterned(value);
|
||||
}
|
||||
|
||||
public static string Intern(this string value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
|
||||
return string.Intern(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region comparing
|
||||
|
||||
#region Is
|
||||
|
||||
public static bool Is(this string a, string b)
|
||||
=> string.Equals(a, b, DefaultComparison);
|
||||
public static bool Is(this string a, string b, StringComparison comparisonType)
|
||||
=> string.Equals(a, b, comparisonType);
|
||||
|
||||
#endregion
|
||||
|
||||
#region BeginWith
|
||||
|
||||
public static bool BeginWith(this string s, char c)
|
||||
{
|
||||
if (s.IsNullOrEmpty()) return false;
|
||||
return s[0] == c;
|
||||
}
|
||||
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
|
||||
{
|
||||
if (s.IsNullOrEmpty()) return false;
|
||||
return chars.Contains(s[0]);
|
||||
}
|
||||
public static bool BeginWithAny(this string s, params char[] chars)
|
||||
=> s.BeginWithAny(chars.AsEnumerable());
|
||||
|
||||
public static bool BeginWith(this string a, string b)
|
||||
{
|
||||
if (a == null || b == null) return false;
|
||||
|
||||
return a.StartsWith(b, DefaultComparison);
|
||||
}
|
||||
public static bool BeginWith(this string a, string b, StringComparison comparisonType)
|
||||
{
|
||||
if (a == null || b == null) return false;
|
||||
|
||||
return a.StartsWith(b, comparisonType);
|
||||
}
|
||||
#if !PCL
|
||||
public static bool BeginWith(this string a, string b, bool ignoreCase, CultureInfo culture)
|
||||
{
|
||||
if (a == null || b == null) return false;
|
||||
|
||||
return a.StartsWith(b, ignoreCase, culture);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region FinishWith
|
||||
|
||||
public static bool FinishWith(this string s, char c)
|
||||
{
|
||||
if (s.IsNullOrEmpty()) return false;
|
||||
return s.Last() == c;
|
||||
}
|
||||
public static bool FinishWithAny(this string s, IEnumerable<char> chars)
|
||||
{
|
||||
if (s.IsNullOrEmpty()) return false;
|
||||
return chars.Contains(s.Last());
|
||||
}
|
||||
public static bool FinishWithAny(this string s, params char[] chars)
|
||||
=> s.FinishWithAny(chars.AsEnumerable());
|
||||
|
||||
public static bool FinishWith(this string a, string b)
|
||||
{
|
||||
if (a == null || b == null) return false;
|
||||
|
||||
return a.EndsWith(b, DefaultComparison);
|
||||
}
|
||||
public static bool FinishWith(this string a, string b, StringComparison comparisonType)
|
||||
{
|
||||
if (a == null || b == null) return false;
|
||||
|
||||
return a.EndsWith(b, comparisonType);
|
||||
}
|
||||
#if !PCL
|
||||
public static bool FinishWith(this string a, string b, bool ignoreCase, CultureInfo culture)
|
||||
{
|
||||
if (a == null || b == null) return false;
|
||||
|
||||
return a.EndsWith(b, ignoreCase, culture);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region ToLines
|
||||
|
||||
public static IEnumerable<string> ToLines(this TextReader reader)
|
||||
{
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
yield return line;
|
||||
}
|
||||
public static IEnumerable<string> NonEmptyLines(this TextReader reader)
|
||||
{
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line == "") continue;
|
||||
yield return line;
|
||||
}
|
||||
}
|
||||
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
|
||||
{
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.IsWhiteSpace()) continue;
|
||||
yield return line;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region others
|
||||
|
||||
private static readonly char[][] Quotes = new[]
|
||||
{
|
||||
"\"\"",
|
||||
"''",
|
||||
"“”",
|
||||
"‘’",
|
||||
"『』",
|
||||
"「」",
|
||||
"〖〗",
|
||||
"【】",
|
||||
}.Select(s => s.ToCharArray()).ToArray();
|
||||
public static string Enquote(this string value)
|
||||
{
|
||||
if (value == null)
|
||||
return "(null)";
|
||||
|
||||
foreach (var pair in Quotes)
|
||||
{
|
||||
if (value.IndexOfAny(pair) < 0)
|
||||
return pair[0] + value + pair[1];
|
||||
}
|
||||
|
||||
return '"' + value.Replace("\\", @"\\").Replace("\"", @"\""") + '"';
|
||||
}
|
||||
|
||||
public static string Replace(this string value, string find, string rep, StringComparison comparsionType)
|
||||
{
|
||||
if (find.IsNullOrEmpty())
|
||||
throw new ArgumentException(null, nameof(find));
|
||||
if (rep == null)
|
||||
rep = "";
|
||||
if (value.IsNullOrEmpty())
|
||||
return value;
|
||||
|
||||
var sb = new StringBuilder(value.Length);
|
||||
|
||||
var last = 0;
|
||||
var len = find.Length;
|
||||
var idx = value.IndexOf(find, DefaultComparison);
|
||||
while (idx != -1)
|
||||
{
|
||||
sb.Append(value.Substring(last, idx - last));
|
||||
sb.Append(rep);
|
||||
idx += len;
|
||||
|
||||
last = idx;
|
||||
idx = value.IndexOf(find, idx, comparsionType);
|
||||
}
|
||||
sb.Append(value.Substring(last));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
public static string ReplaceEx(this string value, string find, string rep)
|
||||
=> value.Replace(find, rep, DefaultComparison);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -630,11 +630,11 @@ namespace Shadowsocks.View
|
||||
{
|
||||
if (!onlinePACItem.Checked)
|
||||
{
|
||||
if (String.IsNullOrEmpty(controller.GetConfigurationCopy().pacUrl))
|
||||
if (controller.GetConfigurationCopy().pacUrl.IsNullOrEmpty())
|
||||
{
|
||||
UpdateOnlinePACURLItem_Click(sender, e);
|
||||
}
|
||||
if (!String.IsNullOrEmpty(controller.GetConfigurationCopy().pacUrl))
|
||||
if (!controller.GetConfigurationCopy().pacUrl.IsNullOrEmpty())
|
||||
{
|
||||
localPACItem.Checked = false;
|
||||
onlinePACItem.Checked = true;
|
||||
@@ -651,7 +651,7 @@ namespace Shadowsocks.View
|
||||
I18N.GetString("Please input PAC Url"),
|
||||
I18N.GetString("Edit Online PAC URL"),
|
||||
origPacUrl, -1, -1);
|
||||
if (!string.IsNullOrEmpty(pacUrl) && pacUrl != origPacUrl)
|
||||
if (!pacUrl.IsNullOrEmpty() && pacUrl != origPacUrl)
|
||||
{
|
||||
controller.SavePACUrl(pacUrl);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Costura.Fody" version="1.3.3.0" targetFramework="net4-client" developmentDependency="true" />
|
||||
<package id="Caseless.Fody" version="1.4.1" targetFramework="net40-client" developmentDependency="true" />
|
||||
<package id="Costura.Fody" version="1.3.3.0" targetFramework="net40-client" developmentDependency="true" />
|
||||
<package id="Fody" version="1.29.4" targetFramework="net40-client" developmentDependency="true" />
|
||||
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net40-client" />
|
||||
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net40-client" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net40-client" />
|
||||
<package id="Microsoft.Net.Http" version="2.0.20710.0" targetFramework="net4-client" />
|
||||
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net40-client" />
|
||||
<package id="StringEx.CS" version="0.2" targetFramework="net40-client" />
|
||||
<package id="System.Net.Http" version="2.0.20710.0" targetFramework="net40-client" />
|
||||
</packages>
|
||||
@@ -205,6 +205,7 @@
|
||||
<Compile Include="Controller\Strategy\BalancingStrategy.cs" />
|
||||
<Compile Include="Controller\Strategy\StrategyManager.cs" />
|
||||
<Compile Include="Controller\Strategy\IStrategy.cs" />
|
||||
<Compile Include="StringEx.cs" />
|
||||
<Compile Include="Util\Util.cs" />
|
||||
<Compile Include="View\ConfigForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -334,6 +335,43 @@
|
||||
</Target>
|
||||
<Import Project="3rd\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('3rd\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
|
||||
<Import Project="3rd\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets" Condition="Exists('3rd\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets')" />
|
||||
<UsingTask TaskName="CosturaCleanup" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" TaskFactory="CodeTaskFactory">
|
||||
<ParameterGroup>
|
||||
<Config Output="false" Required="true" ParameterType="Microsoft.Build.Framework.ITaskItem" />
|
||||
<Files Output="false" Required="true" ParameterType="Microsoft.Build.Framework.ITaskItem[]" />
|
||||
</ParameterGroup>
|
||||
<Task Evaluate="true">
|
||||
<Reference xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Include="System.Xml" />
|
||||
<Reference xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Include="System.Xml.Linq" />
|
||||
<Using xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Namespace="System" />
|
||||
<Using xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Namespace="System.IO" />
|
||||
<Using xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Namespace="System.Xml.Linq" />
|
||||
<Code xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
var config = XElement.Load(Config.ItemSpec).Elements("Costura").FirstOrDefault();
|
||||
|
||||
if (config == null) return true;
|
||||
|
||||
var excludedAssemblies = new List<string>();
|
||||
var attribute = config.Attribute("ExcludeAssemblies");
|
||||
if (attribute != null)
|
||||
foreach (var item in attribute.Value.Split('|').Select(x => x.Trim()).Where(x => x != string.Empty))
|
||||
excludedAssemblies.Add(item);
|
||||
var element = config.Element("ExcludeAssemblies");
|
||||
if (element != null)
|
||||
foreach (var item in element.Value.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).Where(x => x != string.Empty))
|
||||
excludedAssemblies.Add(item);
|
||||
|
||||
var filesToCleanup = Files.Select(f => f.ItemSpec).Where(f => !excludedAssemblies.Contains(Path.GetFileNameWithoutExtension(f), StringComparer.InvariantCultureIgnoreCase));
|
||||
|
||||
foreach (var item in filesToCleanup)
|
||||
File.Delete(item);
|
||||
]]>
|
||||
</Code></Task>
|
||||
</UsingTask>
|
||||
<Target Name="CleanReferenceCopyLocalPaths" AfterTargets="AfterBuild;NonWinFodyTarget">
|
||||
<CosturaCleanup Config="FodyWeavers.xml" Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
|
||||
</Target>
|
||||
<!-- 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">
|
||||
|
||||
Executable → Regular
+32
-30
@@ -1,30 +1,32 @@
|
||||
|
||||
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
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Build.0 = Debug|x86
|
||||
{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
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
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
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Build.0 = Debug|x86
|
||||
{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
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user