Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Titanium-Web-Proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Titanium-Web-Proxy
Commits
ca06c7ab
Commit
ca06c7ab
authored
Jul 27, 2018
by
justcoding121
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
#466 add TcpTimeWait seconds and socket reuse option
parent
315592a9
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
92 additions
and
72 deletions
+92
-72
TcpExtensions.cs
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
+41
-24
TcpClientConnection.cs
Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs
+11
-2
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+9
-43
TcpServerConnection.cs
Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs
+12
-3
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+19
-0
No files found.
Titanium.Web.Proxy/Extensions/TcpExtensions.cs
View file @
ca06c7ab
...
@@ -6,46 +6,63 @@ namespace Titanium.Web.Proxy.Extensions
...
@@ -6,46 +6,63 @@ namespace Titanium.Web.Proxy.Extensions
{
{
internal
static
class
TcpExtensions
internal
static
class
TcpExtensions
{
{
private
static
readonly
Func
<
Socket
,
bool
>
socketCleanedUpGetter
;
internal
static
void
CloseSocket
(
this
TcpClient
tcpClient
)
static
TcpExtensions
()
{
{
var
property
=
typeof
(
Socket
).
GetProperty
(
"CleanedUp"
,
BindingFlags
.
NonPublic
|
BindingFlags
.
Instance
);
if
(
tcpClient
==
null
)
if
(
property
!=
null
)
{
{
var
method
=
property
.
GetMethod
;
return
;
if
(
method
!=
null
&&
method
.
ReturnType
==
typeof
(
bool
))
}
try
{
{
socketCleanedUpGetter
=
tcpClient
.
Close
();
(
Func
<
Socket
,
bool
>)
Delegate
.
CreateDelegate
(
typeof
(
Func
<
Socket
,
bool
>),
method
);
}
}
catch
{
// ignored
}
}
}
}
internal
static
void
CloseSocket
(
this
TcpClient
tcpClient
)
/// <summary>
/// Check if a TcpClient is good to be used.
/// This only checks if send is working so local socket is still connected.
/// Receive can only be verified by doing a valid read from server without exceptions.
/// So in our case we should retry with new connection from pool if first read after getting the connection fails.
/// https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected(v=vs.110).aspx
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
internal
static
bool
IsGoodConnection
(
this
TcpClient
client
)
{
{
if
(
tcpClient
==
null
)
var
socket
=
client
.
Client
;
if
(!
client
.
Connected
||
!
socket
.
Connected
)
{
{
return
;
return
false
;
}
}
// This is how you can determine whether a socket is still connected.
bool
blockingState
=
socket
.
Blocking
;
try
try
{
{
// This line is important!
var
tmp
=
new
byte
[
1
];
// 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
();
socket
.
Blocking
=
false
;
socket
.
Send
(
tmp
,
0
,
0
);
//Connected.
}
}
catch
catch
{
{
// ignored
//Should we let 10035 == WSAEWOULDBLOCK as valid connection?
return
false
;
}
}
finally
{
socket
.
Blocking
=
blockingState
;
}
return
true
;
}
}
}
}
}
}
Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs
View file @
ca06c7ab
...
@@ -5,6 +5,7 @@ using System.Net;
...
@@ -5,6 +5,7 @@ using System.Net;
using
System.Net.Security
;
using
System.Net.Security
;
#endif
#endif
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
namespace
Titanium.Web.Proxy.Network.Tcp
namespace
Titanium.Web.Proxy.Network.Tcp
...
@@ -43,8 +44,16 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -43,8 +44,16 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
/// </summary>
public
void
Dispose
()
public
void
Dispose
()
{
{
Task
.
Run
(
async
()
=>
{
//delay calling tcp connection close()
//so that client have enough time to call close first.
//This way we can push tcp Time_Wait to client side when possible.
await
Task
.
Delay
(
1000
);
proxyServer
.
UpdateClientConnectionCount
(
false
);
proxyServer
.
UpdateClientConnectionCount
(
false
);
tcpClient
.
CloseSocket
();
tcpClient
.
CloseSocket
();
});
}
}
}
}
}
}
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
ca06c7ab
...
@@ -191,7 +191,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -191,7 +191,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
var
cutOff
=
DateTime
.
Now
.
AddSeconds
(-
1
*
proxyServer
.
ConnectionTimeOutSeconds
+
3
);
var
cutOff
=
DateTime
.
Now
.
AddSeconds
(-
1
*
proxyServer
.
ConnectionTimeOutSeconds
+
3
);
if
(
recentConnection
.
LastAccess
>
cutOff
if
(
recentConnection
.
LastAccess
>
cutOff
&&
isGoodConnection
(
recentConnection
.
TcpClient
))
&&
recentConnection
.
TcpClient
.
IsGoodConnection
(
))
{
{
return
recentConnection
;
return
recentConnection
;
}
}
...
@@ -275,6 +275,13 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -275,6 +275,13 @@ namespace Titanium.Web.Proxy.Network.Tcp
ReceiveBufferSize
=
proxyServer
.
BufferSize
ReceiveBufferSize
=
proxyServer
.
BufferSize
};
};
if
(
proxyServer
.
ReuseSocket
)
{
tcpClient
.
Client
.
SetSocketOption
(
SocketOptionLevel
.
Socket
,
SocketOptionName
.
ReuseAddress
,
true
);
}
tcpClient
.
LingerState
=
new
LingerOption
(
true
,
proxyServer
.
TcpTimeWaitSeconds
);
// If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
// If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
if
(
useUpstreamProxy
)
if
(
useUpstreamProxy
)
{
{
...
@@ -501,47 +508,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -501,47 +508,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
}
}
}
}
/// <summary>
/// Check if a TcpClient is good to be used.
/// This only checks if send is working so local socket is still connected.
/// Receive can only be verified by doing a valid read from server without exceptions.
/// So in our case we should retry with new connection from pool if first read after getting the connection fails.
/// https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected(v=vs.110).aspx
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
private
static
bool
isGoodConnection
(
TcpClient
client
)
{
var
socket
=
client
.
Client
;
if
(!
client
.
Connected
||
!
socket
.
Connected
)
{
return
false
;
}
// This is how you can determine whether a socket is still connected.
bool
blockingState
=
socket
.
Blocking
;
try
{
var
tmp
=
new
byte
[
1
];
socket
.
Blocking
=
false
;
socket
.
Send
(
tmp
,
0
,
0
);
//Connected.
}
catch
{
//Should we let 10035 == WSAEWOULDBLOCK as valid connection?
return
false
;
}
finally
{
socket
.
Blocking
=
blockingState
;
}
return
true
;
}
public
void
Dispose
()
public
void
Dispose
()
{
{
runCleanUpTask
=
false
;
runCleanUpTask
=
false
;
...
...
Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs
View file @
ca06c7ab
...
@@ -4,6 +4,7 @@ using System.Net;
...
@@ -4,6 +4,7 @@ using System.Net;
using
System.Net.Security
;
using
System.Net.Security
;
#endif
#endif
using
System.Net.Sockets
;
using
System.Net.Sockets
;
using
System.Threading.Tasks
;
using
StreamExtended.Network
;
using
StreamExtended.Network
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
...
@@ -85,9 +86,17 @@ namespace Titanium.Web.Proxy.Network.Tcp
...
@@ -85,9 +86,17 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
/// </summary>
public
void
Dispose
()
public
void
Dispose
()
{
{
Task
.
Run
(
async
()
=>
{
//delay calling tcp connection close()
//so that server have enough time to call close first.
//This way we can push tcp Time_Wait to server side when possible.
await
Task
.
Delay
(
1000
);
proxyServer
.
UpdateServerConnectionCount
(
false
);
proxyServer
.
UpdateServerConnectionCount
(
false
);
Stream
?.
Dispose
();
Stream
?.
Dispose
();
tcpClient
.
CloseSocket
();
tcpClient
.
CloseSocket
();
});
}
}
}
}
}
}
Titanium.Web.Proxy/ProxyServer.cs
View file @
ca06c7ab
...
@@ -186,6 +186,18 @@ namespace Titanium.Web.Proxy
...
@@ -186,6 +186,18 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
public
int
MaxCachedConnections
{
get
;
set
;
}
=
2
;
public
int
MaxCachedConnections
{
get
;
set
;
}
=
2
;
/// <summary>
/// Number of seconds to linger when Tcp connection is in TIME_WAIT state.
/// Default value is 3.
/// </summary>
public
int
TcpTimeWaitSeconds
{
get
;
set
;
}
=
3
;
/// <summary>
/// Should we resues client/server tcp sockets.
/// Default is true.
/// </summary>
public
bool
ReuseSocket
{
get
;
set
;
}
=
true
;
/// <summary>
/// <summary>
/// Total number of active client connections.
/// Total number of active client connections.
/// </summary>
/// </summary>
...
@@ -619,6 +631,12 @@ namespace Titanium.Web.Proxy
...
@@ -619,6 +631,12 @@ namespace Titanium.Web.Proxy
private
void
listen
(
ProxyEndPoint
endPoint
)
private
void
listen
(
ProxyEndPoint
endPoint
)
{
{
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
endPoint
.
Listener
=
new
TcpListener
(
endPoint
.
IpAddress
,
endPoint
.
Port
);
if
(
ReuseSocket
)
{
endPoint
.
Listener
.
Server
.
SetSocketOption
(
SocketOptionLevel
.
Socket
,
SocketOptionName
.
ReuseAddress
,
true
);
}
try
try
{
{
endPoint
.
Listener
.
Start
();
endPoint
.
Listener
.
Start
();
...
@@ -718,6 +736,7 @@ namespace Titanium.Web.Proxy
...
@@ -718,6 +736,7 @@ namespace Titanium.Web.Proxy
tcpClient
.
SendTimeout
=
ConnectionTimeOutSeconds
*
1000
;
tcpClient
.
SendTimeout
=
ConnectionTimeOutSeconds
*
1000
;
tcpClient
.
SendBufferSize
=
BufferSize
;
tcpClient
.
SendBufferSize
=
BufferSize
;
tcpClient
.
ReceiveBufferSize
=
BufferSize
;
tcpClient
.
ReceiveBufferSize
=
BufferSize
;
tcpClient
.
LingerState
=
new
LingerOption
(
true
,
TcpTimeWaitSeconds
);
await
InvokeConnectionCreateEvent
(
tcpClient
,
true
);
await
InvokeConnectionCreateEvent
(
tcpClient
,
true
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment