11from socketserver import BaseRequestHandler , TCPServer , ThreadingMixIn
2- from socket import socket , AF_INET , SOCK_STREAM , gethostbyname , error
2+ from socket import socket , AF_INET , SOCK_STREAM , gethostbyname , error , timeout
33import threading
44import logging
55from enum import Enum , auto
@@ -21,6 +21,7 @@ class TcpProxySockHandler(BaseRequestHandler):
2121 PROXY_HOST = None
2222 PROXY_PORT = None
2323 Logger = logging .getLogger ("TcpProxyHandler" )
24+ CONNECTION_ACTIVE = True
2425
2526 def handle (self ):
2627 # self.request is the TCP socket connected to the client
@@ -30,46 +31,38 @@ def handle(self):
3031 # Try to connect to the server and send data
3132 try :
3233 sock .connect ((self .PROXY_HOST , self .PROXY_PORT ))
33- self .transferData (self .request , sock )
34- # Receive data from the server
35- self .Logger .info ("Receive data: %s <- %s:%s" % (self .client_address [0 ], self .PROXY_HOST , self .PROXY_PORT ))
36- self .transferData (sock , self .request )
34+
35+ requestThread = threading .Thread (target = self .transfer_data , args = (self .request , sock ))
36+ requestThread .daemon = True
37+ requestThread .start ()
38+
39+ self .transfer_data (sock , self .request )
40+
3741 finally :
3842 sock .close ()
43+ self .CONNECTION_ACTIVE = False
44+ self .Logger .info ("Connection %s -> %s:%s closed" % (self .client_address [0 ], self .PROXY_HOST , self .PROXY_PORT ))
3945
40- def transferData (self , sock1 : socket , sock2 : socket , max_read_try = 10 , receive_message_length = 2048 ):
41- read_try = 0
42- last_try = False
43- sock1 .setblocking (0 )
46+ def transfer_data (self , sock1 : socket , sock2 : socket , receive_message_length = 2048 ):
47+ #setup socket receive timeout
48+ sock1 .settimeout (5.0 )
4449 while True :
4550 try :
51+ if not self .CONNECTION_ACTIVE or self .server .SHUTDOWN_REQUESTED :
52+ return
4653 msg = sock1 .recv (receive_message_length )
4754 if not msg :
48- return
55+ break
4956 sock2 .sendall (msg )
50-
51- read_try = 0
52- if last_try and len (msg ) > 0 :
53- last_try = False
54- if len (msg ) < (receive_message_length / 2 ):
55- if last_try :
56- return
57- else :
58- last_try = True
59- except error as e :
60- if e .errno != errno .EAGAIN and e .errno != errno .EWOULDBLOCK :
61- raise e
62- if read_try > max_read_try :
63- return
64- read_try += 1
65- time .sleep (0.1 )
66- continue
57+ except timeout :
58+ pass
59+ self .CONNECTION_ACTIVE = False
6760
6861class ThreadedTCPServer (ThreadingMixIn , TCPServer ):
69- pass
62+ SHUTDOWN_REQUESTED = False
7063
7164class ProxyServer ():
72-
65+
7366 def __init__ (self , proxy_host , proxy_port , type = ProxyType .TCP ):
7467 if (type != ProxyType .TCP ):
7568 raise NotImplementedError ("Only TCP Proxy implemented" )
@@ -93,5 +86,6 @@ def start(self):
9386 self .logger .info ("Starting %s proxy to %s:%s" , self .type , self .proxy_host , self .proxy_port )
9487
9588 def stop (self ):
89+ self .server .SHUTDOWN_REQUESTED = True
9690 self .server .shutdown ()
9791 self .logger .info ("Stopping %s proxy to %s:%s" , self .type , self .proxy_host , self .proxy_port )
0 commit comments