[Zodb-checkins] CVS: StandaloneZODB/ZEO/zrpc - connection.py:1.1.2.2.2.2 marshal.py:1.1.2.1.2.2

Jeremy Hylton jeremy@zope.com
Fri, 26 Apr 2002 15:25:30 -0400


Update of /cvs-repository/StandaloneZODB/ZEO/zrpc
In directory cvs.zope.org:/tmp/cvs-serv11377/zrpc

Modified Files:
      Tag: ZEO2-branch
	connection.py marshal.py 
Log Message:
First step words protocol negotiation.

New client sends a 4-byte protocol id to the server.   XXX Is this
sufficient for now?

Also, rename "wait_for_server_on_startup" to "wait".  This change
affects a ctor calls in a bunch of files.


=== StandaloneZODB/ZEO/zrpc/connection.py 1.1.2.2.2.1 => 1.1.2.2.2.2 ===
     __super_close = smac.SizedMessageAsyncConnection.close
     __super_writable = smac.SizedMessageAsyncConnection.writable
+    __super_message_output = smac.SizedMessageAsyncConnection.message_output
+
+    protocol_version = "Z200"
 
     def __init__(self, sock, addr, obj=None):
         self.obj = None
@@ -88,6 +91,7 @@
         self.__reply_lock = threading.Lock()
         self.__reply_lock.acquire()
         self.register_object(obj)
+        self.handshake()
 
     def __repr__(self):
         return "<%s %s>" % (self.__class__.__name__, self.addr)
@@ -108,6 +112,25 @@
         """Register obj as the true object to invoke methods on"""
         self.obj = obj
 
+    def handshake(self):
+        # When a connection is created the first message sent is a
+        # 4-byte protocol version.  This mechanism should allow the
+        # protocol to evolve over time, and let servers handle clients
+        # using multiple versions of the protocol.
+
+        # The mechanism replace the message_input() method for the
+        # first message received.
+
+        # The client sends the protocol version it is using.
+        self._message_input = self.message_input
+        self.message_input = self.recv_handshake
+        self.message_output(self.protocol_version)
+
+    def recv_handshake(self, message):
+        if message == self.protocol_version:
+            self.message_input = self._message_input
+        # otherwise do something else...
+    
     def message_input(self, message):
         """Decoding an incoming message and dispatch it"""
         # XXX Not sure what to do with errors that reach this level.
@@ -298,8 +321,9 @@
 
 class ServerConnection(Connection):
     """Connection on the server side"""
-    # XXX Do we need this class anymore?
 
+    # The server side does not send a protocol message.  Instead, it
+    # adapts to whatever the client sends it.
 
 class ManagedServerConnection(ServerConnection):
     """A connection that notifies its ConnectionManager of closing"""


=== StandaloneZODB/ZEO/zrpc/marshal.py 1.1.2.1.2.1 => 1.1.2.1.2.2 ===
 import cPickle
 from cStringIO import StringIO
+import struct
 import types
 
 class Marshaller:
@@ -30,6 +31,8 @@
               cPickle.PickleError,
               cPickle.PicklingError)
 
+    VERSION = 1
+
     def encode(self, msgid, flags, name, args):
         """Returns an encoded message"""
         return self.pickle((msgid, flags, name, args), 1)
@@ -41,10 +44,10 @@
 
         try:
             return unpickler.load() # msgid, flags, name, args
-        except (cPickle.UnpicklingError, IndexError), err_msg:
+        except (self.errors, IndexError), err_msg:
             log("can't decode %s" % repr(msg), level=zLOG.ERROR)
             raise DecodingError(msg)
-
+        
 _globals = globals()
 _silly = ('__doc__',)