diff --git a/README.rst b/README.rst index 476f0ed..123f7ab 100644 --- a/README.rst +++ b/README.rst @@ -73,7 +73,7 @@ accepts the following configuration parameters when it is initialized: Argument Default Explanation ===================== ================= ======================================== ``library`` Test library instance or module to host. Mandatory argument. - ``host`` ``'127.0.0.1'`` Address to listen. Use ``'0.0.0.0'`` to listen to all available interfaces. + ``host`` ``'127.0.0.1'`` Address to listen. Use ``'0.0.0.0'`` to listen to all available IPv4 addresses. ``port`` ``8270`` Port to listen. Use ``0`` to select a free port automatically. Can be given as an integer or as a string. The default port ``8270`` is `registered by IANA`__ for remote server usage. ``port_file`` ``None`` File to write the port that is used. ``None`` (default) means no such file is written. ``allow_stop`` ``'DEPRECATED'`` Deprecated since version 1.1. Use ``allow_remote_stop`` instead. @@ -243,6 +243,29 @@ using ``stop`` argument on the command line or by using the ``stop_remote_server`` function programmatically. Testing and stopping should work also with other Robot Framework remote server implementations. +Simple IPv6 Support +------------------- + +RobotRemoteServer instances can bind to IPv6 addresses as well as IPv4 addresses; +both specific addresses and the 'any available address' equivalent to IPv4's +'0.0.0.0': '::'. + +To use IPv6 addresses, it is necessary to set the class variable `TCPServer.address_family` +*before* the `import` of `RobotRemoteServer`, as shown in the example below. + +.. sourcecode:: python + + import socketserver + import socket + + socketserver.TCPServer.address_family = socket.AF_INET6 + + from robotremoteserver import RobotRemoteServer + from mylibrary import MyLibrary + + RobotRemoteServer (MyLibrary (), host = "::") + + Listing keywords and viewing documentation ------------------------------------------ diff --git a/example/exipv6.py b/example/exipv6.py new file mode 100644 index 0000000..2620f38 --- /dev/null +++ b/example/exipv6.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# example of how to get RobotRemtoteServer working with IPv6: set up socketserver.TTCPServer.addresse_family +# class variable before importing RobotRemoteServer. Then use IPv6 notation, rather than IPv4 + +import sys + +import socketserver +import socket + +socketserver.TCPServer.address_family = socket.AF_INET6 + +from robotremoteserver import RobotRemoteServer + +from examplelibrary import ExampleLibrary + +if __name__ == '__main__': + # listen on any IPv6 address, including all IPv4 addresses on the host + #RobotRemoteServer(ExampleLibrary(), host="::", *sys.argv[1:]) + # listen on local loopback interface + #RobotRemoteServer(ExampleLibrary(), host="::1", *sys.argv[1:]) + # example encoding of IPv4 RFC1918 address as IPv6 address + #RobotRemoteServer(ExampleLibrary(), host="::ffff:192.168.194.81", *sys.argv[1:]) + # IPv4 notation will fail + #RobotRemoteServer(ExampleLibrary(), host="192.168.194.81", *sys.argv[1:]) + # listen on any IPv4 address + RobotRemoteServer(ExampleLibrary(), host="::ffff:0.0.0.0", *sys.argv[1:]) diff --git a/example/tests.robot b/example/tests.robot index 6e05fb6..03656e6 100644 --- a/example/tests.robot +++ b/example/tests.robot @@ -2,7 +2,13 @@ Library Remote http://${ADDRESS}:${PORT} *** Variables *** -${ADDRESS} 127.0.0.1 +# localhost may be a suitable alias for the local IP stack loopback address +${ADDRESS} localhost +# alternatively, use a protocol specific loopback address +# IPv6 loopback address +#${ADDRESS} ::1 +# IPv4 loopback address +#${ADDRESS} 127.0.0.1 ${PORT} 8270 *** Test Cases *** diff --git a/src/robotremoteserver.py b/src/robotremoteserver.py index 62fc5ed..bc324be 100644 --- a/src/robotremoteserver.py +++ b/src/robotremoteserver.py @@ -24,6 +24,12 @@ import threading import traceback +import socketserver +import socket + +socketserver.TCPServer.address_family = socket.AF_INET6 + + if sys.version_info < (3,): from SimpleXMLRPCServer import SimpleXMLRPCServer from StringIO import StringIO @@ -49,13 +55,14 @@ class RobotRemoteServer(object): - def __init__(self, library, host='127.0.0.1', port=8270, port_file=None, + def __init__(self, library, host='::1', port=8270, port_file=None, allow_stop='DEPRECATED', serve=True, allow_remote_stop=True): """Configure and start-up remote server. :param library: Test library instance or module to host. :param host: Address to listen. Use ``'0.0.0.0'`` to listen - to all available interfaces. + to all available interfaces that have an IPv4 + address. :param port: Port to listen. Use ``0`` to select a free port automatically. Can be given as an integer or as a string. @@ -149,7 +156,7 @@ def _announce_stop(self, log, port_file): def _log(self, action, log=True, warn=False): if log: - address = '%s:%s' % self.server_address + address = '%s:%s' % self.server_address [:2] if warn: print('*WARN*', end=' ') print('Robot Framework remote server at %s %s.' % (address, action))