예제 #1
0
파일: core.py 프로젝트: adityax10/Pyro4
 def parseMessageHeader(cls, headerData):
     """Parses a message header. Returns a tuple of messagetype, messageflags, sequencenumber, datalength, datahmac."""
     if not headerData or len(headerData)!=cls.HEADERSIZE:
         raise errors.ProtocolError("header data size mismatch")
     tag, ver, msgType, flags, seq, dataLen, headerchecksum, datahmac = struct.unpack(cls.headerFmt, headerData)
     if tag!=cls.pyro_tag or ver!=constants.PROTOCOL_VERSION:
         raise errors.ProtocolError("invalid data or unsupported protocol version")
     if headerchecksum!=(msgType+ver+dataLen+flags+seq+MessageFactory.MAGIC)&0xffff:
         raise errors.ProtocolError("header checksum mismatch")
     return msgType, flags, seq, dataLen, datahmac
예제 #2
0
 def from_header(cls, headerData):
     """Parses a message header. Does not yet process the annotations chunks and message data."""
     if not headerData or len(headerData)!=cls.header_size:
         raise errors.ProtocolError("header data size mismatch")
     tag, ver, msg_type, flags, seq, data_size, serializer_id, annotations_size, _, checksum = struct.unpack(cls.header_format, headerData)
     if tag!=b"PYRO" or ver!=constants.PROTOCOL_VERSION:
         raise errors.ProtocolError("invalid data or unsupported protocol version")
     if checksum!=(msg_type+ver+data_size+annotations_size+flags+serializer_id+seq+cls.checksum_magic)&0xffff:
         raise errors.ProtocolError("header checksum mismatch")
     msg = Message(msg_type, b"", serializer_id, flags, seq)
     msg.data_size = data_size
     msg.annotations_size = annotations_size
     return msg
예제 #3
0
 def __init__(self,
              msgType,
              databytes,
              serializer_id,
              flags,
              seq,
              annotations=None,
              hmac_key=None):
     self.type = msgType
     self.flags = flags
     self.seq = seq
     self.data = databytes
     self.data_size = len(self.data)
     self.serializer_id = serializer_id
     self.annotations = annotations or {}
     self.hmac_key = hmac_key
     if self.hmac_key:
         self.annotations["HMAC"] = self.hmac()
     self.annotations_size = sum(
         [6 + len(v) for v in self.annotations.values()])
     if 0 < Pyro4.config.MAX_MESSAGE_SIZE < (self.data_size +
                                             self.annotations_size):
         raise errors.ProtocolError(
             "max message size exceeded (%d where max=%d)" %
             (self.data_size + self.annotations_size,
              Pyro4.config.MAX_MESSAGE_SIZE))
예제 #4
0
 def recv(cls, connection, requiredMsgTypes=None, hmac_key=None):
     """
     Receives a pyro message from a given connection.
     Accepts the given message types (None=any, or pass a sequence).
     Also reads annotation chunks and the actual payload data.
     Validates a HMAC chunk if present.
     """
     msg = cls.from_header(connection.recv(cls.header_size))
     msg.hmac_key = hmac_key
     if 0 < Pyro4.config.MAX_MESSAGE_SIZE < (msg.data_size +
                                             msg.annotations_size):
         errorMsg = "max message size exceeded (%d where max=%d)" % (
             msg.data_size + msg.annotations_size,
             Pyro4.config.MAX_MESSAGE_SIZE)
         log.error("connection " + str(connection) + ": " + errorMsg)
         connection.close(
         )  # close the socket because at this point we can't return the correct sequence number for returning an error message
         raise errors.ProtocolError(errorMsg)
     if requiredMsgTypes and msg.type not in requiredMsgTypes:
         err = "invalid msg type %d received" % msg.type
         log.error(err)
         raise errors.ProtocolError(err)
     if msg.annotations_size:
         # read annotation chunks
         annotations_data = connection.recv(msg.annotations_size)
         msg.annotations = {}
         i = 0
         while i < msg.annotations_size:
             anno, length = struct.unpack("!4sH", annotations_data[i:i + 6])
             if sys.version_info >= (3, 0):
                 anno = anno.decode("ASCII")
             msg.annotations[anno] = annotations_data[i + 6:i + 6 + length]
             i += 6 + length
     # read data
     msg.data = connection.recv(msg.data_size)
     if "HMAC" in msg.annotations and hmac_key:
         if msg.annotations["HMAC"] != msg.hmac():
             raise errors.SecurityError("message hmac mismatch")
     elif ("HMAC" in msg.annotations) != bool(hmac_key):
         # Not allowed: message contains hmac but hmac_key is not set, or vice versa.
         err = "hmac key config not symmetric"
         log.warning(err)
         raise errors.SecurityError(err)
     return msg
예제 #5
0
파일: core.py 프로젝트: niccokunzmann/ping
 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)
예제 #6
0
파일: core.py 프로젝트: adityax10/Pyro4
 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.
                 msgType, flags, seq, data = MessageFactory.getMessage(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:
                     raise errors.CommunicationError(err)
             else:
                 if msgType==MessageFactory.MSG_CONNECTFAIL:
                     error="connection rejected"
                     if data:
                         if sys.version_info>=(3,0):
                             data=str(data,"utf-8")
                         error+=", reason: "+data
                     conn.close()
                     log.error(error)
                     raise errors.CommunicationError(error)
                 elif msgType==MessageFactory.MSG_CONNECTOK:
                     self._pyroConnection=conn
                     if replaceUri:
                         log.debug("replacing uri with bound one")
                         self._pyroUri=uri
                     log.debug("connected to %s", self._pyroUri)
                     return True
                 else:
                     conn.close()
                     err="connect: invalid msg type %d received" % msgType
                     log.error(err)
                     raise errors.ProtocolError(err)
예제 #7
0
 def __annotations_bytes(self):
     if self.annotations:
         a = []
         for k, v in self.annotations.items():
             if len(k) != 4:
                 raise errors.ProtocolError("annotation key must be of length 4")
             if sys.version_info >= (3, 0):
                 k = k.encode("ASCII")
             a.append(struct.pack("!4sH", k, len(v)))
             a.append(v)
         return b"".join(a)
     return b""
예제 #8
0
파일: core.py 프로젝트: adityax10/Pyro4
 def createMessage(cls, msgType, databytes, flags, seq):
     """creates a message containing a header followed by the given databytes"""
     databytes=databytes or cls.empty_bytes
     if 0 < Pyro4.config.MAX_MESSAGE_SIZE < len(databytes):
         raise errors.ProtocolError("max message size exceeded (%d where max=%d)" % (len(databytes), Pyro4.config.MAX_MESSAGE_SIZE))
     if Pyro4.config.HMAC_KEY:
         flags|=MessageFactory.FLAGS_HMAC
         bodyhmac=hmac.new(Pyro4.config.HMAC_KEY, databytes, digestmod=hashlib.sha1).digest()
     else:
         bodyhmac=MessageFactory.empty_hmac
     headerchecksum=(msgType+constants.PROTOCOL_VERSION+len(databytes)+flags+seq+MessageFactory.MAGIC)&0xffff
     msg=struct.pack(cls.headerFmt, cls.pyro_tag, constants.PROTOCOL_VERSION, msgType, flags, seq, len(databytes), headerchecksum, bodyhmac)
     return msg+databytes
예제 #9
0
파일: core.py 프로젝트: adityax10/Pyro4
 def getMessage(cls, connection, requiredMsgType):
     headerdata = connection.recv(cls.HEADERSIZE)
     msgType, flags, seq, datalen, datahmac = cls.parseMessageHeader(headerdata)
     if 0 < Pyro4.config.MAX_MESSAGE_SIZE < datalen:
         errorMsg = "max message size exceeded (%d where max=%d)" % (datalen, Pyro4.config.MAX_MESSAGE_SIZE)
         log.error("connection "+str(connection)+": "+errorMsg)
         connection.close()   # close the socket because at this point we can't return the correct sequence number for returning an error message
         raise errors.ProtocolError(errorMsg)
     if requiredMsgType is not None and msgType != requiredMsgType:
         err="invalid msg type %d received" % msgType
         log.error(err)
         raise errors.ProtocolError(err)
     databytes=connection.recv(datalen)
     local_hmac_set=Pyro4.config.HMAC_KEY is not None and len(Pyro4.config.HMAC_KEY) > 0
     if flags&MessageFactory.FLAGS_HMAC and local_hmac_set:
         if datahmac != hmac.new(Pyro4.config.HMAC_KEY, databytes, digestmod=hashlib.sha1).digest():
             raise errors.SecurityError("message hmac mismatch")
     elif flags&MessageFactory.FLAGS_HMAC != local_hmac_set:
         # Message contains hmac and local HMAC_KEY not set, or vice versa. This is not allowed.
         err="hmac key config not symmetric"
         log.warn(err)
         raise errors.SecurityError(err)
     return msgType, flags, seq, databytes
예제 #10
0
파일: core.py 프로젝트: niccokunzmann/ping
 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
예제 #11
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.
예제 #12
0
 def __pyroCheckSequence(self, seq):
     if seq != self._pyroSeq:
         err = "invoke: reply sequence out of sync, got %d expected %d" % (
             seq, self._pyroSeq)
         log.error(err)
         raise errors.ProtocolError(err)