Example #1
0
File: smac.py Project: Krilivye/ZEO
    def setSessionKey(self, sesskey):
        log("set session key %r" % sesskey)

        # Low-level construction is now delayed until data are sent.
        # This is to allow use of iterators that generate messages
        # only when we're ready to do I/O so that we can effeciently
        # transmit large files.  Because we delay messages, we also
        # have to delay setting the session key to retain proper
        # ordering.

        # The low-level output queue supports strings, a special close
        # marker, and iterators.  It doesn't support callbacks.  We
        # can create a allback by providing an iterator that doesn't
        # yield anything.

        # The hack fucntion below is a callback in iterator's
        # clothing. :)  It never yields anything, but is a generator
        # and thus iterator, because it contains a yield statement.

        def hack():
            self.__hmac_send = hmac.HMAC(sesskey, digestmod=ZEO.hash)
            self.__hmac_recv = hmac.HMAC(sesskey, digestmod=ZEO.hash)
            if False:
                yield b''

        self.message_output(hack())
Example #2
0
    def close(self):
        """Prevent ConnectionManager from opening new connections"""
        self.closed = 1
        self.cond.acquire()
        try:
            t = self.thread
            self.thread = None
        finally:
            self.cond.release()
        if t is not None:
            log("CM.close(): stopping and joining thread")
            t.stop()
            t.join(30)
            if t.isAlive():
                log("CM.close(): self.thread.join() timed out",
                    level=logging.WARNING)

        for fd, obj in list(self.map.items()):
            if obj is not self.trigger:
                try:
                    obj.close()
                except:
                    logging.getLogger(__name__ + '.' +
                                      self.__class__.__name__).critical(
                                          "Couldn't close a dispatcher.",
                                          exc_info=sys.exc_info())

        self.map.clear()
        self.trigger.pull_trigger()
        try:
            self.loop_thread.join(9)
        except RuntimeError:
            pass  # we are the thread :)
        self.trigger.close()
Example #3
0
    def close(self):
        """Prevent ConnectionManager from opening new connections"""
        self.closed = 1
        self.cond.acquire()
        try:
            t = self.thread
            self.thread = None
        finally:
            self.cond.release()
        if t is not None:
            log("CM.close(): stopping and joining thread")
            t.stop()
            t.join(30)
            if t.isAlive():
                log("CM.close(): self.thread.join() timed out",
                    level=logging.WARNING)

        for fd, obj in list(self.map.items()):
            if obj is not self.trigger:
                try:
                    obj.close()
                except:
                    logging.getLogger(__name__+'.'+self.__class__.__name__
                                      ).critical(
                        "Couldn't close a dispatcher.",
                        exc_info=sys.exc_info())

        self.map.clear()
        self.trigger.pull_trigger()
        try:
            self.loop_thread.join(9)
        except RuntimeError:
            pass # we are the thread :)
        self.trigger.close()
Example #4
0
    def message_output(self, message):
        if __debug__:
            if self._debug:
                log("message_output %d bytes: %s hmac=%d" %
                    (len(message), short_repr(message), self.__hmac_send and 1
                     or 0),
                    level=TRACE)

        if self.__closed:
            raise DisconnectedError(
                "This action is temporarily unavailable.<p>")
        self.__output_lock.acquire()
        try:
            # do two separate appends to avoid copying the message string
            if self.__hmac_send:
                self.__output.append(struct.pack(">I", len(message) | MAC_BIT))
                self.__hmac_send.update(message)
                self.__output.append(self.__hmac_send.digest())
            else:
                self.__output.append(struct.pack(">I", len(message)))
            if len(message) <= SEND_SIZE:
                self.__output.append(message)
            else:
                for i in range(0, len(message), SEND_SIZE):
                    self.__output.append(message[i:i + SEND_SIZE])
        finally:
            self.__output_lock.release()
Example #5
0
    def handle_accept(self):
        try:
            sock, addr = self.accept()
        except socket.error as msg:
            log("accepted failed: %s" % msg)
            return


        # 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. :(

        # Drop flow-info from IPv6 addresses
        if addr: # Sometimes None on Mac. See above.
            addr = addr[:2]

        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))
Example #6
0
    def try_connecting(self, timeout):
        """Try connecting to all self.mgr.addrlist addresses.

        Return 1 if a preferred connection was found; 0 if no
        connection was found; and -1 if a fallback connection was
        found.

        If no connection is found within timeout seconds, return 0.
        """
        log("CT: attempting to connect on %d sockets" % len(self.mgr.addrlist))
        deadline = time.time() + timeout
        wrappers = self._create_wrappers()
        for wrap in wrappers.keys():
            if wrap.state == "notified":
                return 1
        try:
            if time.time() > deadline:
                return 0
            r = self._connect_wrappers(wrappers, deadline)
            if r is not None:
                return r
            if time.time() > deadline:
                return 0
            r = self._fallback_wrappers(wrappers, deadline)
            if r is not None:
                return r
            # Alas, no luck.
            assert not wrappers
        finally:
            for wrap in wrappers.keys():
                wrap.close()
            del wrappers
        return 0
Example #7
0
    def handle_accept(self):
        try:
            sock, addr = self.accept()
        except socket.error as msg:
            log("accepted failed: %s" % msg)
            return

        # 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. :(

        # Drop flow-info from IPv6 addresses
        if addr:  # Sometimes None on Mac. See above.
            addr = addr[:2]

        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))
Example #8
0
    def try_connecting(self, timeout):
        """Try connecting to all self.mgr.addrlist addresses.

        Return 1 if a preferred connection was found; 0 if no
        connection was found; and -1 if a fallback connection was
        found.

        If no connection is found within timeout seconds, return 0.
        """
        log("CT: attempting to connect on %d sockets" % len(self.mgr.addrlist))
        deadline = time.time() + timeout
        wrappers = self._create_wrappers()
        for wrap in wrappers.keys():
            if wrap.state == "notified":
                return 1
        try:
            if time.time() > deadline:
                return 0
            r = self._connect_wrappers(wrappers, deadline)
            if r is not None:
                return r
            if time.time() > deadline:
                return 0
            r = self._fallback_wrappers(wrappers, deadline)
            if r is not None:
                return r
            # Alas, no luck.
            assert not wrappers
        finally:
            for wrap in wrappers.keys():
                wrap.close()
            del wrappers
        return 0
Example #9
0
    def setSessionKey(self, sesskey):
        log("set session key %r" % sesskey)

        # Low-level construction is now delayed until data are sent.
        # This is to allow use of iterators that generate messages
        # only when we're ready to do I/O so that we can effeciently
        # transmit large files.  Because we delay messages, we also
        # have to delay setting the session key to retain proper
        # ordering.

        # The low-level output queue supports strings, a special close
        # marker, and iterators.  It doesn't support callbacks.  We
        # can create a allback by providing an iterator that doesn't
        # yield anything.

        # The hack fucntion below is a callback in iterator's
        # clothing. :)  It never yields anything, but is a generator
        # and thus iterator, because it contains a yield statement.

        def hack():
            self.__hmac_send = hmac.HMAC(sesskey, digestmod=ZEO.hash)
            self.__hmac_recv = hmac.HMAC(sesskey, digestmod=ZEO.hash)
            if False:
                yield ''

        self.message_output(hack())
Example #10
0
    def message_output(self, message):
        if __debug__:
            if self._debug:
                log("message_output %d bytes: %s hmac=%d" %
                    (len(message), short_repr(message),
                    self.__hmac_send and 1 or 0),
                    level=TRACE)

        if self.__closed:
            raise DisconnectedError(
                "This action is temporarily unavailable.<p>")
        self.__output_lock.acquire()
        try:
            # do two separate appends to avoid copying the message string
            if self.__hmac_send:
                self.__output.append(struct.pack(">I", len(message) | MAC_BIT))
                self.__hmac_send.update(message)
                self.__output.append(self.__hmac_send.digest())
            else:
                self.__output.append(struct.pack(">I", len(message)))
            if len(message) <= SEND_SIZE:
                self.__output.append(message)
            else:
                for i in range(0, len(message), SEND_SIZE):
                    self.__output.append(message[i:i+SEND_SIZE])
        finally:
            self.__output_lock.release()
Example #11
0
 def _open_socket(self):
     if type(self.addr) == types.TupleType:
         self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
     else:
         self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
     self.set_reuse_addr()
     log("listening on %s" % str(self.addr), logging.INFO)
     self.bind(self.addr)
     self.listen(5)
Example #12
0
 def _open_socket(self):
     if type(self.addr) == types.TupleType:
         self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
     else:
         self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
     self.set_reuse_addr()
     log("listening on %s" % str(self.addr), logging.INFO)
     self.bind(self.addr)
     self.listen(5)
Example #13
0
    def decode(self, msg):
        """Decodes msg and returns its parts"""
        unpickler = cPickle.Unpickler(StringIO(msg))
        unpickler.find_global = server_find_global

        try:
            return unpickler.load()  # msgid, flags, name, args
        except:
            log("can't decode message: %s" % short_repr(msg), level=logging.ERROR)
            raise
Example #14
0
def server_decode(msg):
    """Decodes msg and returns its parts"""
    unpickler = Unpickler(StringIO(msg))
    unpickler.find_global = server_find_global

    try:
        return unpickler.load()  # msgid, flags, name, args
    except:
        log("can't decode message: %s" % short_repr(msg), level=logging.ERROR)
        raise
Example #15
0
 def connect_done(self, conn, preferred):
     # Called by ConnectWrapper.notify_client() after notifying the client
     log("CM.connect_done(preferred=%s)" % preferred)
     self.cond.acquire()
     try:
         self.connection = conn
         if preferred:
             self.thread = None
         self.cond.notifyAll() # Wake up connect(sync=1)
     finally:
         self.cond.release()
Example #16
0
 def connect_done(self, conn, preferred):
     # Called by ConnectWrapper.notify_client() after notifying the client
     log("CM.connect_done(preferred=%s)" % preferred)
     self.cond.acquire()
     try:
         self.connection = conn
         if preferred:
             self.thread = None
         self.cond.notifyAll()  # Wake up connect(sync=1)
     finally:
         self.cond.release()
Example #17
0
def decode(msg):
    """Decodes msg and returns its parts"""
    unpickler = Unpickler(BytesIO(msg))
    unpickler.find_global = find_global
    try:
        unpickler.find_class = find_global  # PyPy, zodbpickle, the non-c-accelerated version
    except AttributeError:
        pass
    try:
        return unpickler.load()  # msgid, flags, name, args
    except:
        log("can't decode message: %s" % short_repr(msg), level=logging.ERROR)
        raise
Example #18
0
def decode(msg):
    """Decodes msg and returns its parts"""
    unpickler = Unpickler(BytesIO(msg))
    unpickler.find_global = find_global
    try:
        unpickler.find_class = find_global # PyPy, zodbpickle, the non-c-accelerated version
    except AttributeError:
        pass
    try:
        return unpickler.load() # msgid, flags, name, args
    except:
        log("can't decode message: %s" % short_repr(msg),
            level=logging.ERROR)
        raise
Example #19
0
 def close_conn(self, conn):
     # Called by the connection when it is closed
     self.cond.acquire()
     try:
         if conn is not self.connection:
             # Closing a non-current connection
             log("CM.close_conn() non-current", level=BLATHER)
             return
         log("CM.close_conn()")
         self.connection = None
     finally:
         self.cond.release()
     self.client.notifyDisconnected()
     if not self.closed:
         self.connect()
Example #20
0
 def close_conn(self, conn):
     # Called by the connection when it is closed
     self.cond.acquire()
     try:
         if conn is not self.connection:
             # Closing a non-current connection
             log("CM.close_conn() non-current", level=BLATHER)
             return
         log("CM.close_conn()")
         self.connection = None
     finally:
         self.cond.release()
     self.client.notifyDisconnected()
     if not self.closed:
         self.connect()
Example #21
0
class Dispatcher(asyncore.dispatcher):
    """A server that accepts incoming RPC connections"""
    __super_init = asyncore.dispatcher.__init__

    def __init__(self, addr, factory=Connection):
        self.__super_init()
        self.addr = addr
        self.factory = factory
        self._open_socket()

    def _open_socket(self):
        if type(self.addr) == types.TupleType:
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        else:
            self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.set_reuse_addr()
        log("listening on %s" % str(self.addr), logging.INFO)
        self.bind(self.addr)
        self.listen(5)

    def writable(self):
        return 0

    def readable(self):
        return 1

    def handle_accept(self):
        try:
            sock, addr = self.accept()
        except socket.error, msg:
            log("accepted failed: %s" % msg)
            return
        c = self.factory(sock, addr)
        log("connect from %s: %s" % (repr(addr), c))
Example #22
0
    def notify_client(self):
        """Call the client's notifyConnected().

        If this succeeds, call the manager's connect_done().

        If the client is already connected, we assume it's a fallback
        connection, and the new connection must be a preferred
        connection.  The client will close the old connection.
        """
        try:
            self.client.notifyConnected(self.conn)
        except:
            log("CW: error in notifyConnected (%s)" % repr(self.addr),
                level=logging.ERROR, exc_info=True)
            self.close()
            return
        self.state = "notified"
        self.mgr.connect_done(self.conn, self.preferred)
Example #23
0
 def run(self):
     delay = self.mgr.tmin
     success = 0
     # Don't wait too long the first time.
     # TODO: make timeout configurable?
     attempt_timeout = 5
     while not self.stopped:
         success = self.try_connecting(attempt_timeout)
         if not self.one_attempt.isSet():
             self.one_attempt.set()
             attempt_timeout = 75
         if success > 0:
             break
         time.sleep(delay)
         if self.mgr.is_connected():
             log("CT: still trying to replace fallback connection",
                 level=logging.INFO)
         delay = min(delay * 2, self.mgr.tmax)
     log("CT: exiting thread: %s" % self.getName())
Example #24
0
 def connect(self, sync=0):
     self.cond.acquire()
     try:
         if self.connection is not None:
             return
         t = self.thread
         if t is None:
             log("CM.connect(): starting ConnectThread")
             self.thread = t = ConnectThread(self, self.client)
             t.setDaemon(1)
             t.start()
         if sync:
             while self.connection is None and t.isAlive():
                 self.cond.wait(self.sync_wait)
                 if self.connection is None:
                     log("CM.connect(sync=1): still waiting...")
             assert self.connection is not None
     finally:
         self.cond.release()
Example #25
0
 def connect(self, sync=0):
     self.cond.acquire()
     try:
         if self.connection is not None:
             return
         t = self.thread
         if t is None:
             log("CM.connect(): starting ConnectThread")
             self.thread = t = ConnectThread(self, self.client)
             t.setDaemon(1)
             t.start()
         if sync:
             while self.connection is None and t.isAlive():
                 self.cond.wait(self.sync_wait)
                 if self.connection is None:
                     log("CM.connect(sync=1): still waiting...")
             assert self.connection is not None
     finally:
         self.cond.release()
Example #26
0
 def run(self):
     delay = self.mgr.tmin
     success = 0
     # Don't wait too long the first time.
     # TODO: make timeout configurable?
     attempt_timeout = 5
     while not self.stopped:
         success = self.try_connecting(attempt_timeout)
         if not self.one_attempt.isSet():
             self.one_attempt.set()
             attempt_timeout = 75
         if success > 0:
             break
         time.sleep(delay)
         if self.mgr.is_connected():
             log("CT: still trying to replace fallback connection",
                 level=logging.INFO)
         delay = min(delay*2, self.mgr.tmax)
     log("CT: exiting thread: %s" % self.getName())
Example #27
0
 def __init__(self, domain, addr, mgr, client):
     """Store arguments and create non-blocking socket."""
     self.domain = domain
     self.addr = addr
     self.mgr = mgr
     self.client = client
     # These attributes are part of the interface
     self.state = "closed"
     self.sock = None
     self.conn = None
     self.preferred = 0
     log("CW: attempt to connect to %s" % repr(addr))
     try:
         self.sock = socket.socket(domain, socket.SOCK_STREAM)
     except socket.error as err:
         log("CW: can't create socket, domain=%s: %s" % (domain, err),
             level=logging.ERROR)
         self.close()
         return
     self.sock.setblocking(0)
     self.state = "opened"
Example #28
0
 def __init__(self, domain, addr, mgr, client):
     """Store arguments and create non-blocking socket."""
     self.domain = domain
     self.addr = addr
     self.mgr = mgr
     self.client = client
     # These attributes are part of the interface
     self.state = "closed"
     self.sock = None
     self.conn = None
     self.preferred = 0
     log("CW: attempt to connect to %s" % repr(addr))
     try:
         self.sock = socket.socket(domain, socket.SOCK_STREAM)
     except socket.error as err:
         log("CW: can't create socket, domain=%s: %s" % (domain, err),
             level=logging.ERROR)
         self.close()
         return
     self.sock.setblocking(0)
     self.state = "opened"
Example #29
0
    def test_connection(self):
        """Establish and test a connection at the zrpc level.

        Call the client's testConnection(), giving the client a chance
        to do app-level check of the connection.
        """
        self.conn = ManagedClientConnection(self.sock, self.addr, self.mgr)
        self.sock = None # The socket is now owned by the connection
        try:
            self.preferred = self.client.testConnection(self.conn)
            self.state = "tested"
        except ReadOnlyError:
            log("CW: ReadOnlyError in testConnection (%s)" % repr(self.addr))
            self.close()
            return
        except:
            log("CW: error in testConnection (%s)" % repr(self.addr),
                level=logging.ERROR, exc_info=True)
            self.close()
            return
        if self.preferred:
            self.notify_client()
Example #30
0
 def _open_socket(self):
     if type(self.addr) == types.TupleType:
         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()
     log("listening on %s" % str(self.addr), logging.INFO)
     self.bind(self.addr)
     self.listen(5)
Example #31
0
 def _open_socket(self):
     if type(self.addr) == tuple:
         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()
     log("listening on %s" % str(self.addr), logging.INFO)
     self.bind(self.addr)
     self.listen(5)
Example #32
0
 def _connect_wrappers(self, wrappers, deadline):
     # Next wait until they all actually connect (or fail)
     # The deadline is necessary, because we'd wait forever if a
     # sockets never connects or fails.
     while wrappers:
         if self.stopped:
             for wrap in wrappers.keys():
                 wrap.close()
             return 0
         # Select connecting wrappers
         connecting = [wrap
                       for wrap in wrappers.keys()
                       if wrap.state == "connecting"]
         if not connecting:
             break
         if time.time() > deadline:
             break
         try:
             r, w, x = select.select([], connecting, connecting, 1.0)
             log("CT: select() %d, %d, %d" % tuple(map(len, (r,w,x))))
         except select.error as msg:
             log("CT: select failed; msg=%s" % str(msg),
                 level=logging.WARNING)
             continue
         # Exceptable wrappers are in trouble; close these suckers
         for wrap in x:
             log("CT: closing troubled socket %s" % str(wrap.addr))
             del wrappers[wrap]
             wrap.close()
         # Writable sockets are connected
         for wrap in w:
             wrap.connect_procedure()
             if wrap.state == "notified":
                 del wrappers[wrap] # Don't close this one
                 for wrap in wrappers.keys():
                     wrap.close()
                 return 1
             if wrap.state == "closed":
                 del wrappers[wrap]
Example #33
0
 def _connect_wrappers(self, wrappers, deadline):
     # Next wait until they all actually connect (or fail)
     # The deadline is necessary, because we'd wait forever if a
     # sockets never connects or fails.
     while wrappers:
         if self.stopped:
             for wrap in wrappers.keys():
                 wrap.close()
             return 0
         # Select connecting wrappers
         connecting = [
             wrap for wrap in wrappers.keys() if wrap.state == "connecting"
         ]
         if not connecting:
             break
         if time.time() > deadline:
             break
         try:
             r, w, x = select.select([], connecting, connecting, 1.0)
             log("CT: select() %d, %d, %d" % tuple(map(len, (r, w, x))))
         except select.error as msg:
             log("CT: select failed; msg=%s" % str(msg),
                 level=logging.WARNING)
             continue
         # Exceptable wrappers are in trouble; close these suckers
         for wrap in x:
             log("CT: closing troubled socket %s" % str(wrap.addr))
             del wrappers[wrap]
             wrap.close()
         # Writable sockets are connected
         for wrap in w:
             wrap.connect_procedure()
             if wrap.state == "notified":
                 del wrappers[wrap]  # Don't close this one
                 for wrap in wrappers.keys():
                     wrap.close()
                 return 1
             if wrap.state == "closed":
                 del wrappers[wrap]
Example #34
0
 def connect_procedure(self):
     """Call sock.connect_ex(addr) and interpret result."""
     if self.state in ("opened", "connecting"):
         try:
             err = self.sock.connect_ex(self.addr)
         except socket.error as msg:
             log("CW: connect_ex(%r) failed: %s" % (self.addr, msg),
                 level=logging.ERROR)
             self.close()
             return
         log("CW: connect_ex(%s) returned %s" %
             (self.addr, errno.errorcode.get(err) or str(err)))
         if err in _CONNECT_IN_PROGRESS:
             self.state = "connecting"
             return
         if err not in _CONNECT_OK:
             log("CW: error connecting to %s: %s" %
                 (self.addr, errno.errorcode.get(err) or str(err)),
                 level=logging.WARNING)
             self.close()
             return
         self.state = "connected"
     if self.state == "connected":
         self.test_connection()
Example #35
0
 def connect_procedure(self):
     """Call sock.connect_ex(addr) and interpret result."""
     if self.state in ("opened", "connecting"):
         try:
             err = self.sock.connect_ex(self.addr)
         except socket.error as msg:
             log("CW: connect_ex(%r) failed: %s" % (self.addr, msg),
                 level=logging.ERROR)
             self.close()
             return
         log("CW: connect_ex(%s) returned %s" %
             (self.addr, errno.errorcode.get(err) or str(err)))
         if err in _CONNECT_IN_PROGRESS:
             self.state = "connecting"
             return
         if err not in _CONNECT_OK:
             log("CW: error connecting to %s: %s" %
                 (self.addr, errno.errorcode.get(err) or str(err)),
                 level=logging.WARNING)
             self.close()
             return
         self.state = "connected"
     if self.state == "connected":
         self.test_connection()
Example #36
0
 def setSessionKey(self, sesskey):
     log("set session key %r" % sesskey)
     self.__hmac_send = hmac.HMAC(sesskey, digestmod=sha)
     self.__hmac_recv = hmac.HMAC(sesskey, digestmod=sha)
Example #37
0
 def setSessionKey(self, sesskey):
     log("set session key %r" % sesskey)
     self.__hmac_send = hmac.HMAC(sesskey, digestmod=sha)
     self.__hmac_recv = hmac.HMAC(sesskey, digestmod=sha)
Example #38
0
    def handle_read(self):
        self.__input_lock.acquire()
        try:
            # Use a single __inp buffer and integer indexes to make this fast.
            try:
                d = self.recv(8192)
            except socket.error, err:
                if err[0] in expected_socket_read_errors:
                    return
                raise
            if not d:
                return

            input_len = self.__input_len + len(d)
            msg_size = self.__msg_size
            state = self.__state
            has_mac = self.__has_mac

            inp = self.__inp
            if msg_size > input_len:
                if inp is None:
                    self.__inp = d
                elif type(self.__inp) is StringType:
                    self.__inp = [self.__inp, d]
                else:
                    self.__inp.append(d)
                self.__input_len = input_len
                return  # keep waiting for more input

            # load all previous input and d into single string inp
            if isinstance(inp, StringType):
                inp = inp + d
            elif inp is None:
                inp = d
            else:
                inp.append(d)
                inp = "".join(inp)

            offset = 0
            while (offset + msg_size) <= input_len:
                msg = inp[offset:offset + msg_size]
                offset = offset + msg_size
                if not state:
                    msg_size = struct.unpack(">I", msg)[0]
                    has_mac = msg_size & MAC_BIT
                    if has_mac:
                        msg_size ^= MAC_BIT
                        msg_size += 20
                    elif self.__hmac_send:
                        raise ValueError("Received message without MAC")
                    state = 1
                else:
                    msg_size = 4
                    state = 0
                    # Obscure:  We call message_input() with __input_lock
                    # held!!!  And message_input() may end up calling
                    # message_output(), which has its own lock.  But
                    # message_output() cannot call message_input(), so
                    # the locking order is always consistent, which
                    # prevents deadlock.  Also, message_input() may
                    # take a long time, because it can cause an
                    # incoming call to be handled.  During all this
                    # time, the __input_lock is held.  That's a good
                    # thing, because it serializes incoming calls.
                    if has_mac:
                        mac = msg[:20]
                        msg = msg[20:]
                        if self.__hmac_recv:
                            self.__hmac_recv.update(msg)
                            _mac = self.__hmac_recv.digest()
                            if mac != _mac:
                                raise ValueError("MAC failed: %r != %r" %
                                                 (_mac, mac))
                        else:
                            log("Received MAC but no session key set")
                    elif self.__hmac_send:
                        raise ValueError("Received message without MAC")
                    self.message_input(msg)

            self.__state = state
            self.__has_mac = has_mac
            self.__msg_size = msg_size
            self.__inp = inp[offset:]
            self.__input_len = input_len - offset
Example #39
0
 def error(self, exc_info):
     log("Error raised in delayed method", logging.ERROR, exc_info=True)
     self.return_error(self.msgid, 0, *exc_info[:2])
Example #40
0
File: smac.py Project: Krilivye/ZEO
    def handle_read(self):
        self.__input_lock.acquire()
        try:
            # Use a single __inp buffer and integer indexes to make this fast.
            try:
                d = self.recv(8192)
            except socket.error as err:
                if err[0] in expected_socket_read_errors:
                    return
                raise
            if not d:
                return

            input_len = self.__input_len + len(d)
            msg_size = self.__msg_size
            state = self.__state
            has_mac = self.__has_mac

            inp = self.__inp
            if msg_size > input_len:
                if inp is None:
                    self.__inp = d
                elif isinstance(self.__inp, six.binary_type):
                    self.__inp = [self.__inp, d]
                else:
                    self.__inp.append(d)
                self.__input_len = input_len
                return # keep waiting for more input

            # load all previous input and d into single string inp
            if isinstance(inp, six.binary_type):
                inp = inp + d
            elif inp is None:
                inp = d
            else:
                inp.append(d)
                inp = b"".join(inp)

            offset = 0
            while (offset + msg_size) <= input_len:
                msg = inp[offset:offset + msg_size]
                offset = offset + msg_size
                if not state:
                    msg_size = struct.unpack(">I", msg)[0]
                    has_mac = msg_size & MAC_BIT
                    if has_mac:
                        msg_size ^= MAC_BIT
                        msg_size += 20
                    elif self.__hmac_send:
                        raise ValueError("Received message without MAC")
                    state = 1
                else:
                    msg_size = 4
                    state = 0
                    # Obscure:  We call message_input() with __input_lock
                    # held!!!  And message_input() may end up calling
                    # message_output(), which has its own lock.  But
                    # message_output() cannot call message_input(), so
                    # the locking order is always consistent, which
                    # prevents deadlock.  Also, message_input() may
                    # take a long time, because it can cause an
                    # incoming call to be handled.  During all this
                    # time, the __input_lock is held.  That's a good
                    # thing, because it serializes incoming calls.
                    if has_mac:
                        mac = msg[:20]
                        msg = msg[20:]
                        if self.__hmac_recv:
                            self.__hmac_recv.update(msg)
                            _mac = self.__hmac_recv.digest()
                            if mac != _mac:
                                raise ValueError("MAC failed: %r != %r"
                                                 % (_mac, mac))
                        else:
                            log("Received MAC but no session key set")
                    elif self.__hmac_send:
                        raise ValueError("Received message without MAC")
                    self.message_input(msg)

            self.__state = state
            self.__has_mac = has_mac
            self.__msg_size = msg_size
            self.__inp = inp[offset:]
            self.__input_len = input_len - offset
        finally:
            self.__input_lock.release()
Example #41
0
 def error(self, exc_info):
     self.ready.wait()
     log("Error raised in delayed method", logging.ERROR, exc_info=exc_info)
     self.conn.call_from_thread(Delay.error, self, exc_info)
Example #42
0
 def error(self, exc_info):
     self.sent = 'error'
     log("Error raised in delayed method", logging.ERROR, exc_info=True)
     self.conn.return_error(self.msgid, *exc_info[:2])
Example #43
0
 def error(self, exc_info):
     self.sent = 'error'
     log("Error raised in delayed method", logging.ERROR, exc_info=True)
     self.conn.return_error(self.msgid, *exc_info[:2])
Example #44
0
 def handle_accept(self):
     try:
         sock, addr = self.accept()
     except socket.error, msg:
         log("accepted failed: %s" % msg)
         return
Example #45
0
class Dispatcher(asyncore.dispatcher):
    """A server that accepts incoming RPC connections"""
    __super_init = asyncore.dispatcher.__init__

    def __init__(self, addr, factory=Connection):
        self.__super_init()
        self.addr = addr
        self.factory = factory
        self._open_socket()

    def _open_socket(self):
        if type(self.addr) == types.TupleType:
            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()
        log("listening on %s" % str(self.addr), logging.INFO)
        self.bind(self.addr)
        self.listen(5)

    def writable(self):
        return 0

    def readable(self):
        return 1

    def handle_accept(self):
        try:
            sock, addr = self.accept()
        except socket.error, msg:
            log("accepted failed: %s" % msg)
            return

        # 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. :(

        # Drop flow-info from IPv6 addresses
        if addr:  # Sometimes None on Mac. See above.
            addr = addr[:2]

        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))
Example #46
0
 def error(self, exc_info):
     self.ready.wait()
     log("Error raised in delayed method", logging.ERROR, exc_info=exc_info)
     self.conn.call_from_thread(Delay.error, self, exc_info)
Example #47
0
 def error(self, exc_info):
     log("Error raised in delayed method", logging.ERROR, exc_info=True)
     self.return_error(self.msgid, 0, *exc_info[:2])
Example #48
0
 def handle_accept(self):
     try:
         sock, addr = self.accept()
     except socket.error, msg:
         log("accepted failed: %s" % msg)
         return