Skip to content

Commit 21dbc4d

Browse files
committed
Add dbgpproxy support
1 parent f61a967 commit 21dbc4d

3 files changed

Lines changed: 104 additions & 7 deletions

File tree

‎plugin/vdebug.vim‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ let g:vdebug_options_defaults = {
7979
\ 'port' : 9000,
8080
\ 'timeout' : 20,
8181
\ 'server' : '',
82+
\ "proxy_host" : '',
83+
\ "proxy_port" : 9001,
8284
\ 'on_close' : 'stop',
8385
\ 'break_on_open' : 1,
8486
\ 'ide_key' : '',

‎python3/vdebug/connection.py‎

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import threading
66
import time
77
import asyncio
8+
import xml.etree.ElementTree as ET
89

910
from . 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

159202
class 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):

‎python3/vdebug/listener.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ def __init__(self):
2222
def start(self):
2323
self.__server.start(opts.Options.get('server'),
2424
opts.Options.get('port', int),
25+
opts.Options.get('proxy_host'),
26+
opts.Options.get('proxy_port', int),
27+
opts.Options.get('ide_key'),
2528
opts.Options.get('timeout', int))
2629

2730
def stop(self):
@@ -51,7 +54,10 @@ def start(self):
5154
if opts.Options.get("auto_start", int):
5255
vim.command('autocmd Vdebug CursorHold,CursorHoldI,CursorMoved,CursorMovedI,FocusGained,FocusLost * python3 debugger.start_if_ready()')
5356
self.__server.start(opts.Options.get('server'),
54-
opts.Options.get('port', int))
57+
opts.Options.get('port', int),
58+
opts.Options.get('proxy_host'),
59+
opts.Options.get('proxy_port', int),
60+
opts.Options.get('ide_key'))
5561

5662
def stop(self):
5763
if opts.Options.get("auto_start", bool):

0 commit comments

Comments
 (0)