def checkBadMessage2(self): # just like a real message, but with an unpicklable argument global Hack class Hack: pass msg = Marshaller().encode(1, 0, "foo", (Hack(),)) self._bad_message(msg) del Hack
def __init__(self, sock, addr, obj, tag, map=None): self.obj = None self.marshal = Marshaller() self.closed = False self.peer_protocol_version = None # set in recv_handshake() assert tag in "CS" self.tag = tag self.logger = logging.getLogger('ZEO.zrpc.Connection(%c)' % tag) if isinstance(addr, tuple): self.log_label = "(%s:%d) " % addr else: self.log_label = "(%s) " % addr # Supply our own socket map, so that we don't get registered with # the asyncore socket map just yet. The initial protocol messages # are treated very specially, and we dare not get invoked by asyncore # before that special-case setup is complete. Some of that setup # occurs near the end of this constructor, and the rest is done by # a concrete subclass's handshake() method. Unfortunately, because # we ultimately derive from asyncore.dispatcher, it's not possible # to invoke the superclass constructor without asyncore stuffing # us into _some_ socket map. ourmap = {} self.__super_init(sock, addr, map=ourmap) # A Connection either uses asyncore directly or relies on an # asyncore mainloop running in a separate thread. If # thr_async is true, then the mainloop is running in a # separate thread. If thr_async is true, then the asyncore # trigger (self.trigger) is used to notify that thread of # activity on the current thread. self.thr_async = False self.trigger = None self._prepare_async() # The singleton dict is used in synchronous mode when a method # needs to call into asyncore to try to force some I/O to occur. # The singleton dict is a socket map containing only this object. self._singleton = {self._fileno: self} # msgid_lock guards access to msgid self.msgid = 0 self.msgid_lock = threading.Lock() # replies_cond is used to block when a synchronous call is # waiting for a response self.replies_cond = threading.Condition() self.replies = {} # waiting_for_reply is used internally to indicate whether # a call is in progress. setting a session key is deferred # until after the call returns. self.waiting_for_reply = False self.delay_sesskey = None self.register_object(obj) # The first message we see is a protocol handshake. message_input() # is temporarily replaced by recv_handshake() to treat that message # specially. revc_handshake() does "del self.message_input", which # uncovers the normal message_input() method thereafter. self.message_input = self.recv_handshake # Server and client need to do different things for protocol # negotiation, and handshake() is implemented differently in each. self.handshake() # Now it's safe to register with asyncore's socket map; it was not # safe before message_input was replaced, or before handshake() was # invoked. # Obscure: in Python 2.4, the base asyncore.dispatcher class grew # a ._map attribute, which is used instead of asyncore's global # socket map when ._map isn't None. Because we passed `ourmap` to # the base class constructor above, in 2.4 asyncore believes we want # to use `ourmap` instead of the global socket map -- but we don't. # So we have to replace our ._map with the global socket map, and # update the global socket map with `ourmap`. Replacing our ._map # isn't necessary before Python 2.4, but doesn't hurt then (it just # gives us an unused attribute in 2.3); updating the global socket # map is necessary regardless of Python version. if map is None: map = asyncore.socket_map self._map = map map.update(ourmap)