IPv6: use urlparse and socket.create_connection to enhance socket:// and rfc227:// clients with IPv4+IPV6 support
diff --git a/serial/urlhandler/protocol_socket.py b/serial/urlhandler/protocol_socket.py
index 0b3d555..2b63c0d 100644
--- a/serial/urlhandler/protocol_socket.py
+++ b/serial/urlhandler/protocol_socket.py
@@ -10,7 +10,7 @@
# The purpose of this module is that applications using pySerial can connect to
# TCP/IP to serial port converters that do not support RFC 2217.
#
-# (C) 2001-2011 Chris Liechti <cliechti@gmx.net>
+# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
# this is distributed under a free software license, see license.txt
#
# URL format: socket://<host>:<port>[/option[/option...]]
@@ -22,6 +22,7 @@
import socket
import select
import logging
+import urlparse
# map log level names to constants. used in fromURL()
LOGGER_LEVELS = {
@@ -51,8 +52,7 @@
raise SerialException("Port is already open.")
try:
# XXX in future replace with create_connection (py >=2.6)
- self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self._socket.connect(self.fromURL(self.portstr))
+ self._socket = socket.create_connection(self.fromURL(self.portstr))
except Exception as msg:
self._socket = None
raise SerialException("Could not open port %s: %s" % (self.portstr, msg))
@@ -99,31 +99,30 @@
def fromURL(self, url):
"""extract host and port from an URL string"""
- if url.lower().startswith("socket://"): url = url[9:]
+ parts = urlparse.urlsplit(url)
+ if parts.scheme.lower() != "socket":
+ raise SerialException('expected a string in the form "socket://<host>:<port>[/option[/option...]]": not starting with socket:// (%r)' % (parts.scheme,))
try:
- # is there a "path" (our options)?
- if '/' in url:
- # cut away options
- url, options = url.split('/', 1)
- # process options now, directly altering self
- for option in options.split('/'):
- if '=' in option:
- option, value = option.split('=', 1)
- else:
- value = None
- if option == 'logging':
- logging.basicConfig() # XXX is that good to call it here?
- self.logger = logging.getLogger('pySerial.socket')
- self.logger.setLevel(LOGGER_LEVELS[value])
- self.logger.debug('enabled logging')
- else:
- raise ValueError('unknown option: %r' % (option,))
+ # process options now, directly altering self
+ for option in parts.path.lower().split('/'):
+ if '=' in option:
+ option, value = option.split('=', 1)
+ else:
+ value = None
+ if not option:
+ pass
+ elif option == 'logging':
+ logging.basicConfig() # XXX is that good to call it here?
+ self.logger = logging.getLogger('pySerial.socket')
+ self.logger.setLevel(LOGGER_LEVELS[value])
+ self.logger.debug('enabled logging')
+ else:
+ raise ValueError('unknown option: %r' % (option,))
# get host and port
- host, port = url.split(':', 1) # may raise ValueError because of unpacking
- port = int(port) # and this if it's not a number
+ host, port = parts.hostname, parts.port
if not 0 <= port < 65536: raise ValueError("port not in range 0...65535")
except ValueError as e:
- raise SerialException('expected a string in the form "[rfc2217://]<host>:<port>[/option[/option...]]": %s' % e)
+ raise SerialException('expected a string in the form "socket://<host>:<port>[/option[/option...]]": %s' % e)
return (host, port)
# - - - - - - - - - - - - - - - - - - - - - - - -