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())
def _pyro_run_call(obj, method, vargs, kwargs): log = logger.debug try: method = util.getAttribute(obj, method) return method(*vargs, **kwargs) # this is the actual method call to the Pyro object except Exception: xt, xv = sys.exc_info()[0:2] log("Exception occurred while handling request: %s", xv) xv._pyroTraceback = util.formatTraceback(detailed=Pyro4.config.DETAILED_TRACEBACK) if sys.platform == "cli": util.fixIronPythonExceptionForPickle(xv, True) # piggyback attributes return xv
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() if methodname in self._pyroAsyncs: flags |= MessageFactory.FLAGS_ASYNC future = futures.ClientFuture(self) # daemon needed to register the special asynchronous calls if not self._pyroFutureDaemon: self.__pyroCreateFutureDaemon() self._pyroFutureDaemon.register(future) logging.debug("Going to send client future %s", self._pyroFutureDaemon.uriFor(future)) vargs = (future,) + vargs # special way to send the future data, compressed=self._pyroSerializer.serialize( (self._pyroConnection.objectId, methodname, vargs, kwargs), compress=Pyro4.config.COMPRESSION) if compressed: flags |= MessageFactory.FLAGS_COMPRESSED if methodname in self._pyroOneway: flags |= MessageFactory.FLAGS_ONEWAY with self.__pyroLock: self._pyroSeq=(self._pyroSeq+1)&0xffff data=MessageFactory.createMessage(MessageFactory.MSG_INVOKE, data, flags, self._pyroSeq) try: self._pyroConnection.send(data) del data # invite GC to collect the object, don't wait for out-of-scope if flags & MessageFactory.FLAGS_ONEWAY: return None # oneway call, no response data # TODO methods marked both oneway and isasync should returning an ImmediateFuture with None as result elif flags & MessageFactory.FLAGS_ASYNC: return future else: msgType, flags, seq, data = MessageFactory.getMessage(self._pyroConnection, MessageFactory.MSG_RESULT) self.__pyroCheckSequence(seq) data=self._pyroSerializer.deserialize(data, compressed=flags & MessageFactory.FLAGS_COMPRESSED) if flags & MessageFactory.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
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
def _sendExceptionResponse(self, connection, seq, 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 try: data, _=self.serializer.serialize(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, _=self.serializer.serialize(exc_value) msg=MessageFactory.createMessage(MessageFactory.MSG_RESULT, data, MessageFactory.FLAGS_EXCEPTION, seq) del data connection.send(msg)
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)
def raiseIt(self): if sys.platform=="cli": util.fixIronPythonExceptionForPickle(self.exception, False) raise self.exception
def raiseIt(self): if sys.platform == "cli": util.fixIronPythonExceptionForPickle(self.exception, False) raise self.exception
def raiseIt(self): from Pyro4.util import fixIronPythonExceptionForPickle # XXX circular if sys.platform == "cli": fixIronPythonExceptionForPickle(self.exception, False) raise self.exception
def raiseIt(self): from Pyro4.util import fixIronPythonExceptionForPickle # XXX circular if sys.platform == "cli": fixIronPythonExceptionForPickle(self.exception, False) raise self.exception
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.
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 seq=0 wasBatched=False isCallback=False client_future = None try: msgType, flags, seq, data = MessageFactory.getMessage(conn, MessageFactory.MSG_INVOKE) objId, method, vargs, kwargs=self.serializer.deserialize( data, compressed=flags & MessageFactory.FLAGS_COMPRESSED) del data # invite GC to collect the object, don't wait for out-of-scope obj=self.objectsById.get(objId) if flags & MessageFactory.FLAGS_ASYNC: client_future = vargs[0] client_future._pyroOneway.update(["set_cancelled", "set_result", "set_exception", "set_progress"]) vargs = vargs[1:] elif flags & MessageFactory.FLAGS_ASYNC_CANCEL: client_future_uri = vargs[0] 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 flags & MessageFactory.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 elif flags & MessageFactory.FLAGS_ASYNC_CANCEL: data=self._cancelFuture(client_future_uri) else: # normal single method call method=util.resolveDottedAttribute(obj, method, Pyro4.config.DOTTEDNAMES) if flags & MessageFactory.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() elif flags & MessageFactory.FLAGS_ASYNC: future=method(*vargs, **kwargs) self._followFuture(future, client_future) 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 flags & MessageFactory.FLAGS_ONEWAY: return # oneway call, don't send a response elif flags & MessageFactory.FLAGS_ASYNC: return # async call, don't send a response yet else: data, compressed=self.serializer.serialize(data, compress=Pyro4.config.COMPRESSION) flags=0 if compressed: flags |= MessageFactory.FLAGS_COMPRESSED if wasBatched: flags |= MessageFactory.FLAGS_BATCH msg=MessageFactory.createMessage(MessageFactory.MSG_RESULT, data, flags, seq) del data conn.send(msg) except Exception as ex: xt,xv=sys.exc_info()[0:2] if xt is not errors.ConnectionClosedError: log.debug("Exception occurred while handling request: %r", xv) if client_future is not None: # send exception to the client future client_future.set_exception(ex) elif not flags & MessageFactory.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, seq, xv, tblines) if isCallback or isinstance(xv, (errors.CommunicationError, errors.SecurityError)): raise # re-raise if flagged as callback, communication or security error.