Exemplo n.º 1
0
class Daemon(object):
    """
    Pyro daemon. Contains server side logic and dispatches incoming remote method calls
    to the appropriate objects.
    """
    def __init__(self, host=None, port=0):
        if host is None:
            host=Pyro.config.HOST
        if Pyro.config.SERVERTYPE=="thread":
            self.transportServer=SocketServer_Threadpool(self, host, port, Pyro.config.COMMTIMEOUT)
        elif Pyro.config.SERVERTYPE=="select":
            self.transportServer=SocketServer_Select(self, host, port, Pyro.config.COMMTIMEOUT)
        else:
            raise Pyro.errors.PyroError("invalid server type '%s'" % Pyro.config.SERVERTYPE)
        self.locationStr=self.transportServer.locationStr
        log.debug("created daemon on %s", self.locationStr) 
        self.serializer=Pyro.util.Serializer()
        pyroObject=DaemonObject(self)
        pyroObject._pyroId=Pyro.constants.DAEMON_NAME
        self.objectsById={pyroObject._pyroId: pyroObject}
        self.__mustshutdown=False
        self.__loopstopped=threadutil.Event()
        self.__loopstopped.set()

    def fileno(self):
        return self.transportServer.fileno()
    @property
    def sock(self):
        return self.transportServer.sock

    def requestLoop(self, loopCondition=lambda:True):
        """
        Goes in a loop to service incoming requests, until someone breaks this
        or calls shutdown from another thread.
        """  
        self.__mustshutdown=False
        log.info("daemon %s entering requestloop", self.locationStr)
        try:
            self.__loopstopped.clear()
            condition=lambda: not self.__mustshutdown and loopCondition()
            self.transportServer.requestLoop(loopCondition=condition)
        finally:
            self.__loopstopped.set()
        log.debug("daemon exits requestloop")

    def handleRequests(self):
        return self.transportServer.handleRequests()

    def shutdown(self):
        """Cleanly terminate a deamon that is running in the requestloop. It must be running
        in a different thread, or this method will deadlock."""
        log.debug("daemon shutting down")
        self.__mustshutdown=True
        self.pingConnection()
        time.sleep(0.05)
        self.close()
        self.__loopstopped.wait()
        log.info("daemon %s shut down", self.locationStr)

    def pingConnection(self):
        """bit of a hack to trigger a blocking server to get out of the loop, useful at clean shutdowns"""
        self.transportServer.pingConnection()

    def handshake(self, conn):
        if not Pyro.config.CONNECTHANDSHAKE:
            return True
        """Perform connection handshake with new clients"""
        header=conn.recv(MessageFactory.HEADERSIZE)
        msgType,flags,dataLen=MessageFactory.parseMessageHeader(header) #@UnusedVariable (pydev)
        if msgType!=MessageFactory.MSG_CONNECT:
            err="expected MSG_CONNECT message, got %d" % msgType
            log.warn(err)
            raise Pyro.errors.ProtocolError(err)
        if dataLen>0:
            conn.recv(dataLen) # read away any trailing data (unused at the moment)
        msg=MessageFactory.createMessage(MessageFactory.MSG_CONNECTOK,None,0)
        conn.send(msg)
        return True

    def handleRequest(self, conn):
        """
        Handle incoming Pyro request. Catches any exception that may occur and
        wraps it in a reply to the calling side, as to not make this server side loop
        terminate due to exceptions caused by remote invocations.
        """
        flags=0
        try:
            header=conn.recv(MessageFactory.HEADERSIZE)
            msgType,flags,dataLen=MessageFactory.parseMessageHeader(header)
            if msgType!=MessageFactory.MSG_INVOKE:
                err="handlerequest: invalid msg type %d received" % msgType
                log.warn(err)
                raise Pyro.errors.ProtocolError(err)
            data=conn.recv(dataLen)
            objId, method, vargs, kwargs=self.serializer.deserialize(
                                           data,compressed=flags & MessageFactory.FLAGS_COMPRESSED)
            obj=self.objectsById.get(objId)
            if obj is not None:
                if kwargs and sys.version_info<(2,6,5) and os.name!="java":
                    # Python before 2.6.5 doesn't accept unicode keyword arguments
                    kwargs = dict((str(k),kwargs[k]) for k in kwargs)
                log.debug("calling %s.%s",obj.__class__.__name__,method)
                obj=Pyro.util.resolveDottedAttribute(obj,method,Pyro.config.DOTTEDNAMES)
                if flags & MessageFactory.FLAGS_ONEWAY and Pyro.config.ONEWAY_THREADED:
                    # oneway call to be run inside its own thread
                    thread=threadutil.Thread(target=obj, args=vargs, kwargs=kwargs)
                    thread.setDaemon(True)
                    thread.start()
                else:
                    data=obj(*vargs,**kwargs)   # this is the actual method call to the Pyro object
            else:
                log.debug("unknown object requested: %s",objId)
                raise Pyro.errors.DaemonError("unknown object")
            if flags & MessageFactory.FLAGS_ONEWAY:
                return   # oneway call, don't send a response
            else:
                data,compressed=self.serializer.serialize(data,compress=Pyro.config.COMPRESSION)
                flags=0
                if compressed:
                    flags |= MessageFactory.FLAGS_COMPRESSED
                msg=MessageFactory.createMessage(MessageFactory.MSG_RESULT, data, flags)
                del data
                conn.send(msg)
        except Pyro.errors.CommunicationError,x:
            # communication errors are not handled here (including TimeoutError)
            raise
        except Exception,x:
            # all other errors are caught
            log.debug("Exception occurred while handling request: %s",x)
            if not flags & MessageFactory.FLAGS_ONEWAY:
                # only return the error to the client if it wasn't a oneway call
                tblines=Pyro.util.formatTraceback(detailed=Pyro.config.DETAILED_TRACEBACK)
                self.sendExceptionResponse(conn, x, tblines)
Exemplo n.º 2
0
class Daemon(object):
    """
    Pyro daemon. Contains server side logic and dispatches incoming remote method calls
    to the appropriate objects.
    """
    def __init__(self, host=None, port=0):
        if host is None:
            host = Pyro.config.HOST
        if Pyro.config.SERVERTYPE == "thread":
            self.transportServer = SocketServer_Threadpool(
                self, host, port, Pyro.config.COMMTIMEOUT)
        elif Pyro.config.SERVERTYPE == "select":
            self.transportServer = SocketServer_Select(self, host, port,
                                                       Pyro.config.COMMTIMEOUT)
        else:
            raise Pyro.errors.PyroError("invalid server type '%s'" %
                                        Pyro.config.SERVERTYPE)
        self.locationStr = self.transportServer.locationStr
        log.debug("created daemon on %s", self.locationStr)
        self.serializer = Pyro.util.Serializer()
        pyroObject = DaemonObject(self)
        pyroObject._pyroId = Pyro.constants.DAEMON_NAME
        self.objectsById = {pyroObject._pyroId: pyroObject}
        self.__mustshutdown = False
        self.__loopstopped = threadutil.Event()
        self.__loopstopped.set()

    def fileno(self):
        return self.transportServer.fileno()

    @property
    def sock(self):
        return self.transportServer.sock

    def requestLoop(self, loopCondition=lambda: True):
        """
        Goes in a loop to service incoming requests, until someone breaks this
        or calls shutdown from another thread.
        """
        self.__mustshutdown = False
        log.info("daemon %s entering requestloop", self.locationStr)
        try:
            self.__loopstopped.clear()
            condition = lambda: not self.__mustshutdown and loopCondition()
            self.transportServer.requestLoop(loopCondition=condition)
        finally:
            self.__loopstopped.set()
        log.debug("daemon exits requestloop")

    def handleRequests(self):
        return self.transportServer.handleRequests()

    def shutdown(self):
        """Cleanly terminate a deamon that is running in the requestloop. It must be running
        in a different thread, or this method will deadlock."""
        log.debug("daemon shutting down")
        self.__mustshutdown = True
        self.pingConnection()
        time.sleep(0.05)
        self.close()
        self.__loopstopped.wait()
        log.info("daemon %s shut down", self.locationStr)

    def pingConnection(self):
        """bit of a hack to trigger a blocking server to get out of the loop, useful at clean shutdowns"""
        self.transportServer.pingConnection()

    def handshake(self, conn):
        if not Pyro.config.CONNECTHANDSHAKE:
            return True
        """Perform connection handshake with new clients"""
        header = conn.recv(MessageFactory.HEADERSIZE)
        msgType, flags, dataLen = MessageFactory.parseMessageHeader(
            header)  #@UnusedVariable (pydev)
        if msgType != MessageFactory.MSG_CONNECT:
            err = "expected MSG_CONNECT message, got %d" % msgType
            log.warn(err)
            raise Pyro.errors.ProtocolError(err)
        if dataLen > 0:
            conn.recv(
                dataLen)  # read away any trailing data (unused at the moment)
        msg = MessageFactory.createMessage(MessageFactory.MSG_CONNECTOK, None,
                                           0)
        conn.send(msg)
        return True

    def handleRequest(self, conn):
        """
        Handle incoming Pyro request. Catches any exception that may occur and
        wraps it in a reply to the calling side, as to not make this server side loop
        terminate due to exceptions caused by remote invocations.
        """
        flags = 0
        try:
            header = conn.recv(MessageFactory.HEADERSIZE)
            msgType, flags, dataLen = MessageFactory.parseMessageHeader(header)
            if msgType != MessageFactory.MSG_INVOKE:
                err = "handlerequest: invalid msg type %d received" % msgType
                log.warn(err)
                raise Pyro.errors.ProtocolError(err)
            data = conn.recv(dataLen)
            objId, method, vargs, kwargs = self.serializer.deserialize(
                data, compressed=flags & MessageFactory.FLAGS_COMPRESSED)
            obj = self.objectsById.get(objId)
            if obj is not None:
                if kwargs and sys.version_info < (2, 6,
                                                  5) and os.name != "java":
                    # Python before 2.6.5 doesn't accept unicode keyword arguments
                    kwargs = dict((str(k), kwargs[k]) for k in kwargs)
                log.debug("calling %s.%s", obj.__class__.__name__, method)
                obj = Pyro.util.resolveDottedAttribute(obj, method,
                                                       Pyro.config.DOTTEDNAMES)
                if flags & MessageFactory.FLAGS_ONEWAY and Pyro.config.ONEWAY_THREADED:
                    # oneway call to be run inside its own thread
                    thread = threadutil.Thread(target=obj,
                                               args=vargs,
                                               kwargs=kwargs)
                    thread.setDaemon(True)
                    thread.start()
                else:
                    data = obj(
                        *vargs, **kwargs
                    )  # this is the actual method call to the Pyro object
            else:
                log.debug("unknown object requested: %s", objId)
                raise Pyro.errors.DaemonError("unknown object")
            if flags & MessageFactory.FLAGS_ONEWAY:
                return  # oneway call, don't send a response
            else:
                data, compressed = self.serializer.serialize(
                    data, compress=Pyro.config.COMPRESSION)
                flags = 0
                if compressed:
                    flags |= MessageFactory.FLAGS_COMPRESSED
                msg = MessageFactory.createMessage(MessageFactory.MSG_RESULT,
                                                   data, flags)
                del data
                conn.send(msg)
        except Pyro.errors.CommunicationError, x:
            # communication errors are not handled here (including TimeoutError)
            raise
        except Exception, x:
            # all other errors are caught
            log.debug("Exception occurred while handling request: %s", x)
            if not flags & MessageFactory.FLAGS_ONEWAY:
                # only return the error to the client if it wasn't a oneway call
                tblines = Pyro.util.formatTraceback(
                    detailed=Pyro.config.DETAILED_TRACEBACK)
                self.sendExceptionResponse(conn, x, tblines)