Browse Source

fix: using event to avoid hanging when redirect standard output/error (#1755)

tags/4.1.0
liyuan Allen Zhu 6 years ago
parent
commit
bef37135ec
1 changed files with 67 additions and 35 deletions
  1. +67
    -35
      shadowsocks-csharp/Util/SystemProxy/Sysproxy.cs

+ 67
- 35
shadowsocks-csharp/Util/SystemProxy/Sysproxy.cs View File

@@ -1,10 +1,11 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using Shadowsocks.Controller;
using Shadowsocks.Properties;
using Shadowsocks.Model;
using System.Text;
using Newtonsoft.Json;
namespace Shadowsocks.Util.SystemProxy
@@ -83,43 +84,78 @@ namespace Shadowsocks.Util.SystemProxy
private static void ExecSysproxy(string arguments)
{
using (var process = new Process())
// using event to avoid hanging when redirect standard output/error
// ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
// and http://blog.csdn.net/zhangweixing0/article/details/7356841
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
// Configure the process using the StartInfo properties.
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
using (var process = new Process())
{
// Configure the process using the StartInfo properties.
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
// Need to provide encoding info, or output/error strings we got will be wrong.
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
// Need to provide encoding info, or output/error strings we got will be wrong.
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.StartInfo.CreateNoWindow = true;
var stderr = process.StandardError.ReadToEnd();
var stdout = process.StandardOutput.ReadToEnd();
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
process.WaitForExit();
process.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(e.Data);
}
};
var exitCode = process.ExitCode;
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
{
throw new ProxyException(stderr);
}
process.Start();
if (arguments == "query")
{
if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
var stderr = error.ToString();
var stdout = output.ToString();
var exitCode = process.ExitCode;
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
{
// we cannot get user settings
throw new ProxyException("failed to query wininet settings");
throw new ProxyException(stderr);
}
if (arguments == "query") {
if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty()) {
// we cannot get user settings
throw new ProxyException("failed to query wininet settings");
}
_queryStr = stdout;
}
_queryStr = stdout;
}
}
}
@@ -147,13 +183,9 @@ namespace Shadowsocks.Util.SystemProxy
{
string configContent = File.ReadAllText(Utils.GetTempPath(_userWininetConfigFile));
_userSettings = JsonConvert.DeserializeObject<SysproxyConfig>(configContent);
}
catch (Exception)
{
} catch(Exception) {
// Suppress all exceptions. finally block will initialize new user config settings.
}
finally
{
} finally {
if (_userSettings == null) _userSettings = new SysproxyConfig();
}
}


Loading…
Cancel
Save