2011-04-09 03:04:02 +00:00
|
|
|
libsearpc 1.0
|
|
|
|
|
|
|
|
Last Modified: 2011-4-8
|
|
|
|
|
|
|
|
This file is free software; as a special exception the author gives
|
|
|
|
unlimited permission to copy and/or distribute it, with or without
|
|
|
|
modifications, as long as this notice is preserved.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
|
|
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
2011-04-08 12:27:39 +00:00
|
|
|
|
|
|
|
Introduction
|
|
|
|
======
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
* Define your RPC function with the our marco.
|
|
|
|
* 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
|
|
|
|
**`searpc-client.h`**. To call the functions, the client needs to create
|
|
|
|
a SearpcClient object and supply a transport function. For example:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* define a RPC function which takes a string argument and returns
|
|
|
|
* an integer. The xxx_int__string naming convention is used to
|
|
|
|
* indicate the types of the param(string) and the return value(int).
|
|
|
|
*/
|
|
|
|
SEARPC_CLIENT_DEFUN_INT__STRING(searpc_demo_int__string)
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
The **`SEARPC_CLIENT_DEFUN_XXX__YYY`** macro defines a client side RPC function.
|
|
|
|
**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,
|
|
|
|
**`SEARPC_CLIENT_DEFUN_INT__STRING_STRING`** defines a RPC function which takes two
|
|
|
|
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.
|
|
|
|
* fcall_len: the length of **`fcall_str`**.
|
|
|
|
* ret_len: place to get the length of the returned json data stream.
|
|
|
|
* Returns: the JSON data stream ready for transporting.
|
|
|
|
*/
|
|
|
|
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 ###
|
|
|
|
|
|
|
|
* **`Marshal`**: The process of packing the result of the RPC function
|
|
|
|
into JSON data format stream is called marshalling, and the
|
|
|
|
function used to pack the result is called a **`marshal`**.
|
|
|
|
|
|
|
|
* **`Signature`**: Signatures are used to identify different types of
|
|
|
|
marshals. After the execution of a RPC function on the server side,
|
|
|
|
different types of results need different marshals.
|
|
|
|
|
|
|
|
* **`Function table`**: The hash table used to store the (funcname, func)
|
|
|
|
pairs.
|
|
|
|
|
|
|
|
* **`Marshal table`**: The hash table used to store the (signature,
|
|
|
|
marshal) pairs.
|
|
|
|
|
|
|
|
|
|
|
|
### Register your function ###
|
|
|
|
|
|
|
|
The **`seaprc_server_register_function`** routine registers a function as
|
|
|
|
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)
|
|
|
|
|
|
|
|
Before calling **`searpc_server_register_function`**, you need to call
|
|
|
|
**`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
|
|
|
|
**`searpc_server_call_function()`** routine, which will automatically do the
|
|
|
|
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.
|
|
|
|
|
|
|
|
The prototype of **`searpc_server_call_function`** is:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
|
|
|
|
The value returned by **`searpc_server_call_function()`** is the JSON data
|
|
|
|
ready for transportation, which you can send to the client directly.
|
|
|
|
|
|
|
|
In the client side, Searpc would unpack the data stream and return the value
|
|
|
|
contained within it as the return value of the client-side RPC function defined
|
|
|
|
in the macro **`SEARPC_CLIENT_DEFUN_XXX__YYY()`**.
|
|
|
|
|
|
|
|
|
|
|
|
Pysearpc
|
|
|
|
======
|
|
|
|
|
|
|
|
**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
|
|
|
|
provide a **`call_remote_func_sync`** method, which is equivalent to the
|
|
|
|
**`transport_callback`**.
|
|
|
|
|
|
|
|
To define your RPC funtion, use the **`@searpc_func`** decorator. It is
|
|
|
|
equivalent to **`SEARPC_CLIENT_DEFUN_XXX__YYY`** macro. To define a RPC
|
|
|
|
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
|
|
|
|
|
|
|
|
To run the demo, run the server demo in a shell, and run the client demo(either
|
|
|
|
the C or Python demo) in another.
|
|
|
|
|
|
|
|
|
|
|
|
Thread Safety
|
|
|
|
======
|
|
|
|
|
|
|
|
|
|
|
|
Extend Searpc
|
|
|
|
======
|
|
|
|
|
|
|
|
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
|
|
|
|
=====
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
License
|
|
|
|
======
|
|
|
|
|
2011-04-09 03:53:55 +00:00
|
|
|
You may redistribute copies of libsearpc under the terms of the GNU LGPL(Lesser General Public License). For
|
2011-04-09 03:04:02 +00:00
|
|
|
more information about these matters, see the files named 'LICENSE' and 'COPYING'.
|