Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions plugin/vdebug.vim
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ let g:vdebug_options_defaults = {
\ 'port' : 9000,
\ 'timeout' : 20,
\ 'server' : '',
\ "proxy_host" : '',
\ "proxy_port" : 9001,
\ 'on_close' : 'stop',
\ 'break_on_open' : 1,
\ 'ide_key' : '',
Expand Down
97 changes: 91 additions & 6 deletions python3/vdebug/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import threading
import time
import asyncio
import xml.etree.ElementTree as ET

from . import log

Expand Down Expand Up @@ -103,13 +104,17 @@ def __init__(self, input_stream=None):
"""
self.__sock = None
self.input_stream = input_stream
self.proxy_success = False

def start(self, host='', port=9000, timeout=30):
def start(self, host='', proxy_host = '', proxy_port = 9001, idekey = None, port=9000, timeout=30):
"""Listen for a connection from the debugger. Listening for the actual
connection is handled by self.listen()

host -- host name where debugger is running (default '')
port -- port number which debugger is listening on (default 9000)
proxy_host -- If using a DBGp Proxy, host name where the proxy is running (default None to disable)
proxy_port -- If using a DBGp Proxy, port where the proxy is listening for debugger connections (default 9001)
idekey -- The idekey that our Api() wrapper is expecting. Only required if using a proxy
timeout -- time in seconds to wait for a debugger connection before giving up (default 30)
"""
print('Waiting for a connection (Ctrl-C to cancel, this message will '
Expand All @@ -120,13 +125,17 @@ def start(self, host='', port=9000, timeout=30):
serv.setblocking(1)
serv.bind((host, port))
serv.listen(5)
self.__sock = self.listen(serv, timeout)
if proxy_host and proxy_port:
# Register ourselves with the proxy server
self.proxyinit(proxy_host, proxy_port, port, idekey)
self.__sock = self.accept(serv, timeout)
except socket.timeout:
raise TimeoutError("Timeout waiting for connection")
finally:
self.proxystop(proxy_host, proxy_port, idekey)
serv.close()

def listen(self, serv, timeout):
def accept(self, serv, timeout):
"""Non-blocking listener. Provides support for keyboard interrupts from
the user. Although it's non-blocking, the user interface will still
block until the timeout is reached.
Expand Down Expand Up @@ -155,13 +164,50 @@ def socket(self):
def has_socket(self):
return self.__sock is not None

def proxyinit(self, proxy_host, proxy_port, port, idekey):
"""Register ourselves with the proxy."""
if not proxy_host or not proxy_port:
return

self.log("Connecting to DBGp proxy [%s:%d]" % (proxy_host, proxy_port))
proxy_conn = socket.create_connection((proxy_host, proxy_port), 30)

self.log("Sending proxyinit command")
msg = 'proxyinit -p %d -k %s -m 0' % (port, idekey)
proxy_conn.send(msg.encode())
proxy_conn.shutdown(socket.SHUT_WR)

# Parse proxy response
response = proxy_conn.recv(8192)
proxy_conn.close()
response = ET.fromstring(response)
self.proxy_success = bool(response.get("success"))

def proxystop(self, proxy_host, proxy_port, idekey):
"""De-register ourselves from the proxy."""
if not self.proxy_success:
return

proxy_conn = socket.create_connection((proxy_host, proxy_port), 30)

self.log("Sending proxystop command")
msg = 'proxystop -k %s' % str(idekey)
proxy_conn.send(msg.encode())
proxy_conn.close()
self.proxy_success = False



class BackgroundSocketCreator(threading.Thread):

def __init__(self, host, port, output_q):
def __init__(self, host, port, proxy_host, proxy_port, idekey, output_q):
self.__output_q = output_q
self.__host = host
self.__port = port
self.__proxy_host = proxy_host
self.__proxy_port = proxy_port
self.__idekey = idekey
self.proxy_success = False
self.__socket_task = None
self.__loop = None
threading.Thread.__init__(self)
Expand Down Expand Up @@ -189,6 +235,9 @@ async def run_async(self):
try:
# using ensure_future here since before 3.7, this is not a coroutine, but returns a future
self.__socket_task = asyncio.ensure_future(self.__loop.sock_accept(s))
if self.__proxy_host and self.__proxy_port:
# Register ourselves with the proxy server
await self.proxyinit()
client, address = await self.__socket_task
# set resulting socket to blocking
client.setblocking(True)
Expand All @@ -197,6 +246,7 @@ async def run_async(self):
self.__output_q.put((client, address))
break
except socket.error:
await self.proxystop()
# No connection
pass
except socket.error as socket_error:
Expand All @@ -214,9 +264,44 @@ async def run_async(self):
self.log("Error: %s" % str(sys.exc_info()))
self.log("Stopping server")
finally:
await self.proxystop()
self.log("Finishing socket server")
s.close()

async def proxyinit(self):
"""Register ourselves with the proxy."""
if not self.__proxy_host or not self.__proxy_port:
return

self.log("Connecting to DBGp proxy [%s:%d]" % (self.__proxy_host, self.__proxy_port))
proxy_conn = socket.create_connection((self.__proxy_host, self.__proxy_port), 30)

self.log("Sending proxyinit command")
msg = 'proxyinit -p %d -k %s -m 0' % (self.__port, self.__idekey)
proxy_conn.send(msg.encode())
proxy_conn.shutdown(socket.SHUT_WR)

# Parse proxy response
response = proxy_conn.recv(8192)
proxy_conn.close()
response = ET.fromstring(response)
self.proxy_success = bool(response.get("success"))

async def proxystop(self):
"""De-register ourselves from the proxy."""
if not self.proxy_success:
return

proxy_conn = socket.create_connection((self.__proxy_host, self.__proxy_port), 30)

self.log("Sending proxystop command")
msg = 'proxystop -k %s' % str(self.__idekey)
proxy_conn.send(msg.encode())
proxy_conn.close()
self.proxy_success = False



def _exit(self):
if self.__socket_task:
# this will raise asyncio.CancelledError
Expand All @@ -236,10 +321,10 @@ def __init__(self):
def __del__(self):
self.stop()

def start(self, host, port):
def start(self, host, port, proxy_host, proxy_port, ide_key):
if not self.is_alive():
self.__thread = BackgroundSocketCreator(
host, port, self.__socket_q)
host, port, proxy_host, proxy_port, ide_key, self.__socket_q)
self.__thread.start()

def is_alive(self):
Expand Down
8 changes: 7 additions & 1 deletion python3/vdebug/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ def __init__(self):
def start(self):
self.__server.start(opts.Options.get('server'),
opts.Options.get('port', int),
opts.Options.get('proxy_host'),
opts.Options.get('proxy_port', int),
opts.Options.get('ide_key'),
opts.Options.get('timeout', int))

def stop(self):
Expand Down Expand Up @@ -51,7 +54,10 @@ def start(self):
if opts.Options.get("auto_start", int):
vim.command('autocmd Vdebug CursorHold,CursorHoldI,CursorMoved,CursorMovedI,FocusGained,FocusLost * python3 debugger.start_if_ready()')
self.__server.start(opts.Options.get('server'),
opts.Options.get('port', int))
opts.Options.get('port', int),
opts.Options.get('proxy_host'),
opts.Options.get('proxy_port', int),
opts.Options.get('ide_key'))

def stop(self):
if opts.Options.get("auto_start", bool):
Expand Down