SVN: ZODB/branches/3.9/src/ On Mac OS X, clients that connected and disconnected quickly could

Jim Fulton <[email protected]>
Newsgroups gmane.comp.python.zope.zodb.cvs
Message-ID <[email protected]>
Log message for revision 111511:
  On Mac OS X, clients that connected and disconnected quickly could
  cause a ZEO server to stop accepting connections, due to a failure
  to catch errors in the initial part of the connection process.
  
  The failure to properly handle exceptions while accepting
  connections is potentially problematic on other platforms.
  
  Fixes: https://bugs.launchpad.net/zodb/+bug/135108
  

Changed:
  U   ZODB/branches/3.9/src/CHANGES.txt
  U   ZODB/branches/3.9/src/ZEO/tests/testZEO.py
  U   ZODB/branches/3.9/src/ZEO/zrpc/server.py

-=-
Modified: ZODB/branches/3.9/src/CHANGES.txt
===================================================================
--- ZODB/branches/3.9/src/CHANGES.txt	2010-04-27 18:35:21 UTC (rev 111510)
+++ ZODB/branches/3.9/src/CHANGES.txt	2010-04-27 20:23:12 UTC (rev 111511)
@@ -2,6 +2,21 @@
  Change History
 ================
 
+3.9.6 (unreleased)
+==================
+
+Bugs Fixed
+----------
+
+- On Mac OS X, clients that connected and disconnected quickly could
+  cause a ZEO server to stop accepting connections, due to a failure
+  to catch errors in the initial part of the connection process.
+
+  The failure to properly handle exceptions while accepting
+  connections is potentially problematic on other platforms.
+
+  Fixes: https://bugs.launchpad.net/zodb/+bug/135108
+
 3.9.5 (2010-04-23)
 ==================
 

Modified: ZODB/branches/3.9/src/ZEO/tests/testZEO.py
===================================================================
--- ZODB/branches/3.9/src/ZEO/tests/testZEO.py	2010-04-27 18:35:21 UTC (rev 111510)
+++ ZODB/branches/3.9/src/ZEO/tests/testZEO.py	2010-04-27 20:23:12 UTC (rev 111511)
@@ -1227,6 +1227,34 @@
     testing exit immediately
     """
 
+def quick_close_doesnt_kill_server():
+    r"""
+
+    Start a server:
+
+    >>> addr, _ = start_server()
+
+    Now connect and immediately disconnect. This caused the server to
+    die in the past:
+
+    >>> import socket, struct
+    >>> for i in range(5):
+    ...     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    ...     s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
+    ...                  struct.pack('ii', 1, 0))
+    ...     s.connect(addr)
+    ...     s.close()
+
+    Now we should be able to connect as normal:
+
+    >>> db = ZEO.DB(addr)
+    >>> db.storage.is_connected()
+    True
+
+    >>> db.close()
+
+    """
+
 slow_test_classes = [
     BlobAdaptedFileStorageTests, BlobWritableCacheTests,
     DemoStorageTests, FileStorageTests, MappingStorageTests,

Modified: ZODB/branches/3.9/src/ZEO/zrpc/server.py
===================================================================
--- ZODB/branches/3.9/src/ZEO/zrpc/server.py	2010-04-27 18:35:21 UTC (rev 111510)
+++ ZODB/branches/3.9/src/ZEO/zrpc/server.py	2010-04-27 20:23:12 UTC (rev 111511)
@@ -17,6 +17,7 @@
 
 from ZEO.zrpc.connection import Connection
 from ZEO.zrpc.log import log
+import ZEO.zrpc.log
 import logging
 
 # Export the main asyncore loop
@@ -54,5 +55,23 @@
         except socket.error, msg:
             log("accepted failed: %s" % msg)
             return
-        c = self.factory(sock, addr)
-        log("connect from %s: %s" % (repr(addr), c))
+
+        # 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,
+        # quick_close_doesnt_kill_server, causes addr to be None and
+        # we'd have to write a test for the non-None case, which is
+        # *even* harder to provoke. :/ So we'll leave things as they
+        # are for now.
+
+        # It might be better to check whether the socket has been
+        # closed, but I don't see a way to do that. :(
+
+        try:
+            c = self.factory(sock, addr)
+        except:
+            if sock.fileno() in asyncore.socket_map:
+                del asyncore.socket_map[sock.fileno()]
+            ZEO.zrpc.log.logger.exception("Error in handle_accept")
+        else:
+            log("connect from %s: %s" % (repr(addr), c))
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.