[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