55import threading
66import time
77import asyncio
8+ import xml .etree .ElementTree as ET
89
910from . import log
1011
@@ -103,13 +104,17 @@ def __init__(self, input_stream=None):
103104 """
104105 self .__sock = None
105106 self .input_stream = input_stream
107+ self .proxy_success = False
106108
107- def start (self , host = '' , port = 9000 , timeout = 30 ):
109+ def start (self , host = '' , proxy_host = '' , proxy_port = 9001 , idekey = None , port = 9000 , timeout = 30 ):
108110 """Listen for a connection from the debugger. Listening for the actual
109111 connection is handled by self.listen()
110112
111113 host -- host name where debugger is running (default '')
112114 port -- port number which debugger is listening on (default 9000)
115+ proxy_host -- If using a DBGp Proxy, host name where the proxy is running (default None to disable)
116+ proxy_port -- If using a DBGp Proxy, port where the proxy is listening for debugger connections (default 9001)
117+ idekey -- The idekey that our Api() wrapper is expecting. Only required if using a proxy
113118 timeout -- time in seconds to wait for a debugger connection before giving up (default 30)
114119 """
115120 print ('Waiting for a connection (Ctrl-C to cancel, this message will '
@@ -120,13 +125,18 @@ def start(self, host='', port=9000, timeout=30):
120125 serv .setblocking (1 )
121126 serv .bind ((host , port ))
122127 serv .listen (5 )
123- self .__sock = self .listen (serv , timeout )
128+ if proxy_host and proxy_port :
129+ # Register ourselves with the proxy server
130+ self .proxyinit (proxy_host , proxy_port , port , idekey )
131+ self .__sock = self .accept (serv , timeout )
124132 except socket .timeout :
133+ self .proxystop ()
125134 raise TimeoutError ("Timeout waiting for connection" )
126135 finally :
136+ self .proxystop (proxy_host , proxy_port , idekey )
127137 serv .close ()
128138
129- def listen (self , serv , timeout ):
139+ def accept (self , serv , timeout ):
130140 """Non-blocking listener. Provides support for keyboard interrupts from
131141 the user. Although it's non-blocking, the user interface will still
132142 block until the timeout is reached.
@@ -155,13 +165,50 @@ def socket(self):
155165 def has_socket (self ):
156166 return self .__sock is not None
157167
168+ def proxyinit (self , proxy_host , proxy_port , port , idekey ):
169+ """Register ourselves with the proxy."""
170+ if not proxy_host or not proxy_port :
171+ return
172+
173+ self .log ("Connecting to DBGp proxy [%s:%d]" % (proxy_host , proxy_port ))
174+ proxy_conn = socket .create_connection ((proxy_host , proxy_port ), 30 )
175+
176+ self .log ("Sending proxyinit command" )
177+ msg = 'proxyinit -p %d -k %s -m 0' % (port , idekey )
178+ proxy_conn .send (msg .encode ())
179+ proxy_conn .shutdown (socket .SHUT_WR )
180+
181+ # Parse proxy response
182+ response = proxy_conn .recv (8192 )
183+ proxy_conn .close ()
184+ response = ET .fromstring (response )
185+ self .proxy_success = bool (response .get ("success" ))
186+
187+ def proxystop (self , proxy_host , proxy_port , idekey ):
188+ """De-register ourselves from the proxy."""
189+ if not self .proxy_success :
190+ return
191+
192+ proxy_conn = socket .create_connection ((proxy_host , proxy_port ), 30 )
193+
194+ self .log ("Sending proxystop command" )
195+ msg = 'proxystop -k %s' % str (idekey )
196+ proxy_conn .send (msg .encode ())
197+ proxy_conn .close ()
198+ self .proxy_success = False
199+
200+
158201
159202class BackgroundSocketCreator (threading .Thread ):
160203
161- def __init__ (self , host , port , output_q ):
204+ def __init__ (self , host , port , proxy_host , proxy_port , idekey , output_q ):
162205 self .__output_q = output_q
163206 self .__host = host
164207 self .__port = port
208+ self .__proxy_host = proxy_host
209+ self .__proxy_port = proxy_port
210+ self .__idekey = idekey
211+ self .proxy_success = False
165212 self .__socket_task = None
166213 self .__loop = None
167214 threading .Thread .__init__ (self )
@@ -189,6 +236,9 @@ async def run_async(self):
189236 try :
190237 # using ensure_future here since before 3.7, this is not a coroutine, but returns a future
191238 self .__socket_task = asyncio .ensure_future (self .__loop .sock_accept (s ))
239+ if self .__proxy_host and self .__proxy_port :
240+ # Register ourselves with the proxy server
241+ await self .proxyinit ()
192242 client , address = await self .__socket_task
193243 # set resulting socket to blocking
194244 client .setblocking (True )
@@ -197,26 +247,65 @@ async def run_async(self):
197247 self .__output_q .put ((client , address ))
198248 break
199249 except socket .error :
250+ await self .proxystop ()
200251 # No connection
201252 pass
202253 except socket .error as socket_error :
254+ await self .proxystop ()
203255 self .log ("Error: %s" % str (sys .exc_info ()))
204256 self .log ("Stopping server" )
205257
206258 if socket_error .errno == errno .EADDRINUSE :
207259 self .log ("Address already in use" )
208260 print ("Socket is already in use" )
209261 except asyncio .CancelledError as e :
262+ await self .proxystop ()
210263 self .log ("Stopping server" )
211264 self .__socket_task = None
212265 except Exception as e :
266+ await self .proxystop ()
213267 print ("Exception caught" )
214268 self .log ("Error: %s" % str (sys .exc_info ()))
215269 self .log ("Stopping server" )
216270 finally :
271+ await self .proxystop ()
217272 self .log ("Finishing socket server" )
218273 s .close ()
219274
275+ async def proxyinit (self ):
276+ """Register ourselves with the proxy."""
277+ if not self .__proxy_host or not self .__proxy_port :
278+ return
279+
280+ self .log ("Connecting to DBGp proxy [%s:%d]" % (self .__proxy_host , self .__proxy_port ))
281+ proxy_conn = socket .create_connection ((self .__proxy_host , self .__proxy_port ), 30 )
282+
283+ self .log ("Sending proxyinit command" )
284+ msg = 'proxyinit -p %d -k %s -m 0' % (self .__port , self .__idekey )
285+ proxy_conn .send (msg .encode ())
286+ proxy_conn .shutdown (socket .SHUT_WR )
287+
288+ # Parse proxy response
289+ response = proxy_conn .recv (8192 )
290+ proxy_conn .close ()
291+ response = ET .fromstring (response )
292+ self .proxy_success = bool (response .get ("success" ))
293+
294+ async def proxystop (self ):
295+ """De-register ourselves from the proxy."""
296+ if not self .proxy_success :
297+ return
298+
299+ proxy_conn = socket .create_connection ((self .__proxy_host , self .__proxy_port ), 30 )
300+
301+ self .log ("Sending proxystop command" )
302+ msg = 'proxystop -k %s' % str (self .__idekey )
303+ proxy_conn .send (msg .encode ())
304+ proxy_conn .close ()
305+ self .proxy_success = False
306+
307+
308+
220309 def _exit (self ):
221310 if self .__socket_task :
222311 # this will raise asyncio.CancelledError
@@ -236,10 +325,10 @@ def __init__(self):
236325 def __del__ (self ):
237326 self .stop ()
238327
239- def start (self , host , port ):
328+ def start (self , host , port , proxy_host , proxy_port , ide_key ):
240329 if not self .is_alive ():
241330 self .__thread = BackgroundSocketCreator (
242- host , port , self .__socket_q )
331+ host , port , proxy_host , proxy_port , ide_key , self .__socket_q )
243332 self .__thread .start ()
244333
245334 def is_alive (self ):
0 commit comments