Merge branch 'master' of https://github.com/shadowsocks/shadowsocks-windows.git into dev_proxy
# Conflicts: # shadowsocks-csharp/Controller/Service/TCPRelay.cs # shadowsocks-csharp/Controller/ShadowsocksController.cs # shadowsocks-csharp/View/MenuViewController.cs
This commit is contained in:
@@ -107,67 +107,30 @@ namespace Shadowsocks.Controller
|
||||
var bytes = inbound - lastInbound;
|
||||
_lastInboundCounter[id] = inbound;
|
||||
var inboundSpeed = GetSpeedInKiBPerSecond(bytes, _monitorInterval.TotalSeconds);
|
||||
_inboundSpeedRecords.GetOrAdd(id, new List<int> {inboundSpeed}).Add(inboundSpeed);
|
||||
_inboundSpeedRecords.GetOrAdd(id, (k) =>
|
||||
{
|
||||
List<int> records = new List<int>();
|
||||
records.Add(inboundSpeed);
|
||||
return records;
|
||||
});
|
||||
|
||||
var lastOutbound = _lastOutboundCounter[id];
|
||||
var outbound = _outboundCounter[id];
|
||||
bytes = outbound - lastOutbound;
|
||||
_lastOutboundCounter[id] = outbound;
|
||||
var outboundSpeed = GetSpeedInKiBPerSecond(bytes, _monitorInterval.TotalSeconds);
|
||||
_outboundSpeedRecords.GetOrAdd(id, new List<int> {outboundSpeed}).Add(outboundSpeed);
|
||||
_outboundSpeedRecords.GetOrAdd(id, (k) =>
|
||||
{
|
||||
List<int> records = new List<int>();
|
||||
records.Add(outboundSpeed);
|
||||
return records;
|
||||
});
|
||||
|
||||
Logging.Debug(
|
||||
$"{id}: current/max inbound {inboundSpeed}/{_inboundSpeedRecords[id].Max()} KiB/s, current/max outbound {outboundSpeed}/{_outboundSpeedRecords[id].Max()} KiB/s");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ICMPResult> ICMPTest(Server server)
|
||||
{
|
||||
Logging.Debug("Ping " + server.FriendlyName());
|
||||
if (server.server == "") return null;
|
||||
var result = new ICMPResult(server);
|
||||
try
|
||||
{
|
||||
var IP =
|
||||
Dns.GetHostAddresses(server.server)
|
||||
.First(
|
||||
ip =>
|
||||
ip.AddressFamily == AddressFamily.InterNetwork ||
|
||||
ip.AddressFamily == AddressFamily.InterNetworkV6);
|
||||
var ping = new Ping();
|
||||
|
||||
foreach (var _ in Enumerable.Range(0, Repeat))
|
||||
{
|
||||
try
|
||||
{
|
||||
var reply = await ping.SendTaskAsync(IP, TimeoutMilliseconds);
|
||||
if (reply.Status.Equals(IPStatus.Success))
|
||||
{
|
||||
result.RoundtripTime.Add((int?) reply.RoundtripTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.RoundtripTime.Add(null);
|
||||
}
|
||||
|
||||
//Do ICMPTest in a random frequency
|
||||
Thread.Sleep(TimeoutMilliseconds + new Random().Next()%TimeoutMilliseconds);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error($"An exception occured while eveluating {server.FriendlyName()}");
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error($"An exception occured while eveluating {server.FriendlyName()}");
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
_inboundSpeedRecords.Clear();
|
||||
@@ -178,15 +141,14 @@ namespace Shadowsocks.Controller
|
||||
private void Run(object _)
|
||||
{
|
||||
UpdateRecords();
|
||||
Save();
|
||||
Reset();
|
||||
FilterRawStatistics();
|
||||
}
|
||||
|
||||
private async void UpdateRecords()
|
||||
private void UpdateRecords()
|
||||
{
|
||||
var records = new Dictionary<string, StatisticsRecord>();
|
||||
|
||||
UpdateRecordsState state = new UpdateRecordsState();
|
||||
state.counter = _controller.GetCurrentConfiguration().configs.Count;
|
||||
foreach (var server in _controller.GetCurrentConfiguration().configs)
|
||||
{
|
||||
var id = server.Identifier();
|
||||
@@ -202,43 +164,80 @@ namespace Shadowsocks.Controller
|
||||
records[id] = record;
|
||||
else
|
||||
records.Add(id, record);
|
||||
}
|
||||
|
||||
if (Config.Ping)
|
||||
{
|
||||
var icmpResults = await TaskEx.WhenAll(_controller.GetCurrentConfiguration().configs.Select(ICMPTest));
|
||||
foreach (var result in icmpResults.Where(result => result != null))
|
||||
if (Config.Ping)
|
||||
{
|
||||
records[result.Server.Identifier()].SetResponse(result.RoundtripTime);
|
||||
MyPing ping = new MyPing(server, Repeat);
|
||||
ping.Completed += ping_Completed;
|
||||
ping.Start(new PingState { state = state, record = record });
|
||||
}
|
||||
else if (!record.IsEmptyData())
|
||||
{
|
||||
AppendRecord(id, record);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kv in records.Where(kv => !kv.Value.IsEmptyData()))
|
||||
if (!Config.Ping)
|
||||
{
|
||||
AppendRecord(kv.Key, kv.Value);
|
||||
Save();
|
||||
FilterRawStatistics();
|
||||
}
|
||||
}
|
||||
|
||||
private void ping_Completed(object sender, MyPing.CompletedEventArgs e)
|
||||
{
|
||||
PingState pingState = (PingState)e.UserState;
|
||||
UpdateRecordsState state = pingState.state;
|
||||
Server server = e.Server;
|
||||
StatisticsRecord record = pingState.record;
|
||||
record.SetResponse(e.RoundtripTime);
|
||||
if (!record.IsEmptyData())
|
||||
{
|
||||
AppendRecord(server.Identifier(), record);
|
||||
}
|
||||
Logging.Debug($"Ping {server.FriendlyName()} {e.RoundtripTime.Count} times, {(100 - record.PackageLoss * 100)}% packages loss, min {record.MinResponse} ms, max {record.MaxResponse} ms, avg {record.AverageResponse} ms");
|
||||
if (Interlocked.Decrement(ref state.counter) == 0)
|
||||
{
|
||||
Save();
|
||||
FilterRawStatistics();
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendRecord(string serverIdentifier, StatisticsRecord record)
|
||||
{
|
||||
List<StatisticsRecord> records;
|
||||
if (!RawStatistics.TryGetValue(serverIdentifier, out records))
|
||||
try
|
||||
{
|
||||
records = new List<StatisticsRecord>();
|
||||
List<StatisticsRecord> records;
|
||||
lock (RawStatistics)
|
||||
{
|
||||
if (!RawStatistics.TryGetValue(serverIdentifier, out records))
|
||||
{
|
||||
records = new List<StatisticsRecord>();
|
||||
RawStatistics[serverIdentifier] = records;
|
||||
}
|
||||
}
|
||||
records.Add(record);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
records.Add(record);
|
||||
RawStatistics[serverIdentifier] = records;
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
Logging.Debug($"save statistics to {AvailabilityStatisticsFile}");
|
||||
if (RawStatistics.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var content = JsonConvert.SerializeObject(RawStatistics, Formatting.None);
|
||||
string content;
|
||||
#if DEBUG
|
||||
content = JsonConvert.SerializeObject(RawStatistics, Formatting.Indented);
|
||||
#else
|
||||
content = JsonConvert.SerializeObject(RawStatistics, Formatting.None);
|
||||
#endif
|
||||
File.WriteAllText(AvailabilityStatisticsFile, content);
|
||||
}
|
||||
catch (IOException e)
|
||||
@@ -258,17 +257,25 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void FilterRawStatistics()
|
||||
{
|
||||
if (RawStatistics == null) return;
|
||||
if (FilteredStatistics == null)
|
||||
try
|
||||
{
|
||||
FilteredStatistics = new Statistics();
|
||||
}
|
||||
Logging.Debug("filter raw statistics");
|
||||
if (RawStatistics == null) return;
|
||||
if (FilteredStatistics == null)
|
||||
{
|
||||
FilteredStatistics = new Statistics();
|
||||
}
|
||||
|
||||
foreach (var serverAndRecords in RawStatistics)
|
||||
foreach (var serverAndRecords in RawStatistics)
|
||||
{
|
||||
var server = serverAndRecords.Key;
|
||||
var filteredRecords = serverAndRecords.Value.FindAll(IsValidRecord);
|
||||
FilteredStatistics[server] = filteredRecords;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var server = serverAndRecords.Key;
|
||||
var filteredRecords = serverAndRecords.Value.FindAll(IsValidRecord);
|
||||
FilteredStatistics[server] = filteredRecords;
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,21 +305,10 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private static int GetSpeedInKiBPerSecond(long bytes, double seconds)
|
||||
{
|
||||
var result = (int) (bytes/seconds)/1024;
|
||||
var result = (int)(bytes / seconds) / 1024;
|
||||
return result;
|
||||
}
|
||||
|
||||
private class ICMPResult
|
||||
{
|
||||
internal readonly List<int?> RoundtripTime = new List<int?>();
|
||||
internal readonly Server Server;
|
||||
|
||||
internal ICMPResult(Server server)
|
||||
{
|
||||
Server = server;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_recorder.Dispose();
|
||||
@@ -321,44 +317,158 @@ namespace Shadowsocks.Controller
|
||||
|
||||
public void UpdateLatency(Server server, int latency)
|
||||
{
|
||||
List<int> records;
|
||||
_latencyRecords.TryGetValue(server.Identifier(), out records);
|
||||
if (records == null)
|
||||
_latencyRecords.GetOrAdd(server.Identifier(), (k) =>
|
||||
{
|
||||
records = new List<int>();
|
||||
}
|
||||
records.Add(latency);
|
||||
_latencyRecords[server.Identifier()] = records;
|
||||
List<int> records = new List<int>();
|
||||
records.Add(latency);
|
||||
return records;
|
||||
});
|
||||
}
|
||||
|
||||
public void UpdateInboundCounter(Server server, long n)
|
||||
{
|
||||
long count;
|
||||
if (_inboundCounter.TryGetValue(server.Identifier(), out count))
|
||||
_inboundCounter.AddOrUpdate(server.Identifier(), (k) =>
|
||||
{
|
||||
count += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = n;
|
||||
_lastInboundCounter[server.Identifier()] = 0;
|
||||
}
|
||||
_inboundCounter[server.Identifier()] = count;
|
||||
_lastInboundCounter.GetOrAdd(server.Identifier(), 0);
|
||||
return n;
|
||||
}, (k, v) => (v + n));
|
||||
}
|
||||
|
||||
public void UpdateOutboundCounter(Server server, long n)
|
||||
{
|
||||
long count;
|
||||
if (_outboundCounter.TryGetValue(server.Identifier(), out count))
|
||||
_outboundCounter.AddOrUpdate(server.Identifier(), (k) =>
|
||||
{
|
||||
count += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = n;
|
||||
_lastOutboundCounter[server.Identifier()] = 0;
|
||||
}
|
||||
_outboundCounter[server.Identifier()] = count;
|
||||
_lastOutboundCounter.GetOrAdd(server.Identifier(), 0);
|
||||
return n;
|
||||
}, (k, v) => (v + n));
|
||||
}
|
||||
|
||||
class UpdateRecordsState
|
||||
{
|
||||
public int counter;
|
||||
}
|
||||
|
||||
class PingState
|
||||
{
|
||||
public UpdateRecordsState state;
|
||||
public StatisticsRecord record;
|
||||
}
|
||||
|
||||
class MyPing
|
||||
{
|
||||
//arguments for ICMP tests
|
||||
public const int TimeoutMilliseconds = 500;
|
||||
|
||||
public EventHandler<CompletedEventArgs> Completed;
|
||||
private Server server;
|
||||
|
||||
private int repeat;
|
||||
private IPAddress ip;
|
||||
private Ping ping;
|
||||
private List<int?> RoundtripTime;
|
||||
|
||||
public MyPing(Server server, int repeat)
|
||||
{
|
||||
this.server = server;
|
||||
this.repeat = repeat;
|
||||
RoundtripTime = new List<int?>(repeat);
|
||||
ping = new Ping();
|
||||
ping.PingCompleted += Ping_PingCompleted;
|
||||
}
|
||||
|
||||
public void Start(object userstate)
|
||||
{
|
||||
if (server.server == "")
|
||||
{
|
||||
FireCompleted(new Exception("Invalid Server"), userstate);
|
||||
return;
|
||||
}
|
||||
new Task(() => ICMPTest(0, userstate)).Start();
|
||||
}
|
||||
|
||||
private void ICMPTest(int delay, object userstate)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logging.Debug($"Ping {server.FriendlyName()}");
|
||||
if (ip == null)
|
||||
{
|
||||
ip = Dns.GetHostAddresses(server.server)
|
||||
.First(
|
||||
ip =>
|
||||
ip.AddressFamily == AddressFamily.InterNetwork ||
|
||||
ip.AddressFamily == AddressFamily.InterNetworkV6);
|
||||
}
|
||||
repeat--;
|
||||
if (delay > 0)
|
||||
Thread.Sleep(delay);
|
||||
ping.SendAsync(ip, TimeoutMilliseconds, userstate);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error($"An exception occured while eveluating {server.FriendlyName()}");
|
||||
Logging.LogUsefulException(e);
|
||||
FireCompleted(e, userstate);
|
||||
}
|
||||
}
|
||||
|
||||
private void Ping_PingCompleted(object sender, PingCompletedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Reply.Status == IPStatus.Success)
|
||||
{
|
||||
Logging.Debug($"Ping {server.FriendlyName()} {e.Reply.RoundtripTime} ms");
|
||||
RoundtripTime.Add((int?)e.Reply.RoundtripTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Debug($"Ping {server.FriendlyName()} timeout");
|
||||
RoundtripTime.Add(null);
|
||||
}
|
||||
TestNext(e.UserState);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Error($"An exception occured while eveluating {server.FriendlyName()}");
|
||||
Logging.LogUsefulException(ex);
|
||||
FireCompleted(ex, e.UserState);
|
||||
}
|
||||
}
|
||||
|
||||
private void TestNext(object userstate)
|
||||
{
|
||||
if (repeat > 0)
|
||||
{
|
||||
//Do ICMPTest in a random frequency
|
||||
int delay = TimeoutMilliseconds + new Random().Next() % TimeoutMilliseconds;
|
||||
new Task(() => ICMPTest(delay, userstate)).Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
FireCompleted(null, userstate);
|
||||
}
|
||||
}
|
||||
|
||||
private void FireCompleted(Exception error, object userstate)
|
||||
{
|
||||
Completed?.Invoke(this, new CompletedEventArgs
|
||||
{
|
||||
Error = error,
|
||||
Server = server,
|
||||
RoundtripTime = RoundtripTime,
|
||||
UserState = userstate
|
||||
});
|
||||
}
|
||||
|
||||
public class CompletedEventArgs : EventArgs
|
||||
{
|
||||
public Exception Error;
|
||||
public Server Server;
|
||||
public List<int?> RoundtripTime;
|
||||
public object UserState;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,20 +47,7 @@ namespace Shadowsocks.Controller
|
||||
Process[] existingPolipo = Process.GetProcessesByName("ss_privoxy");
|
||||
foreach (Process p in existingPolipo)
|
||||
{
|
||||
try
|
||||
{
|
||||
p.CloseMainWindow();
|
||||
p.WaitForExit(100);
|
||||
if (!p.HasExited)
|
||||
{
|
||||
p.Kill();
|
||||
p.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
KillProcess(p);
|
||||
}
|
||||
string polipoConfig = Resources.privoxy_conf;
|
||||
_runningPort = this.GetFreePort();
|
||||
@@ -86,20 +73,30 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
if (_process != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_process.Kill();
|
||||
_process.WaitForExit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
KillProcess(_process);
|
||||
_process = null;
|
||||
}
|
||||
RefreshTrayArea();
|
||||
}
|
||||
|
||||
private static void KillProcess(Process p)
|
||||
{
|
||||
try
|
||||
{
|
||||
p.CloseMainWindow();
|
||||
p.WaitForExit(100);
|
||||
if (!p.HasExited)
|
||||
{
|
||||
p.Kill();
|
||||
p.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetFreePort()
|
||||
{
|
||||
int defaultPort = 8123;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Timers;
|
||||
@@ -17,10 +18,7 @@ namespace Shadowsocks.Controller
|
||||
private DateTime _lastSweepTime;
|
||||
private Configuration _config;
|
||||
|
||||
public ISet<TCPHandler> Handlers
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public ISet<TCPHandler> Handlers { get; set; }
|
||||
|
||||
public TCPRelay(ShadowsocksController controller, Configuration conf)
|
||||
{
|
||||
@@ -32,19 +30,14 @@ namespace Shadowsocks.Controller
|
||||
|
||||
public bool Handle(byte[] firstPacket, int length, Socket socket, object state)
|
||||
{
|
||||
if (socket.ProtocolType != ProtocolType.Tcp)
|
||||
{
|
||||
if (socket.ProtocolType != ProtocolType.Tcp
|
||||
|| (length < 2 || firstPacket[0] != 5))
|
||||
return false;
|
||||
}
|
||||
if (length < 2 || firstPacket[0] != 5)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||||
TCPHandler handler = new TCPHandler(this, _config);
|
||||
handler.connection = socket;
|
||||
handler.controller = _controller;
|
||||
handler.relay = this;
|
||||
handler.tcprelay = this;
|
||||
|
||||
handler.Start(firstPacket, length);
|
||||
IList<TCPHandler> handlersToClose = new List<TCPHandler>();
|
||||
@@ -56,12 +49,8 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
_lastSweepTime = now;
|
||||
foreach (TCPHandler handler1 in Handlers)
|
||||
{
|
||||
if (now - handler1.lastActivity > TimeSpan.FromSeconds(900))
|
||||
{
|
||||
handlersToClose.Add(handler1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (TCPHandler handler1 in handlersToClose)
|
||||
@@ -90,6 +79,11 @@ namespace Shadowsocks.Controller
|
||||
|
||||
class TCPHandler
|
||||
{
|
||||
// Size of receive buffer.
|
||||
public static readonly int RecvSize = 8192;
|
||||
public static readonly int RecvReserveSize = IVEncryptor.ONETIMEAUTH_BYTES + IVEncryptor.AUTH_BYTES; // reserve for one-time auth
|
||||
public static readonly int BufferSize = RecvSize + RecvReserveSize + 32;
|
||||
|
||||
// public Encryptor encryptor;
|
||||
public IEncryptor encryptor;
|
||||
public Server server;
|
||||
@@ -97,63 +91,52 @@ namespace Shadowsocks.Controller
|
||||
public IProxy remote;
|
||||
public Socket connection;
|
||||
public ShadowsocksController controller;
|
||||
public TCPRelay relay;
|
||||
public Configuration config;
|
||||
public TCPRelay tcprelay;
|
||||
|
||||
public DateTime lastActivity;
|
||||
|
||||
private const int maxRetry = 4;
|
||||
private int retryCount = 0;
|
||||
private bool proxyConnected;
|
||||
private bool destConnected;
|
||||
private const int MaxRetry = 4;
|
||||
private int _retryCount = 0;
|
||||
private bool _proxyConnected;
|
||||
private bool _destConnected;
|
||||
|
||||
private byte command;
|
||||
private byte _command;
|
||||
private byte[] _firstPacket;
|
||||
private int _firstPacketLength;
|
||||
// Size of receive buffer.
|
||||
public const int RecvSize = 8192;
|
||||
public const int RecvReserveSize = IVEncryptor.ONETIMEAUTH_BYTES + IVEncryptor.AUTH_BYTES; // reserve for one-time auth
|
||||
public const int BufferSize = RecvSize + RecvReserveSize + 32;
|
||||
|
||||
private int totalRead = 0;
|
||||
private int totalWrite = 0;
|
||||
private int _totalRead = 0;
|
||||
private int _totalWrite = 0;
|
||||
|
||||
// remote receive buffer
|
||||
private byte[] remoteRecvBuffer = new byte[BufferSize];
|
||||
// remote send buffer
|
||||
private byte[] remoteSendBuffer = new byte[BufferSize];
|
||||
// connection receive buffer
|
||||
private byte[] connetionRecvBuffer = new byte[BufferSize];
|
||||
// connection send buffer
|
||||
private byte[] connetionSendBuffer = new byte[BufferSize];
|
||||
// Received data string.
|
||||
private byte[] _remoteRecvBuffer = new byte[BufferSize];
|
||||
private byte[] _remoteSendBuffer = new byte[BufferSize];
|
||||
private byte[] _connetionRecvBuffer = new byte[BufferSize];
|
||||
private byte[] _connetionSendBuffer = new byte[BufferSize];
|
||||
|
||||
private bool connectionShutdown = false;
|
||||
private bool remoteShutdown = false;
|
||||
private bool closed = false;
|
||||
private bool _connectionShutdown = false;
|
||||
private bool _remoteShutdown = false;
|
||||
private bool _closed = false;
|
||||
|
||||
private object encryptionLock = new object();
|
||||
private object decryptionLock = new object();
|
||||
private object _encryptionLock = new object();
|
||||
private object _decryptionLock = new object();
|
||||
|
||||
private DateTime _startConnectTime;
|
||||
private DateTime _startReceivingTime;
|
||||
private DateTime _startSendingTime;
|
||||
private int _bytesToSend;
|
||||
private TCPRelay tcprelay; // TODO: tcprelay ?= relay
|
||||
private TCPRelay _tcprelay; // TODO: is _tcprelay equals tcprelay declared above?
|
||||
private Configuration _config;
|
||||
|
||||
public TCPHandler(TCPRelay tcprelay, Configuration config)
|
||||
{
|
||||
this.tcprelay = tcprelay;
|
||||
this.config = config;
|
||||
this._tcprelay = tcprelay;
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
public void CreateRemote()
|
||||
{
|
||||
Server server = controller.GetAServer(IStrategyCallerType.TCP, (IPEndPoint)connection.RemoteEndPoint);
|
||||
if (server == null || server.server == "")
|
||||
{
|
||||
throw new ArgumentException("No server configured");
|
||||
}
|
||||
encryptor = EncryptorFactory.GetEncryptor(server.method, server.password, server.auth, false);
|
||||
this.server = server;
|
||||
}
|
||||
@@ -168,72 +151,53 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void CheckClose()
|
||||
{
|
||||
if (connectionShutdown && remoteShutdown)
|
||||
{
|
||||
if (_connectionShutdown && _remoteShutdown)
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
lock (relay.Handlers)
|
||||
lock (tcprelay.Handlers)
|
||||
{
|
||||
relay.Handlers.Remove(this);
|
||||
tcprelay.Handlers.Remove(this);
|
||||
}
|
||||
lock (this)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
lock (this) {
|
||||
if (_closed) return;
|
||||
_closed = true;
|
||||
}
|
||||
if (connection != null)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
connection.Shutdown(SocketShutdown.Both);
|
||||
connection.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
connection?.Shutdown(SocketShutdown.Both);
|
||||
connection?.Close();
|
||||
}
|
||||
if (remote != null)
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
remote.Shutdown(SocketShutdown.Both);
|
||||
remote.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
lock (encryptionLock)
|
||||
try
|
||||
{
|
||||
lock (decryptionLock)
|
||||
remote?.Shutdown(SocketShutdown.Both);
|
||||
remote?.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
lock (_encryptionLock)
|
||||
{
|
||||
lock (_decryptionLock)
|
||||
{
|
||||
if (encryptor != null)
|
||||
{
|
||||
((IDisposable)encryptor).Dispose();
|
||||
}
|
||||
encryptor?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandshakeReceive()
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
int bytesRead = _firstPacketLength;
|
||||
|
||||
if (bytesRead > 1)
|
||||
{
|
||||
byte[] response = { 5, 0 };
|
||||
@@ -243,12 +207,10 @@ namespace Shadowsocks.Controller
|
||||
response = new byte[] { 0, 91 };
|
||||
Logging.Error("socks 5 protocol error");
|
||||
}
|
||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null);
|
||||
connection.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(HandshakeSendCallback), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -259,10 +221,7 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void HandshakeSendCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
connection.EndSend(ar);
|
||||
@@ -274,7 +233,7 @@ namespace Shadowsocks.Controller
|
||||
// +-----+-----+-------+------+----------+----------+
|
||||
// Skip first 3 bytes
|
||||
// TODO validate
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, 3, 0, new AsyncCallback(handshakeReceive2Callback), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, 3, SocketFlags.None, new AsyncCallback(handshakeReceive2Callback), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -285,26 +244,20 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void handshakeReceive2Callback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
int bytesRead = connection.EndReceive(ar);
|
||||
|
||||
if (bytesRead >= 3)
|
||||
{
|
||||
command = connetionRecvBuffer[1];
|
||||
if (command == 1)
|
||||
_command = _connetionRecvBuffer[1];
|
||||
if (_command == 1)
|
||||
{
|
||||
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
|
||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ResponseCallback), null);
|
||||
connection.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(ResponseCallback), null);
|
||||
}
|
||||
else if (command == 3)
|
||||
{
|
||||
else if (_command == 3)
|
||||
HandleUDPAssociate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -326,33 +279,31 @@ namespace Shadowsocks.Controller
|
||||
int port = endPoint.Port;
|
||||
byte[] response = new byte[4 + address.Length + 2];
|
||||
response[0] = 5;
|
||||
if (endPoint.AddressFamily == AddressFamily.InterNetwork)
|
||||
switch (endPoint.AddressFamily)
|
||||
{
|
||||
response[3] = 1;
|
||||
}
|
||||
else if (endPoint.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
response[3] = 4;
|
||||
case AddressFamily.InterNetwork:
|
||||
response[3] = 1;
|
||||
break;
|
||||
case AddressFamily.InterNetworkV6:
|
||||
response[3] = 4;
|
||||
break;
|
||||
}
|
||||
address.CopyTo(response, 4);
|
||||
response[response.Length - 1] = (byte)(port & 0xFF);
|
||||
response[response.Length - 2] = (byte)((port >> 8) & 0xFF);
|
||||
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ReadAll), true);
|
||||
connection.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(ReadAll), true);
|
||||
}
|
||||
|
||||
private void ReadAll(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
if (ar.AsyncState != null)
|
||||
{
|
||||
connection.EndSend(ar);
|
||||
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(ReadAll), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -360,12 +311,10 @@ namespace Shadowsocks.Controller
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(ReadAll), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -380,10 +329,8 @@ namespace Shadowsocks.Controller
|
||||
try
|
||||
{
|
||||
connection.EndSend(ar);
|
||||
|
||||
StartConnect();
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
@@ -405,10 +352,7 @@ namespace Shadowsocks.Controller
|
||||
private class ServerTimer : Timer
|
||||
{
|
||||
public Server Server;
|
||||
|
||||
public ServerTimer(int p) : base(p)
|
||||
{
|
||||
}
|
||||
public ServerTimer(int p) : base(p) { }
|
||||
}
|
||||
|
||||
private void StartConnect()
|
||||
@@ -429,17 +373,17 @@ namespace Shadowsocks.Controller
|
||||
|
||||
// Setting up proxy
|
||||
IPEndPoint proxyEP;
|
||||
if (config.useProxy)
|
||||
if (_config.useProxy)
|
||||
{
|
||||
parsed = IPAddress.TryParse(config.proxyServer, out ipAddress);
|
||||
parsed = IPAddress.TryParse(_config.proxyServer, out ipAddress);
|
||||
if (!parsed)
|
||||
{
|
||||
IPHostEntry ipHostInfo = Dns.GetHostEntry(config.proxyServer);
|
||||
IPHostEntry ipHostInfo = Dns.GetHostEntry(_config.proxyServer);
|
||||
ipAddress = ipHostInfo.AddressList[0];
|
||||
}
|
||||
|
||||
remote = new Socks5Proxy();
|
||||
proxyEP = new IPEndPoint(ipAddress, config.proxyPort);
|
||||
proxyEP = new IPEndPoint(ipAddress, _config.proxyPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -455,7 +399,7 @@ namespace Shadowsocks.Controller
|
||||
proxyTimer.DestEndPoint = destEP;
|
||||
proxyTimer.Server = server;
|
||||
|
||||
proxyConnected = false;
|
||||
_proxyConnected = false;
|
||||
|
||||
// Connect to the proxy server.
|
||||
remote.BeginConnectProxy(proxyEP, new AsyncCallback(ProxyConnectCallback), proxyTimer);
|
||||
@@ -469,7 +413,7 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void proxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (proxyConnected || destConnected)
|
||||
if (_proxyConnected || _destConnected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -483,7 +427,7 @@ namespace Shadowsocks.Controller
|
||||
private void ProxyConnectCallback(IAsyncResult ar)
|
||||
{
|
||||
Server server = null;
|
||||
if (closed)
|
||||
if (_closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -499,19 +443,18 @@ namespace Shadowsocks.Controller
|
||||
// Complete the connection.
|
||||
remote.EndConnectProxy(ar);
|
||||
|
||||
proxyConnected = true;
|
||||
_proxyConnected = true;
|
||||
|
||||
Logging.Debug($"Socket connected to proxy {remote.ProxyEndPoint}");
|
||||
|
||||
|
||||
_startConnectTime = DateTime.Now;
|
||||
ServerTimer connectTimer = new ServerTimer(3000);
|
||||
connectTimer.AutoReset = false;
|
||||
connectTimer.Elapsed += destConnectTimer_Elapsed;
|
||||
connectTimer.Enabled = true;
|
||||
connectTimer.Server = server;
|
||||
|
||||
destConnected = false;
|
||||
|
||||
_destConnected = false;
|
||||
// Connect to the remote endpoint.
|
||||
remote.BeginConnectDest(destEP, new AsyncCallback(ConnectCallback), connectTimer);
|
||||
}
|
||||
@@ -527,16 +470,14 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void destConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (destConnected)
|
||||
if (_destConnected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Server server = ((ServerTimer)sender).Server;
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
if (strategy != null)
|
||||
{
|
||||
strategy.SetFailure(server);
|
||||
}
|
||||
strategy?.SetFailure(server);
|
||||
Logging.Info($"{server.FriendlyName()} timed out");
|
||||
remote.Close();
|
||||
RetryConnect();
|
||||
@@ -544,25 +485,19 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void RetryConnect()
|
||||
{
|
||||
if (retryCount < maxRetry)
|
||||
if (_retryCount < MaxRetry)
|
||||
{
|
||||
Logging.Debug($"Connection failed, retry ({retryCount})");
|
||||
Logging.Debug($"Connection failed, retry ({_retryCount})");
|
||||
StartConnect();
|
||||
retryCount++;
|
||||
_retryCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectCallback(IAsyncResult ar)
|
||||
{
|
||||
Server server = null;
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
ServerTimer timer = (ServerTimer)ar.AsyncState;
|
||||
@@ -573,15 +508,13 @@ namespace Shadowsocks.Controller
|
||||
|
||||
// Complete the connection.
|
||||
remote.EndConnectDest(ar);
|
||||
|
||||
destConnected = true;
|
||||
|
||||
Logging.Debug($"Socket connected to {remote.DestEndPoint}");
|
||||
|
||||
_destConnected = true;
|
||||
|
||||
var latency = DateTime.Now - _startConnectTime;
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
strategy?.UpdateLatency(server, latency);
|
||||
tcprelay.UpdateLatency(server, latency);
|
||||
_tcprelay.UpdateLatency(server, latency);
|
||||
|
||||
StartPipe();
|
||||
}
|
||||
@@ -593,10 +526,7 @@ namespace Shadowsocks.Controller
|
||||
if (server != null)
|
||||
{
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
if (strategy != null)
|
||||
{
|
||||
strategy.SetFailure(server);
|
||||
}
|
||||
strategy?.SetFailure(server);
|
||||
}
|
||||
Logging.LogUsefulException(e);
|
||||
RetryConnect();
|
||||
@@ -605,15 +535,12 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void StartPipe()
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
_startReceivingTime = DateTime.Now;
|
||||
remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -624,49 +551,30 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void PipeRemoteReceiveCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
int bytesRead = remote.EndReceive(ar);
|
||||
totalRead += bytesRead;
|
||||
tcprelay.UpdateInboundCounter(server, bytesRead);
|
||||
|
||||
_totalRead += bytesRead;
|
||||
_tcprelay.UpdateInboundCounter(server, bytesRead);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
lastActivity = DateTime.Now;
|
||||
int bytesToSend;
|
||||
lock (decryptionLock)
|
||||
lock (_decryptionLock)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
encryptor.Decrypt(remoteRecvBuffer, bytesRead, remoteSendBuffer, out bytesToSend);
|
||||
if (_closed) return;
|
||||
encryptor.Decrypt(_remoteRecvBuffer, bytesRead, _remoteSendBuffer, out bytesToSend);
|
||||
}
|
||||
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, bytesToSend, "TCP Relay", "@PipeRemoteReceiveCallback() (download)");
|
||||
connection.BeginSend(remoteSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeConnectionSendCallback), null);
|
||||
|
||||
connection.BeginSend(_remoteSendBuffer, 0, bytesToSend, SocketFlags.None, new AsyncCallback(PipeConnectionSendCallback), null);
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
if (strategy != null)
|
||||
{
|
||||
strategy.UpdateLastRead(server);
|
||||
}
|
||||
strategy?.UpdateLastRead(server);
|
||||
}
|
||||
else
|
||||
{
|
||||
connection.Shutdown(SocketShutdown.Send);
|
||||
connectionShutdown = true;
|
||||
_connectionShutdown = true;
|
||||
CheckClose();
|
||||
|
||||
//if (totalRead == 0)
|
||||
//{
|
||||
// // closed before anything received, reports as failure
|
||||
// // disable this feature
|
||||
// controller.GetCurrentStrategy().SetFailure(this.server);
|
||||
//}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -678,39 +586,58 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void PipeConnectionReceiveCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
int bytesRead = connection.EndReceive(ar);
|
||||
totalWrite += bytesRead;
|
||||
|
||||
_totalWrite += bytesRead;
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
int bytesToSend;
|
||||
lock (encryptionLock)
|
||||
int atyp = _connetionRecvBuffer[0];
|
||||
string dst_addr;
|
||||
int dst_port;
|
||||
switch (atyp)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend);
|
||||
case 1: // IPv4 address, 4 bytes
|
||||
dst_addr = new IPAddress(_connetionRecvBuffer.Skip(1).Take(4).ToArray()).ToString();
|
||||
dst_port = (_connetionRecvBuffer[5] << 8) + _connetionRecvBuffer[6];
|
||||
if ( _config.isVerboseLogging ) {
|
||||
Logging.Info( $"connect to {dst_addr}:{dst_port}" );
|
||||
}
|
||||
break;
|
||||
case 3: // domain name, length + str
|
||||
int len = _connetionRecvBuffer[1];
|
||||
dst_addr = System.Text.Encoding.UTF8.GetString(_connetionRecvBuffer, 2, len);
|
||||
dst_port = (_connetionRecvBuffer[len + 2] << 8) + _connetionRecvBuffer[len + 3];
|
||||
if ( _config.isVerboseLogging ) {
|
||||
Logging.Info( $"connect to {dst_addr}:{dst_port}" );
|
||||
}
|
||||
break;
|
||||
case 4: // IPv6 address, 16 bytes
|
||||
dst_addr = new IPAddress(_connetionRecvBuffer.Skip(1).Take(16).ToArray()).ToString();
|
||||
dst_port = (_connetionRecvBuffer[17] << 8) + _connetionRecvBuffer[18];
|
||||
if ( _config.isVerboseLogging ) {
|
||||
Logging.Info( $"connect to [{dst_addr}]:{dst_port}" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, bytesToSend, "TCP Relay", "@PipeConnectionReceiveCallback() (upload)");
|
||||
tcprelay.UpdateOutboundCounter(server, bytesToSend);
|
||||
int bytesToSend;
|
||||
lock (_encryptionLock)
|
||||
{
|
||||
if (_closed) return;
|
||||
encryptor.Encrypt(_connetionRecvBuffer, bytesRead, _connetionSendBuffer, out bytesToSend);
|
||||
}
|
||||
_tcprelay.UpdateOutboundCounter(server, bytesToSend);
|
||||
_startSendingTime = DateTime.Now;
|
||||
_bytesToSend = bytesToSend;
|
||||
remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeRemoteSendCallback), null);
|
||||
|
||||
remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None, new AsyncCallback(PipeRemoteSendCallback), null);
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
strategy?.UpdateLastWrite(server);
|
||||
}
|
||||
else
|
||||
{
|
||||
remote.Shutdown(SocketShutdown.Send);
|
||||
remoteShutdown = true;
|
||||
_remoteShutdown = true;
|
||||
CheckClose();
|
||||
}
|
||||
}
|
||||
@@ -723,14 +650,11 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void PipeRemoteSendCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
remote.EndSend(ar);
|
||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -741,14 +665,11 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void PipeConnectionSendCallback(IAsyncResult ar)
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
connection.EndSend(ar);
|
||||
remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
Executable → Regular
+71
-4
@@ -5,7 +5,6 @@ using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using Shadowsocks.Controller.Strategy;
|
||||
@@ -23,6 +22,7 @@ namespace Shadowsocks.Controller
|
||||
// interacts with low level logic
|
||||
|
||||
private Thread _ramThread;
|
||||
private Thread _trafficThread;
|
||||
|
||||
private Listener _listener;
|
||||
private PACServer _pacServer;
|
||||
@@ -35,6 +35,7 @@ namespace Shadowsocks.Controller
|
||||
|
||||
public long inboundCounter = 0;
|
||||
public long outboundCounter = 0;
|
||||
public QueueLast<TrafficPerSecond> traffic;
|
||||
|
||||
private bool stopped = false;
|
||||
|
||||
@@ -45,10 +46,30 @@ namespace Shadowsocks.Controller
|
||||
public string Path;
|
||||
}
|
||||
|
||||
public class QueueLast<T> : Queue<T>
|
||||
{
|
||||
public T Last { get; private set; }
|
||||
public new void Enqueue(T item)
|
||||
{
|
||||
Last = item;
|
||||
base.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
public class TrafficPerSecond
|
||||
{
|
||||
public long inboundCounter;
|
||||
public long outboundCounter;
|
||||
public long inboundIncreasement;
|
||||
public long outboundIncreasement;
|
||||
}
|
||||
|
||||
public event EventHandler ConfigChanged;
|
||||
public event EventHandler EnableStatusChanged;
|
||||
public event EventHandler EnableGlobalChanged;
|
||||
public event EventHandler ShareOverLANStatusChanged;
|
||||
public event EventHandler VerboseLoggingStatusChanged;
|
||||
public event EventHandler TrafficChanged;
|
||||
|
||||
// when user clicked Edit PAC, and PAC file has already created
|
||||
public event EventHandler<PathEventArgs> PACFileReadyToOpen;
|
||||
@@ -66,6 +87,7 @@ namespace Shadowsocks.Controller
|
||||
StatisticsConfiguration = StatisticsStrategyConfiguration.Load();
|
||||
_strategyManager = new StrategyManager(this);
|
||||
StartReleasingMemory();
|
||||
StartTrafficStatistics(60);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
@@ -205,6 +227,15 @@ namespace Shadowsocks.Controller
|
||||
SaveConfig(_config);
|
||||
}
|
||||
|
||||
public void ToggleVerboseLogging(bool enabled)
|
||||
{
|
||||
_config.isVerboseLogging = enabled;
|
||||
SaveConfig(_config);
|
||||
if ( VerboseLoggingStatusChanged != null ) {
|
||||
VerboseLoggingStatusChanged(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectServerIndex(int index)
|
||||
{
|
||||
_config.index = index;
|
||||
@@ -327,7 +358,7 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
if (_config.availabilityStatistics)
|
||||
{
|
||||
new Task(() => availabilityStatistics.UpdateLatency(server, (int) latency.TotalMilliseconds)).Start();
|
||||
availabilityStatistics.UpdateLatency(server, (int)latency.TotalMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +367,7 @@ namespace Shadowsocks.Controller
|
||||
Interlocked.Add(ref inboundCounter, n);
|
||||
if (_config.availabilityStatistics)
|
||||
{
|
||||
new Task(() => availabilityStatistics.UpdateInboundCounter(server, n)).Start();
|
||||
availabilityStatistics.UpdateInboundCounter(server, n);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,7 +376,7 @@ namespace Shadowsocks.Controller
|
||||
Interlocked.Add(ref outboundCounter, n);
|
||||
if (_config.availabilityStatistics)
|
||||
{
|
||||
new Task(() => availabilityStatistics.UpdateOutboundCounter(server, n)).Start();
|
||||
availabilityStatistics.UpdateOutboundCounter(server, n);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,5 +561,41 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
}
|
||||
|
||||
private void StartTrafficStatistics(int queueMaxSize)
|
||||
{
|
||||
traffic = new QueueLast<TrafficPerSecond>();
|
||||
for (int i = 0; i < queueMaxSize; i++)
|
||||
{
|
||||
traffic.Enqueue(new TrafficPerSecond());
|
||||
}
|
||||
_trafficThread = new Thread(new ThreadStart(() => TrafficStatistics(queueMaxSize)));
|
||||
_trafficThread.IsBackground = true;
|
||||
_trafficThread.Start();
|
||||
}
|
||||
|
||||
private void TrafficStatistics(int queueMaxSize)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
TrafficPerSecond previous = traffic.Last;
|
||||
TrafficPerSecond current = new TrafficPerSecond();
|
||||
current.inboundCounter = inboundCounter;
|
||||
current.outboundCounter = outboundCounter;
|
||||
current.inboundIncreasement = inboundCounter - previous.inboundCounter;
|
||||
current.outboundIncreasement = outboundCounter - previous.outboundCounter;
|
||||
|
||||
traffic.Enqueue(current);
|
||||
if (traffic.Count > queueMaxSize)
|
||||
traffic.Dequeue();
|
||||
|
||||
if (TrafficChanged != null)
|
||||
{
|
||||
TrafficChanged(this, new EventArgs());
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ Show QRCode...=显示二维码...
|
||||
Scan QRCode from Screen...=扫描屏幕上的二维码...
|
||||
Availability Statistics=统计可用性
|
||||
Show Logs...=显示日志...
|
||||
Verbose Logging=详细记录日志
|
||||
Updates...=更新...
|
||||
Check for Updates...=检查更新
|
||||
Check for Updates at Startup=启动时检查更新
|
||||
@@ -70,6 +71,8 @@ Change &Font=设置字体(&F)
|
||||
&Top Most=置顶(&T)
|
||||
&Show Toolbar=显示工具栏(&S)
|
||||
Log Viewer=日志查看器
|
||||
Inbound=入站
|
||||
Outbound=出站
|
||||
|
||||
# QRCode Form
|
||||
|
||||
@@ -109,3 +112,5 @@ Failed to decode QRCode=无法解析二维码
|
||||
Failed to update registry=无法修改注册表
|
||||
System Proxy On: =系统代理已启用:
|
||||
Running: Port {0}=正在运行:端口 {0}
|
||||
Unexpect error, shadowsocks will be exit. Please report to=非预期错误,Shadowsocks将退出。请提交此错误到
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Shadowsocks.Model
|
||||
public bool useOnlinePac;
|
||||
public bool availabilityStatistics;
|
||||
public bool autoCheckUpdate;
|
||||
public bool isVerboseLogging;
|
||||
public LogViewerConfig logViewer;
|
||||
public bool useProxy;
|
||||
public string proxyServer;
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Shadowsocks
|
||||
Utils.ReleaseMemory(true);
|
||||
using (Mutex mutex = new Mutex(false, "Global\\Shadowsocks_" + Application.StartupPath.GetHashCode()))
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
@@ -53,5 +54,19 @@ namespace Shadowsocks
|
||||
Application.Run();
|
||||
}
|
||||
}
|
||||
|
||||
private static int exited = 0;
|
||||
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
if (Interlocked.Increment(ref exited) == 1)
|
||||
{
|
||||
Logging.Error(e.ExceptionObject?.ToString());
|
||||
MessageBox.Show(I18N.GetString("Unexpect error, shadowsocks will be exit. Please report to") +
|
||||
" https://github.com/shadowsocks/shadowsocks-windows/issues " +
|
||||
Environment.NewLine + (e.ExceptionObject?.ToString()),
|
||||
"Shadowsocks Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-1
@@ -182,7 +182,27 @@ namespace Shadowsocks.Properties {
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap ssIn24 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ssIn24", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap ssOut24 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ssOut24", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
|
||||
@@ -148,6 +148,12 @@
|
||||
<data name="ss24" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\ss24.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="ssIn24" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\ssIn24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="ssOut24" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\ssOut24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="ssw128" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 224 B |
Binary file not shown.
|
After Width: | Height: | Size: 211 B |
@@ -76,7 +76,8 @@ namespace Shadowsocks.Util
|
||||
//
|
||||
// just kidding
|
||||
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle,
|
||||
(UIntPtr)0xFFFFFFFF, (UIntPtr)0xFFFFFFFF);
|
||||
(UIntPtr)0xFFFFFFFF,
|
||||
(UIntPtr)0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +88,8 @@ namespace Shadowsocks.Util
|
||||
using (MemoryStream sb = new MemoryStream())
|
||||
{
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(buf),
|
||||
CompressionMode.Decompress, false))
|
||||
CompressionMode.Decompress,
|
||||
false))
|
||||
{
|
||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
@@ -100,29 +102,49 @@ namespace Shadowsocks.Util
|
||||
|
||||
public static string FormatBandwidth(long n)
|
||||
{
|
||||
var result = GetBandwidthScale(n);
|
||||
return $"{result.Item1:0.##}{result.Item2}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return scaled bandwidth
|
||||
/// </summary>
|
||||
/// <param name="n">Raw bandwidth</param>
|
||||
/// <returns>
|
||||
/// Item1: float, bandwidth with suitable scale (eg. 56)
|
||||
/// Item2: string, scale unit name (eg. KiB)
|
||||
/// Item3: long, scale unit (eg. 1024)
|
||||
/// </returns>
|
||||
public static Tuple<float, string, long> GetBandwidthScale(long n)
|
||||
{
|
||||
long scale = 1;
|
||||
float f = n;
|
||||
string unit = "B";
|
||||
if (f > 1024)
|
||||
{
|
||||
f = f / 1024;
|
||||
scale <<= 10;
|
||||
unit = "KiB";
|
||||
}
|
||||
if (f > 1024)
|
||||
{
|
||||
f = f / 1024;
|
||||
scale <<= 10;
|
||||
unit = "MiB";
|
||||
}
|
||||
if (f > 1024)
|
||||
{
|
||||
f = f / 1024;
|
||||
scale <<= 10;
|
||||
unit = "GiB";
|
||||
}
|
||||
if (f > 1024)
|
||||
{
|
||||
f = f / 1024;
|
||||
scale <<= 10;
|
||||
unit = "TiB";
|
||||
}
|
||||
return $"{f:0.##}{unit}";
|
||||
return new Tuple<float, string, long>(f, unit, scale);
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
|
||||
+89
-14
@@ -29,6 +29,10 @@
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
|
||||
System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
|
||||
System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
|
||||
System.Windows.Forms.DataVisualization.Charting.Series series2 = new System.Windows.Forms.DataVisualization.Charting.Series();
|
||||
this.LogMessageTextBox = new System.Windows.Forms.TextBox();
|
||||
this.MainMenu = new System.Windows.Forms.MainMenu(this.components);
|
||||
this.FileMenuItem = new System.Windows.Forms.MenuItem();
|
||||
@@ -47,8 +51,15 @@
|
||||
this.WrapTextCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.ToolbarFlowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.trafficChart = new System.Windows.Forms.DataVisualization.Charting.Chart();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.ToolbarFlowLayoutPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trafficChart)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// LogMessageTextBox
|
||||
@@ -57,13 +68,13 @@
|
||||
this.LogMessageTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.LogMessageTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.LogMessageTextBox.ForeColor = System.Drawing.Color.White;
|
||||
this.LogMessageTextBox.Location = new System.Drawing.Point(3, 40);
|
||||
this.LogMessageTextBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.LogMessageTextBox.MaxLength = 2147483647;
|
||||
this.LogMessageTextBox.Multiline = true;
|
||||
this.LogMessageTextBox.Name = "LogMessageTextBox";
|
||||
this.LogMessageTextBox.ReadOnly = true;
|
||||
this.LogMessageTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.LogMessageTextBox.Size = new System.Drawing.Size(378, 131);
|
||||
this.LogMessageTextBox.Size = new System.Drawing.Size(378, 74);
|
||||
this.LogMessageTextBox.TabIndex = 0;
|
||||
//
|
||||
// MainMenu
|
||||
@@ -144,9 +155,9 @@
|
||||
this.TopMostCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.TopMostCheckBox.AutoSize = true;
|
||||
this.TopMostCheckBox.Location = new System.Drawing.Point(247, 3);
|
||||
this.TopMostCheckBox.Location = new System.Drawing.Point(249, 3);
|
||||
this.TopMostCheckBox.Name = "TopMostCheckBox";
|
||||
this.TopMostCheckBox.Size = new System.Drawing.Size(71, 25);
|
||||
this.TopMostCheckBox.Size = new System.Drawing.Size(72, 23);
|
||||
this.TopMostCheckBox.TabIndex = 3;
|
||||
this.TopMostCheckBox.Text = "&Top Most";
|
||||
this.TopMostCheckBox.UseVisualStyleBackColor = true;
|
||||
@@ -157,7 +168,7 @@
|
||||
this.ChangeFontButton.AutoSize = true;
|
||||
this.ChangeFontButton.Location = new System.Drawing.Point(84, 3);
|
||||
this.ChangeFontButton.Name = "ChangeFontButton";
|
||||
this.ChangeFontButton.Size = new System.Drawing.Size(75, 25);
|
||||
this.ChangeFontButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ChangeFontButton.TabIndex = 2;
|
||||
this.ChangeFontButton.Text = "&Font";
|
||||
this.ChangeFontButton.UseVisualStyleBackColor = true;
|
||||
@@ -168,7 +179,7 @@
|
||||
this.CleanLogsButton.AutoSize = true;
|
||||
this.CleanLogsButton.Location = new System.Drawing.Point(3, 3);
|
||||
this.CleanLogsButton.Name = "CleanLogsButton";
|
||||
this.CleanLogsButton.Size = new System.Drawing.Size(75, 25);
|
||||
this.CleanLogsButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.CleanLogsButton.TabIndex = 1;
|
||||
this.CleanLogsButton.Text = "&Clean Logs";
|
||||
this.CleanLogsButton.UseVisualStyleBackColor = true;
|
||||
@@ -181,7 +192,7 @@
|
||||
this.WrapTextCheckBox.AutoSize = true;
|
||||
this.WrapTextCheckBox.Location = new System.Drawing.Point(165, 3);
|
||||
this.WrapTextCheckBox.Name = "WrapTextCheckBox";
|
||||
this.WrapTextCheckBox.Size = new System.Drawing.Size(76, 25);
|
||||
this.WrapTextCheckBox.Size = new System.Drawing.Size(78, 23);
|
||||
this.WrapTextCheckBox.TabIndex = 0;
|
||||
this.WrapTextCheckBox.Text = "&Wrap Text";
|
||||
this.WrapTextCheckBox.UseVisualStyleBackColor = true;
|
||||
@@ -191,15 +202,15 @@
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 1;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.LogMessageTextBox, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.ToolbarFlowLayoutPanel, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.splitContainer1, 0, 1);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 2;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(384, 174);
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(384, 161);
|
||||
this.tableLayoutPanel1.TabIndex = 2;
|
||||
//
|
||||
// ToolbarFlowLayoutPanel
|
||||
@@ -212,17 +223,73 @@
|
||||
this.ToolbarFlowLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ToolbarFlowLayoutPanel.Location = new System.Drawing.Point(3, 3);
|
||||
this.ToolbarFlowLayoutPanel.Name = "ToolbarFlowLayoutPanel";
|
||||
this.ToolbarFlowLayoutPanel.Size = new System.Drawing.Size(378, 31);
|
||||
this.ToolbarFlowLayoutPanel.Size = new System.Drawing.Size(378, 29);
|
||||
this.ToolbarFlowLayoutPanel.TabIndex = 2;
|
||||
//
|
||||
// splitContainer1
|
||||
//
|
||||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer1.Location = new System.Drawing.Point(3, 38);
|
||||
this.splitContainer1.Name = "splitContainer1";
|
||||
this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
|
||||
//
|
||||
// splitContainer1.Panel1
|
||||
//
|
||||
this.splitContainer1.Panel1.Controls.Add(this.LogMessageTextBox);
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.trafficChart);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(378, 120);
|
||||
this.splitContainer1.SplitterDistance = 74;
|
||||
this.splitContainer1.TabIndex = 3;
|
||||
//
|
||||
// trafficChart
|
||||
//
|
||||
chartArea1.AxisX.LabelStyle.Enabled = false;
|
||||
chartArea1.AxisX.MajorGrid.Interval = 5D;
|
||||
chartArea1.AxisX.MajorGrid.LineColor = System.Drawing.Color.LightGray;
|
||||
chartArea1.AxisX.MajorTickMark.Enabled = false;
|
||||
chartArea1.AxisY.IntervalAutoMode = System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode.VariableCount;
|
||||
chartArea1.AxisY.LabelAutoFitMaxFontSize = 8;
|
||||
chartArea1.AxisY.LabelStyle.Interval = 0D;
|
||||
chartArea1.AxisY.MajorGrid.LineColor = System.Drawing.Color.LightGray;
|
||||
chartArea1.AxisY.MajorTickMark.Enabled = false;
|
||||
chartArea1.AxisY2.MajorGrid.LineColor = System.Drawing.Color.LightGray;
|
||||
chartArea1.AxisY2.Minimum = 0D;
|
||||
chartArea1.Name = "ChartArea1";
|
||||
this.trafficChart.ChartAreas.Add(chartArea1);
|
||||
this.trafficChart.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
legend1.MaximumAutoSize = 25F;
|
||||
legend1.Name = "Legend1";
|
||||
this.trafficChart.Legends.Add(legend1);
|
||||
this.trafficChart.Location = new System.Drawing.Point(0, 0);
|
||||
this.trafficChart.Name = "trafficChart";
|
||||
this.trafficChart.Palette = System.Windows.Forms.DataVisualization.Charting.ChartColorPalette.None;
|
||||
series1.ChartArea = "ChartArea1";
|
||||
series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
|
||||
series1.IsXValueIndexed = true;
|
||||
series1.Legend = "Legend1";
|
||||
series1.Name = "Inbound";
|
||||
series2.ChartArea = "ChartArea1";
|
||||
series2.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
|
||||
series2.IsXValueIndexed = true;
|
||||
series2.Legend = "Legend1";
|
||||
series2.Name = "Outbound";
|
||||
this.trafficChart.Series.Add(series1);
|
||||
this.trafficChart.Series.Add(series2);
|
||||
this.trafficChart.Size = new System.Drawing.Size(378, 42);
|
||||
this.trafficChart.TabIndex = 0;
|
||||
this.trafficChart.Text = "chart1";
|
||||
//
|
||||
// LogForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(384, 174);
|
||||
this.ClientSize = new System.Drawing.Size(384, 161);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Menu = this.MainMenu;
|
||||
this.MinimumSize = new System.Drawing.Size(400, 213);
|
||||
this.MinimumSize = new System.Drawing.Size(400, 200);
|
||||
this.Name = "LogForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Log Viewer";
|
||||
@@ -233,6 +300,12 @@
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.ToolbarFlowLayoutPanel.ResumeLayout(false);
|
||||
this.ToolbarFlowLayoutPanel.PerformLayout();
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel1.PerformLayout();
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.trafficChart)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
@@ -257,5 +330,7 @@
|
||||
private System.Windows.Forms.FlowLayoutPanel ToolbarFlowLayoutPanel;
|
||||
private System.Windows.Forms.MenuItem MenuItemSeparater;
|
||||
private System.Windows.Forms.MenuItem ShowToolbarMenuItem;
|
||||
private System.Windows.Forms.SplitContainer splitContainer1;
|
||||
private System.Windows.Forms.DataVisualization.Charting.Chart trafficChart;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.DataVisualization.Charting;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Properties;
|
||||
@@ -18,6 +21,15 @@ namespace Shadowsocks.View
|
||||
const int BACK_OFFSET = 65536;
|
||||
ShadowsocksController controller;
|
||||
|
||||
#region chart
|
||||
List<float> inboundPoints = new List<float>();
|
||||
List<float> outboundPoints = new List<float>();
|
||||
long maxSpeed = 0;
|
||||
Tuple<float, string, long> bandwidthScale = new Tuple<float, string, long>(0, "B", 1);
|
||||
TextAnnotation inboundAnnotation = new TextAnnotation();
|
||||
TextAnnotation outboundAnnotation = new TextAnnotation();
|
||||
#endregion
|
||||
|
||||
public LogForm(ShadowsocksController controller, string filename)
|
||||
{
|
||||
this.controller = controller;
|
||||
@@ -30,7 +42,8 @@ namespace Shadowsocks.View
|
||||
{
|
||||
config = new LogViewerConfig();
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
topMostTrigger = config.topMost;
|
||||
wrapTextTrigger = config.wrapText;
|
||||
toolbarTrigger = config.toolbarShown;
|
||||
@@ -39,9 +52,54 @@ namespace Shadowsocks.View
|
||||
LogMessageTextBox.Font = config.GetFont();
|
||||
}
|
||||
|
||||
controller.TrafficChanged += controller_TrafficChanged;
|
||||
|
||||
UpdateTexts();
|
||||
}
|
||||
|
||||
private void controller_TrafficChanged(object sender, EventArgs e)
|
||||
{
|
||||
inboundPoints.Clear();
|
||||
outboundPoints.Clear();
|
||||
foreach (var trafficPerSecond in controller.traffic)
|
||||
{
|
||||
inboundPoints.Add(trafficPerSecond.inboundIncreasement);
|
||||
outboundPoints.Add(trafficPerSecond.outboundIncreasement);
|
||||
maxSpeed = Math.Max(maxSpeed, Math.Max(trafficPerSecond.inboundIncreasement, trafficPerSecond.outboundIncreasement));
|
||||
}
|
||||
|
||||
bandwidthScale = Utils.GetBandwidthScale(maxSpeed);
|
||||
|
||||
//rescale the original data points, since it is List<float>, .ForEach does not work
|
||||
inboundPoints = inboundPoints.Select(p => p / bandwidthScale.Item3).ToList();
|
||||
outboundPoints = outboundPoints.Select(p => p / bandwidthScale.Item3).ToList();
|
||||
|
||||
try
|
||||
{
|
||||
if (trafficChart.InvokeRequired)
|
||||
{
|
||||
trafficChart.Invoke(new Action(() =>
|
||||
{
|
||||
trafficChart.Series["Inbound"].Points.DataBindY(inboundPoints);
|
||||
trafficChart.Series["Outbound"].Points.DataBindY(outboundPoints);
|
||||
trafficChart.ChartAreas[0].AxisY.LabelStyle.Format = "{0:0.##} " + bandwidthScale.Item2;
|
||||
inboundAnnotation.AnchorDataPoint = trafficChart.Series["Inbound"].Points.Last();
|
||||
inboundAnnotation.Text = Utils.FormatBandwidth(controller.traffic.Last.inboundIncreasement);
|
||||
outboundAnnotation.AnchorDataPoint = trafficChart.Series["Outbound"].Points.Last();
|
||||
outboundAnnotation.Text = Utils.FormatBandwidth(controller.traffic.Last.outboundIncreasement);
|
||||
trafficChart.Annotations.Clear();
|
||||
trafficChart.Annotations.Add(inboundAnnotation);
|
||||
trafficChart.Annotations.Add(outboundAnnotation);
|
||||
}));
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException ex)
|
||||
{
|
||||
// suppress the thread race error:
|
||||
// when closing the form but the Invoked Action is still working and cause 'Chart is Disposed' exception
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTexts()
|
||||
{
|
||||
FileMenuItem.Text = I18N.GetString("&File");
|
||||
@@ -58,6 +116,9 @@ namespace Shadowsocks.View
|
||||
TopMostMenuItem.Text = I18N.GetString("&Top Most");
|
||||
ShowToolbarMenuItem.Text = I18N.GetString("&Show Toolbar");
|
||||
Text = I18N.GetString("Log Viewer");
|
||||
// traffic chart
|
||||
trafficChart.Series["Inbound"].LegendText = I18N.GetString("Inbound");
|
||||
trafficChart.Series["Outbound"].LegendText = I18N.GetString("Outbound");
|
||||
}
|
||||
|
||||
private void Timer_Tick(object sender, EventArgs e)
|
||||
@@ -144,6 +205,7 @@ namespace Shadowsocks.View
|
||||
private void LogForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
timer.Stop();
|
||||
controller.TrafficChanged -= controller_TrafficChanged;
|
||||
LogViewerConfig config = controller.GetConfigurationCopy().logViewer;
|
||||
if (config == null)
|
||||
config = new LogViewerConfig();
|
||||
|
||||
@@ -144,4 +144,7 @@
|
||||
<metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>39</value>
|
||||
</metadata>
|
||||
</root>
|
||||
Executable → Regular
+68
-6
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using ZXing;
|
||||
@@ -25,6 +26,8 @@ namespace Shadowsocks.View
|
||||
private UpdateChecker updateChecker;
|
||||
|
||||
private NotifyIcon _notifyIcon;
|
||||
private Bitmap icon_baseBitmap;
|
||||
private Icon icon_base, icon_in, icon_out, icon_both, targetIcon;
|
||||
private ContextMenu contextMenu1;
|
||||
|
||||
private bool _isFirstRun;
|
||||
@@ -46,6 +49,7 @@ namespace Shadowsocks.View
|
||||
private MenuItem editOnlinePACItem;
|
||||
private MenuItem autoCheckUpdatesToggleItem;
|
||||
private MenuItem proxyItem;
|
||||
private MenuItem VerboseLoggingToggleItem;
|
||||
private ConfigForm configForm;
|
||||
private ProxyForm proxyForm;
|
||||
private List<LogForm> logForms = new List<LogForm>();
|
||||
@@ -63,6 +67,7 @@ namespace Shadowsocks.View
|
||||
controller.PACFileReadyToOpen += controller_FileReadyToOpen;
|
||||
controller.UserRuleFileReadyToOpen += controller_FileReadyToOpen;
|
||||
controller.ShareOverLANStatusChanged += controller_ShareOverLANStatusChanged;
|
||||
controller.VerboseLoggingStatusChanged += controller_VerboseLoggingStatusChanged;
|
||||
controller.EnableGlobalChanged += controller_EnableGlobalChanged;
|
||||
controller.Errored += controller_Errored;
|
||||
controller.UpdatePACFromGFWListCompleted += controller_UpdatePACFromGFWListCompleted;
|
||||
@@ -76,6 +81,7 @@ namespace Shadowsocks.View
|
||||
_notifyIcon.MouseClick += notifyIcon1_Click;
|
||||
_notifyIcon.MouseDoubleClick += notifyIcon1_DoubleClick;
|
||||
_notifyIcon.BalloonTipClosed += _notifyIcon_BalloonTipClosed;
|
||||
controller.TrafficChanged += controller_TrafficChanged;
|
||||
|
||||
this.updateChecker = new UpdateChecker();
|
||||
updateChecker.CheckUpdateCompleted += updateChecker_CheckUpdateCompleted;
|
||||
@@ -96,6 +102,32 @@ namespace Shadowsocks.View
|
||||
}
|
||||
}
|
||||
|
||||
private void controller_TrafficChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (icon_baseBitmap == null)
|
||||
return;
|
||||
|
||||
Icon newIcon;
|
||||
|
||||
bool hasInbound = controller.traffic.Last.inboundIncreasement > 0;
|
||||
bool hasOutbound = controller.traffic.Last.outboundIncreasement > 0;
|
||||
|
||||
if (hasInbound && hasOutbound)
|
||||
newIcon = icon_both;
|
||||
else if (hasInbound)
|
||||
newIcon = icon_in;
|
||||
else if (hasOutbound)
|
||||
newIcon = icon_out;
|
||||
else
|
||||
newIcon = icon_base;
|
||||
|
||||
if (newIcon != this.targetIcon)
|
||||
{
|
||||
this.targetIcon = newIcon;
|
||||
_notifyIcon.Icon = newIcon;
|
||||
}
|
||||
}
|
||||
|
||||
void controller_Errored(object sender, System.IO.ErrorEventArgs e)
|
||||
{
|
||||
MessageBox.Show(e.GetException().ToString(), String.Format(I18N.GetString("Shadowsocks Error: {0}"), e.GetException().Message));
|
||||
@@ -107,26 +139,32 @@ namespace Shadowsocks.View
|
||||
Graphics graphics = Graphics.FromHwnd(IntPtr.Zero);
|
||||
dpi = (int)graphics.DpiX;
|
||||
graphics.Dispose();
|
||||
Bitmap icon = null;
|
||||
icon_baseBitmap = null;
|
||||
if (dpi < 97)
|
||||
{
|
||||
// dpi = 96;
|
||||
icon = Resources.ss16;
|
||||
icon_baseBitmap = Resources.ss16;
|
||||
}
|
||||
else if (dpi < 121)
|
||||
{
|
||||
// dpi = 120;
|
||||
icon = Resources.ss20;
|
||||
icon_baseBitmap = Resources.ss20;
|
||||
}
|
||||
else
|
||||
{
|
||||
icon = Resources.ss24;
|
||||
icon_baseBitmap = Resources.ss24;
|
||||
}
|
||||
Configuration config = controller.GetConfigurationCopy();
|
||||
bool enabled = config.enabled;
|
||||
bool global = config.global;
|
||||
icon = getTrayIconByState(icon, enabled, global);
|
||||
_notifyIcon.Icon = Icon.FromHandle(icon.GetHicon());
|
||||
icon_baseBitmap = getTrayIconByState(icon_baseBitmap, enabled, global);
|
||||
|
||||
icon_base = Icon.FromHandle(icon_baseBitmap.GetHicon());
|
||||
targetIcon = icon_base;
|
||||
icon_in = Icon.FromHandle(AddBitmapOverlay(icon_baseBitmap, Resources.ssIn24).GetHicon());
|
||||
icon_out = Icon.FromHandle(AddBitmapOverlay(icon_baseBitmap, Resources.ssOut24).GetHicon());
|
||||
icon_both = Icon.FromHandle(AddBitmapOverlay(icon_baseBitmap, Resources.ssIn24, Resources.ssOut24).GetHicon());
|
||||
_notifyIcon.Icon = targetIcon;
|
||||
|
||||
string serverInfo = null;
|
||||
if (controller.GetCurrentStrategy() != null)
|
||||
@@ -179,6 +217,19 @@ namespace Shadowsocks.View
|
||||
return iconCopy;
|
||||
}
|
||||
|
||||
private Bitmap AddBitmapOverlay(Bitmap original, params Bitmap[] overlays)
|
||||
{
|
||||
Bitmap bitmap = new Bitmap(original.Width, original.Height, PixelFormat.Format64bppArgb);
|
||||
Graphics canvas = Graphics.FromImage(bitmap);
|
||||
canvas.DrawImage(original, new Point(0, 0));
|
||||
foreach (Bitmap overlay in overlays)
|
||||
{
|
||||
canvas.DrawImage(new Bitmap(overlay, original.Size), new Point(0, 0));
|
||||
}
|
||||
canvas.Save();
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private MenuItem CreateMenuItem(string text, EventHandler click)
|
||||
{
|
||||
return new MenuItem(I18N.GetString(text), click);
|
||||
@@ -219,6 +270,7 @@ namespace Shadowsocks.View
|
||||
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
|
||||
new MenuItem("-"),
|
||||
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)),
|
||||
this.VerboseLoggingToggleItem = CreateMenuItem( "Verbose Logging", new EventHandler(this.VerboseLoggingToggleItem_Click) ),
|
||||
CreateMenuGroup("Updates...", new MenuItem[] {
|
||||
CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)),
|
||||
new MenuItem("-"),
|
||||
@@ -247,6 +299,10 @@ namespace Shadowsocks.View
|
||||
ShareOverLANItem.Checked = controller.GetConfigurationCopy().shareOverLan;
|
||||
}
|
||||
|
||||
void controller_VerboseLoggingStatusChanged(object sender, EventArgs e) {
|
||||
VerboseLoggingToggleItem.Checked = controller.GetConfigurationCopy().isVerboseLogging;
|
||||
}
|
||||
|
||||
void controller_EnableGlobalChanged(object sender, EventArgs e)
|
||||
{
|
||||
globalModeItem.Checked = controller.GetConfigurationCopy().global;
|
||||
@@ -323,6 +379,7 @@ namespace Shadowsocks.View
|
||||
globalModeItem.Checked = config.global;
|
||||
PACModeItem.Checked = !config.global;
|
||||
ShareOverLANItem.Checked = config.shareOverLan;
|
||||
VerboseLoggingToggleItem.Checked = config.isVerboseLogging;
|
||||
AutoStartupItem.Checked = AutoStartup.Check();
|
||||
onlinePACItem.Checked = onlinePACItem.Enabled && config.useOnlinePac;
|
||||
localPACItem.Checked = !onlinePACItem.Checked;
|
||||
@@ -550,6 +607,11 @@ namespace Shadowsocks.View
|
||||
logForms.Add(f);
|
||||
}
|
||||
|
||||
private void VerboseLoggingToggleItem_Click( object sender, EventArgs e ) {
|
||||
VerboseLoggingToggleItem.Checked = ! VerboseLoggingToggleItem.Checked;
|
||||
controller.ToggleVerboseLogging( VerboseLoggingToggleItem.Checked );
|
||||
}
|
||||
|
||||
private void StatisticsConfigItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
StatisticsStrategyConfigurationForm form = new StatisticsStrategyConfigurationForm(controller);
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
<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>
|
||||
@@ -66,18 +66,6 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualBasic" />
|
||||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\Newtonsoft.Json.8.0.2\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
@@ -88,27 +76,7 @@
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IO, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\Microsoft.Bcl.1.1.10\lib\net40\System.IO.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.WebRequest.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\Microsoft.Bcl.1.1.10\lib\net40\System.Runtime.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\Microsoft.Bcl.1.1.10\lib\net40\System.Threading.Tasks.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Windows.Forms.DataVisualization" />
|
||||
<Reference Include="System.Xaml" />
|
||||
@@ -303,6 +271,8 @@
|
||||
<Content Include="FodyWeavers.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Resources\ssIn24.png" />
|
||||
<Content Include="Resources\ssOut24.png" />
|
||||
<Content Include="shadowsocks.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -342,10 +312,8 @@
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('3rd\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '3rd\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
|
||||
<Error Condition="!Exists('3rd\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '3rd\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets'))" />
|
||||
</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>
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
|
||||
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
|
||||
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
|
||||
<package id="System.Net.Http" version="4.0.0" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -35,29 +35,9 @@
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\shadowsocks-csharp\3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\shadowsocks-csharp\3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\shadowsocks-csharp\3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\shadowsocks-csharp\3rd\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\shadowsocks-csharp\3rd\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
@@ -82,9 +62,6 @@
|
||||
<Name>shadowsocks-csharp</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
|
||||
<ItemGroup>
|
||||
@@ -105,13 +82,6 @@
|
||||
</Choose>
|
||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\shadowsocks-csharp\3rd\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\shadowsocks-csharp\3rd\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\shadowsocks-csharp\3rd\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\shadowsocks-csharp\3rd\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
|
||||
</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">
|
||||
|
||||
Reference in New Issue
Block a user