diff --git a/README.markdown b/README.markdown index 7a5412e..00d6ddf 100644 --- a/README.markdown +++ b/README.markdown @@ -12,9 +12,9 @@ server side should take an extra GError argument to report error. The returned json object contains three fields: * **ret**: the return value of the RPC function -* **err_code**: error code. This field is only set if 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 +* **err_msg**: error message. This field is only set if the RPC function reports an error. Compile @@ -23,11 +23,11 @@ Compile Just ./autogen.sh; ./configure; make; make install - + To enable profile, Use - + CFLAGS="-DPROFILE" ./configure - + When profile is enabled, the time spend in each rpc call will be printed. Example @@ -57,7 +57,7 @@ transport function. For example: Suppose we have a `get_substring` function defined in server as follows: gchar *get_substring (const gchar *orig_str, int sub_len, GError **error) - + To call this function, we type: gchar* result; @@ -70,7 +70,7 @@ is the function name. The remain parameters specify the number of parameters the function took and the type of each parameter and its value. So 2, "string", "hello", "int", 2 - + means "get_substring" takes 2 parameters, the first is of type "string", the value is "hello", the second is of type "int", the value is 2. @@ -78,7 +78,7 @@ means "get_substring" takes 2 parameters, the first is of type "string", the val ### 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. @@ -90,9 +90,9 @@ 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: +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`. @@ -101,7 +101,7 @@ The prototype of the transport function is: */ static char *transport_callback (void *arg, const char *fcall_str, size_t fcall_len, size_t *ret_len); - + Server ------ @@ -119,7 +119,7 @@ And Searpc handles the others for you. 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**. - + * **Signature**: Every function has a signature determined by its return type and parameter types. Knowning a function's signature enable us to use a corresponding marshal to call it and convert @@ -130,7 +130,7 @@ And Searpc handles the others for you. First write rpc_table.py to contain the rpc function signatures as follows: - + # [ , [] ] func_table = [ [ "int", ["string"] ], @@ -139,9 +139,9 @@ First write rpc_table.py to contain the rpc function signatures as follows: Add makefile rule: - searpc-signature.h searpc-marshal.h: rpc_table.py - python searpc-codegen.py rpc_table.py - + searpc-signature.h searpc-marshal.h &: rpc_table.py + searpc-codegen.py $< + `searpc-signature.h` and `searpc-marshal.h` will be created containing the function signatures and corresponding marshals. `searpc-marshal.h` also contains a function called `register_marshals`. @@ -158,12 +158,12 @@ Then we init the server as follows: /* register_marshals is defined in searpc-marshal.h */ searpc_server_init(register_marshals); } - + ### Register Functions ### To register a function we first need to create a service. A service is -a set of functions. +a set of functions. Suppose we want to make `searpc_strlen` callable from some network clients, we can do this by putting the following code somewhere: @@ -176,15 +176,15 @@ clients, we can do this by putting the following code somewhere: else return strlen(str); } - + static void register_functions() { - + searpc_create_service("searpc-demo"); /* The first parameter is the implementation function. - * The second parameter is the name of the rpc function the + * The second parameter is the name of the rpc function the * client would call. * The third parameter is the signature. */ @@ -194,7 +194,7 @@ clients, we can do this by putting the following code somewhere: searpc_signature_int__string()); } - + The `seaprc_server_register_function` routine registers a function as a RPC function. The prototype of this function is: @@ -202,7 +202,7 @@ prototype of this function is: /* * service: the name of the service * func: pointer to the function you want to register - * fname: the name of the function. It would be the key of your + * 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 @@ -225,9 +225,9 @@ following work for you: * Lookup the function in internal 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: - + /* * service: Service name. * data: The incoming JSON data stream. @@ -239,7 +239,7 @@ The prototype of `searpc_server_call_function` is: gchar *data, gsize len, gsize *ret_len) The value returned by `searpc_server_call_function()` is the JSON data -ready to send back to the client. +ready to send back to the client. Note, the JSON data stream from client does not contain the service name, it's left to the transport layer to solve the problem. There are @@ -247,7 +247,7 @@ several ways, for example: 1. You may listen on different sockets and determine the service by the incoming socket. -2. The client transport function prepend the service name into the request +2. The client transport function prepend the service name into the request before the json data, and the server transport function first read the service name and read the json data. @@ -267,7 +267,7 @@ function which accepts multiple params, here is an example: 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 @@ -279,7 +279,7 @@ See the demo program for a more detailed example. Demos ===== -There are well-commented demos in both C and Python. +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 @@ -295,7 +295,7 @@ Dependency The following packages are required to build libsearpc: -* glib-2.0 >= 2.26.0 +* glib-2.0 >= 2.26.0 * gobject-2.0 >= 2.26.0 * jansson >= 2.2.1 * python simplejson (for pysearpc) diff --git a/demo/demo-async-client.c b/demo/demo-async-client.c index c99fd07..6dbd877 100644 --- a/demo/demo-async-client.c +++ b/demo/demo-async-client.c @@ -68,7 +68,7 @@ transport_read(TcpTransport *trans) fprintf(stderr, "read packet failed: %s\n", strerror(errno)); exit(-1); } - + ret_len = ntohs(pac->length); searpc_client_generic_callback (pac->data, ret_len, trans->rpc_priv, NULL); trans->rpc_priv = NULL; @@ -79,7 +79,7 @@ strlen_callback(void *vresult, void *user_data, GError *error) { const char *str = user_data; int len = *((int *)vresult); - + g_assert (strcmp(str, "user data") == 0); printf("the length of string 'hello searpc' is %d.\n", len); } diff --git a/demo/pysearpc-demo-client.py b/demo/pysearpc-demo-client.py index 5dbfcc8..b4287ec 100644 --- a/demo/pysearpc-demo-client.py +++ b/demo/pysearpc-demo-client.py @@ -24,7 +24,7 @@ def recv_all(sock, length): return data class SampleRpcClient(SearpcClient): - + def call_remote_func_sync(self, fcall_str): """ called by searpc_func to send the request and receive the result @@ -34,7 +34,7 @@ def call_remote_func_sync(self, fcall_str): # connect to server s.connect((SERVER_ADDR, SERVER_PORT)) # send the header - header = pack('!h', len(fcall_str)); + header = pack('!h', len(fcall_str)); s.sendall(header) # send the JSON data s.sendall(fcall_str) diff --git a/demo/searpc-demo-client.c b/demo/searpc-demo-client.c index 540c056..5cc8444 100644 --- a/demo/searpc-demo-client.c +++ b/demo/searpc-demo-client.c @@ -34,7 +34,7 @@ static char *transport_callback(void *arg, const char *fcall_str, int fd, ret; char buf[BUFLEN]; packet *pac, *pac_ret; - + fd = (int)(long) arg; pac = (packet *)buf; @@ -47,14 +47,14 @@ static char *transport_callback(void *arg, const char *fcall_str, fprintf (stderr, "write failed: %s\n", strerror(errno)); exit(-1); } - + /* read the returned packet */ pac_ret = read_packet(fd, buf); if (pac_ret == NULL) { fprintf(stderr, "read packet failed: %s\n", strerror(errno)); exit(-1); } - + *ret_len = ntohs(pac_ret->length); return g_strndup(pac_ret->data, *ret_len); @@ -65,7 +65,7 @@ void searpc_set_objlist_to_ret_object (json_t *object, GList *ret) { GList *ptr; - + if (ret == NULL) json_object_set_new (object, "ret", json_null ()); else { @@ -141,9 +141,9 @@ rpc_glist_test(int sockfd, struct sockaddr_in *servaddr, SearpcClient *rpc_clien if (error != NULL) { fprintf(stderr, "error: %s\n", error->message); exit(-1); - } + } else printf("%s\n", json_dumps (object, JSON_INDENT(2))); - + json_t *array = json_object_get (object, "ret"); if (json_array_size(array) != count) { printf("Glisttest fail.\n"); diff --git a/demo/searpc-demo-packet.h b/demo/searpc-demo-packet.h index 6552396..279f589 100644 --- a/demo/searpc-demo-packet.h +++ b/demo/searpc-demo-packet.h @@ -13,7 +13,7 @@ #include #include #include - #define UNUSED + #define UNUSED #else #include #endif @@ -64,7 +64,7 @@ readn(int fd, char *buf, size_t n) if ( (nread = recv(fd, buf, nleft, 0)) < 0) { #else if ( (nread = read(fd, buf, nleft)) < 0) { -#endif +#endif if (errno == EINTR) nread = 0; /* and call read() again */ else @@ -76,7 +76,7 @@ readn(int fd, char *buf, size_t n) buf += nread; } - return(n - nleft); /* return >= 0 */ + return(n - nleft); /* return >= 0 */ } @@ -101,7 +101,7 @@ read_packet(int sockfd, char *buf) return pac; } - + #endif diff --git a/demo/searpc-demo-server.c b/demo/searpc-demo-server.c index 0411c14..e37fbca 100644 --- a/demo/searpc-demo-server.c +++ b/demo/searpc-demo-server.c @@ -61,7 +61,7 @@ start_rpc_service(void) searpc_create_service("searpc-demo"); /* The first parameter is the implementation function. - * The second parameter is the name of the rpc function the + * The second parameter is the name of the rpc function the * client would call. * The third parameter is the signature. */ @@ -129,8 +129,6 @@ main(int argc, char *argv[]) } while (1) { - GError *error = NULL; - clilen = sizeof(client_addr); connfd = accept(listenfd, (struct sockaddr *)&client_addr, &clilen); if (connfd < 0) { @@ -143,7 +141,7 @@ main(int argc, char *argv[]) if (pac == NULL) { fprintf(stderr, "read packet failed: %s\n", strerror(errno)); exit(-1); - } + } gsize ret_len; int fcall_len = ntohs(pac->length); @@ -153,6 +151,7 @@ main(int argc, char *argv[]) pac_ret = (packet *)buf; pac_ret->length = htons((uint16_t)ret_len); memcpy(pac_ret->data, res, ret_len); + free(res); /* send the ret packet */ if (writen (connfd, buf, PACKET_HEADER_LENGTH + ret_len) == -1) { diff --git a/lib/searpc-client.c b/lib/searpc-client.c index c15a90b..1a2d24e 100644 --- a/lib/searpc-client.c +++ b/lib/searpc-client.c @@ -64,7 +64,7 @@ static char * fcall_to_str (const char *fname, int n_params, va_list args, gsize *len) { json_t *array; - + array = json_array (); json_array_append_new (array, json_string(fname)); @@ -114,7 +114,7 @@ searpc_client_call (SearpcClient *client, const char *fname, g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return; } - + char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); @@ -138,7 +138,7 @@ searpc_client_call (SearpcClient *client, const char *fname, *((json_t **)ret_ptr) = searpc_client_fret__json(fret, ret_len, error); else g_warning ("unrecognized return type %s\n", ret_type); - + g_free (fstr); g_free (fret); } @@ -160,7 +160,7 @@ searpc_client_call__int (SearpcClient *client, const char *fname, g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return 0; } - + char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); @@ -191,7 +191,7 @@ searpc_client_call__int64 (SearpcClient *client, const char *fname, g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return 0; } - + char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); @@ -222,7 +222,7 @@ searpc_client_call__string (SearpcClient *client, const char *fname, g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return NULL; } - + char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); @@ -255,7 +255,7 @@ searpc_client_call__object (SearpcClient *client, const char *fname, g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return NULL; } - + char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); @@ -490,7 +490,7 @@ searpc_client_async_call__string (SearpcClient *client, int searpc_client_async_call__object (SearpcClient *client, const char *fname, - AsyncCallback callback, + AsyncCallback callback, GType object_type, void *cbdata, int n_params, ...) { @@ -510,7 +510,7 @@ searpc_client_async_call__object (SearpcClient *client, int searpc_client_async_call__objlist (SearpcClient *client, const char *fname, - AsyncCallback callback, + AsyncCallback callback, GType object_type, void *cbdata, int n_params, ...) { @@ -524,7 +524,7 @@ searpc_client_async_call__objlist (SearpcClient *client, object_type, cbdata, n_params, args); va_end (args); - return ret; + return ret; } int @@ -582,7 +582,7 @@ handle_ret_common (char *data, size_t len, json_t **object, GError **error) return 0; } - + char * searpc_client_fret__string (char *data, size_t len, GError **error) @@ -643,7 +643,7 @@ searpc_client_fret__object (GType gtype, char *data, size_t len, GError **error) json_decref(object); return NULL; } - + ret = json_gobject_deserialize(gtype, member); json_decref(object); return ret; @@ -672,7 +672,7 @@ searpc_client_fret__objlist (GType gtype, char *data, size_t len, GError **error json_t *member = json_array_get (array, i); GObject *obj = json_gobject_deserialize(gtype, member); if (obj == NULL) { - g_set_error (error, DFT_DOMAIN, 503, + g_set_error (error, DFT_DOMAIN, 503, "Invalid data: object list contains null"); clean_objlist(ret); json_decref(object); diff --git a/lib/searpc-client.h b/lib/searpc-client.h index 157a407..27bdd42 100644 --- a/lib/searpc-client.h +++ b/lib/searpc-client.h @@ -36,7 +36,7 @@ typedef void (*AsyncCallback) (void *result, void *user_data, GError *error); struct _SearpcClient { TransportCB send; void *arg; - + AsyncTransportSend async_send; void *async_arg; }; @@ -111,14 +111,14 @@ searpc_client_async_call__string (SearpcClient *client, LIBSEARPC_API int searpc_client_async_call__object (SearpcClient *client, const char *fname, - AsyncCallback callback, + AsyncCallback callback, GType object_type, void *cbdata, int n_params, ...); LIBSEARPC_API int searpc_client_async_call__objlist (SearpcClient *client, const char *fname, - AsyncCallback callback, + AsyncCallback callback, GType object_type, void *cbdata, int n_params, ...); diff --git a/lib/searpc-server.c b/lib/searpc-server.c index c4dd2bb..d24348e 100644 --- a/lib/searpc-server.c +++ b/lib/searpc-server.c @@ -71,7 +71,7 @@ searpc_create_service (const char *svc_name) service = g_new0 (SearpcService, 1); service->name = g_strdup(svc_name); - service->func_table = g_hash_table_new_full (g_str_hash, g_str_equal, + service->func_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)func_item_free); g_hash_table_insert (service_table, service->name, service); @@ -128,7 +128,7 @@ void searpc_set_objlist_to_ret_object (json_t *object, GList *ret) { GList *ptr; - + if (ret == NULL) json_object_set_new (object, "ret", json_null ()); else { @@ -264,7 +264,7 @@ searpc_server_final(void) g_hash_table_destroy (marshal_table); } -gboolean +gboolean searpc_server_register_marshal (gchar *signature, SearpcMarshalFunc marshal) { MarshalItem *mitem; @@ -285,7 +285,7 @@ searpc_server_register_marshal (gchar *signature, SearpcMarshalFunc marshal) return TRUE; } -gboolean +gboolean searpc_server_register_function (const char *svc_name, void *func, const gchar *fname, gchar *signature) { @@ -364,7 +364,7 @@ print_slow_log_if_necessary (const char *svc_name, const char *func, gsize len, #endif /* Called by RPC transport. */ -char* +char* searpc_server_call_function (const char *svc_name, gchar *func, gsize len, gsize *ret_len) { @@ -388,14 +388,14 @@ searpc_server_call_function (const char *svc_name, snprintf (buf, 255, "cannot find service %s.", svc_name); return error_to_json (501, buf, ret_len); } - + array = json_loadb (func, len, 0 ,&jerror); - + if (!array) { char buf[512]; setjetoge(&jerror,&error); snprintf (buf, 511, "failed to load RPC call: %s\n", error->message); - json_decref (array); + json_decref (array); g_error_free(error); return error_to_json (511, buf, ret_len); } @@ -426,7 +426,7 @@ searpc_server_call_function (const char *svc_name, return ret; } -char* +char* searpc_compute_signature(const gchar *ret_type, int pnum, ...) { va_list ap; @@ -434,9 +434,9 @@ searpc_compute_signature(const gchar *ret_type, int pnum, ...) char *ret; GChecksum *cksum = g_checksum_new (G_CHECKSUM_MD5); - + g_checksum_update (cksum, (const guchar*)ret_type, -1); - + va_start(ap, pnum); for (; i