Commit 40cd60cc authored by Honfika's avatar Honfika

Do not call LingerState on disposed sockets. (#107)

parent 9d037680
using Titanium.Web.Proxy.Helpers; using System;
using System.Net.Sockets;
using System.Reflection;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
internal static class TcpExtensions internal static class TcpExtensions
{ {
private static readonly Func<Socket, bool> socketCleanedUpGetter;
static TcpExtensions()
{
var property = typeof(Socket).GetProperty("CleanedUp", BindingFlags.NonPublic | BindingFlags.Instance);
if (property != null)
{
var method = property.GetMethod;
if (method != null && method.ReturnType == typeof(bool))
{
socketCleanedUpGetter = (Func<Socket, bool>)Delegate.CreateDelegate(typeof(Func<Socket, bool>), method);
}
}
}
/// <summary> /// <summary>
/// Gets the local port from a native TCP row object. /// Gets the local port from a native TCP row object.
...@@ -24,5 +41,30 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -24,5 +41,30 @@ namespace Titanium.Web.Proxy.Extensions
{ {
return (tcpRow.remotePort1 << 8) + tcpRow.remotePort2 + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16); return (tcpRow.remotePort1 << 8) + tcpRow.remotePort2 + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16);
} }
internal static void CloseSocket(this TcpClient tcpClient)
{
if (tcpClient == null)
{
return;
}
try
{
//This line is important!
//contributors please don't remove it without discussion
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes
if (socketCleanedUpGetter == null || !socketCleanedUpGetter(tcpClient.Client))
{
tcpClient.LingerState = new LingerOption(true, 0);
}
tcpClient.Close();
}
catch
{
}
}
} }
} }
...@@ -111,6 +111,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -111,6 +111,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="clientStream"></param> /// <param name="clientStream"></param>
/// <param name="serverStream"></param> /// <param name="serverStream"></param>
/// <param name="bufferSize"></param>
/// <param name="onDataSend"></param> /// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param> /// <param name="onDataReceive"></param>
/// <returns></returns> /// <returns></returns>
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System; using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -68,21 +69,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -68,21 +69,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
Stream?.Dispose(); Stream?.Dispose();
try TcpClient.CloseSocket();
{
if (TcpClient != null)
{
//This line is important!
//contributors please don't remove it without discussion
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes
TcpClient.LingerState = new LingerOption(true, 0);
TcpClient.Close();
}
}
catch
{
}
} }
} }
} }
...@@ -9,6 +9,7 @@ using System.Threading; ...@@ -9,6 +9,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Network; using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Helpers.WinHttp; using Titanium.Web.Proxy.Helpers.WinHttp;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -765,22 +766,7 @@ namespace Titanium.Web.Proxy ...@@ -765,22 +766,7 @@ namespace Titanium.Web.Proxy
finally finally
{ {
UpdateClientConnectionCount(false); UpdateClientConnectionCount(false);
tcpClient.CloseSocket();
try
{
if (tcpClient != null)
{
//This line is important!
//contributors please don't remove it without discussion
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes
tcpClient.LingerState = new LingerOption(true, 0);
tcpClient.Close();
}
}
catch
{
}
} }
} }
......
using System; using System;
using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Security; using System.Net.Security;
...@@ -177,7 +178,8 @@ namespace Titanium.Web.Proxy ...@@ -177,7 +178,8 @@ namespace Titanium.Web.Proxy
} }
await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize, await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
(buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }); (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); });
} }
finally finally
{ {
...@@ -193,8 +195,17 @@ namespace Titanium.Web.Proxy ...@@ -193,8 +195,17 @@ namespace Titanium.Web.Proxy
disposed = await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter, disposed = await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
httpRemoteUri.Scheme == UriSchemeHttps ? httpRemoteUri.Host : null, endPoint, connectRequest); httpRemoteUri.Scheme == UriSchemeHttps ? httpRemoteUri.Host : null, endPoint, connectRequest);
} }
catch (IOException e)
{
ExceptionFunc(new Exception("Connection was aborted", e));
}
catch (SocketException e)
{
ExceptionFunc(new Exception("Could not connect", e));
}
catch (Exception e) catch (Exception e)
{ {
// is this the correct error message?
ExceptionFunc(new Exception("Error whilst authorizing request", e)); ExceptionFunc(new Exception("Error whilst authorizing request", e));
} }
finally finally
...@@ -392,7 +403,8 @@ namespace Titanium.Web.Proxy ...@@ -392,7 +403,8 @@ namespace Titanium.Web.Proxy
} }
await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize, await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
(buffer, offset, count) => { args.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); }); (buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); });
args.Dispose(); args.Dispose();
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment