5858_CONNECT_TIMEOUT = 20.0
5959
6060
61+ def _partition_ipv6 (source ):
62+ if source .find (']' ) == - 1 :
63+ raise InvalidURI ("an IPv6 address literal must be "
64+ "enclosed in '[' and ']' characters." )
65+ i = source .find (']:' )
66+ if i == - 1 :
67+ return (source [1 :- 1 ], None )
68+ return (source [1 : i ], source [i + 2 :])
69+
70+
6171def _partition (source , sub ):
6272 """Our own string partitioning method.
6373
@@ -74,7 +84,14 @@ def _str_to_node(string, default_port=27017):
7484
7585 "localhost:27017" -> ("localhost", 27017)
7686 """
77- (host , port ) = _partition (string , ":" )
87+ # IPv6 literal
88+ if string [0 ] == '[' :
89+ host , port = _partition_ipv6 (string )
90+ elif string .count (':' ) > 1 or string .find (']' ) != - 1 :
91+ raise InvalidURI ("an IPv6 address literal must be "
92+ "enclosed in '[' and ']' characters." )
93+ else :
94+ host , port = _partition (string , ":" )
7895 if port :
7996 port = int (port )
8097 else :
@@ -240,9 +257,11 @@ def __init__(self, host=None, port=None, pool_size=None,
240257 username, and password present will be used.
241258
242259 :Parameters:
243- - `host` (optional): hostname or IPv4 address of the
260+ - `host` (optional): hostname or IP address of the
244261 instance to connect to, or a mongodb URI, or a list of
245- hostnames / mongodb URIs
262+ hostnames / mongodb URIs. If `host` is an IPv6 literal
263+ it must be enclosed in '[' and ']' characters following
264+ the RFC2732 URL syntax (e.g. '[::1]' for localhost)
246265 - `port` (optional): port number on which to connect
247266 - `pool_size` (optional): DEPRECATED
248267 - `auto_start_request` (optional): DEPRECATED
@@ -585,12 +604,23 @@ def __connect(self):
585604 host , port = self .__find_master ()
586605
587606 try :
588- sock = socket .socket ()
589- sock .setsockopt (socket .IPPROTO_TCP , socket .TCP_NODELAY , 1 )
590- sock .settimeout (self .__network_timeout or _CONNECT_TIMEOUT )
591- sock .connect ((host , port ))
592- sock .settimeout (self .__network_timeout )
593- return sock
607+ try :
608+ # Prefer IPv4. If there is demand for an option
609+ # to specify one or the other we can add it later.
610+ sock = socket .socket (socket .AF_INET )
611+ sock .setsockopt (socket .IPPROTO_TCP , socket .TCP_NODELAY , 1 )
612+ sock .settimeout (self .__network_timeout or _CONNECT_TIMEOUT )
613+ sock .connect ((host , port ))
614+ sock .settimeout (self .__network_timeout )
615+ return sock
616+ except socket .gaierror :
617+ # If that fails try IPv6
618+ sock = socket .socket (socket .AF_INET6 )
619+ sock .setsockopt (socket .IPPROTO_TCP , socket .TCP_NODELAY , 1 )
620+ sock .settimeout (self .__network_timeout or _CONNECT_TIMEOUT )
621+ sock .connect ((host , port ))
622+ sock .settimeout (self .__network_timeout )
623+ return sock
594624 except socket .error :
595625 self .disconnect ()
596626 raise AutoReconnect ("could not connect to %r" % list (self .__nodes ))
0 commit comments