33
44import logging
55from abc import abstractmethod , ABCMeta
6- from asyncio import Task , AbstractEventLoop , CancelledError
6+ from asyncio import Task , AbstractEventLoop
77from asyncio .protocols import BufferedProtocol , BaseProtocol
88from asyncio .transports import Transport , BaseTransport
99from collections import deque
1010from functools import partial
1111from socket import AddressFamily , SocketKind
12- from typing import Any , Type , Optional , Tuple , Deque , Set
12+ from typing import Type , Optional , Tuple , Deque
1313from typing_extensions import Final
1414from uuid import uuid4
1515
2727
2828class _Base (BufferedProtocol , metaclass = ABCMeta ):
2929
30+ __slots__ = ['_paused' , '_buf' , '_queue' , '_transport' , '_sock_info' ]
31+
3032 def __init__ (self , buf_len : int ) -> None :
3133 super ().__init__ ()
3234 self ._paused = False
@@ -41,15 +43,10 @@ def sock_info(self) -> SocketInfo:
4143 assert sock_info is not None
4244 return sock_info
4345
44- @property
45- def is_open (self ) -> bool :
46- return self ._sock_info is not None
47-
4846 def close (self ) -> None :
4947 if self ._transport is not None :
5048 self ._transport .close ()
5149 self ._transport = None
52- self ._sock_info = None
5350
5451 def write (self , data : memoryview ) -> None :
5552 transport = self ._transport
@@ -97,6 +94,9 @@ def proxy_data(self, data: memoryview) -> None:
9794
9895class DownstreamProtocol (_Base ):
9996
97+ __slots__ = ['loop' , 'dnsbl' , 'upstream' , 'id' , '_dnsbl_task' , '_waiting' ,
98+ '_waiting_closed' , '_upstream' , '_upstream_factory' ]
99+
100100 def __init__ (self , upstream_protocol : Type [UpstreamProtocol ],
101101 loop : AbstractEventLoop , buf_len : int , dnsbl : Dnsbl ,
102102 upstream : Address ) -> None :
@@ -105,56 +105,57 @@ def __init__(self, upstream_protocol: Type[UpstreamProtocol],
105105 self .dnsbl : Final = dnsbl
106106 self .upstream : Final = upstream
107107 self .id : Final = uuid4 ().bytes
108+ self ._dnsbl_task : Optional [Task [Optional [str ]]] = None
108109 self ._waiting : Deque [memoryview ] = deque ()
109- self ._tasks : Set [ Task [ Any ]] = set ()
110+ self ._waiting_closed = False
110111 self ._upstream : Optional [UpstreamProtocol ] = None
111112 self ._upstream_factory = partial (upstream_protocol , self , buf_len ,
112113 upstream .pp )
113114
114- def close (self ) -> None :
115- super ().close ()
116- for task in self ._tasks :
117- task .cancel ()
118- if self ._upstream is not None :
119- upstream = self ._upstream
120- self ._upstream = None
121- upstream .close ()
122-
123115 def _set_client (self , connect_task : Task [_Connect ]) -> None :
116+ dnsbl_task = self ._dnsbl_task
117+ assert dnsbl_task is not None
124118 try :
125119 _ , upstream = connect_task .result ()
126- except CancelledError :
127- pass # Connection was never established
128120 except OSError :
129121 self .close ()
122+ dnsbl_task .cancel ()
130123 _log .exception ('[%s] Connection failed: %s' ,
131124 self .id .hex (), self .upstream )
132125 else :
133126 assert isinstance (upstream , UpstreamProtocol )
134127 self ._upstream = upstream
135- waiting = self ._waiting
136- while waiting :
137- data = waiting .popleft ()
138- upstream .write (data )
128+ dnsbl_task .add_done_callback (self ._send_initial )
129+
130+ def _send_initial (self , dnsbl_task : Task [Optional [str ]]) -> None :
131+ upstream = self ._upstream
132+ assert upstream is not None
133+ upstream .write_header (dnsbl_task .result ())
134+ waiting = self ._waiting
135+ while waiting :
136+ data = waiting .popleft ()
137+ upstream .write (data )
138+ if self ._waiting_closed :
139+ upstream .close ()
139140
140141 def connection_made (self , transport : BaseTransport ) -> None :
141142 super ().connection_made (transport )
142143 _log .info ('[%s] Downstream connection received: %s' ,
143144 self .id .hex (), self .sock_info )
144145 loop = self .loop
145- dnsbl_task = loop .create_task (self .dnsbl .lookup (self .sock_info ))
146- self ._tasks .add (dnsbl_task )
147- dnsbl_task .add_done_callback (self ._tasks .discard )
146+ self ._dnsbl_task = loop .create_task (self .dnsbl .lookup (self .sock_info ))
148147 connect_task = loop .create_task (
149- loop .create_connection (partial ( self ._upstream_factory , dnsbl_task ) ,
148+ loop .create_connection (self ._upstream_factory ,
150149 self .upstream .host , self .upstream .port or 0 ,
151150 ssl = self .upstream .ssl ))
152- self ._tasks .add (connect_task )
153- connect_task .add_done_callback (self ._tasks .discard )
154151 connect_task .add_done_callback (self ._set_client )
155152
156153 def connection_lost (self , exc : Optional [Exception ]) -> None :
157154 super ().connection_lost (exc )
155+ if self ._upstream is None :
156+ self ._waiting_closed = True
157+ else :
158+ self ._upstream .close ()
158159 _log .info ('[%s] Downstream connection closed' , self .id .hex ())
159160
160161 def proxy_data (self , data : memoryview ) -> None :
@@ -167,39 +168,34 @@ def proxy_data(self, data: memoryview) -> None:
167168
168169class UpstreamProtocol (_Base ):
169170
171+ __slots__ = ['pp' , 'downstream' ]
172+
170173 def __init__ (self , downstream : DownstreamProtocol , buf_len : int ,
171- pp : ProxyProtocol , dnsbl_task : Task [ Optional [ str ]] ) -> None :
174+ pp : ProxyProtocol ) -> None :
172175 super ().__init__ (buf_len )
173176 self .pp : Final = pp
174177 self .downstream : Final = downstream
175- self .dnsbl_task : Final = dnsbl_task
176178
177179 def close (self ) -> None :
178180 super ().close ()
179181 self .downstream .close ()
180182
181- def build_pp_header (self ) -> bytes :
183+ def build_pp_header (self , dnsbl : Optional [ str ] ) -> bytes :
182184 sock_info = self .downstream .sock_info
183185 sock = sock_info .socket
184186 ssl_object = sock_info .transport .get_extra_info ('ssl_object' )
185187 try :
186188 protocol : Optional [SocketKind ] = SocketKind (sock .proto )
187189 except ValueError :
188190 protocol = None
189- dnsbl = self .dnsbl_task .result ()
190- return self .pp .build (sock .getpeername (), sock .getsockname (),
191+ return self .pp .build (sock_info .peername , sock_info .sockname ,
191192 family = AddressFamily (sock .family ),
192193 protocol = protocol , unique_id = self .downstream .id ,
193194 ssl = ssl_object , dnsbl = dnsbl )
194195
195- def connection_made (self , transport : BaseTransport ) -> None :
196- super ().connection_made (transport )
197- self .dnsbl_task .add_done_callback (self ._write_header )
198-
199- def _write_header (self , task : Task [Any ]) -> None :
200- if self .downstream .is_open :
201- header = self .build_pp_header ()
202- self .write (memoryview (header ))
196+ def write_header (self , dnsbl : Optional [str ]) -> None :
197+ header = self .build_pp_header (dnsbl )
198+ self .write (memoryview (header ))
203199
204200 def proxy_data (self , data : memoryview ) -> None :
205201 self .downstream .write (data )
0 commit comments