diff --git a/shadowsocks-csharp/Controller/Logging.cs b/shadowsocks-csharp/Controller/Logging.cs index c705fdd9..1ea6f276 100755 --- a/shadowsocks-csharp/Controller/Logging.cs +++ b/shadowsocks-csharp/Controller/Logging.cs @@ -6,6 +6,7 @@ using System.Net; using System.Diagnostics; using System.Text; using Shadowsocks.Util; +using Shadowsocks.Util.SystemProxy; namespace Shadowsocks.Controller { @@ -145,6 +146,24 @@ namespace Shadowsocks.Controller { Info(e); } + } + else if (e is ProxyException) + { + var ex = (ProxyException)e; + switch (ex.Type) + { + case ProxyExceptionType.FailToRun: + case ProxyExceptionType.QueryReturnMalformed: + case ProxyExceptionType.SysproxyExitError: + Error($"sysproxy - {ex.Type.ToString()}:{ex.Message}"); + break; + case ProxyExceptionType.QueryReturnEmpty: + case ProxyExceptionType.Unspecific: + Error($"sysproxy - {ex.Type.ToString()}"); + break; + } + + } else { diff --git a/shadowsocks-csharp/Controller/System/SystemProxy.cs b/shadowsocks-csharp/Controller/System/SystemProxy.cs index ccf18ff1..dbb6548f 100644 --- a/shadowsocks-csharp/Controller/System/SystemProxy.cs +++ b/shadowsocks-csharp/Controller/System/SystemProxy.cs @@ -1,4 +1,5 @@ using System; +using System.Windows.Forms; using Shadowsocks.Model; using Shadowsocks.Util.SystemProxy; @@ -11,7 +12,7 @@ namespace Shadowsocks.Controller return value.ToString("yyyyMMddHHmmssfff"); } - public static void Update(Configuration config, bool forceDisable, PACServer pacSrv) + public static void Update(Configuration config, bool forceDisable, PACServer pacSrv, bool noRetry = false) { bool global = config.global; bool enabled = config.enabled; @@ -51,6 +52,19 @@ namespace Shadowsocks.Controller catch (ProxyException ex) { Logging.LogUsefulException(ex); + if (ex.Type != ProxyExceptionType.Unspecific && !noRetry) + { + var ret = MessageBox.Show(I18N.GetString("Error occured when process proxy setting, do you want reset current setting and retry?"), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning); + if (ret == DialogResult.Yes) + { + Sysproxy.ResetIEProxy(); + Update(config, forceDisable, pacSrv, true); + } + } + else + { + MessageBox.Show(I18N.GetString("Unrecoverable proxy setting error occured, see log for detail"), I18N.GetString("Shadowsocks"), MessageBoxButtons.OK, MessageBoxIcon.Error); + } } } } diff --git a/shadowsocks-csharp/Data/ja.txt b/shadowsocks-csharp/Data/ja.txt index 648dec08..06ce0513 100644 --- a/shadowsocks-csharp/Data/ja.txt +++ b/shadowsocks-csharp/Data/ja.txt @@ -147,4 +147,4 @@ Proxy request failed=プロキシ要求が失敗しました。 Proxy handshake failed=プロキシ ハンドシェイクに失敗しました。 Register hotkey failed=ホットキーの登錄に失敗しました。 Cannot parse hotkey: {0}=ホットキーを解析できません: {0} -Timeout is invalid, it should not exceed {0}=タイムアウト値が無効です。{0} 以下の値を指定して下さい。 +Timeout is invalid, it should not exceed {0}=タイムアウト値が無効です。{0} 以下の値を指定して下さい。 \ No newline at end of file diff --git a/shadowsocks-csharp/Data/zh_CN.txt b/shadowsocks-csharp/Data/zh_CN.txt index df47fb2d..9cc80ff8 100644 --- a/shadowsocks-csharp/Data/zh_CN.txt +++ b/shadowsocks-csharp/Data/zh_CN.txt @@ -148,3 +148,6 @@ Proxy handshake failed=代理握手失败 Register hotkey failed=注册快捷键失败 Cannot parse hotkey: {0}=解析快捷键失败: {0} Timeout is invalid, it should not exceed {0}=超时无效,不应超过 {0} + +Error occured when process proxy setting, do you want reset current setting and retry?=处理代理设置时发生错误,是否重置当前代理设置并重试? +Unrecoverable proxy setting error occured, see log for detail=发生不可恢复的代理设置错误,查看日志以取得详情 \ No newline at end of file diff --git a/shadowsocks-csharp/Data/zh_TW.txt b/shadowsocks-csharp/Data/zh_TW.txt index f9736b7d..703d4c65 100644 --- a/shadowsocks-csharp/Data/zh_TW.txt +++ b/shadowsocks-csharp/Data/zh_TW.txt @@ -147,4 +147,4 @@ Proxy request failed=Proxy 要求失敗 Proxy handshake failed=Proxy 交握失敗 Register hotkey failed=註冊快速鍵失敗 Cannot parse hotkey: {0}=剖析快速鍵失敗: {0} -Timeout is invalid, it should not exceed {0}=逾時無效,不應超過 {0} +Timeout is invalid, it should not exceed {0}=逾時無效,不應超過 {0} \ No newline at end of file diff --git a/shadowsocks-csharp/Util/SystemProxy/ProxyException.cs b/shadowsocks-csharp/Util/SystemProxy/ProxyException.cs index 67a00e2c..76e858cb 100644 --- a/shadowsocks-csharp/Util/SystemProxy/ProxyException.cs +++ b/shadowsocks-csharp/Util/SystemProxy/ProxyException.cs @@ -7,8 +7,20 @@ using System.Threading.Tasks; namespace Shadowsocks.Util.SystemProxy { + enum ProxyExceptionType + { + Unspecific, + FailToRun, + QueryReturnEmpty, + SysproxyExitError, + QueryReturnMalformed + } + class ProxyException : Exception { + // provide more specific information about exception + public ProxyExceptionType Type { get; } + public ProxyException() { } @@ -24,5 +36,24 @@ namespace Shadowsocks.Util.SystemProxy protected ProxyException(SerializationInfo info, StreamingContext context) : base(info, context) { } + public ProxyException(ProxyExceptionType type) + { + this.Type = type; + } + + public ProxyException(ProxyExceptionType type, string message) : base(message) + { + this.Type = type; + } + + public ProxyException(ProxyExceptionType type, string message, Exception innerException) : base(message, innerException) + { + this.Type = type; + } + + protected ProxyException(ProxyExceptionType type, SerializationInfo info, StreamingContext context) : base(info, context) + { + this.Type = type; + } } } diff --git a/shadowsocks-csharp/Util/SystemProxy/Sysproxy.cs b/shadowsocks-csharp/Util/SystemProxy/Sysproxy.cs index 7248fded..c28d8c52 100644 --- a/shadowsocks-csharp/Util/SystemProxy/Sysproxy.cs +++ b/shadowsocks-csharp/Util/SystemProxy/Sysproxy.cs @@ -1,12 +1,12 @@ -using System; +using Newtonsoft.Json; +using Shadowsocks.Controller; +using Shadowsocks.Model; +using Shadowsocks.Properties; +using System; using System.Diagnostics; using System.IO; using System.Text; using System.Threading; -using Shadowsocks.Controller; -using Shadowsocks.Properties; -using Shadowsocks.Model; -using Newtonsoft.Json; namespace Shadowsocks.Util.SystemProxy { @@ -82,6 +82,26 @@ namespace Shadowsocks.Util.SystemProxy ExecSysproxy(arguments); } + + // set system proxy to 1 (null) (null) (null) + public static bool ResetIEProxy() + { + try + { + // clear user-wininet.json + _userSettings = new SysproxyConfig(); + Save(); + // clear system setting + ExecSysproxy("set 1 - - -"); + } + catch (Exception e) + { + return false; + } + + return true; + } + private static void ExecSysproxy(string arguments) { // using event to avoid hanging when redirect standard output/error @@ -132,27 +152,35 @@ namespace Shadowsocks.Util.SystemProxy error.AppendLine(e.Data); } }; + try + { + process.Start(); - process.Start(); - - process.BeginErrorReadLine(); - process.BeginOutputReadLine(); - - process.WaitForExit(); + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + process.WaitForExit(); + } + catch (System.ComponentModel.Win32Exception e) + { + // log the arguements + throw new ProxyException(ProxyExceptionType.FailToRun, process.StartInfo.Arguments, e); + } var stderr = error.ToString(); var stdout = output.ToString(); var exitCode = process.ExitCode; if (exitCode != (int)RET_ERRORS.RET_NO_ERROR) { - throw new ProxyException(stderr); + throw new ProxyException(ProxyExceptionType.SysproxyExitError, stderr); } - if (arguments == "query") { - if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty()) { + if (arguments == "query") + { + if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty()) + { // we cannot get user settings - throw new ProxyException("failed to query wininet settings"); + throw new ProxyException(ProxyExceptionType.QueryReturnEmpty); } _queryStr = stdout; } @@ -183,9 +211,13 @@ namespace Shadowsocks.Util.SystemProxy { string configContent = File.ReadAllText(Utils.GetTempPath(_userWininetConfigFile)); _userSettings = JsonConvert.DeserializeObject(configContent); - } catch(Exception) { + } + catch (Exception) + { // Suppress all exceptions. finally block will initialize new user config settings. - } finally { + } + finally + { if (_userSettings == null) _userSettings = new SysproxyConfig(); } } @@ -193,6 +225,21 @@ namespace Shadowsocks.Util.SystemProxy private static void ParseQueryStr(string str) { string[] userSettingsArr = str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + + // sometimes sysproxy output in utf16le instead of ascii + // manually translate it + if (userSettingsArr.Length != 4) + { + byte[] strByte = Encoding.ASCII.GetBytes(str); + str = Encoding.Unicode.GetString(strByte); + userSettingsArr = str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + // still fail, throw exception with string hexdump + if (userSettingsArr.Length != 4) + { + throw new ProxyException(ProxyExceptionType.QueryReturnMalformed, BitConverter.ToString(strByte)); + } + } + _userSettings.Flags = userSettingsArr[0]; // handle output from WinINET