From 824128881a6461ea9ab8949855cf1d6d4490355a Mon Sep 17 00:00:00 2001 From: Mattia Barbon Date: Thu, 30 Oct 2014 15:27:30 +0100 Subject: [PATCH] Support communication with the debugged process over UNIX-domain sockets --- doc/Vdebug.txt | 19 +++++++++++ plugin/python/vdebug/dbgp.py | 54 +++++++++++++++++++++++++++----- plugin/python/vdebug/runner.py | 30 ++++++++++++------ plugin/python/vdebug/ui/vimui.py | 8 ++--- plugin/vdebug.vim | 2 ++ 5 files changed, 91 insertions(+), 22 deletions(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index 75608472..b7262ef9 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -785,8 +785,10 @@ retain option settings by adding them to your vimrc. The default options look like this: > let g:vdebug_options= { + \ "socket_type": "tcp", \ "port" : 9000, \ "server" : 'localhost', + \ "unix_permissions": 0700, \ "timeout" : 20, \ "on_close" : 'detach', \ "break_on_open" : 1, @@ -810,6 +812,13 @@ if you don't set them. Here is a list of all the available options. + *VdebugOptions-socket_type* +g:vdebug_options["socket_type"] (default = "tcp") + This sets whether Vdebug waits over a TCP or an Unix-domain + socket. When set to "tcp" the listening address is configured via + the port and server options, when set to "unix" the listening path + is configured via the unix_path option. + *VdebugOptions-port* g:vdebug_options["port"] (default = 9000) This sets the port that Vdebug will use to listen for connections. Xdebug @@ -823,6 +832,16 @@ g:vdebug_options["server"] (default = "localhost") running on the same machine and also connecting to localhost. If you want to debug a script on a different machine, look at |VdebugRemote|. + *VdebugOptions-unix_path* +g:vdebug_options["unix_path"] (default = empty) + This sets the path that Vdebug will use to listen for connections + when listening over an Unix-domain socket. + + *VdebugOptions-unix_permissions* +g:vdebug_options["unix_permissions"] (default = 0700) + This sets the permissions of the Unix-domain socket that Vdebug + will use to listen for connections. + *VdebugOptions-timeout* g:vdebug_options["timeout"] (default = 20) Number of seconds to wait for when listening for a connection. VIM will diff --git a/plugin/python/vdebug/dbgp.py b/plugin/python/vdebug/dbgp.py index 3e3790cc..483c206f 100644 --- a/plugin/python/vdebug/dbgp.py +++ b/plugin/python/vdebug/dbgp.py @@ -3,6 +3,7 @@ import vdebug.log import base64 import time +import os """ Response objects for the DBGP module.""" @@ -381,20 +382,31 @@ class Connection: address = None isconned = 0 - def __init__(self, host = '', port = 9000, timeout = 30, input_stream = None): + def __init__(self, endpoint, timeout = 30, input_stream = None): """Create a new Connection. The connection is not established until open() is called. - host -- host name where debugger is running (default '') - port -- port number which debugger is listening on (default 9000) + endpoint -- dictionary containing connection parameters + { + "socket_type": "tcp" (default)/"unix", + # for TCP sockets + "server": "localhost", + "port": 9000, + # for UNIX-domain sockets + "unix_path": "/path/to/socket", + "unix_permissions": 0777, + } timeout -- time in seconds to wait for a debugger connection before giving up (default 30) input_stream -- object for checking input stream and user interrupts (default None) + + Both "server" and "port" parameters are required for TCP sockets, for UNIX-domain sockets + only "unix_path" is required. """ - self.port = port - self.host = host + self.endpoint = endpoint self.timeout = timeout self.input_stream = input_stream + self.address_type = self.endpoint['socket_type'] def __del__(self): """Make sure the connection is closed.""" @@ -404,15 +416,41 @@ def isconnected(self): """Whether the connection has been established.""" return self.isconned + def address_description(self): + """Human-readable local address""" + if self.endpoint['socket_type'] == 'tcp': + return "%s:%s" %(self.endpoint['server'],self.endpoint['port']) + else: + return self.endpoint['unix_path'] + + def peer_description(self): + """Human-readable peer address""" + if self.endpoint['socket_type'] == 'tcp': + return "%s:%s" %(self.address[0],self.address[1]) + else: + return self.endpoint['unix_path'] + def open(self): """Listen for a connection from the debugger. Listening for the actual connection is handled by self.listen().""" print 'Waiting for a connection (Ctrl-C to cancel, this message will self-destruct in ',self.timeout,' seconds...)' - serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if self.address_type == 'tcp': + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + else: + serv = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: - serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serv.setblocking(0) - serv.bind((self.host, self.port)) + if self.endpoint.get('socket_type', 'tcp') == 'tcp': + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serv.bind((self.endpoint['server'], self.endpoint['port'])) + else: + path = self.endpoint['unix_path'] + if os.path.exists(path): + os.unlink(path) + serv.bind(path) + if self.endpoint.get('unix_permissions'): + os.chmod(path, self.endpoint['unix_permissions']); + serv.listen(5) (self.sock, self.address) = self.listen(serv, self.timeout) self.sock.settimeout(None) diff --git a/plugin/python/vdebug/runner.py b/plugin/python/vdebug/runner.py index 174c3162..eaf983ef 100644 --- a/plugin/python/vdebug/runner.py +++ b/plugin/python/vdebug/runner.py @@ -16,6 +16,14 @@ class Runner: an interface that Vim can use to send commands. """ + ENDPOINT_ARGS = [ + ('socket_type', str), + ('server', str), + ('port', int), + ('unix_path', str), + ('unix_group', str), + ('unix_permissions', int), + ] def __init__(self): self.api = None vdebug.opts.Options.set(vim.eval('g:vdebug_options')) @@ -39,21 +47,23 @@ def open(self): vdebug.log.Log.set_logger(vdebug.log.FileLogger(\ vdebug.opts.Options.get('debug_file_level'),\ vdebug.opts.Options.get('debug_file'))) + endpoint = {} + for arg, pytype in Runner.ENDPOINT_ARGS: + if vdebug.opts.Options.isset(arg): + endpoint[arg] = vdebug.opts.Options.get(arg, pytype) self.listen(\ - vdebug.opts.Options.get('server'),\ - vdebug.opts.Options.get('port',int),\ + endpoint,\ vdebug.opts.Options.get('timeout',int)) self.ui.open() self.keymapper.map() self.ui.set_listener_details(\ - vdebug.opts.Options.get('server'),\ - vdebug.opts.Options.get('port'),\ + self.api.conn.address_description(),\ vdebug.opts.Options.get('ide_key')) - addr = self.api.conn.address - vdebug.log.Log("Found connection from " + str(addr),vdebug.log.Logger.INFO) - self.ui.set_conn_details(addr[0],addr[1]) + addr = self.api.conn.peer_description() + vdebug.log.Log("Found connection from " + addr,vdebug.log.Logger.INFO) + self.ui.set_conn_details(addr) self.set_features() self.breakpoints.update_lines(self.ui.get_breakpoint_sign_positions()) @@ -253,7 +263,7 @@ def run_to_cursor(self): self.api.breakpoint_set(bp.get_cmd()) self.run() - def listen(self,server,port,timeout): + def listen(self,endpoint,timeout): """Open the vdebug.dbgp API with connection. Uses existing connection if possible. @@ -269,8 +279,8 @@ def listen(self,server,port,timeout): check_ide_key = True if len(ide_key) == 0: check_ide_key = False - - connection = vdebug.dbgp.Connection(server,port,\ + + connection = vdebug.dbgp.Connection(endpoint, timeout,vdebug.util.InputStream()) self.api = vdebug.dbgp.Api(connection) diff --git a/plugin/python/vdebug/ui/vimui.py b/plugin/python/vdebug/ui/vimui.py index 2be0e1bb..c5fef693 100644 --- a/plugin/python/vdebug/ui/vimui.py +++ b/plugin/python/vdebug/ui/vimui.py @@ -87,14 +87,14 @@ def mark_as_stopped(self): self.statuswin.set_status("stopped") self.remove_conn_details() - def set_conn_details(self,addr,port): - self.statuswin.insert("Connected to %s:%s" %(addr,port),2,True) + def set_conn_details(self,description): + self.statuswin.insert("Connected to %s" %(description),2,True) def remove_conn_details(self): self.statuswin.insert("Not connected",2,True) - def set_listener_details(self,addr,port,idekey): - details = "Listening on %s:%s" %(addr,port) + def set_listener_details(self,description,idekey): + details = "Listening on %s" %(description) if len(idekey): details += " (IDE key: %s)" % idekey self.statuswin.insert(details,1,True) diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index c1adea1a..ce937490 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -83,9 +83,11 @@ let g:vdebug_keymap_defaults = { \} let g:vdebug_options_defaults = { +\ "socket_type": "tcp", \ "port" : 9000, \ "timeout" : 20, \ "server" : 'localhost', +\ "unix_permissions": 0700, \ "on_close" : 'detach', \ "break_on_open" : 1, \ "ide_key" : '',