@@ -1,9 +1,9 @@ | |||
using Shadowsocks.Util; | |||
using System; | |||
using System.Collections.Generic; | |||
using System; | |||
using System.IO; | |||
using System.Net.Sockets; | |||
using System.Text; | |||
using System.Net; | |||
using Shadowsocks.Util; | |||
namespace Shadowsocks.Controller | |||
{ | |||
@@ -15,8 +15,7 @@ namespace Shadowsocks.Controller | |||
{ | |||
try | |||
{ | |||
string temppath = Utils.GetTempPath(); | |||
LogFile = Path.Combine(temppath, "shadowsocks.log"); | |||
LogFile = Utils.GetTempPath("shadowsocks.log"); | |||
FileStream fs = new FileStream(LogFile, FileMode.Append); | |||
StreamWriterWithTimestamp sw = new StreamWriterWithTimestamp(fs); | |||
sw.AutoFlush = true; | |||
@@ -34,7 +33,7 @@ namespace Shadowsocks.Controller | |||
public static void Error(object o) | |||
{ | |||
Console.WriteLine("[E] "+ o); | |||
Console.WriteLine("[E] " + o); | |||
} | |||
public static void Info(object o) | |||
@@ -49,6 +48,25 @@ namespace Shadowsocks.Controller | |||
#endif | |||
} | |||
#if DEBUG | |||
public static void Debug(EndPoint local, EndPoint remote, int len, string header = null, string tailer = null) | |||
{ | |||
if (header == null && tailer == null) | |||
Debug($"{local} => {remote} (size={len})"); | |||
else if (header == null && tailer != null) | |||
Debug($"{local} => {remote} (size={len}), {tailer}"); | |||
else if (header != null && tailer == null) | |||
Debug($"{header}: {local} => {remote} (size={len})"); | |||
else | |||
Debug($"{header}: {local} => {remote} (size={len}), {tailer}"); | |||
} | |||
public static void Debug(Socket sock, int len, string header = null, string tailer = null) | |||
{ | |||
Debug(sock.LocalEndPoint, sock.RemoteEndPoint, len, header, tailer); | |||
} | |||
#endif | |||
public static void LogUsefulException(Exception e) | |||
{ | |||
// just log useful exceptions, not all of them | |||
@@ -9,6 +9,7 @@ using System.Net.NetworkInformation; | |||
using System.Net.Sockets; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Util; | |||
@@ -30,8 +31,8 @@ namespace Shadowsocks.Controller | |||
public Statistics FilteredStatistics { get; private set; } | |||
public static readonly DateTime UnknownDateTime = new DateTime(1970, 1, 1); | |||
private int Repeat => _config.RepeatTimesNum; | |||
private const int RetryInterval = 2*60*1000; //retry 2 minutes after failed | |||
private int Interval => (int) TimeSpan.FromMinutes(_config.DataCollectionMinutes).TotalMilliseconds; | |||
private const int RetryInterval = 2 * 60 * 1000; //retry 2 minutes after failed | |||
private int Interval => (int)TimeSpan.FromMinutes(_config.DataCollectionMinutes).TotalMilliseconds; | |||
private Timer _timer; | |||
private State _state; | |||
private List<Server> _servers; | |||
@@ -42,8 +43,7 @@ namespace Shadowsocks.Controller | |||
//static constructor to initialize every public static fields before refereced | |||
static AvailabilityStatistics() | |||
{ | |||
var temppath = Utils.GetTempPath(); | |||
AvailabilityStatisticsFile = Path.Combine(temppath, StatisticsFilesName); | |||
AvailabilityStatisticsFile = Utils.GetTempPath(StatisticsFilesName); | |||
} | |||
public AvailabilityStatistics(Configuration config, StatisticsStrategyConfiguration statisticsConfig) | |||
@@ -181,11 +181,11 @@ namespace Shadowsocks.Controller | |||
if (!File.Exists(AvailabilityStatisticsFile)) | |||
{ | |||
var headerLine = string.Join(Delimiter, data.Select(kv => kv.Key).ToArray()); | |||
lines = new[] {headerLine, dataLine}; | |||
lines = new[] { headerLine, dataLine }; | |||
} | |||
else | |||
{ | |||
lines = new[] {dataLine}; | |||
lines = new[] { dataLine }; | |||
} | |||
try | |||
{ | |||
@@ -248,30 +248,29 @@ namespace Shadowsocks.Controller | |||
Logging.Debug($"loading statistics from {path}"); | |||
if (!File.Exists(path)) | |||
{ | |||
Console.WriteLine($"statistics file does not exist, try to reload {RetryInterval/60/1000} minutes later"); | |||
Console.WriteLine($"statistics file does not exist, try to reload {RetryInterval / 60 / 1000} minutes later"); | |||
_timer.Change(RetryInterval, Interval); | |||
return; | |||
} | |||
RawStatistics = (from l in File.ReadAllLines(path) | |||
.Skip(1) | |||
let strings = l.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries) | |||
let rawData = new RawStatisticsData | |||
{ | |||
Timestamp = ParseExactOrUnknown(strings[0]), | |||
ServerName = strings[1], | |||
ICMPStatus = strings[2], | |||
RoundtripTime = int.Parse(strings[3]), | |||
Geolocation = 5 > strings.Length ? | |||
null | |||
: strings[4], | |||
ISP = 6 > strings.Length ? null : strings[5] | |||
} | |||
group rawData by rawData.ServerName into server | |||
select new | |||
{ | |||
ServerName = server.Key, | |||
data = server.ToList() | |||
}).ToDictionary(server => server.ServerName, server=> server.data); | |||
RawStatistics = (from l in File.ReadAllLines(path).Skip(1) | |||
let strings = l.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) | |||
let rawData = new RawStatisticsData | |||
{ | |||
Timestamp = ParseExactOrUnknown(strings[0]), | |||
ServerName = strings[1], | |||
ICMPStatus = strings[2], | |||
RoundtripTime = int.Parse(strings[3]), | |||
Geolocation = 5 > strings.Length ? | |||
null | |||
: strings[4], | |||
ISP = 6 > strings.Length ? null : strings[5] | |||
} | |||
group rawData by rawData.ServerName into server | |||
select new | |||
{ | |||
ServerName = server.Key, | |||
data = server.ToList() | |||
}).ToDictionary(server => server.ServerName, server => server.data); | |||
} | |||
catch (Exception e) | |||
{ | |||
@@ -300,7 +299,7 @@ namespace Shadowsocks.Controller | |||
public string ICMPStatus; | |||
public int RoundtripTime; | |||
public string Geolocation; | |||
public string ISP ; | |||
public string ISP; | |||
} | |||
public class StatisticsData | |||
@@ -310,6 +309,5 @@ namespace Shadowsocks.Controller | |||
public int MinResponse; | |||
public int MaxResponse; | |||
} | |||
} | |||
} |
@@ -1,12 +1,12 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using System.Net; | |||
using System.IO; | |||
using System.Net; | |||
using System.Text; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Properties; | |||
using SimpleJson; | |||
using Shadowsocks.Util; | |||
using Shadowsocks.Model; | |||
namespace Shadowsocks.Controller | |||
{ | |||
@@ -38,13 +38,13 @@ namespace Shadowsocks.Controller | |||
{ | |||
try | |||
{ | |||
File.WriteAllText(Utils.GetTempPath() + "\\gfwlist.txt", e.Result, Encoding.UTF8); | |||
File.WriteAllText(Utils.GetTempPath("gfwlist.txt"), e.Result, Encoding.UTF8); | |||
List<string> lines = ParseResult(e.Result); | |||
if (File.Exists(USER_RULE_FILE)) | |||
{ | |||
string local = File.ReadAllText(USER_RULE_FILE, Encoding.UTF8); | |||
string[] rules = local.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); | |||
foreach(string rule in rules) | |||
foreach (string rule in rules) | |||
{ | |||
if (rule.StartsWith("!") || rule.StartsWith("[")) | |||
continue; | |||
@@ -146,8 +146,8 @@ Content-Type: application/x-ns-proxy-autoconfig | |||
Content-Length: {0} | |||
Connection: Close | |||
", System.Text.Encoding.UTF8.GetBytes(pac).Length) + pac; | |||
byte[] response = System.Text.Encoding.UTF8.GetBytes(text); | |||
", Encoding.UTF8.GetBytes(pac).Length) + pac; | |||
byte[] response = Encoding.UTF8.GetBytes(text); | |||
socket.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), socket); | |||
Util.Utils.ReleaseMemory(true); | |||
} | |||
@@ -1,14 +1,14 @@ | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Properties; | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.IO; | |||
using System.IO.Compression; | |||
using System.Text; | |||
using System.Net.NetworkInformation; | |||
using System.Net; | |||
using System.Net.NetworkInformation; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.Util; | |||
namespace Shadowsocks.Controller | |||
@@ -16,16 +16,14 @@ namespace Shadowsocks.Controller | |||
class PolipoRunner | |||
{ | |||
private Process _process; | |||
private static string temppath; | |||
private int _runningPort; | |||
static PolipoRunner() | |||
{ | |||
temppath = Utils.GetTempPath(); | |||
try | |||
{ | |||
FileManager.UncompressFile(temppath + "/ss_privoxy.exe", Resources.privoxy_exe); | |||
FileManager.UncompressFile(temppath + "/mgwz.dll", Resources.mgwz_dll); | |||
FileManager.UncompressFile(Utils.GetTempPath("ss_privoxy.exe"), Resources.privoxy_exe); | |||
FileManager.UncompressFile(Utils.GetTempPath("mgwz.dll"), Resources.mgwz_dll); | |||
} | |||
catch (IOException e) | |||
{ | |||
@@ -64,20 +62,16 @@ namespace Shadowsocks.Controller | |||
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString()); | |||
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_PORT__", _runningPort.ToString()); | |||
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1"); | |||
FileManager.ByteArrayToFile(temppath + "/privoxy.conf", System.Text.Encoding.UTF8.GetBytes(polipoConfig)); | |||
FileManager.ByteArrayToFile(Utils.GetTempPath("privoxy.conf"), Encoding.UTF8.GetBytes(polipoConfig)); | |||
if (!(temppath.EndsWith("\\") || temppath.EndsWith("/"))) { | |||
temppath = temppath + "\\"; | |||
} | |||
_process = new Process(); | |||
// Configure the process using the StartInfo properties. | |||
_process.StartInfo.FileName = temppath + "ss_privoxy.exe"; | |||
_process.StartInfo.Arguments = " \"" + temppath + "privoxy.conf\""; | |||
_process.StartInfo.FileName = "ss_privoxy.exe"; | |||
_process.StartInfo.Arguments = "privoxy.conf"; | |||
_process.StartInfo.WorkingDirectory = Utils.GetTempPath(); | |||
_process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; | |||
_process.StartInfo.UseShellExecute = true; | |||
_process.StartInfo.CreateNoWindow = true; | |||
//_process.StartInfo.RedirectStandardOutput = true; | |||
//_process.StartInfo.RedirectStandardError = true; | |||
_process.Start(); | |||
} | |||
RefreshTrayArea(); | |||
@@ -1,11 +1,8 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Reflection; | |||
using System.Text; | |||
using System.Text.RegularExpressions; | |||
using System.IO; | |||
using SimpleJson; | |||
using Shadowsocks.Model; | |||
@@ -129,8 +126,7 @@ namespace Shadowsocks.Controller | |||
{ | |||
try | |||
{ | |||
string temppath = Utils.GetTempPath(); | |||
LatestVersionLocalName = Path.Combine(temppath, LatestVersionName); | |||
LatestVersionLocalName = Utils.GetTempPath(LatestVersionName); | |||
WebClient http = CreateWebClient(); | |||
http.DownloadFileCompleted += Http_DownloadFileCompleted; | |||
http.DownloadFileAsync(new Uri(LatestVersionURL), LatestVersionLocalName); | |||
@@ -145,7 +141,7 @@ namespace Shadowsocks.Controller | |||
{ | |||
try | |||
{ | |||
if(e.Error != null) | |||
if (e.Error != null) | |||
{ | |||
Logging.LogUsefulException(e.Error); | |||
return; | |||
@@ -241,6 +237,5 @@ namespace Shadowsocks.Controller | |||
return Asset.CompareVersion(x.version, y.version); | |||
} | |||
} | |||
} | |||
} |
@@ -443,12 +443,12 @@ namespace Shadowsocks.Controller | |||
private void pacServer_UserRuleFileChanged(object sender, EventArgs e) | |||
{ | |||
// TODO: this is a dirty hack. (from code GListUpdater.http_DownloadStringCompleted()) | |||
if (!File.Exists(Utils.GetTempPath() + "\\gfwlist.txt")) | |||
if (!File.Exists(Utils.GetTempPath("gfwlist.txt"))) | |||
{ | |||
UpdatePACFromGFWList(); | |||
return; | |||
} | |||
List<string> lines = GFWListUpdater.ParseResult(File.ReadAllText(Utils.GetTempPath() + "\\gfwlist.txt")); | |||
List<string> lines = GFWListUpdater.ParseResult(File.ReadAllText(Utils.GetTempPath("gfwlist.txt"))); | |||
if (File.Exists(PACServer.USER_RULE_FILE)) | |||
{ | |||
string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8); | |||
@@ -1,11 +1,10 @@ | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.Util; | |||
using System; | |||
using System.Collections.Generic; | |||
using System; | |||
using System.IO; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.Util; | |||
namespace Shadowsocks.Encryption | |||
{ | |||
@@ -15,8 +14,7 @@ namespace Shadowsocks.Encryption | |||
static MbedTLS() | |||
{ | |||
string tempPath = Utils.GetTempPath(); | |||
string dllPath = tempPath + "/libsscrypto.dll"; | |||
string dllPath = Utils.GetTempPath("libsscrypto.dll"); | |||
try | |||
{ | |||
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll); | |||
@@ -59,10 +57,9 @@ namespace Shadowsocks.Encryption | |||
public extern static void md5_starts(IntPtr ctx); | |||
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] | |||
public extern static void md5_update(IntPtr ctx, byte[] input, uint ilen ); | |||
public extern static void md5_update(IntPtr ctx, byte[] input, uint ilen); | |||
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] | |||
public extern static void md5_finish(IntPtr ctx, byte[] output); | |||
} | |||
} |
@@ -1,11 +1,10 @@ | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.Util; | |||
using System; | |||
using System.Collections.Generic; | |||
using System; | |||
using System.IO; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.Util; | |||
namespace Shadowsocks.Encryption | |||
{ | |||
@@ -19,8 +18,7 @@ namespace Shadowsocks.Encryption | |||
static PolarSSL() | |||
{ | |||
string tempPath = Utils.GetTempPath(); | |||
string dllPath = tempPath + "/libsscrypto.dll"; | |||
string dllPath = Utils.GetTempPath("libsscrypto.dll"); | |||
try | |||
{ | |||
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll); | |||
@@ -63,6 +61,5 @@ namespace Shadowsocks.Encryption | |||
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] | |||
public extern static int arc4_crypt(IntPtr ctx, int length, byte[] input, byte[] output); | |||
} | |||
} |
@@ -1,11 +1,10 @@ | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.Util; | |||
using System; | |||
using System.Collections.Generic; | |||
using System; | |||
using System.IO; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.Util; | |||
namespace Shadowsocks.Encryption | |||
{ | |||
@@ -15,8 +14,7 @@ namespace Shadowsocks.Encryption | |||
static Sodium() | |||
{ | |||
string tempPath = Utils.GetTempPath(); | |||
string dllPath = tempPath + "/libsscrypto.dll"; | |||
string dllPath = Utils.GetTempPath("libsscrypto.dll"); | |||
try | |||
{ | |||
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll); | |||
@@ -47,7 +45,6 @@ namespace Shadowsocks.Encryption | |||
public extern static void ss_sha1_hmac_ex(byte[] key, uint keylen, | |||
byte[] input, int ioff, uint ilen, | |||
byte[] output); | |||
} | |||
} | |||
@@ -1,13 +1,13 @@ | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.View; | |||
using System; | |||
using System.Collections.Generic; | |||
using System; | |||
using System.Diagnostics; | |||
using System.IO; | |||
using System.Threading; | |||
using System.Windows.Forms; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Util; | |||
using Shadowsocks.View; | |||
namespace Shadowsocks | |||
{ | |||
static class Program | |||
@@ -18,7 +18,7 @@ namespace Shadowsocks | |||
[STAThread] | |||
static void Main() | |||
{ | |||
Util.Utils.ReleaseMemory(true); | |||
Utils.ReleaseMemory(true); | |||
using (Mutex mutex = new Mutex(false, "Global\\Shadowsocks_" + Application.StartupPath.GetHashCode())) | |||
{ | |||
Application.EnableVisualStyles(); | |||
@@ -37,15 +37,19 @@ namespace Shadowsocks | |||
return; | |||
} | |||
Directory.SetCurrentDirectory(Application.StartupPath); | |||
#if DEBUG | |||
Logging.OpenLogFile(); | |||
// truncate privoxy log file while debugging | |||
string privoxyLogFilename = Utils.GetTempPath("privoxy.log"); | |||
if (File.Exists(privoxyLogFilename)) | |||
using (new FileStream(privoxyLogFilename, FileMode.Truncate)) { } | |||
#else | |||
Logging.OpenLogFile(); | |||
#endif | |||
ShadowsocksController controller = new ShadowsocksController(); | |||
MenuViewController viewController = new MenuViewController(controller); | |||
controller.Start(); | |||
Application.Run(); | |||
} | |||
} | |||
@@ -11,23 +11,38 @@ namespace Shadowsocks.Util | |||
{ | |||
public class Utils | |||
{ | |||
private static string TempPath = null; | |||
// return path to store temporary files | |||
public static string GetTempPath() | |||
{ | |||
if (File.Exists(Application.StartupPath + "\\shadowsocks_portable_mode.txt")) | |||
if (TempPath == null) | |||
{ | |||
try | |||
{ | |||
Directory.CreateDirectory(Application.StartupPath + "\\temp"); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.LogUsefulException(e); | |||
} | |||
// don't use "/", it will fail when we call explorer /select xxx/temp\xxx.log | |||
return Application.StartupPath + "\\temp"; | |||
if (File.Exists(Path.Combine(Application.StartupPath, "shadowsocks_portable_mode.txt"))) | |||
try | |||
{ | |||
Directory.CreateDirectory(Path.Combine(Application.StartupPath, "temp")); | |||
} | |||
catch (Exception e) | |||
{ | |||
TempPath = Path.GetTempPath(); | |||
Logging.LogUsefulException(e); | |||
} | |||
finally | |||
{ | |||
// don't use "/", it will fail when we call explorer /select xxx/temp\xxx.log | |||
TempPath = Path.Combine(Application.StartupPath, "temp"); | |||
} | |||
else | |||
TempPath = Path.GetTempPath(); | |||
} | |||
return Path.GetTempPath(); | |||
return TempPath; | |||
} | |||
// return a full path with filename combined which pointed to the temporary directory | |||
public static string GetTempPath(string filename) | |||
{ | |||
return Path.Combine(GetTempPath(), filename); | |||
} | |||
public static void ReleaseMemory(bool removePages) | |||