Room Manager 0.1
room reservation management system
|
Protocol specification for the roomman RPC. More...
#define | ROOMMAN_RPC_PROT_VERSION (0xC8) |
Current Version of the roomman RPC protocol. | |
#define | ROOMMAN_RPC_PROT_HEADER_SIZE (8) |
Size in byte of the RPC protocol header. | |
#define | ROOMMAN_RPC_MASK_FLAG_ERROR (0x02) |
Bit mask for the error flag (set if the message is an error) | |
#define | ROOMMAN_RPC_MASK_FLAG_RESPONSE (0x01) |
Bit mask for the response flag (set if the message is a response) | |
#define | ROOMMAN_RPC_MASK_FLAG_REQUEST (0x00) |
Bit mask if message is an normal request message. | |
#define | ROOMMAN_RPC_FUNCID_SET_USERNAME (0x0001) |
id for the roomman_set_username() RPC call | |
#define | ROOMMAN_RPC_FUNCID_CREATE (0x0002) |
id for the roomman_create_room() RPC call | |
#define | ROOMMAN_RPC_FUNCID_DELETE (0x0003) |
id for the roomman_delete_room() RPC call | |
#define | ROOMMAN_RPC_FUNCID_UPDATE_CAPACITY (0x0004) |
id for the roomman_update_capacity() RPC call | |
#define | ROOMMAN_RPC_FUNCID_RESERVE (0x0005) |
id for the roomman_reserve_room() RPC call | |
#define | ROOMMAN_RPC_FUNCID_CLEAR (0x0006) |
id for the roomman_clear_reservation() RPC call | |
#define | ROOMMAN_RPC_FUNCID_ADD_PERSONS (0x0007) |
id for the roomman_add_persons() RPC call | |
#define | ROOMMAN_RPC_FUNCID_REMOVE_PERSONS (0x0008) |
id for the roomman_remove_persons() RPC call | |
#define | ROOMMAN_RPC_FUNCID_LOOKUP (0x0009) |
id for the roomman_lookup() RPC call | |
#define | ROOMMAN_RPC_FUNCID_READENTRY (0x000a) |
id for the roomman_readentry() RPC call | |
#define | ROOMMAN_RPC_FUNCID_DIRECTORY (0x000b) |
id for the roomman_directory() RPC call | |
Protocol specification for the roomman RPC.
This file is to be included by all applications implementing the roomman RPC protocol. It defines necessary IDs and the protocol itself.
This file specifices the protocol to offer the functionality of the roomman libary over an RPC mechanism for remote users.
The RPC server provides access to the roomman lib functionality and offers the roomman lib functions as RPC calls.
One successfull RPC call consists of one request message sent by the client and a response message sent by the server.
The request message identifies the requested roomman lib call and provides the necessary in parameters of the function.
The server unmarshals the request and the provided parameters and calls the requested roomman lib function with the given parameters. The server creates a response message, marshals the return and all out parameters of the called roomman lib function and sends it to the client.
The following sequence diagram gives an abstract overview of the procedure for the function roomman_create_room()
+-------+ +-----------+ +-----------+ +-------------+ | Main | | RPCClient | | RPCServer | | RoomManLib | +-------+ +-----------+ +-----------+ +-------------+ | | | | | roomman_create_room() | | |------------------>| | | | | createRequestMsg() | | | |------------------- | | | | | | | | |<------------------ | | | | sendRequest | | | |------------------------->| | | | | unmarshalRequest | | | |----------------- | | | | | | | | |<---------------- | | | | roomman_create_room() | | | |------------------------>| | | | | | | | return | | | |<------------------------| | | | | | | | marshallResponse | | | |----------------- | | | | | | | | |<---------------- | | | sendResponse | | | |<-------------------------| | | | unmarshalResponse | | | |------------------ | | | | | | | | |<----------------- | | | return | | | |<------------------| | | | | | |
If the called roomman lib function returns an error, a special error message is constructed and send to the client as response!
The messages of the roomman RPC protocol consists of a common header and the encoded payload. For each primitive data type and the necessary composite data types an encoding is defined in the following subsections.
A signed integer has the size of 32 bit. It is encoded in the normal network byte order (Big Endian).
(MSB) (LSB) +-------+-------+-------+-------+ |byte 0 |byte 1 |byte 2 |byte 3 | int32_t +-------+-------+-------+-------+ <------------32 bits------------>
An unsigned integer has the size of 32 bit. It is encoded in the normal network byte order (Big Endian).
(MSB) (LSB) +-------+-------+-------+-------+ |byte 0 |byte 1 |byte 2 |byte 3 | uint32_t +-------+-------+-------+-------+ <------------32 bits------------>
A signed short has the size of 16 bit. It is encoded in the normal network byte order (Big Endian).
(MSB) (LSB) +-------+-------+ |byte 0 |byte 1 | int16_t +-------+-------+ <----16 bits---->
An unsigned short has the size of 16 bit. It is encoded in the normal network byte order (Big Endian).
(MSB) (LSB) +-------+-------+ |byte 0 |byte 1 | uint16_t +-------+-------+ <----16 bits---->
Strings are transmitted as US-ASCII with one byte per character.
Since the roomman lib uses strings with a fixed size it is necessary to always transmit the maximum amount of bytes, even if the number of actually valid characters is less.
This means if the string "Hello" with 5 + 1 characters (+1 for the string terminating zero byte) is to be transmitted and if the fixed string size is 32 bytes, then the whole 32 bytes must transmitted.
IMPORTANT: all remaining bytes not used for characters must be set to zero!
0 1 ... +--------+--------+...+--------+--------+...+--------+ | byte 0 | byte 1 |...|byte n-1| 0 |...| 0 | +--------+--------+...+--------+--------+...+--------+ |<-----------n bytes---------->|<------r bytes------>| |<-----------n+r (where (n+r) = fixed length)------------>| FIXED-LENGTH STRING
For example the string "Harald" with a fixed length of 32 (31 + at least one \0) should be transmitted as
0x48 0x61 0x72 0x61 0x6c 0x64 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
The members of a c struct are encoded sequentially in the same order as within the struct with their appropriate encoding method. A padding must not be added. If the native representation of a struct within memory includes a padding, it has to be removed.
structs are implicitly typed, therefore the identifier is not transmitted.
struct { component-declaration-A; component-declaration-B; ... } identifier;
+-------------+-------------+... | component A | component B |... STRUCTURE +-------------+-------------+..
The header of the roomman RPC protocol has a fixed size of 8 bytes. The header is the same for all RPC requests as well as for responses.
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------------------------------------------------------+ | Version | Flags | Msg-ID | +---------------------------------------------------------------+ | Payload-Length | RPC-Call-ID | +---------------------------------------------------------------+ | ~ ~ Payload (Payload-Length * bytes) | +---------------------------------------------------------------+
The second byte of the header is used for flags.
The first bit indicates the type of a message. If it is not set (and no error flag), then the message is a request. If it is set, the message is a reponse.
The second bit indicates an error message. If it is set, the reponse contains an error code. For a request the error bit shall not be set.
The remaining bits are reserved for future use and shall not be used.
Each request shall have an ID. The corresponding response shall use the same ID. Seperate requests, at least in one session, should not have the same ID.
The message ID has the size of 16 bits and is an unsigned integer.
The length of the payload following the header is encoded in an unsigned 16 bit integer. Therefore it is not possible to send messages with more than 65535 bytes of payload.
The size of the header is not part of the encoded payload lenght!
Each of the roomman libary functions has an assigned ID. This ID is used to specify the nature of the request and the corresponding reponse.
If a client wants to call a roomman libary function by RPC, the ID of this function must be used. The server's response must use the same ID.
The payload is marshalled after the header into the RPC message. It contains the arguments of the called roomman libary functions.
The arguments are marshalled in the order of the parameter list of the function prototype. The corresponding encodings for the data type must be used. The parameter name is not part of the payload!
This applies to request messages as well as to response messages! It is necessary to differenciate between "in", "out" and "inout" parameters.
A request message contains all the arguments with an in and inout direction assigned.
A response message starts with the result value! After the return value the out and inout arguments are marshalled in the order of their position in the parameter list of the function call. If there is no out or inout parameter, only the return value is part of the payload!
The data of the payload is not aligned, padding must not be used!
An RPC request is sent by the client to the server and contains the message header and the encoded arguments of the roomman libary function to be called.
As an example the function roomman_readentry shall be called with the argument 23 for the ID parameter. The parameters building, name, and capacity are output parameters and therefore not part of the request message!
int16_t roomman_readentry(roomid_t ID, char* building, char* name, uint16_t* capacity)
There should be separate encoding functions for each possible datatype. These should return the size of the encoded data in bytes. This can be used to simplify the encoding sequence. If "b" is the pointer to the byte buffer to store the message and "size" contains the amount of encoded bytes so far, the encoding functions can be called in the following manner:
The following figure is an abstract example of a possible (simplified!) call sequence to create a request message.
+-------+ +-----------+ +---------+ +-----------+ | Main | | RPCClient | | Helper | | RPCServer | +-------+ +-----------+ +---------+ +-----------+ | | | | | roomman_readentry(ID, &b, &r, &c) | | |------------------------>| | | | | createReadEntryRequestMsg() | | | |---------------------------- | | | | | | | | |<--------------------------- | | | | | | | | encode_octet(b,0xC8) // header version | | | |----------------------------------------->| | | | return size = 1| | | |<-----------------------------------------| | | | encode_octet(b,0) // flags | | | |----------------------------------------->| | | | return size = 1 | | | |<-----------------------------------------| | | | encode_uint16(b,msg-id) | | | |----------------------------------------->| | | | return size = 2 | | | |<-----------------------------------------| | | | | | | | encode_uint16(b,4) //payload len = 4 | | | |----------------------------------------->| | | | return size = 2 | | | |<-----------------------------------------| | | | encode_uint16(b,ROOMMAN_RPC_FUNCID_READ) | | | |----------------------------------------->| | | | return size = 2| | | |<-----------------------------------------| | | | encode_uint32(b,ID) // payload in-para | | | |----------------------------------------->| | | | return size = 4 | | | |<-----------------------------------------| | | | | | | | sendRequest | | | |------------------------------------------------------>| | | | |
On the receiver side the request message has to be unmarshalled. There should be seperate decoding functions returning the size for the data types as well.
The following abstract (and simplified!!) diagram shows the sequence of the decoding.
+-----------+ +-----------+ +---------+ | RPCClient | | RPCServer | | Helper | +-----------+ +-----------+ +---------+ | | | | sendRequest | | |------------------>| | | | receiveBytes(8) // receive header | | |---------------- | | | | | | |<--------------- | | | decode_octet(b,&version) | | |--------------------------------------->| | | return size = 1 | | |<---------------------------------------| | | decode_octet(b,&flags) | | |--------------------------------------->| | | return size = 1 | | |<---------------------------------------| | | decode_uint16(b,&msg_id) | | |--------------------------------------->| | | return size = 2 | | |<---------------------------------------| | | decode_uint16(b,&pay_size) | | |--------------------------------------->| | | return size = 2 | | |<---------------------------------------| | | decode_uint16(b,&rpc_func_id) | | |--------------------------------------->| | | return size = 2 | | |<---------------------------------------| | | receiveBytes(pay_size) // payload | | |---------------------------------- | | | | | | |<--------------------------------- | | | decodeReadEntry | | |---------------- | | | | | | |<--------------- | | | decode_uint32(b,&room_id) | | |--------------------------------------->| | | return size = 4| | |<---------------------------------------| | | |
After the server has executed the requested roomman libary function call, it assembles a response message and sends it to the requesting client.
To continue the example the call of roomman_readentry() shall have returned two strings and an integer value.
Since these values are passed as out paramaters they have to be part of the payload
The call of the function was sucessfull, therefore the return value is "0" or "1". The return value have to be the first encoded data in the payload!
The following abstract (and simplified!!) diagram shows the sequence of the encoding.
+-----------+ +-----------+ +---------+ | RPCClient | | RPCServer | | Helper | +-----------+ +-----------+ +---------+ | | | | | handleReadEntry | | |---------------- | | | | | | |<--------------- | | | createReadEntryRespMsg() | | |------------------------- | | | | | | |<------------------------ | | | encode_octet(b,0xC8) // version | | |---------------------------------------->| | | return size = 1 | | |<----------------------------------------| | | encode_octet(b,ROOM..._FLAG_RESPONSE) | | |---------------------------------------->| | | return size = 1 | | |<----------------------------------------| | | encode_uint16(b,msg_id) //msg id of req | | |---------------------------------------->| | | return size = 2 | | |<----------------------------------------| | | encode_uint16(b,134) // size payload | | |---------------------------------------->| | | return size = 2 | | |<----------------------------------------| | | encode_uint16(b,ROOMMAN_RPC_FUNCID_READ)| | |---------------------------------------->| | | return size = 2 | | |<----------------------------------------| | | encode_int16(b,0) // return code value | | |---------------------------------------->| | | return size = 2 | | |<----------------------------------------| | | encode_sstring(b,"BCN",32) // building | | |---------------------------------------->| | | return size = 32| | |<----------------------------------------| | | encode_sstring(b,"331",32) // room | | |---------------------------------------->| | | return size = 32| | |<----------------------------------------| | | encode_uint16(b,32) // occupied| | |---------------------------------------->| | | return size = 2 | | |<----------------------------------------| | | encode_uint16(b,32) // capacity| | |---------------------------------------->| | | return size = 2 | | |<----------------------------------------| | | encode_sstring(b,"",32) // reserved_by | | |---------------------------------------->| | | return size = 32| | |<----------------------------------------| | | | | sendResponse | | |<-------------------| | | | |
The steps to be taken for decoding at the client side is analogous.
In case the roomman libary function returned an error, an error message is created an returned.
The difference to an normal response message is:
#define ROOMMAN_RPC_FUNCID_ADD_PERSONS (0x0007) |
id for the roomman_add_persons() RPC call
Definition at line 64 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_CLEAR (0x0006) |
id for the roomman_clear_reservation() RPC call
Definition at line 63 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_CREATE (0x0002) |
id for the roomman_create_room() RPC call
Definition at line 59 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_DELETE (0x0003) |
id for the roomman_delete_room() RPC call
Definition at line 60 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_DIRECTORY (0x000b) |
id for the roomman_directory() RPC call
Definition at line 68 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_LOOKUP (0x0009) |
id for the roomman_lookup() RPC call
Definition at line 66 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_READENTRY (0x000a) |
id for the roomman_readentry() RPC call
Definition at line 67 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_REMOVE_PERSONS (0x0008) |
id for the roomman_remove_persons() RPC call
Definition at line 65 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_RESERVE (0x0005) |
id for the roomman_reserve_room() RPC call
Definition at line 62 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_SET_USERNAME (0x0001) |
id for the roomman_set_username() RPC call
Specification of the RPC-Call-IDs for the supported roommanlib functions
Definition at line 58 of file roommanprotocol.h.
#define ROOMMAN_RPC_FUNCID_UPDATE_CAPACITY (0x0004) |
id for the roomman_update_capacity() RPC call
Definition at line 61 of file roommanprotocol.h.
#define ROOMMAN_RPC_MASK_FLAG_ERROR (0x02) |
Bit mask for the error flag (set if the message is an error)
Bit masks for the protocol flags
Definition at line 45 of file roommanprotocol.h.
#define ROOMMAN_RPC_MASK_FLAG_REQUEST (0x00) |
Bit mask if message is an normal request message.
Definition at line 47 of file roommanprotocol.h.
#define ROOMMAN_RPC_MASK_FLAG_RESPONSE (0x01) |
Bit mask for the response flag (set if the message is a response)
Definition at line 46 of file roommanprotocol.h.
#define ROOMMAN_RPC_PROT_HEADER_SIZE (8) |
Size in byte of the RPC protocol header.
Definition at line 37 of file roommanprotocol.h.
#define ROOMMAN_RPC_PROT_VERSION (0xC8) |
Current Version of the roomman RPC protocol.
Definition at line 35 of file roommanprotocol.h.