Browse Source

Fix a memory leak.

Caused by not call SocketAsyncEventArgs.Dispose().
tags/3.3
noisyfox Syrone Wong 9 years ago
parent
commit
e364457b1b
2 changed files with 53 additions and 13 deletions
  1. +14
    -3
      shadowsocks-csharp/Controller/Service/TCPRelay.cs
  2. +39
    -10
      shadowsocks-csharp/Util/SocketUtil.cs

+ 14
- 3
shadowsocks-csharp/Controller/Service/TCPRelay.cs View File

@@ -449,11 +449,17 @@ namespace Shadowsocks.Controller
private void proxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e) private void proxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{ {
var timer = (ProxyTimer) sender;
timer.Elapsed -= proxyConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
if (_proxyConnected || _destConnected) if (_proxyConnected || _destConnected)
{ {
return; return;
} }
var proxy = ((ProxyTimer)sender).Session.Remote;
var proxy = timer.Session.Remote;
Logging.Info($"Proxy {proxy.ProxyEndPoint} timed out"); Logging.Info($"Proxy {proxy.ProxyEndPoint} timed out");
proxy.Close(); proxy.Close();
@@ -516,13 +522,18 @@ namespace Shadowsocks.Controller
private void destConnectTimer_Elapsed(object sender, ElapsedEventArgs e) private void destConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{ {
var timer = (ServerTimer)sender;
timer.Elapsed -= destConnectTimer_Elapsed;
timer.Enabled = false;
timer.Dispose();
if (_destConnected) if (_destConnected)
{ {
return; return;
} }
var session = ((ServerTimer) sender).Session;
Server server = ((ServerTimer)sender).Server;
var session = timer.Session;
Server server = timer.Server;
IStrategy strategy = controller.GetCurrentStrategy(); IStrategy strategy = controller.GetCurrentStrategy();
strategy?.SetFailure(server); strategy?.SetFailure(server);
Logging.Info($"{server.FriendlyName()} timed out"); Logging.Info($"{server.FriendlyName()} timed out");


+ 39
- 10
shadowsocks-csharp/Util/SocketUtil.cs View File

@@ -36,10 +36,27 @@ namespace Shadowsocks.Util
return new DnsEndPoint2(host, port); 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) public TcpUserToken(AsyncCallback callback, object state, SocketAsyncEventArgs args)
{ {
@@ -48,17 +65,27 @@ namespace Shadowsocks.Util
Args = args; 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) private static void OnTcpConnectCompleted(object sender, SocketAsyncEventArgs args)
{ {
args.Completed -= OnTcpConnectCompleted;
TcpUserToken token = (TcpUserToken) args.UserToken; 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) public static void BeginConnectTcp(EndPoint endPoint, AsyncCallback callback, object state)
@@ -74,12 +101,14 @@ namespace Shadowsocks.Util


public static Socket EndConnectTcp(IAsyncResult asyncResult) 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)); throw new ArgumentException("Invalid asyncResult.", nameof(asyncResult));
} }


var tut = r.UserToken;

var arg = tut.Args; var arg = tut.Args;


if (arg.SocketError != SocketError.Success) if (arg.SocketError != SocketError.Success)


Loading…
Cancel
Save