diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs
index 98d22c74a..07fc38536 100644
--- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs
+++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs
@@ -22,7 +22,7 @@ public abstract class SessionEventArgsBase : EventArgs, IDisposable
{
private static bool isWindowsAuthenticationSupported => RunTime.IsWindows;
- internal readonly CancellationTokenSource CancellationTokenSource;
+ internal readonly CancellationTokenSource? CancellationTokenSource;
internal TcpServerConnection ServerConnection => HttpClient.Connection;
diff --git a/src/Titanium.Web.Proxy/Helpers/RunTime.cs b/src/Titanium.Web.Proxy/Helpers/RunTime.cs
index b2d1e9847..a03cbbb7f 100644
--- a/src/Titanium.Web.Proxy/Helpers/RunTime.cs
+++ b/src/Titanium.Web.Proxy/Helpers/RunTime.cs
@@ -1,6 +1,8 @@
-using System;
+using System;
+using System.Reflection;
using System.Text;
using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
namespace Titanium.Web.Proxy.Helpers
{
@@ -41,6 +43,62 @@ public static class RunTime
public static bool IsUwpOnWindows => IsWindows && UwpHelper.IsRunningAsUwp();
public static bool IsMac => isRunningOnMac;
+
+ ///
+ /// Is socket reuse available to use?
+ ///
+ public static bool IsSocketReuseAvailable => isSocketReuseAvailable();
+
+ private static bool? _isSocketReuseAvailable;
+
+ private static bool isSocketReuseAvailable()
+ {
+ // use the cached value if we have one
+ if (_isSocketReuseAvailable != null)
+ return _isSocketReuseAvailable.Value;
+
+ try
+ {
+ if (IsWindows)
+ {
+ // since we are on windows just return true
+ // store the result in our static object so we don't have to be bothered going through all this more than once
+ _isSocketReuseAvailable = true;
+ return true;
+ }
+
+ // get the currently running framework name and version (EX: .NETFramework,Version=v4.5.1) (Ex: .NETCoreApp,Version=v2.0)
+ string ver = Assembly.GetEntryAssembly()?.GetCustomAttribute()?.FrameworkName;
+
+ if (ver == null)
+ return false; // play it safe if we can not figure out what the framework is
+
+ // make sure we are on .NETCoreApp
+ ver = ver.ToLower(); // make everything lowercase to simplify comparison
+ if (ver.Contains(".netcoreapp"))
+ {
+ var versionString = ver.Replace(".netcoreapp,version=v", "");
+ var versionArr = versionString.Split('.');
+ var majorVersion = Convert.ToInt32(versionArr[0]);
+
+ var result = majorVersion >= 3; // version 3 and up supports socket reuse
+
+ // store the result in our static object so we don't have to be bothered going through all this more than once
+ _isSocketReuseAvailable = result;
+ return result;
+ }
+
+ // store the result in our static object so we don't have to be bothered going through all this more than once
+ _isSocketReuseAvailable = false;
+ return false;
+ }
+ catch
+ {
+ // store the result in our static object so we don't have to be bothered going through all this more than once
+ _isSocketReuseAvailable = false;
+ return false;
+ }
+ }
// https://github.com/qmatteoq/DesktopBridgeHelpers/blob/master/DesktopBridge.Helpers/Helpers.cs
private class UwpHelper
diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
index b65b554f4..8f45b0608 100644
--- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
@@ -315,8 +315,7 @@ private async Task createServerConnection(string remoteHost
tcpClient.SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000;
tcpClient.LingerState = new LingerOption(true, proxyServer.TcpTimeWaitSeconds);
- // linux has a bug with socket reuse in .net core.
- if (proxyServer.ReuseSocket && RunTime.IsWindows)
+ if (proxyServer.ReuseSocket && RunTime.IsSocketReuseAvailable)
{
tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
@@ -417,7 +416,7 @@ private async Task createServerConnection(string remoteHost
throw;
}
- return new TcpServerConnection(proxyServer, tcpClient)
+ return new TcpServerConnection(proxyServer, tcpClient, stream)
{
UpStreamProxy = externalProxy,
UpStreamEndPoint = upStreamEndPoint,
@@ -426,8 +425,6 @@ private async Task createServerConnection(string remoteHost
IsHttps = isHttps,
NegotiatedApplicationProtocol = negotiatedApplicationProtocol,
UseUpstreamProxy = useUpstreamProxy,
- StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferPool),
- Stream = stream,
Version = httpVersion
};
}
diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs
index 62276d8ca..d6a0e7e81 100644
--- a/src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs
+++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs
@@ -15,12 +15,14 @@ namespace Titanium.Web.Proxy.Network.Tcp
///
internal class TcpServerConnection : IDisposable
{
- internal TcpServerConnection(ProxyServer proxyServer, TcpClient tcpClient)
+ internal TcpServerConnection(ProxyServer proxyServer, TcpClient tcpClient, CustomBufferedStream stream)
{
this.tcpClient = tcpClient;
LastAccess = DateTime.Now;
this.proxyServer = proxyServer;
this.proxyServer.UpdateServerConnectionCount(true);
+ StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferPool);
+ Stream = stream;
}
private ProxyServer proxyServer { get; }
@@ -59,12 +61,12 @@ internal TcpServerConnection(ProxyServer proxyServer, TcpClient tcpClient)
///
/// Used to write lines to server
///
- internal HttpRequestWriter? StreamWriter { get; set; }
+ internal HttpRequestWriter StreamWriter { get; }
///
/// Server stream
///
- internal CustomBufferedStream? Stream { get; set; }
+ internal CustomBufferedStream Stream { get; }
///
/// Last time this connection was used
diff --git a/src/Titanium.Web.Proxy/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs
index d7d89eb7e..0126a9358 100644
--- a/src/Titanium.Web.Proxy/ProxyServer.cs
+++ b/src/Titanium.Web.Proxy/ProxyServer.cs
@@ -55,7 +55,7 @@ public partial class ProxyServer : IDisposable
///
/// Upstream proxy manager.
///
- private WinHttpWebProxyFinder systemProxyResolver;
+ private WinHttpWebProxyFinder? systemProxyResolver;
///
@@ -421,7 +421,7 @@ public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint)
/// The proxy protocol type.
public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType)
{
- if (!RunTime.IsWindows)
+ if (systemProxySettingsManager == null)
{
throw new NotSupportedException(@"Setting system proxy settings are only supported in Windows.
Please manually confugure you operating system to use this proxy's port and address.");
@@ -515,7 +515,7 @@ public void DisableSystemHttpsProxy()
///
public void RestoreOriginalProxySettings()
{
- if (!RunTime.IsWindows)
+ if (systemProxySettingsManager == null)
{
throw new NotSupportedException(@"Setting system proxy settings are only supported in Windows.
Please manually configure your operating system to use this proxy's port and address.");
@@ -529,7 +529,7 @@ public void RestoreOriginalProxySettings()
///
public void DisableSystemProxy(ProxyProtocolType protocolType)
{
- if (!RunTime.IsWindows)
+ if (systemProxySettingsManager == null)
{
throw new NotSupportedException(@"Setting system proxy settings are only supported in Windows.
Please manually configure your operating system to use this proxy's port and address.");
@@ -543,7 +543,7 @@ public void DisableSystemProxy(ProxyProtocolType protocolType)
///
public void DisableAllSystemProxies()
{
- if (!RunTime.IsWindows)
+ if (systemProxySettingsManager == null)
{
throw new NotSupportedException(@"Setting system proxy settings are only supported in Windows.
Please manually confugure you operating system to use this proxy's port and address.");
@@ -622,7 +622,7 @@ public void Stop()
throw new Exception("Proxy is not running.");
}
- if (RunTime.IsWindows && !RunTime.IsUwpOnWindows)
+ if (systemProxySettingsManager != null)
{
bool setAsSystemProxy = ProxyEndPoints.OfType()
.Any(x => x.IsSystemHttpProxy || x.IsSystemHttpsProxy);
@@ -654,8 +654,7 @@ private void listen(ProxyEndPoint endPoint)
{
endPoint.Listener = new TcpListener(endPoint.IpAddress, endPoint.Port);
- // linux/macOS has a bug with socket reuse in .net core.
- if (ReuseSocket && RunTime.IsWindows)
+ if (ReuseSocket && RunTime.IsSocketReuseAvailable)
{
endPoint.Listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}