diff --git a/shadowsocks-csharp/Controller/Logging.cs b/shadowsocks-csharp/Controller/Logging.cs index fb07dcae..3db34658 100755 --- a/shadowsocks-csharp/Controller/Logging.cs +++ b/shadowsocks-csharp/Controller/Logging.cs @@ -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 diff --git a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs index 4d3bc119..bbb7a9c2 100644 --- a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs +++ b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs @@ -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 _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; } - } } diff --git a/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs b/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs index 96d86ba0..e0fd12f4 100644 --- a/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs @@ -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 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; diff --git a/shadowsocks-csharp/Controller/Service/PACServer.cs b/shadowsocks-csharp/Controller/Service/PACServer.cs index c428fe0c..ac8b762a 100644 --- a/shadowsocks-csharp/Controller/Service/PACServer.cs +++ b/shadowsocks-csharp/Controller/Service/PACServer.cs @@ -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); } diff --git a/shadowsocks-csharp/Controller/Service/PolipoRunner.cs b/shadowsocks-csharp/Controller/Service/PolipoRunner.cs index ad582d1e..f824c2e5 100644 --- a/shadowsocks-csharp/Controller/Service/PolipoRunner.cs +++ b/shadowsocks-csharp/Controller/Service/PolipoRunner.cs @@ -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(); diff --git a/shadowsocks-csharp/Controller/Service/UpdateChecker.cs b/shadowsocks-csharp/Controller/Service/UpdateChecker.cs index 45962353..59ff3cf6 100644 --- a/shadowsocks-csharp/Controller/Service/UpdateChecker.cs +++ b/shadowsocks-csharp/Controller/Service/UpdateChecker.cs @@ -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); } } - } } diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index e826f8e7..1dfd81d2 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -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 lines = GFWListUpdater.ParseResult(File.ReadAllText(Utils.GetTempPath() + "\\gfwlist.txt")); + List 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); diff --git a/shadowsocks-csharp/Encryption/MbedTLS.cs b/shadowsocks-csharp/Encryption/MbedTLS.cs index a9266a2c..8ad9cd09 100644 --- a/shadowsocks-csharp/Encryption/MbedTLS.cs +++ b/shadowsocks-csharp/Encryption/MbedTLS.cs @@ -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); - } } diff --git a/shadowsocks-csharp/Encryption/PolarSSL.cs b/shadowsocks-csharp/Encryption/PolarSSL.cs index 3c1d8831..ddf59564 100755 --- a/shadowsocks-csharp/Encryption/PolarSSL.cs +++ b/shadowsocks-csharp/Encryption/PolarSSL.cs @@ -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); - } } diff --git a/shadowsocks-csharp/Encryption/Sodium.cs b/shadowsocks-csharp/Encryption/Sodium.cs index 7a9d0c3c..3d20bdea 100755 --- a/shadowsocks-csharp/Encryption/Sodium.cs +++ b/shadowsocks-csharp/Encryption/Sodium.cs @@ -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); - } } diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index efa241e9..977ebffd 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -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(); } } diff --git a/shadowsocks-csharp/Util/Util.cs b/shadowsocks-csharp/Util/Util.cs index 450faa56..0fe193c7 100755 --- a/shadowsocks-csharp/Util/Util.cs +++ b/shadowsocks-csharp/Util/Util.cs @@ -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)