Example #1
0
 def testCustomHandshake(self):
     conn = ConnectionMock()
     class CustomHandshakeDaemon(Pyro4.core.Daemon):
         def validateHandshake(self, conn, data):
             return ["sure", "have", "fun"]
         def annotations(self):
             ann = super(CustomHandshakeDaemon, self).annotations()
             ann["XYZZ"] = b"custom annotation set by daemon"
             return ann
     with CustomHandshakeDaemon(port=0) as d:
         corr_id = uuid.uuid4()
         self.sendHandshakeMessage(conn, correlation_id=corr_id)
         self.assertNotEqual(corr_id, current_context.correlation_id)
         success = d._handshake(conn)
         self.assertTrue(success)
         self.assertEqual(corr_id, current_context.correlation_id)
         msg = Pyro4.message.Message.recv(conn, hmac_key=d._pyroHmacKey)
         self.assertEqual(Pyro4.message.MSG_CONNECTOK, msg.type)
         self.assertEqual(99, msg.seq)
         self.assertEqual(2, len(msg.annotations))
         self.assertEqual(corr_id.bytes, msg.annotations["CORR"])
         self.assertEqual(b"custom annotation set by daemon", msg.annotations["XYZZ"])
         ser = get_serializer_by_id(msg.serializer_id)
         data = ser.deserializeData(msg.data, msg.flags & Pyro4.message.FLAGS_COMPRESSED)
         self.assertEqual(["sure", "have", "fun"], data)
Example #2
0
 def testCustomHandshake(self):
     conn = ConnectionMock()
     class CustomHandshakeDaemon(Pyro4.core.Daemon):
         def validateHandshake(self, conn, data):
             return ["sure", "have", "fun"]
         def annotations(self):
             ann = super(CustomHandshakeDaemon, self).annotations()
             ann["XYZZ"] = b"custom annotation set by daemon"
             return ann
     with CustomHandshakeDaemon(port=0) as d:
         corr_id = uuid.uuid4()
         self.sendHandshakeMessage(conn, correlation_id=corr_id)
         self.assertNotEqual(corr_id, current_context.correlation_id)
         success = d._handshake(conn)
         self.assertTrue(success)
         self.assertEqual(corr_id, current_context.correlation_id)
         msg = Pyro4.message.Message.recv(conn, hmac_key=d._pyroHmacKey)
         self.assertEqual(Pyro4.message.MSG_CONNECTOK, msg.type)
         self.assertEqual(99, msg.seq)
         self.assertEqual(2, len(msg.annotations))
         self.assertEqual(corr_id.bytes, msg.annotations["CORR"])
         self.assertEqual(b"custom annotation set by daemon", msg.annotations["XYZZ"])
         ser = get_serializer_by_id(msg.serializer_id)
         data = ser.deserializeData(msg.data, msg.flags & Pyro4.message.FLAGS_COMPRESSED)
         self.assertEqual(["sure", "have", "fun"], data)
Example #3
0
 def _sendExceptionResponse(self, connection, seq, serializer_id, exc_value,
                            tbinfo):
     """send an exception back including the local traceback info"""
     exc_value._pyroTraceback = tbinfo
     if sys.platform == "cli":
         util.fixIronPythonExceptionForPickle(exc_value,
                                              True)  # piggyback attributes
     serializer = util.get_serializer_by_id(serializer_id)
     try:
         data, compressed = serializer.serializeData(exc_value)
     except:
         # the exception object couldn't be serialized, use a generic PyroError instead
         xt, xv, tb = sys.exc_info()
         msg = "Error serializing exception: %s. Original exception: %s: %s" % (
             str(xv), type(exc_value), str(exc_value))
         exc_value = errors.PyroError(msg)
         exc_value._pyroTraceback = tbinfo
         if sys.platform == "cli":
             util.fixIronPythonExceptionForPickle(
                 exc_value, True)  # piggyback attributes
         data, compressed = serializer.serializeData(exc_value)
     flags = Pyro4.message.FLAGS_EXCEPTION
     if compressed:
         flags |= Pyro4.message.FLAGS_COMPRESSED
     if Pyro4.config.LOGWIRE:
         log.debug(
             "daemon wiredata sending (error response): msgtype=%d flags=0x%x ser=%d seq=%d data=%r"
             % (Pyro4.message.MSG_RESULT, flags, serializer.serializer_id,
                seq, data))
     msg = Message(Pyro4.message.MSG_RESULT, data, serializer.serializer_id,
                   flags, seq)
     connection.send(msg.to_bytes())
Example #4
0
 def testMetaSerialization(self):
     with Pyro4.core.Daemon() as d:
         daemon_obj = d.objectsById[Pyro4.constants.DAEMON_NAME]
         meta = daemon_obj.get_metadata(Pyro4.constants.DAEMON_NAME)
         for ser_id in [Pyro4.message.SERIALIZER_JSON, Pyro4.message.SERIALIZER_MARSHAL, Pyro4.message.SERIALIZER_PICKLE, Pyro4.message.SERIALIZER_SERPENT]:
             serializer = get_serializer_by_id(ser_id)
             data = serializer.dumps(meta)
             _ = serializer.loads(data)
Example #5
0
 def testMetaSerialization(self):
     with Pyro4.core.Daemon() as d:
         daemon_obj = d.objectsById[Pyro4.constants.DAEMON_NAME]
         meta = daemon_obj.get_metadata(Pyro4.constants.DAEMON_NAME)
         for ser_id in [Pyro4.message.SERIALIZER_JSON, Pyro4.message.SERIALIZER_MARSHAL, Pyro4.message.SERIALIZER_PICKLE, Pyro4.message.SERIALIZER_SERPENT]:
             serializer = get_serializer_by_id(ser_id)
             data = serializer.dumps(meta)
             _ = serializer.loads(data)
         try:
             serializer = get_serializer_by_id(Pyro4.message.SERIALIZER_DILL)
         except SerializeError:
             # dill is optional for ironpython alone
             if sys.platform != "cli":
                 raise
         else:
             data = serializer.dumps(meta)
             _ = serializer.loads(data)
Example #6
0
 def sendHandshakeMessage(self, conn, correlation_id=None):
     ser = get_serializer_by_id(Pyro4.message.SERIALIZER_MARSHAL)
     data, _ = ser.serializeData({"handshake": "hello", "object": Pyro4.constants.DAEMON_NAME}, False)
     annotations = {"CORR": correlation_id.bytes} if correlation_id else None
     msg = Pyro4.message.Message(
         Pyro4.message.MSG_CONNECT, data, Pyro4.message.SERIALIZER_MARSHAL, 0, 99, annotations=annotations
     )
     msg.send(conn)
Example #7
0
 def __pyroCreateConnection(self, replaceUri=False):
     """
     Connects this proxy to the remote Pyro daemon. Does connection handshake.
     Returns true if a new connection was made, false if an existing one was already present.
     """
     with self.__pyroConnLock:
         if self._pyroConnection is not None:
             return False     # already connected
         from Pyro4.naming import resolve  # don't import this globally because of cyclic dependancy
         uri=resolve(self._pyroUri)
         # socket connection (normal or Unix domain socket)
         conn=None
         log.debug("connecting to %s", uri)
         connect_location=uri.sockname if uri.sockname else (uri.host, uri.port)
         with self.__pyroLock:
             try:
                 if self._pyroConnection is not None:
                     return False    # already connected
                 sock=socketutil.createSocket(connect=connect_location, reuseaddr=Pyro4.config.SOCK_REUSE, timeout=self.__pyroTimeout)
                 conn=socketutil.SocketConnection(sock, uri.object)
                 # Do handshake. For now, no need to send anything. (message type CONNECT is not yet used)
                 msg = Message.recv(conn, None)
                 # any trailing data (dataLen>0) is an error message, if any
             except Exception:
                 x=sys.exc_info()[1]
                 if conn:
                     conn.close()
                 err="cannot connect: %s" % x
                 log.error(err)
                 if isinstance(x, errors.CommunicationError):
                     raise
                 else:
                     ce = errors.CommunicationError(err)
                     ce.__cause__ = x
                     raise ce
             else:
                 if msg.type==Pyro4.message.MSG_CONNECTFAIL:
                     error="connection rejected"
                     if msg.data:
                         serializer = util.get_serializer_by_id(msg.serializer_id)
                         data = serializer.deserializeData(msg.data, compressed=msg.flags & Pyro4.message.FLAGS_COMPRESSED)
                         error += ", reason: " + data
                     conn.close()
                     log.error(error)
                     raise errors.CommunicationError(error)
                 elif msg.type==Pyro4.message.MSG_CONNECTOK:
                     self._pyroConnection=conn
                     if replaceUri:
                         self._pyroUri=uri
                     log.debug("connected to %s", self._pyroUri)
                     return True
                 else:
                     conn.close()
                     err="connect: invalid msg type %d received" % msg.type
                     log.error(err)
                     raise errors.ProtocolError(err)
Example #8
0
 def testMetaSerialization(self):
     with Pyro4.core.Daemon() as d:
         daemon_obj = d.objectsById[Pyro4.constants.DAEMON_NAME]
         meta = daemon_obj.get_metadata(Pyro4.constants.DAEMON_NAME)
         for ser_id in [Pyro4.message.SERIALIZER_JSON, Pyro4.message.SERIALIZER_MARSHAL, Pyro4.message.SERIALIZER_PICKLE, Pyro4.message.SERIALIZER_SERPENT, Pyro4.message.SERIALIZER_DILL]:
             import platform
             if platform.python_implementation() in ('IronPython', 'PyPy') and \
                ser_id == Pyro4.message.SERIALIZER_DILL:
                 continue
             serializer = get_serializer_by_id(ser_id)
             data = serializer.dumps(meta)
             _ = serializer.loads(data)
Example #9
0
 def testMetaSerialization(self):
     with Pyro4.core.Daemon() as d:
         daemon_obj = d.objectsById[Pyro4.constants.DAEMON_NAME]
         meta = daemon_obj.get_metadata(Pyro4.constants.DAEMON_NAME)
         for ser_id in [Pyro4.message.SERIALIZER_JSON, Pyro4.message.SERIALIZER_MARSHAL, Pyro4.message.SERIALIZER_PICKLE, Pyro4.message.SERIALIZER_SERPENT, Pyro4.message.SERIALIZER_DILL]:
             import platform
             if platform.python_implementation() in ('IronPython', 'PyPy') and \
                ser_id == Pyro4.message.SERIALIZER_DILL:
                 continue
             serializer = get_serializer_by_id(ser_id)
             data = serializer.dumps(meta)
             _ = serializer.loads(data)
Example #10
0
 def testMetaSerialization(self):
     with Pyro4.core.Daemon() as d:
         daemon_obj = d.objectsById[Pyro4.constants.DAEMON_NAME]
         meta = daemon_obj.get_metadata(Pyro4.constants.DAEMON_NAME)
         for ser_id in [
                 Pyro4.message.SERIALIZER_JSON,
                 Pyro4.message.SERIALIZER_MARSHAL,
                 Pyro4.message.SERIALIZER_PICKLE,
                 Pyro4.message.SERIALIZER_SERPENT
         ]:
             serializer = get_serializer_by_id(ser_id)
             data = serializer.dumps(meta)
             _ = serializer.loads(data)
Example #11
0
    def _pyro_remote_call(self, msg):
        log = logger.debug
        result = []

        # Deserialize
        request_flags = msg.flags
        request_seq = msg.seq
        serializer = util.get_serializer_by_id(msg.serializer_id)
        objId, method, vargs, kwargs = serializer.deserializeCall(msg.data, compressed=msg.flags & Pyro4.message.FLAGS_COMPRESSED)
        del msg  # invite GC to collect the object, don't wait for out-of-scope
        # Individual or batch
        log("Searching for object %s" % str(objId))
        obj = self.factory.objectsById.get(objId)
        log("Found object with type %s" % str(type(obj)))
        if obj is not None:
            # Sanitize kwargs
            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)
            if request_flags & Pyro4.message.FLAGS_BATCH:
                for method, vargs, kwargs in vargs:
                    log("Running call %s with vargs %s and kwargs %s agasint object %s" %
                        (str(method), str(vargs), str(kwargs), str(obj)))
                    response = yield self._pyro_run_call(obj, method, vargs, kwargs)
                    if isinstance(response, Exception):
                        response = _ExceptionWrapper(response)
                    result.append(response)
                # Return the final value
            else:
                log("Running call %s with vargs %s and kwargs %s agasint object %s" %
                    (str(method), str(vargs), str(kwargs), str(obj)))
                if method == "__getattr__":
                    # special case for direct attribute access (only exposed @properties are accessible)
                    result = util.get_exposed_property_value(obj, vargs[0], only_exposed=Pyro4.config.REQUIRE_EXPOSE)
                elif method == "__setattr__":
                    # special case for direct attribute access (only exposed @properties are accessible)
                    result = util.set_exposed_property_value(obj, vargs[0], vargs[1], only_exposed=Pyro4.config.REQUIRE_EXPOSE)
                else:
                    result = yield self._pyro_run_call(obj, method, vargs, kwargs)
                    if isinstance(result, Failure):
                        exception = result.type(result.value)
                        exception._pyroTraceback = result.tb
                        result = exception
            log("Returning result %s from _remote_call" % pformat(result))
            defer.returnValue(result)
        else:
            log("unknown object requested: %s", objId)
            raise Pyro4.core.errors.DaemonError("unknown object")
Example #12
0
 def sendHandshakeMessage(self, conn, correlation_id=None):
     ser = get_serializer_by_id(Pyro4.message.SERIALIZER_MARSHAL)
     data, _ = ser.serializeData(
         {
             "handshake": "hello",
             "object": Pyro4.constants.DAEMON_NAME
         }, False)
     annotations = {
         "CORR": correlation_id.bytes
     } if correlation_id else None
     msg = Pyro4.message.Message(Pyro4.message.MSG_CONNECT,
                                 data,
                                 Pyro4.message.SERIALIZER_MARSHAL,
                                 0,
                                 99,
                                 annotations=annotations)
     msg.send(conn)
Example #13
0
    def _build_response(self, result):
        log = logger.debug
        # Determine appropriate response type
        if self.request.type == message.MSG_PING:
            msg_type = message.MSG_PING
        elif self.request.type == message.MSG_INVOKE:
            msg_type = message.MSG_RESULT
        else:
            err = "Attempting to respond to invalid message type."
            log.exception(err)
            raise errors.ProtocolError(err)

        flags = 0

        # Serialize and set flags
        serializer = util.get_serializer_by_id(self.request.serializer_id)
        try:
            data, compressed = serializer.serializeData(result)
        except:
            # the exception object couldn't be serialized, use a generic PyroError instead
            xt, xv, tb = sys.exc_info()
            msg = "Error serializing exception: %s. Original exception: %s: %s" % (str(xv), type(xv), str(xv))
            exc_value = errors.PyroError(msg)
            exc_value._pyroTraceback = tb
            if sys.platform == "cli":
                util.fixIronPythonExceptionForPickle(exc_value, True)  # piggyback attributes
            data, compressed = serializer.serializeData(exc_value)
        if compressed:
            flags |= message.FLAGS_COMPRESSED
        if self.request.flags & Pyro4.message.FLAGS_BATCH:
            flags |= Pyro4.message.FLAGS_BATCH

        if isinstance(result, Exception):
            flags = message.FLAGS_EXCEPTION
            if Pyro4.config.LOGWIRE:
                log("daemon wiredata sending (error response): msgtype=%d flags=0x%x ser=%d seq=%d data=%r" %
                          (msg_type, flags, serializer.serializer_id, self.request.seq, data))
        elif self.request.type == message.MSG_PING or self.request.type == message.MSG_INVOKE:
            if Pyro4.config.LOGWIRE:
                log("daemon wiredata sending: msgtype=%d flags=0x%x ser=%d seq=%d data=%r" %
                          (msg_type, flags, serializer.serializer_id, self.request.seq, data))

        return Message(msg_type, data, serializer.serializer_id, flags, self.request.seq)
Example #14
0
 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.
     """
     request_flags = 0
     request_seq = 0
     request_serializer_id = util.MarshalSerializer.serializer_id
     wasBatched = False
     isCallback = False
     try:
         msg = Message.recv(
             conn, [Pyro4.message.MSG_INVOKE, Pyro4.message.MSG_PING])
         request_flags = msg.flags
         request_seq = msg.seq
         request_serializer_id = msg.serializer_id
         if Pyro4.config.LOGWIRE:
             log.debug(
                 "daemon wiredata received: msgtype=%d flags=0x%x ser=%d seq=%d data=%r"
                 % (msg.type, msg.flags, msg.serializer_id, msg.seq,
                    msg.data))
         if msg.type == Pyro4.message.MSG_PING:
             # return same seq, but ignore any data (it's a ping, not an echo). Nothing is deserialized.
             msg = Message(Pyro4.message.MSG_PING, b"pong",
                           msg.serializer_id, 0, msg.seq)
             if Pyro4.config.LOGWIRE:
                 log.debug(
                     "daemon wiredata sending: msgtype=%d flags=0x%x ser=%d seq=%d data=%r"
                     % (msg.type, msg.flags, msg.serializer_id, msg.seq,
                        msg.data))
             conn.send(msg.to_bytes())
             return
         if msg.serializer_id not in self.__serializer_ids:
             raise errors.ProtocolError(
                 "message used serializer that is not accepted: %d" %
                 msg.serializer_id)
         serializer = util.get_serializer_by_id(msg.serializer_id)
         objId, method, vargs, kwargs = serializer.deserializeCall(
             msg.data,
             compressed=msg.flags & Pyro4.message.FLAGS_COMPRESSED)
         del msg  # invite GC to collect the object, don't wait for out-of-scope
         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)
             if request_flags & Pyro4.message.FLAGS_BATCH:
                 # batched method calls, loop over them all and collect all results
                 data = []
                 for method, vargs, kwargs in vargs:
                     method = util.resolveDottedAttribute(
                         obj, method, Pyro4.config.DOTTEDNAMES)
                     try:
                         result = method(
                             *vargs, **kwargs
                         )  # this is the actual method call to the Pyro object
                     except Exception:
                         xt, xv = sys.exc_info()[0:2]
                         log.debug(
                             "Exception occurred while handling batched request: %s",
                             xv)
                         xv._pyroTraceback = util.formatTraceback(
                             detailed=Pyro4.config.DETAILED_TRACEBACK)
                         if sys.platform == "cli":
                             util.fixIronPythonExceptionForPickle(
                                 xv, True)  # piggyback attributes
                         data.append(futures._ExceptionWrapper(xv))
                         break  # stop processing the rest of the batch
                     else:
                         data.append(result)
                 wasBatched = True
             else:
                 # normal single method call
                 method = util.resolveDottedAttribute(
                     obj, method, Pyro4.config.DOTTEDNAMES)
                 if request_flags & Pyro4.message.FLAGS_ONEWAY and Pyro4.config.ONEWAY_THREADED:
                     # oneway call to be run inside its own thread
                     thread = threadutil.Thread(target=method,
                                                args=vargs,
                                                kwargs=kwargs)
                     thread.setDaemon(True)
                     thread.start()
                 else:
                     isCallback = getattr(method, "_pyroCallback", False)
                     data = method(
                         *vargs, **kwargs
                     )  # this is the actual method call to the Pyro object
         else:
             log.debug("unknown object requested: %s", objId)
             raise errors.DaemonError("unknown object")
         if request_flags & Pyro4.message.FLAGS_ONEWAY:
             return  # oneway call, don't send a response
         else:
             data, compressed = serializer.serializeData(
                 data, compress=Pyro4.config.COMPRESSION)
             response_flags = 0
             if compressed:
                 response_flags |= Pyro4.message.FLAGS_COMPRESSED
             if wasBatched:
                 response_flags |= Pyro4.message.FLAGS_BATCH
             if Pyro4.config.LOGWIRE:
                 log.debug(
                     "daemon wiredata sending: msgtype=%d flags=0x%x ser=%d seq=%d data=%r"
                     % (Pyro4.message.MSG_RESULT, response_flags,
                        serializer.serializer_id, request_seq, data))
             msg = Message(Pyro4.message.MSG_RESULT, data,
                           serializer.serializer_id, response_flags,
                           request_seq)
             conn.send(msg.to_bytes())
     except Exception:
         xt, xv = sys.exc_info()[0:2]
         if xt is not errors.ConnectionClosedError:
             log.debug("Exception occurred while handling request: %r", xv)
             if not request_flags & Pyro4.message.FLAGS_ONEWAY:
                 # only return the error to the client if it wasn't a oneway call
                 tblines = util.formatTraceback(
                     detailed=Pyro4.config.DETAILED_TRACEBACK)
                 self._sendExceptionResponse(conn, request_seq,
                                             request_serializer_id, xv,
                                             tblines)
         if isCallback or isinstance(
                 xv, (errors.CommunicationError, errors.SecurityError)):
             raise  # re-raise if flagged as callback, communication or security error.