[Zodb-checkins] SVN: ZODB/trunk/ Bug fixed

Jim Fulton jim at zope.com
Mon Sep 27 18:16:10 EDT 2010


Log message for revision 116992:
  Bug fixed
  - ZEO didn't work with IPv6 addrsses.
    Added IPv6 support contributed by Martin v. Lowis.
  

Changed:
  U   ZODB/trunk/doc/zeo.txt
  U   ZODB/trunk/src/CHANGES.txt
  U   ZODB/trunk/src/ZEO/tests/ConnectionTests.py
  U   ZODB/trunk/src/ZEO/tests/testZEO.py
  U   ZODB/trunk/src/ZEO/zrpc/client.py
  U   ZODB/trunk/src/ZEO/zrpc/server.py
  U   ZODB/trunk/src/ZEO/zrpc/smac.py

-=-
Modified: ZODB/trunk/doc/zeo.txt
===================================================================
--- ZODB/trunk/doc/zeo.txt	2010-09-27 21:38:46 UTC (rev 116991)
+++ ZODB/trunk/doc/zeo.txt	2010-09-27 22:16:10 UTC (rev 116992)
@@ -125,7 +125,7 @@
 
     ZEO monitor server version 2.1a1
     Fri Apr  4 16:57:42 2003
-    
+ 
     Storage: 1
     Server started: Fri Apr  4 16:57:37 2003
     Clients: 0
@@ -164,6 +164,9 @@
 be used to with a system that arranges to provide hot backups of
 servers in the case of failure.
 
+If a single address resolves to multiple IPv4 or IPv6 addresses,
+the client will connect to an arbitrary of these addresses.
+
 Authentication
 ~~~~~~~~~~~~~~
 

Modified: ZODB/trunk/src/CHANGES.txt
===================================================================
--- ZODB/trunk/src/CHANGES.txt	2010-09-27 21:38:46 UTC (rev 116991)
+++ ZODB/trunk/src/CHANGES.txt	2010-09-27 22:16:10 UTC (rev 116992)
@@ -8,6 +8,9 @@
 Bugs fixed
 ----------
 
+- ZEO didn't work with IPv6 addrsses.
+  Added IPv6 support contributed by Martin v. Löwis.
+
 - Changes in way that garage collection treats dictionaries in Python
   2.7 broke the object/connection cache implementation.
   (https://bugs.launchpad.net/zodb/+bug/641481)

Modified: ZODB/trunk/src/ZEO/tests/ConnectionTests.py
===================================================================
--- ZODB/trunk/src/ZEO/tests/ConnectionTests.py	2010-09-27 21:38:46 UTC (rev 116991)
+++ ZODB/trunk/src/ZEO/tests/ConnectionTests.py	2010-09-27 22:16:10 UTC (rev 116992)
@@ -16,6 +16,7 @@
 import sys
 import time
 import random
+import socket
 import asyncore
 import threading
 import logging
@@ -1197,3 +1198,18 @@
                 c.close()
             except:
                 pass
+
+# Run IPv6 tests if V6 sockets are supported
+try:
+    socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+except (socket.error, AttributeError):
+    pass
+else:
+    class V6Setup:
+        def _getAddr(self):
+            return '::1', forker.get_port(self)
+
+    _g = globals()
+    for name, value in _g.items():
+        if isinstance(value, type) and issubclass(value, CommonSetupTearDown):
+            _g[name+"V6"] = type(name+"V6", (V6Setup, value), {})

Modified: ZODB/trunk/src/ZEO/tests/testZEO.py
===================================================================
--- ZODB/trunk/src/ZEO/tests/testZEO.py	2010-09-27 21:38:46 UTC (rev 116991)
+++ ZODB/trunk/src/ZEO/tests/testZEO.py	2010-09-27 22:16:10 UTC (rev 116992)
@@ -1148,13 +1148,13 @@
     ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
     ZEO.ClientStorage CRITICAL client
     Client has seen newer transactions than server!
-    ZEO.zrpc ERROR (...) CW: error in notifyConnected (('localhost', ...))
+    ZEO.zrpc ERROR (...) CW: error in notifyConnected (('127.0.0.1', ...))
     Traceback (most recent call last):
     ...
     ClientStorageError: client Client has seen newer transactions than server!
     ZEO.ClientStorage CRITICAL client
     Client has seen newer transactions than server!
-    ZEO.zrpc ERROR (...) CW: error in notifyConnected (('localhost', ...))
+    ZEO.zrpc ERROR (...) CW: error in notifyConnected (('127.0.0.1', ...))
     Traceback (most recent call last):
     ...
     ClientStorageError: client Client has seen newer transactions than server!

Modified: ZODB/trunk/src/ZEO/zrpc/client.py
===================================================================
--- ZODB/trunk/src/ZEO/zrpc/client.py	2010-09-27 21:38:46 UTC (rev 116991)
+++ ZODB/trunk/src/ZEO/zrpc/client.py	2010-09-27 22:16:10 UTC (rev 116992)
@@ -188,7 +188,7 @@
         if (len(addr) == 2
             and isinstance(addr[0], types.StringType)
             and isinstance(addr[1], types.IntType)):
-            return socket.AF_INET
+            return socket.AF_INET # also denotes IPv6
 
         # not anything I know about
         return None
@@ -436,10 +436,25 @@
             del wrappers
         return 0
 
+    def _expand_addrlist(self):
+        for domain, (host, port) in self.addrlist:
+            # AF_INET really means either IPv4 or IPv6, possibly
+            # indirected by DNS. By design, DNS lookup is deferred
+            # until connections get established, so that DNS
+            # reconfiguration can affect failover
+            if domain == socket.AF_INET:
+                for (family, socktype, proto, cannoname, sockaddr
+                     ) in socket.getaddrinfo(host, port):
+                    # for IPv6, drop flowinfo, and restrict addresses
+                    # to [host]:port
+                    yield family, sockaddr[:2]
+            else:
+                yield domain, addr
+
     def _create_wrappers(self):
         # Create socket wrappers
         wrappers = {}  # keys are active wrappers
-        for domain, addr in self.addrlist:
+        for domain, addr in self._expand_addrlist():
             wrap = ConnectWrapper(domain, addr, self.mgr, self.client)
             wrap.connect_procedure()
             if wrap.state == "notified":

Modified: ZODB/trunk/src/ZEO/zrpc/server.py
===================================================================
--- ZODB/trunk/src/ZEO/zrpc/server.py	2010-09-27 21:38:46 UTC (rev 116991)
+++ ZODB/trunk/src/ZEO/zrpc/server.py	2010-09-27 22:16:10 UTC (rev 116992)
@@ -15,6 +15,23 @@
 import socket
 import types
 
+# _has_dualstack: True if the dual-stack sockets are supported
+try:
+    # Check whether IPv6 sockets can be created
+    s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+except (socket.error, AttributeError):
+    _has_dualstack = False
+else:
+    # Check whether enabling dualstack (disabling v6only) works
+    try:
+        s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
+    except (socket.error, AttributeError):
+        _has_dualstack = False
+    else:
+        _has_dualstack = True
+    s.close()
+    del s
+
 from ZEO.zrpc.connection import Connection
 from ZEO.zrpc.log import log
 import ZEO.zrpc.log
@@ -35,7 +52,21 @@
 
     def _open_socket(self):
         if type(self.addr) == types.TupleType:
-            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+            if self.addr[0] == '' and _has_dualstack:
+                # Wildcard listen on all interfaces, both IPv4 and
+                # IPv6 if possible
+                self.create_socket(socket.AF_INET6, socket.SOCK_STREAM)
+                self.socket.setsockopt(
+                    socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
+            elif ':' in self.addr[0]:
+                self.create_socket(socket.AF_INET6, socket.SOCK_STREAM)
+                if _has_dualstack:
+                    # On Linux, IPV6_V6ONLY is off by default.
+                    # If the user explicitly asked for IPv6, don't bind to IPv4
+                    self.socket.setsockopt(
+                        socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, True)
+            else:
+                self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
         else:
             self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
         self.set_reuse_addr()
@@ -56,6 +87,9 @@
             log("accepted failed: %s" % msg)
             return
 
+        # Drop flow-info from IPv6 addresses
+        addr = addr[:2]
+
         # We could short-circuit the attempt below in some edge cases
         # and avoid a log message by checking for addr being None.
         # Unfortunately, our test for the code below,

Modified: ZODB/trunk/src/ZEO/zrpc/smac.py
===================================================================
--- ZODB/trunk/src/ZEO/zrpc/smac.py	2010-09-27 21:38:46 UTC (rev 116991)
+++ ZODB/trunk/src/ZEO/zrpc/smac.py	2010-09-27 22:16:10 UTC (rev 116992)
@@ -120,6 +120,10 @@
 
         self.__super_init(sock, map)
 
+        # asyncore overwrites addr with the getpeername result
+        # restore our value
+        self.addr = addr
+
     def setSessionKey(self, sesskey):
         log("set session key %r" % sesskey)
 



More information about the Zodb-checkins mailing list