Ejemplo n.º 1
0
    def call(self, handle, sig_args, args, callback=None):
        """!
        @brief Do u-RPC call.

        @param handle Remote function handle.
        @param sig_args Signature of arguments.
        @param args Arguments.
        @param callback Called when u-RPC call completed.
        """
        # Decorator style
        if not callback:
            return lambda _callback: self.call(handle, sig_args, args,
                                               _callback)
        # Build u-RPC message
        msg_id = self._counters["send"]
        req = self._build_header(URPC_MSG_CALL, "send")
        # Function handle
        write_data(req, handle, URPC_TYPE_U16)
        # Arguments and types transform
        for i in range(len(sig_args)):
            t = sig_args[i]
            # URPCType subclass argument
            if isinstance(t, type) and issubclass(t, URPCType):
                t = t()
            # URPCType instance
            if isinstance(t, URPCType):
                args[i] = t.dumps(args[i])
                sig_args[i] = t.underlying_type
        # Arguments signature and arguments
        write_vary(req, sig_args)
        self._marshall(req, sig_args, args)
        # Operation callback
        self._oper_callbacks[msg_id] = callback
        # Send request message
        self._send_callback(req.getvalue())
Ejemplo n.º 2
0
    def _handle_call(self, req, msg_id):
        """!
        @brief u-RPC function call handler.

        @param req Request message stream.
        @param msg_id Request message ID.
        @return A u-RPC response message.
        """
        # Function handle
        handle = read_data(req, URPC_TYPE_U16)
        # Arguments and signature
        sig_args = read_vary(req)
        args = self._unmarshall(req, sig_args)
        # Lookup for function in store
        func = seq_get(self._funcs_store, handle)
        if not func:
            raise URPCError(URPC_ERR_NONEXIST)
        # Call function
        sig_rets, result = func(sig_args, args)
        if len(result) != len(sig_rets):
            raise URPCError(URPC_ERR_SIG_INCORRECT)
        # Response message
        res = self._build_header(URPC_MSG_CALL_RESULT, "recv")
        write_data(res, msg_id, URPC_TYPE_U16)
        # Return values and signature
        write_vary(res, sig_rets)
        self._marshall(res, sig_rets, result)
        return res
Ejemplo n.º 3
0
    def _handle_msg(self, req):
        """!
        @brief Handle received u-RPC message.

        @param req Request message stream.
        @return Response message stream.
        """
        # Message ID defaults to 0 (Unknown)
        msg_id = 0
        try:
            # Response stream
            res = None
            # Parse magic string and version
            magic_ver_byte = read_data(req, URPC_TYPE_U8)
            if (magic_ver_byte >> 4) != URPC_MAGIC:
                raise URPCError(URPC_ERR_BROKEN_MSG)
            if (magic_ver_byte & 0xf) != URPC_VERSION:
                raise URPCError(URPC_ERR_NO_SUPPORT)
            # Parse message ID and type
            msg_id = read_data(req, URPC_TYPE_U16)
            msg_type = read_data(req, URPC_TYPE_U8)
            # Call message handler
            msg_handler = _urpc_msg_handlers[msg_type]
            if not msg_handler:
                raise URPCError(URPC_ERR_NO_SUPPORT)
            return msg_handler(self, req, msg_id)
        # URPC error occured
        except URPCError as e:
            res = self._build_header(URPC_MSG_ERROR, "recv")
            # Write request message ID and error code
            write_data(res, msg_id, URPC_TYPE_U16)
            write_data(res, e.reason, URPC_TYPE_U8)
            # Return stream
            return res
Ejemplo n.º 4
0
    def _marshall(self, stream, sig, objects):
        """!
        @brief Marshall objects into data stream.

        @param stream Data stream.
        @param sig Signature of objects.
        @param objects Objects to be marshalled.
        """
        # Check signature
        if len(sig) != len(objects):
            raise URPCError(URPC_ERR_SIG_INCORRECT)
        # Marshall arguments
        for obj, obj_type in zip(objects, sig):
            # Variable length data
            if obj_type == URPC_TYPE_VARY:
                write_vary(stream, obj, "H")
            # Value types
            else:
                write_data(stream, obj, obj_type)
Ejemplo n.º 5
0
    def _handle_func_query(self, req, msg_id):
        """!
        u-RPC function query handler.

        @param req Request message stream.
        @param msg_id Request message ID.
        @return A u-RPC response message.
        """
        # Function name
        name = read_vary(req).decode("utf-8")
        # Search for function in function lookup
        handle = self._func_name_lookup.get(name)
        if handle == None:
            raise URPCError(URPC_ERR_NONEXIST)
        # Response message
        res = self._build_header(URPC_MSG_FUNC_RESP, "recv")
        write_data(res, msg_id, URPC_TYPE_U16)
        write_data(res, handle, URPC_TYPE_U16)
        return res
Ejemplo n.º 6
0
    def _build_header(self, msg_type, counter):
        """!
        @brief Build u-RPC message header.

        (When calling this function, the message counter will be updated)

        @param msg_type Message type.
        @param counter Name of the message counter to use.
        @return Response stream with message header written.
        """
        res = BytesIO()
        # Magic and protocol version
        magic_ver_byte = (URPC_MAGIC << 4) | URPC_VERSION
        write_data(res, magic_ver_byte, URPC_TYPE_U8)
        # Message ID and type
        write_data(res, self._counters[counter], URPC_TYPE_U16)
        write_data(res, msg_type, URPC_TYPE_U8)
        # Update counter
        self._counters[counter] += 1
        if self._counters[counter] >= 2**16:
            self._counters[counter] = 0
        return res