1
0
mirror of https://github.com/haiwen/libsearpc.git synced 2025-05-04 21:26:19 +00:00
libsearpc/README.markdown

8.1 KiB

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.

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.

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.

Dependency

The following packages are required to build libsearpc:

  • glib-2.0 >= 2.16.0
  • gobject-2.0 >= 2.16.0
  • json-glib-1.0 >= 0.10.2
  • pygobject-2.0 >= 2.0 (if you choose to build pysearpc)

License

You may redistribute copies of libsearpc under the terms of the GNU LGPL(Lesser General Public License). For more information about these matters, see the files named 'LICENSE' and 'COPYING'.