Add basic IPv6 support PYTHON-237

commit a6ee56d8bbfdf9e0ca651f5efa6fb71556c650ed
Author: behackett <bernie@10gen.com>
Date:   Tue Apr 12 10:16:08 2011 -0700

    Make IPv4 explicit and add a few more tests.

commit 793584a1c7032f2d2b7f5ae9ca0740ceec84ba98
Author: behackett <bernie@10gen.com>
Date:   Mon Apr 11 16:51:18 2011 -0700

    Preliminary support for IPv6.
This commit is contained in:
behackett 2011-04-12 10:52:25 -07:00
parent b32493548f
commit 5aa62a3c0e
2 changed files with 70 additions and 9 deletions

View File

@ -58,6 +58,16 @@ from pymongo.errors import (AutoReconnect,
_CONNECT_TIMEOUT = 20.0
def _partition_ipv6(source):
if source.find(']') == -1:
raise InvalidURI("an IPv6 address literal must be "
"enclosed in '[' and ']' characters.")
i = source.find(']:')
if i == -1:
return (source[1:-1], None)
return (source[1: i], source[i + 2:])
def _partition(source, sub):
"""Our own string partitioning method.
@ -74,7 +84,14 @@ def _str_to_node(string, default_port=27017):
"localhost:27017" -> ("localhost", 27017)
"""
(host, port) = _partition(string, ":")
# IPv6 literal
if string[0] == '[':
host, port = _partition_ipv6(string)
elif string.count(':') > 1 or string.find(']') != -1:
raise InvalidURI("an IPv6 address literal must be "
"enclosed in '[' and ']' characters.")
else:
host, port = _partition(string, ":")
if port:
port = int(port)
else:
@ -240,9 +257,11 @@ class Connection(object): # TODO support auth for pooling
username, and password present will be used.
:Parameters:
- `host` (optional): hostname or IPv4 address of the
- `host` (optional): hostname or IP address of the
instance to connect to, or a mongodb URI, or a list of
hostnames / mongodb URIs
hostnames / mongodb URIs. If `host` is an IPv6 literal
it must be enclosed in '[' and ']' characters following
the RFC2732 URL syntax (e.g. '[::1]' for localhost)
- `port` (optional): port number on which to connect
- `pool_size` (optional): DEPRECATED
- `auto_start_request` (optional): DEPRECATED
@ -585,12 +604,23 @@ class Connection(object): # TODO support auth for pooling
host, port = self.__find_master()
try:
sock = socket.socket()
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.settimeout(self.__network_timeout or _CONNECT_TIMEOUT)
sock.connect((host, port))
sock.settimeout(self.__network_timeout)
return sock
try:
# Prefer IPv4. If there is demand for an option
# to specify one or the other we can add it later.
sock = socket.socket(socket.AF_INET)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.settimeout(self.__network_timeout or _CONNECT_TIMEOUT)
sock.connect((host, port))
sock.settimeout(self.__network_timeout)
return sock
except socket.gaierror:
# If that fails try IPv6
sock = socket.socket(socket.AF_INET6)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.settimeout(self.__network_timeout or _CONNECT_TIMEOUT)
sock.connect((host, port))
sock.settimeout(self.__network_timeout)
return sock
except socket.error:
self.disconnect()
raise AutoReconnect("could not connect to %r" % list(self.__nodes))

View File

@ -463,6 +463,37 @@ class TestConnection(unittest.TestCase):
aware.pymongo_test.test.find_one()["x"].replace(tzinfo=None),
naive.pymongo_test.test.find_one()["x"])
def test_ipv6(self):
self.assertRaises(InvalidURI, _parse_uri, "::1", 27017)
self.assertRaises(InvalidURI, _parse_uri, "[::1", 27017)
self.assertRaises(InvalidURI, _parse_uri, "::1]:27017")
self.assertRaises(InvalidURI, _parse_uri, "mongodb://::1", 27017)
self.assert_(_parse_uri, "mongodb://[::1]:27017/?slaveOk=true")
self.assert_(_parse_uri,
"[::1]:27017,[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"
":27018,192.168.0.212:27019,localhost:27020")
self.assert_(_parse_uri,
"mongodb://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"
":27017/?slaveOk=true")
try:
connection = Connection("[::1]")
except:
# Either mongod was started without --ipv6
# or the OS doesn't support it (or both).
raise SkipTest()
# Try a few simple things
connection = Connection("mongodb://[::1]:27017")
connection = Connection("mongodb://[::1]:27017/?slaveOk=true")
connection = Connection("[::1]:27017,localhost:27017")
connection = Connection("localhost:27017,[::1]:27017")
connection.pymongo_test.test.save({"dummy": u"object"})
connection.pymongo_test_bernie.test.save({"dummy": u"object"})
dbs = connection.database_names()
self.assert_("pymongo_test" in dbs)
self.assert_("pymongo_test_bernie" in dbs)
if __name__ == "__main__":
unittest.main()