Example #1
0
 def testAnnotationsIdLength4(self):
     try:
         msg = Message(Pyro4.message.MSG_CONNECT, b"hello", self.ser.serializer_id, 0, 0, {"TOOLONG": b"abcde"}, b"secret")
         _ = msg.to_bytes()
         self.fail("should fail, too long")
     except Pyro4.errors.ProtocolError:
         pass
     try:
         msg = Message(Pyro4.message.MSG_CONNECT, b"hello", self.ser.serializer_id, 0, 0, {"QQ": b"abcde"}, b"secret")
         _ = msg.to_bytes()
         self.fail("should fail, too short")
     except Pyro4.errors.ProtocolError:
         pass
Example #2
0
 def testAnnotationsIdLength4(self):
     try:
         msg = Message(Pyro4.message.MSG_CONNECT, b"hello",
                       self.ser.serializer_id, 0, 0, {"TOOLONG": b"abcde"})
         data = msg.to_bytes()
         self.fail("should fail, too long")
     except Pyro4.errors.ProtocolError:
         pass
     try:
         msg = Message(Pyro4.message.MSG_CONNECT, b"hello",
                       self.ser.serializer_id, 0, 0, {"QQ": b"abcde"})
         data = msg.to_bytes()
         self.fail("should fail, too short")
     except Pyro4.errors.ProtocolError:
         pass
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 testRecvNoAnnotations(self):
     msg = Message(Pyro4.message.MSG_CONNECT, b"hello", 42, 0, 0)
     c = ConnectionMock()
     c.send(msg.to_bytes())
     msg = Message.recv(c)
     self.assertEqual(0, len(c.received))
     self.assertEqual(5, msg.data_size)
     self.assertEqual(b"hello", msg.data)
     self.assertEqual(0, msg.annotations_size)
     self.assertEqual(0, len(msg.annotations))
Example #5
0
 def testMessageHeaderDatasize(self):
     msg = Message(Pyro4.message.MSG_RESULT, b"hello", 12345, 60006, 30003)
     msg.data_size = 0x12345678  # hack it to a large value to see if it comes back ok
     hdr = msg.to_bytes()[:24]
     msg = Message.from_header(hdr)
     self.assertEqual(Pyro4.message.MSG_RESULT, msg.type)
     self.assertEqual(60006, msg.flags)
     self.assertEqual(0x12345678, msg.data_size)
     self.assertEqual(12345, msg.serializer_id)
     self.assertEqual(30003, msg.seq)
Example #6
0
 def testRecvNoAnnotations(self):
     msg = Message(Pyro4.message.MSG_CONNECT, b"hello", 42, 0, 0)
     c = ConnectionMock()
     c.send(msg.to_bytes())
     msg = Message.recv(c)
     self.assertEqual(0, len(c.received))
     self.assertEqual(5, msg.data_size)
     self.assertEqual(b"hello", msg.data)
     self.assertEqual(0, msg.annotations_size)
     self.assertEqual(0, len(msg.annotations))
Example #7
0
 def testMessageHeaderDatasize(self):
     msg = Message(Pyro4.message.MSG_RESULT, b"hello", 12345, 60006, 30003, hmac_key=b"secret")
     msg.data_size = 0x12345678  # hack it to a large value to see if it comes back ok
     hdr = msg.to_bytes()[:24]
     msg = Message.from_header(hdr)
     self.assertEqual(Pyro4.message.MSG_RESULT, msg.type)
     self.assertEqual(60006, msg.flags)
     self.assertEqual(0x12345678, msg.data_size)
     self.assertEqual(12345, msg.serializer_id)
     self.assertEqual(30003, msg.seq)
Example #8
0
 def testRecvAnnotations(self):
     annotations = {"TEST": b"abcde"}
     msg = Message(Pyro4.message.MSG_CONNECT, b"hello", self.ser.serializer_id, 0, 0, annotations, b"secret")
     c = ConnectionMock()
     c.send(msg.to_bytes())
     msg = Message.recv(c, hmac_key=b"secret")
     self.assertEqual(0, len(c.received))
     self.assertEqual(5, msg.data_size)
     self.assertEqual(b"hello", msg.data)
     self.assertEqual(b"abcde", msg.annotations["TEST"])
     self.assertIn("HMAC", msg.annotations)
Example #9
0
 def testRecvAnnotations(self):
     annotations = { b"TEST": b"abcde" }
     msg = Message(Pyro4.message.MSG_CONNECT, b"hello", self.ser.serializer_id, 0, 0, annotations)
     c = ConnectionMock()
     c.send(msg.to_bytes())
     msg = Message.recv(c)
     self.assertEquals(0, len(c.received))
     self.assertEquals(5, msg.data_size)
     self.assertEquals(b"hello", msg.data)
     self.assertEquals(b"abcde", msg.annotations[b"TEST"])
     self.assertTrue(b"HMAC" in msg.annotations)
Example #10
0
 def testAnnotations(self):
     annotations = {"TEST": b"abcde"}
     msg = Message(Pyro4.message.MSG_CONNECT, b"hello", self.ser.serializer_id, 0, 0, annotations, b"secret")
     data = msg.to_bytes()
     annotations_size = 4 + 2 + 20 + 4 + 2 + 5
     self.assertEqual(msg.header_size + 5 + annotations_size, len(data))
     self.assertEqual(annotations_size, msg.annotations_size)
     self.assertEqual(2, len(msg.annotations))
     self.assertEqual(b"abcde", msg.annotations["TEST"])
     mac = pyrohmac(b"hello", b"secret", annotations)
     self.assertEqual(mac, msg.annotations["HMAC"])
Example #11
0
 def testAnnotations(self):
     annotations = {"TEST": b"abcde"}
     msg = Message(Pyro4.message.MSG_CONNECT, b"hello",
                   self.ser.serializer_id, 0, 0, annotations)
     data = msg.to_bytes()
     annotations_size = 4 + 2 + 20 + 4 + 2 + 5
     self.assertEqual(msg.header_size + 5 + annotations_size, len(data))
     self.assertEqual(annotations_size, msg.annotations_size)
     self.assertEqual(2, len(msg.annotations))
     self.assertEqual(b"abcde", msg.annotations["TEST"])
     mac = pyrohmac(b"hello", annotations)
     self.assertEqual(mac, msg.annotations["HMAC"])
Example #12
0
 def _handshake(self, conn):
     """Perform connection handshake with new clients"""
     # For now, client is not sending anything. Just respond with a CONNECT_OK.
     # We need a minimal amount of data or the socket will remain blocked
     # on some systems... (messages smaller than 40 bytes)
     # Return True for successful handshake, False if something was wrong.
     # We default to the marshal serializer to send message payload of "ok"
     ser = util.get_serializer("marshal")
     data = ser.dumps("ok")
     msg = Message(Pyro4.message.MSG_CONNECTOK, data, ser.serializer_id, 0, 1)
     conn.send(msg.to_bytes())
     return True
Example #13
0
 def testRecvAnnotations(self):
     annotations = {"TEST": b"abcde"}
     msg = Message(Pyro4.message.MSG_CONNECT, b"hello",
                   self.ser.serializer_id, 0, 0, annotations)
     c = ConnectionMock()
     c.send(msg.to_bytes())
     msg = Message.recv(c)
     self.assertEqual(0, len(c.received))
     self.assertEqual(5, msg.data_size)
     self.assertEqual(b"hello", msg.data)
     self.assertEqual(b"abcde", msg.annotations["TEST"])
     self.assertTrue("HMAC" in msg.annotations)
Example #14
0
 def testChecksum(self):
     msg = Message(Pyro4.message.MSG_RESULT, b"test", 42, 0, 1, hmac_key=b"secret")
     c = ConnectionMock()
     c.send(msg.to_bytes())
     # corrupt the checksum bytes
     data = c.received
     data = data[:msg.header_size - 2] + b'\x00\x00' + data[msg.header_size:]
     c = ConnectionMock(data)
     try:
         Message.recv(c)
         self.fail("crash expected")
     except Pyro4.errors.ProtocolError as x:
         self.assertIn("checksum", str(x))
Example #15
0
 def connectionMade(self):
     """
     Handshake - should replicate Pyro4.Daemon._handshake()
     """
     log = logger.debug
     if self.state == "server":
         log("Connection made with Pyro4Protocol")
         log("... attempting handshake")
         ser = util.get_serializer("marshal")
         data = ser.dumps("ok")
         msg = Message(Pyro4.message.MSG_CONNECTOK, data, ser.serializer_id, 0, 1)
         self.transport.write(msg.to_bytes())
         self.state = "header"
Example #16
0
    def testMessage(self):
        Message(99, b"", self.ser.serializer_id, 0,
                0)  # doesn't check msg type here
        self.assertRaises(Pyro4.errors.ProtocolError, Message.from_header,
                          "FOOBAR")
        msg = Message(Pyro4.message.MSG_CONNECT, b"hello",
                      self.ser.serializer_id, 0, 0)
        self.assertEqual(Pyro4.message.MSG_CONNECT, msg.type)
        self.assertEqual(5, msg.data_size)
        self.assertEqual(b"hello", msg.data)
        self.assertEqual(4 + 2 + 20, msg.annotations_size)
        mac = pyrohmac(b"hello", msg.annotations)
        self.assertDictEqual({"HMAC": mac}, msg.annotations)

        hdr = msg.to_bytes()[:24]
        msg = Message.from_header(hdr)
        self.assertEqual(Pyro4.message.MSG_CONNECT, msg.type)
        self.assertEqual(4 + 2 + 20, msg.annotations_size)
        self.assertEqual(5, msg.data_size)

        hdr = Message(Pyro4.message.MSG_RESULT, b"", self.ser.serializer_id, 0,
                      0).to_bytes()[:24]
        msg = Message.from_header(hdr)
        self.assertEqual(Pyro4.message.MSG_RESULT, msg.type)
        self.assertEqual(4 + 2 + 20, msg.annotations_size)
        self.assertEqual(0, msg.data_size)

        hdr = Message(Pyro4.message.MSG_RESULT, b"hello", 12345, 60006,
                      30003).to_bytes()[:24]
        msg = Message.from_header(hdr)
        self.assertEqual(Pyro4.message.MSG_RESULT, msg.type)
        self.assertEqual(60006, msg.flags)
        self.assertEqual(5, msg.data_size)
        self.assertEqual(12345, msg.serializer_id)
        self.assertEqual(30003, msg.seq)

        msg = Message(255, b"", self.ser.serializer_id, 0, 255).to_bytes()
        self.assertEqual(50, len(msg))
        msg = Message(1, b"", self.ser.serializer_id, 0, 255).to_bytes()
        self.assertEqual(50, len(msg))
        msg = Message(1, b"", self.ser.serializer_id, flags=253,
                      seq=254).to_bytes()
        self.assertEqual(50, len(msg))

        # compression is a job of the code supplying the data, so the messagefactory should leave it untouched
        data = b"x" * 1000
        msg = Message(Pyro4.message.MSG_INVOKE, data, self.ser.serializer_id,
                      0, 0).to_bytes()
        msg2 = Message(Pyro4.message.MSG_INVOKE, data, self.ser.serializer_id,
                       Pyro4.message.FLAGS_COMPRESSED, 0).to_bytes()
        self.assertEqual(len(msg), len(msg2))
Example #17
0
 def testChecksum(self):
     msg = Message(Pyro4.message.MSG_RESULT, b"test", 42, 0, 1)
     c = ConnectionMock()
     c.send(msg.to_bytes())
     # corrupt the checksum bytes
     data = c.received
     data = data[:msg.header_size -
                 2] + b'\x00\x00' + data[msg.header_size:]
     c = ConnectionMock(data)
     try:
         Message.recv(c)
         self.fail("crash expected")
     except Pyro4.errors.ProtocolError as x:
         self.assertTrue("checksum" in str(x))
Example #18
0
    def testMessage(self):
        Message(99, b"", self.ser.serializer_id, 0, 0, hmac_key=b"secret")  # doesn't check msg type here
        self.assertRaises(Pyro4.errors.ProtocolError, Message.from_header, "FOOBAR")
        msg = Message(Pyro4.message.MSG_CONNECT, b"hello", self.ser.serializer_id, 0, 0, hmac_key=b"secret")
        self.assertEqual(Pyro4.message.MSG_CONNECT, msg.type)
        self.assertEqual(5, msg.data_size)
        self.assertEqual(b"hello", msg.data)
        self.assertEqual(4 + 2 + 20, msg.annotations_size)
        mac = pyrohmac(b"hello", b"secret", msg.annotations)
        self.assertDictEqual({"HMAC": mac}, msg.annotations)

        hdr = msg.to_bytes()[:24]
        msg = Message.from_header(hdr)
        self.assertEqual(Pyro4.message.MSG_CONNECT, msg.type)
        self.assertEqual(4 + 2 + 20, msg.annotations_size)
        self.assertEqual(5, msg.data_size)

        hdr = Message(Pyro4.message.MSG_RESULT, b"", self.ser.serializer_id, 0, 0, hmac_key=b"secret").to_bytes()[:24]
        msg = Message.from_header(hdr)
        self.assertEqual(Pyro4.message.MSG_RESULT, msg.type)
        self.assertEqual(4 + 2 + 20, msg.annotations_size)
        self.assertEqual(0, msg.data_size)

        hdr = Message(Pyro4.message.MSG_RESULT, b"hello", 12345, 60006, 30003, hmac_key=b"secret").to_bytes()[:24]
        msg = Message.from_header(hdr)
        self.assertEqual(Pyro4.message.MSG_RESULT, msg.type)
        self.assertEqual(60006, msg.flags)
        self.assertEqual(5, msg.data_size)
        self.assertEqual(12345, msg.serializer_id)
        self.assertEqual(30003, msg.seq)

        msg = Message(255, b"", self.ser.serializer_id, 0, 255, hmac_key=b"secret").to_bytes()
        self.assertEqual(50, len(msg))
        msg = Message(1, b"", self.ser.serializer_id, 0, 255, hmac_key=b"secret").to_bytes()
        self.assertEqual(50, len(msg))
        msg = Message(1, b"", self.ser.serializer_id, flags=253, seq=254, hmac_key=b"secret").to_bytes()
        self.assertEqual(50, len(msg))

        # compression is a job of the code supplying the data, so the messagefactory should leave it untouched
        data = b"x" * 1000
        msg = Message(Pyro4.message.MSG_INVOKE, data, self.ser.serializer_id, 0, 0, hmac_key=b"secret").to_bytes()
        msg2 = Message(
            Pyro4.message.MSG_INVOKE,
            data,
            self.ser.serializer_id,
            Pyro4.message.FLAGS_COMPRESSED,
            0,
            hmac_key=b"secret",
        ).to_bytes()
        self.assertEqual(len(msg), len(msg2))
Example #19
0
 def _pyroInvoke(self, methodname, vargs, kwargs, flags=0):
     """perform the remote method call communication"""
     if self._pyroConnection is None:
         # rebind here, don't do it from inside the invoke because deadlock will occur
         self.__pyroCreateConnection()
     serializer = util.get_serializer(Pyro4.config.SERIALIZER)
     data, compressed = serializer.serializeCall(
         self._pyroConnection.objectId, methodname, vargs, kwargs,
         compress=Pyro4.config.COMPRESSION)
     if compressed:
         flags |= Pyro4.message.FLAGS_COMPRESSED
     if methodname in self._pyroOneway:
         flags |= Pyro4.message.FLAGS_ONEWAY
     with self.__pyroLock:
         self._pyroSeq=(self._pyroSeq+1)&0xffff
         if Pyro4.config.LOGWIRE:
             log.debug("proxy wiredata sending: msgtype=%d flags=0x%x ser=%d seq=%d data=%r" % (Pyro4.message.MSG_INVOKE, flags, serializer.serializer_id, self._pyroSeq, data))
         msg = Message(Pyro4.message.MSG_INVOKE, data, serializer.serializer_id, flags, self._pyroSeq)
         try:
             self._pyroConnection.send(msg.to_bytes())
             del msg  # invite GC to collect the object, don't wait for out-of-scope
             if flags & Pyro4.message.FLAGS_ONEWAY:
                 return None    # oneway call, no response data
             else:
                 msg = Message.recv(self._pyroConnection, [Pyro4.message.MSG_RESULT])
                 if Pyro4.config.LOGWIRE:
                     log.debug("proxy wiredata received: msgtype=%d flags=0x%x ser=%d seq=%d data=%r" % (msg.type, msg.flags, msg.serializer_id, msg.seq, msg.data))
                 self.__pyroCheckSequence(msg.seq)
                 if msg.serializer_id != serializer.serializer_id:
                     error = "invalid serializer in response: %d" % msg.serializer_id
                     log.error(error)
                     raise errors.ProtocolError(error)
                 data = serializer.deserializeData(msg.data, compressed=msg.flags & Pyro4.message.FLAGS_COMPRESSED)
                 if msg.flags & Pyro4.message.FLAGS_EXCEPTION:
                     if sys.platform=="cli":
                         util.fixIronPythonExceptionForPickle(data, False)
                     raise data
                 else:
                     return data
         except (errors.CommunicationError, KeyboardInterrupt):
             # Communication error during read. To avoid corrupt transfers, we close the connection.
             # Otherwise we might receive the previous reply as a result of a new methodcall!
             # Special case for keyboardinterrupt: people pressing ^C to abort the client
             # may be catching the keyboardinterrupt in their code. We should probably be on the
             # safe side and release the proxy connection in this case too, because they might
             # be reusing the proxy object after catching the exception...
             self._pyroRelease()
             raise
Example #20
0
 def testMaxDataSize(self):
     msg = Message(Pyro4.message.MSG_CONNECT, b"hello", 42, 0, 0)
     msg.data_size = 0x7fffffff  # still within 32 bits signed limits
     msg.to_bytes()
     msg.data_size = 0x80000000  # overflow, Pyro has a 2 gigabyte message size limitation
     with self.assertRaises(ValueError) as ex:
         msg.to_bytes()
     self.assertEqual("invalid message size (outside range 0..2Gb)", str(ex.exception))
     msg.data_size = -42
     with self.assertRaises(ValueError) as ex:
         msg.to_bytes()
     self.assertEqual("invalid message size (outside range 0..2Gb)", str(ex.exception))
Example #21
0
 def testMaxDataSize(self):
     msg = Message(Pyro4.message.MSG_CONNECT, b"hello", 42, 0, 0)
     msg.data_size = 0x7fffffff  # still within 32 bits signed limits
     msg.to_bytes()
     msg.data_size = 0x80000000  # overflow, Pyro has a 2 gigabyte message size limitation
     with self.assertRaises(ValueError) as ex:
         msg.to_bytes()
     self.assertEqual("invalid message size (outside range 0..2Gb)",
                      str(ex.exception))
     msg.data_size = -42
     with self.assertRaises(ValueError) as ex:
         msg.to_bytes()
     self.assertEqual("invalid message size (outside range 0..2Gb)",
                      str(ex.exception))
Example #22
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.