diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index 1c02ca25..d266e0ee 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -449,11 +449,17 @@ namespace Shadowsocks.Controller private void proxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e) { + var timer = (ProxyTimer) sender; + timer.Elapsed -= proxyConnectTimer_Elapsed; + timer.Enabled = false; + timer.Dispose(); + + if (_proxyConnected || _destConnected) { return; } - var proxy = ((ProxyTimer)sender).Session.Remote; + var proxy = timer.Session.Remote; Logging.Info($"Proxy {proxy.ProxyEndPoint} timed out"); proxy.Close(); @@ -516,13 +522,18 @@ namespace Shadowsocks.Controller private void destConnectTimer_Elapsed(object sender, ElapsedEventArgs e) { + var timer = (ServerTimer)sender; + timer.Elapsed -= destConnectTimer_Elapsed; + timer.Enabled = false; + timer.Dispose(); + if (_destConnected) { return; } - var session = ((ServerTimer) sender).Session; - Server server = ((ServerTimer)sender).Server; + var session = timer.Session; + Server server = timer.Server; IStrategy strategy = controller.GetCurrentStrategy(); strategy?.SetFailure(server); Logging.Info($"{server.FriendlyName()} timed out"); diff --git a/shadowsocks-csharp/Util/SocketUtil.cs b/shadowsocks-csharp/Util/SocketUtil.cs index d7543b5b..ea55262e 100644 --- a/shadowsocks-csharp/Util/SocketUtil.cs +++ b/shadowsocks-csharp/Util/SocketUtil.cs @@ -36,10 +36,27 @@ namespace Shadowsocks.Util return new DnsEndPoint2(host, port); } - private class TcpUserToken : IAsyncResult + private class AutoReleaseAsyncResult : IAsyncResult { - public AsyncCallback Callback { get; } - public SocketAsyncEventArgs Args { get; } + + public bool IsCompleted { get; } = true; + public WaitHandle AsyncWaitHandle { get; } = null; + public object AsyncState { get; set; } + public bool CompletedSynchronously { get; } = true; + + public TcpUserToken UserToken { get; set; } + + ~AutoReleaseAsyncResult() + { + UserToken.Dispose(); + } + } + + private class TcpUserToken + { + public AsyncCallback Callback { get; private set; } + public SocketAsyncEventArgs Args { get; private set; } + public object AsyncState { get; private set; } public TcpUserToken(AsyncCallback callback, object state, SocketAsyncEventArgs args) { @@ -48,17 +65,27 @@ namespace Shadowsocks.Util Args = args; } - public bool IsCompleted { get; } = true; - public WaitHandle AsyncWaitHandle { get; } = null; - public object AsyncState { get; } - public bool CompletedSynchronously { get; } = true; + public void Dispose() + { + Args?.Dispose(); + Callback = null; + Args = null; + AsyncState = null; + } } private static void OnTcpConnectCompleted(object sender, SocketAsyncEventArgs args) { + args.Completed -= OnTcpConnectCompleted; TcpUserToken token = (TcpUserToken) args.UserToken; - token.Callback(token); + AutoReleaseAsyncResult r = new AutoReleaseAsyncResult + { + AsyncState = token.AsyncState, + UserToken = token + }; + + token.Callback(r); } public static void BeginConnectTcp(EndPoint endPoint, AsyncCallback callback, object state) @@ -74,12 +101,14 @@ namespace Shadowsocks.Util public static Socket EndConnectTcp(IAsyncResult asyncResult) { - var tut = asyncResult as TcpUserToken; - if (tut == null) + var r = asyncResult as AutoReleaseAsyncResult; + if (r == null) { throw new ArgumentException("Invalid asyncResult.", nameof(asyncResult)); } + var tut = r.UserToken; + var arg = tut.Args; if (arg.SocketError != SocketError.Success)