2011-04-08 12:27:39 +00:00
|
|
|
Introduction
|
2011-05-18 03:06:01 +00:00
|
|
|
============
|
2011-04-08 12:27:39 +00:00
|
|
|
|
|
|
|
Searpc is a simple C language RPC framework based on GObject system. Searpc
|
|
|
|
handles the serialization/deserialization part of RPC, the transport
|
|
|
|
part is left to users.
|
|
|
|
|
|
|
|
The serialization/deserialization uses JSON format via json-glib
|
|
|
|
library. A JsonObject is returned from server to client after
|
|
|
|
executing the RPC function. Each RPC function defined in the server side should
|
|
|
|
take an extra GError argument to report error. The returned JsonObject
|
|
|
|
contains three fields:
|
|
|
|
|
|
|
|
* **ret**: the return value of the RPC function
|
|
|
|
* **err_code**: error code. This field is only set if the RPC function
|
|
|
|
reports an error.
|
|
|
|
* **err_msg**: error message. This field is only set if the RPC function
|
|
|
|
reports an error.
|
|
|
|
|
2011-04-09 03:04:02 +00:00
|
|
|
|
|
|
|
|
2011-04-08 12:27:39 +00:00
|
|
|
Example
|
|
|
|
======
|
|
|
|
|
|
|
|
Client
|
|
|
|
------
|
|
|
|
|
|
|
|
In the client side, you need to:
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
* Define your RPC function with our marco.
|
2011-04-08 12:27:39 +00:00
|
|
|
* write code to send the request to server and get the resonpse from it.
|
|
|
|
|
|
|
|
|
|
|
|
### Define your RPC function ###
|
|
|
|
|
|
|
|
The client define RPC functions using macros defined in
|
2011-05-18 03:06:01 +00:00
|
|
|
`searpc-client.h`. To call the functions, the client needs to create
|
2011-04-08 12:27:39 +00:00
|
|
|
a SearpcClient object and supply a transport function. For example:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* define a RPC function which takes a string argument and returns
|
2011-05-18 03:06:01 +00:00
|
|
|
* an integer. The xxx_INT__STRING naming convention is used to
|
2011-04-08 12:27:39 +00:00
|
|
|
* indicate the types of the param(string) and the return value(int).
|
|
|
|
*/
|
2011-05-18 03:06:01 +00:00
|
|
|
SEARPC_CLIENT_DEFUN_INT__STRING(searpc_strlen)
|
2011-04-08 12:27:39 +00:00
|
|
|
|
|
|
|
/* create an rpc_client and supply the transport function. */
|
|
|
|
SearpcClient *rpc_client;
|
|
|
|
rpc_client = searpc_client_new();
|
|
|
|
rpc_client->transport = transport_callback;
|
|
|
|
rpc_client->arg = &sockfd;
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
The `SEARPC_CLIENT_DEFUN_XXX__YYY` macro defines a client side RPC function.
|
2011-04-08 12:27:39 +00:00
|
|
|
**XXX** stands for the return type and **YYY** stands for the param type. If there
|
|
|
|
are multiple params, just append every param type there. For example,
|
2011-05-18 03:06:01 +00:00
|
|
|
`SEARPC_CLIENT_DEFUN_INT__STRING_STRING` defines a RPC function which takes two
|
2011-04-08 12:27:39 +00:00
|
|
|
string params and returns an integer value.
|
|
|
|
|
|
|
|
|
|
|
|
### Transport function ###
|
|
|
|
|
|
|
|
When the client-side function is called, Searpc does the following work:
|
|
|
|
|
|
|
|
* Pack the function name and the params into JSON data format.
|
|
|
|
* Call your transport function to send the JSON data
|
|
|
|
to the server, and get the returned data from the server.
|
|
|
|
* Unpack the returned JSON data and return the value as the return
|
|
|
|
value of the client-side function.
|
|
|
|
|
|
|
|
Your transport function is supposed to:
|
|
|
|
|
|
|
|
* Send the request data to the server.
|
|
|
|
* Receive the returned data from the server.
|
|
|
|
|
|
|
|
The prototype of the transport function is:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* arg: rpc_client->arg. Normally a socket number.
|
|
|
|
* fcall_str: the JSON data stream generated by Searpc.
|
2011-05-18 03:06:01 +00:00
|
|
|
* fcall_len: the length of `fcall_str`.
|
2011-04-08 12:27:39 +00:00
|
|
|
* ret_len: place to get the length of the returned json data stream.
|
2011-05-18 03:06:01 +00:00
|
|
|
* Returns: A newly allocated string stores the JSON data stream.
|
|
|
|
*/
|
2011-04-08 12:27:39 +00:00
|
|
|
static char *transport_callback (void *arg, const char *fcall_str, size_t fcall_len, size_t *ret_len);
|
|
|
|
|
|
|
|
|
|
|
|
Server
|
|
|
|
------
|
|
|
|
|
|
|
|
In the server side, you need to:
|
|
|
|
|
|
|
|
* Register your function
|
|
|
|
* write code to receive the request and send the result
|
|
|
|
|
|
|
|
And Searpc handles the others for you.
|
|
|
|
|
|
|
|
### Concepts ###
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
* **Marshal**: The process of unpacking the function arguments from
|
|
|
|
JSON data, call the RPC function and packing the result into JSON
|
|
|
|
data format is called marshalling. The function used to
|
|
|
|
pack the result is called a **marshal**.
|
2011-04-08 12:27:39 +00:00
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
* **Signature**: Signatures are used to identify different types of
|
2011-04-08 12:27:39 +00:00
|
|
|
marshals. After the execution of a RPC function on the server side,
|
|
|
|
different types of results need different marshals.
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
* **Function table**: The hash table used to store the (funcname, func)
|
2011-04-08 12:27:39 +00:00
|
|
|
pairs.
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
* **Marshal table**: The hash table used to store the (signature,
|
2011-04-08 12:27:39 +00:00
|
|
|
marshal) pairs.
|
|
|
|
|
|
|
|
|
|
|
|
### Register your function ###
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
The `seaprc_server_register_function` routine registers a function as
|
2011-04-08 12:27:39 +00:00
|
|
|
a RPC function. It inserts your function into the function table. The
|
|
|
|
prototype of this function is:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* func: pointer to the function you want to register
|
|
|
|
* fname: the name of the function. It would be the key of your
|
|
|
|
* function in the fucntion hash table.
|
|
|
|
* signature: the identifier used to get the corresponding marshal.
|
|
|
|
* Returns: a gboolean value indicating success or failure
|
|
|
|
*/
|
|
|
|
gboolean searpc_server_register_function (void *func, const gchar *fname, const gchar *signature)
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
Before calling `searpc_server_register_function`, you need to call
|
2011-04-08 12:27:39 +00:00
|
|
|
**`searpc_server_init()`** to do the initialization work.
|
|
|
|
|
|
|
|
|
|
|
|
### Call the RPC fucntion ###
|
|
|
|
|
|
|
|
After the registration, you should listen to the socket and wait for the
|
|
|
|
incoming request data stream. Once you get a valid request, call the
|
2011-05-18 03:06:01 +00:00
|
|
|
`searpc_server_call_function()` routine, which will automatically do the
|
2011-04-08 12:27:39 +00:00
|
|
|
following work for you:
|
|
|
|
|
|
|
|
* Parse the JSON data stream to resolve the function name and the data.
|
|
|
|
* Lookup the function in the function table according to the funcname.
|
|
|
|
* If a proper function is found, call the function with the given params.
|
|
|
|
* Packing the result into a JSON data string.
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
The prototype of `searpc_server_call_function` is:
|
2011-04-08 12:27:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* data: The incoming JSON data stream.
|
|
|
|
* len: The length of **`data`**.
|
|
|
|
* ret_len: Place to hold the length of the JSON data stream to be returned
|
|
|
|
* Returns: The JSON data containing the result of the RPC
|
|
|
|
*/
|
|
|
|
gchar* searpc_server_call_function (gchar *data, gsize len, gsize *ret_len)
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
The value returned by `searpc_server_call_function()` is the JSON data
|
|
|
|
ready to send back to the client.
|
2011-04-08 12:27:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
Pysearpc
|
2011-05-18 03:06:01 +00:00
|
|
|
========
|
2011-04-08 12:27:39 +00:00
|
|
|
|
|
|
|
**Pysearpc** is the Python binding of **Searpc**. Only the client side function is
|
|
|
|
supported. To use it, simply define a class which inherits **SearpcClient**, and
|
2011-05-18 03:06:01 +00:00
|
|
|
provide a `call_remote_func_sync` method, which is equivalent to the
|
|
|
|
`transport_callback`.
|
2011-04-08 12:27:39 +00:00
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
To define your RPC funtion, use the `@searpc_func` decorator. It is
|
|
|
|
equivalent to `SEARPC_CLIENT_DEFUN_XXX__YYY` macro. To define a RPC
|
2011-04-08 12:27:39 +00:00
|
|
|
function which accepts multiple params, here is an example:
|
|
|
|
|
|
|
|
class SampeSearpcClient(SearpcClient):
|
|
|
|
def call_remote_func_sync(self, fcall_str):
|
|
|
|
# your transport code here
|
|
|
|
...
|
|
|
|
|
|
|
|
@searpc_func("int", ["string", "string"])
|
|
|
|
def searpc_demo_func(self):
|
|
|
|
# this is enough for the client side
|
|
|
|
pass
|
|
|
|
|
|
|
|
See the demo program for a more detailed example.
|
|
|
|
|
|
|
|
|
|
|
|
Demos
|
|
|
|
======
|
|
|
|
|
|
|
|
There are well-commented demos in both C and Python.
|
|
|
|
|
|
|
|
* **searpc-demo-server.c**: The server side demo program
|
|
|
|
* **searpc-demo-client.c**: The client side demo in C
|
|
|
|
* **pysearpc-demo-client.py**: The client side demo in Python
|
|
|
|
|
2011-05-18 03:06:01 +00:00
|
|
|
To run the demo, run the server demo in a shell, and run the client
|
|
|
|
demo in another. To run the python demo, you should first install the
|
|
|
|
package and setup the **PYTHONPATH** appropriately.
|
2011-04-08 12:27:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
Thread Safety
|
2011-05-18 03:06:01 +00:00
|
|
|
=============
|
2011-04-08 12:27:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
Extend Searpc
|
2011-05-18 03:06:01 +00:00
|
|
|
=============
|
2011-04-08 12:27:39 +00:00
|
|
|
|
|
|
|
To support new rpc function types,
|
|
|
|
|
|
|
|
1. edit **`rpc_table.py`**,
|
|
|
|
2. call **make genrpc**.
|
|
|
|
3. If the return type is not supported yet, you need also define the
|
|
|
|
corresponding **`searpc_fret_*`** function.
|
2011-04-09 03:04:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
Dependency
|
2011-05-18 03:06:01 +00:00
|
|
|
==========
|
2011-04-09 03:04:02 +00:00
|
|
|
|
|
|
|
The following packages are required to build libsearpc:
|
|
|
|
|
2011-04-09 03:53:55 +00:00
|
|
|
* glib-2.0 >= 2.16.0
|
|
|
|
* gobject-2.0 >= 2.16.0
|
|
|
|
* json-glib-1.0 >= 0.10.2
|
2011-04-09 09:33:28 +00:00
|
|
|
* pygobject-2.0 >= 2.0 (if you choose to build pysearpc)
|
2011-04-09 03:04:02 +00:00
|
|
|
|
|
|
|
|