diff --git a/README.markdown b/README.markdown index 2e654ae..dac8a1c 100644 --- a/README.markdown +++ b/README.markdown @@ -229,4 +229,4 @@ The following packages are required to build libsearpc: * glib-2.0 >= 2.16.0 * gobject-2.0 >= 2.16.0 -* simplejson (for pysearpc) +* python simplejson (for pysearpc) diff --git a/demo/demo-async-client.c b/demo/demo-async-client.c index 612879c..8c1c35f 100644 --- a/demo/demo-async-client.c +++ b/demo/demo-async-client.c @@ -24,10 +24,6 @@ #define BUFLEN 256 #define MAGIC_STRING "ABCD" -/* define the client-side function */ -SEARPC_CLIENT_ASYNC_DEFUN_INT__STRING(searpc_strlen, 0); - - typedef struct { int fd; void *rpc_priv; @@ -47,7 +43,7 @@ static int transport_send(void *arg, char *fcall_str, /* construct the packet */ pac->length = htons((uint16_t)fcall_len); - strncpy(pac->data, fcall_str, fcall_len); + memcpy(pac->data, fcall_str, fcall_len); /* send the packet */ if ( writen (trans->fd, buf, PACKET_HEADER_LENGTH + fcall_len) == -1) { @@ -138,7 +134,9 @@ main(int argc, char *argv[]) rpc_client->async_arg = (void *)(long)transport; /* call the client-side funcion */ - searpc_strlen_async(rpc_client, "hello searpc", strlen_callback, "user data"); + searpc_client_async_call__int(rpc_client, "searpc_strlen", + strlen_callback, "user data", + 1, "string", "hello searpc"); /* call the transport to receive response */ transport_read (transport); diff --git a/demo/pysearpc-demo-client.py b/demo/pysearpc-demo-client.py index 46cb9c7..5dbfcc8 100644 --- a/demo/pysearpc-demo-client.py +++ b/demo/pysearpc-demo-client.py @@ -3,6 +3,8 @@ import sys import socket from struct import pack, unpack +sys.path += ['..'] + from pysearpc import SearpcClient, searpc_func SERVER_ADDR = '127.0.0.1' diff --git a/demo/searpc-demo-client.c b/demo/searpc-demo-client.c index 496cbb7..2b30f3b 100644 --- a/demo/searpc-demo-client.c +++ b/demo/searpc-demo-client.c @@ -25,8 +25,6 @@ #include #endif -/* define the client-side function */ -SEARPC_CLIENT_DEFUN_INT__STRING(searpc_strlen); static char *transport_callback(void *arg, const char *fcall_str, size_t fcall_len, size_t *ret_len) @@ -40,7 +38,7 @@ static char *transport_callback(void *arg, const char *fcall_str, /* construct the packet */ pac->length = htons((uint16_t)fcall_len); - strncpy(pac->data, fcall_str, fcall_len); + memcpy(pac->data, fcall_str, fcall_len); /* send the packet */ if ( writen (fd, buf, PACKET_HEADER_LENGTH + fcall_len) == -1) { @@ -104,7 +102,8 @@ main(int argc, char *argv[]) rpc_client->arg = (void *)(long)sockfd; /* call the client-side funcion */ - ret = searpc_strlen(rpc_client, "hello searpc", &error); + ret = searpc_client_call__int(rpc_client, "searpc_strlen", &error, + 1, "string", "hello searpc"); if (error != NULL) { fprintf(stderr, "error: %s\n", error->message); exit(-1); diff --git a/demo/searpc-demo-server.c b/demo/searpc-demo-server.c index 588b16c..1254e9e 100644 --- a/demo/searpc-demo-server.c +++ b/demo/searpc-demo-server.c @@ -4,8 +4,6 @@ #include #include - - #include #include @@ -122,11 +120,11 @@ main(int argc, char *argv[]) int fcall_len = ntohs(pac->length); /* Execute the RPC function */ char *res = searpc_server_call_function ("searpc-demo", pac->data, fcall_len, - &ret_len, &error); + &ret_len); pac_ret = (packet *)buf; pac_ret->length = htons((uint16_t)ret_len); - strncpy(pac_ret->data, res, ret_len); + memcpy(pac_ret->data, res, ret_len); /* send the ret packet */ if (writen (connfd, buf, PACKET_HEADER_LENGTH + ret_len) == -1) { diff --git a/lib/Makefile.am b/lib/Makefile.am index 55ab041..28babbd 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -14,8 +14,7 @@ # * searpc-marshal.h: contains functions like `marshal_int__string()` # -generated_sources = fcall-impr.h searpc-fcall.h searpc-dfun.h \ - searpc-signature.h marshal.h +generated_sources = searpc-signature.h marshal.h # rpc_headers = fcall-impr.h searpc-fcall.h searpc-dfun.h searpc-signature.h searpc-marshal.h @@ -30,14 +29,14 @@ BUILT_SOURCES = gensource lib_LTLIBRARIES = libsearpc.la -include_HEADERS = searpc-fcall.h searpc-client.h searpc-dfun.h \ +include_HEADERS = searpc-client.h \ searpc-server.h searpc-signature.h searpc-utils.h -noinst_HEADERS = searpc-utils.h fcall-impr.h marshal.h +noinst_HEADERS = searpc-utils.h marshal.h libsearpc_la_SOURCES = searpc-client.c searpc-server.c $(generated_sources) -libsearpc_la_LDFLAGS = -version-info 1:1:0 -no-undefined +libsearpc_la_LDFLAGS = -version-info 1:2:0 -no-undefined libsearpc_la_LIBADD = @GLIB_LIBS@ \ ${top_builddir}/json-glib/json-glib/libsearpc-json-glib.la @@ -50,9 +49,6 @@ gensource: ${generated_sources} ${generated_sources}: gencode.py rpc_table.py @echo "[libsearpc]: generating rpc header files" - python gencode.py gen-fcall > fcall-impr.h - python gencode.py gen-fcall-declare > searpc-fcall.h - python gencode.py gen-dfun-macro > searpc-dfun.h python gencode.py gen-signature > searpc-signature.h python gencode.py gen-marshal > marshal.h @echo "[libsearpc]: done" diff --git a/lib/gencode.py b/lib/gencode.py index 9e66932..565bd21 100644 --- a/lib/gencode.py +++ b/lib/gencode.py @@ -169,219 +169,6 @@ def gen_signature_list(): print generate_signature(item[0], item[1]) -fcall_template = r""" -char* -searpc_client_fcall__${suffix} (const char* fname, ${args}) -{ - JsonArray *array; - - g_return_val_if_fail (fname != NULL, NULL); - - array = json_array_new (); - json_array_add_string_element (array, fname); -${args_to_array} - return fcall_common(array, len); -} -""" - -def gen_fcall(arg_types): - if len(arg_types) == 0: - suffix = "void" - args = "gsize *len" - args_to_array = "" - return string.Template(fcall_template).substitute(suffix=suffix, - args=args, args_to_array=args_to_array) - - suffix = "_".join(arg_types) - args = "" - args_to_array = "" - for i, arg_type in enumerate(arg_types): - args += type_table[arg_type][0] + " param" + str(i+1) + ", " - args_to_array += " " + type_table[arg_type][4] + " (array, param" + str(i+1) +");\n" - args += "gsize *len" - return string.Template(fcall_template).substitute(suffix=suffix, - args=args, args_to_array=args_to_array) - -def gen_fcall_list(): - from rpc_table import func_table - - arg_types_list = [] - for item in func_table: - if item[1] not in arg_types_list: - arg_types_list.append(item[1]) - - for item in arg_types_list: - print gen_fcall(item) - -fcall_declare_template = r""" -char* searpc_client_fcall__${suffix} (const char* fname, ${args}); -""" - -def gen_fcall_declare(arg_types): - if len(arg_types) == 0: - suffix = "void" - args = "gsize *len" - return string.Template(fcall_declare_template).substitute(suffix=suffix, - args=args) - - suffix = "_".join(arg_types) - args = "" - for i, arg_type in enumerate(arg_types): - args += type_table[arg_type][0] + " param" + str(i+1) + ", " - args += "gsize *len" - return string.Template(fcall_declare_template).substitute(suffix=suffix, - args=args) - -def gen_fcall_declare_list(): - from rpc_table import func_table - - arg_types_list = [] - for item in func_table: - if item[1] not in arg_types_list: - arg_types_list.append(item[1]) - - for item in arg_types_list: - print gen_fcall_declare(item) - - -dfun_template_with_gtype = r""" -#define SEARPC_CLIENT_DEFUN_${RET_TYPE}__${ARG_TYPES}(funcname, gtype) \ -static ${ret_type_in_c} \ -funcname (SearpcClient *client, ${args}) \ -{ \ - char *fcall, *fret; \ - size_t fcall_len, ret_len; \ - ${ret_type_in_c} result; \ - \ - fcall = searpc_client_fcall__${arg_types} (#funcname, \ - ${fcall_args}); \ - fret = searpc_client_transport_send (client, \ - fcall, \ - fcall_len, \ - &ret_len); \ - if (!fret) { \ - g_free (fcall); \ - g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); \ - return ${default_value}; \ - } \ - result = searpc_client_fret__${ret_type} (gtype, fret, ret_len, error); \ - \ - g_free (fcall); \ - g_free (fret); \ - return result; \ -} -""" - -dfun_template_without_gtype = r""" -#define SEARPC_CLIENT_DEFUN_${RET_TYPE}__${ARG_TYPES}(funcname) \ -static ${ret_type_in_c} \ -funcname (SearpcClient *client, ${args}) \ -{ \ - char *fcall, *fret; \ - size_t fcall_len, ret_len; \ - ${ret_type_in_c} result; \ - \ - fcall = searpc_client_fcall__${arg_types} (#funcname, \ - ${fcall_args}); \ - fret = searpc_client_transport_send (client, \ - fcall, \ - fcall_len, \ - &ret_len); \ - if (!fret) { \ - g_free (fcall); \ - g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); \ - return ${default_value}; \ - } \ - result = searpc_client_fret__${ret_type} (fret, ret_len, error); \ - \ - g_free (fcall); \ - g_free (fret); \ - return result; \ -} -""" - -def gen_dfun_macro(ret_type, arg_types): - if ret_type in ['object', 'objlist']: - template = string.Template(dfun_template_with_gtype) - else: - template = string.Template(dfun_template_without_gtype) - - if len(arg_types) == 0: - arg_types_str = "void" - else: - arg_types_str = "_".join(arg_types) - - args = "" - for i, arg_type in enumerate(arg_types): - args += type_table[arg_type][0] + " param" + str(i+1) + ", " - args += "GError **error" - - fcall_args = "" - for i, arg_type in enumerate(arg_types): - fcall_args += " param" + str(i+1) + ", " - fcall_args += "&fcall_len" - - default_value = type_table[ret_type][5] - ret_type_in_c = type_table[ret_type][1] - - return template.substitute(ret_type=ret_type, RET_TYPE=ret_type.upper(), - ret_type_in_c=ret_type_in_c, - arg_types=arg_types_str, ARG_TYPES=arg_types_str.upper(), - args=args, fcall_args=fcall_args, - default_value=default_value) - -def gen_dfun_macro_list(): - from rpc_table import func_table - for item in func_table: - print gen_dfun_macro(item[0], item[1]) - - -async_dfun_template = r""" -#define SEARPC_CLIENT_ASYNC_DEFUN_${RET_TYPE}__${ARG_TYPES}(funcname, gtype) \ -static int \ -funcname##_async (SearpcClient *client, ${args} \ - AsyncCallback callback, void *user_data) \ -{ \ - char *fcall; \ - size_t fcall_len; \ - \ - fcall = searpc_client_fcall__${arg_types} (#funcname, \ - ${fcall_args}); \ - return searpc_client_async_call (client, fcall, \ - fcall_len, callback, "${ret_type}", \ - gtype, user_data); \ -} -""" - - -def gen_async_dfun_macro(ret_type, arg_types): - template = string.Template(async_dfun_template) - - if len(arg_types) == 0: - arg_types_str = "void" - else: - arg_types_str = "_".join(arg_types) - - args = "" - for i, arg_type in enumerate(arg_types): - args += type_table[arg_type][0] + " param" + str(i+1) + ", " - - fcall_args = "" - for i, arg_type in enumerate(arg_types): - fcall_args += " param" + str(i+1) + ", " - fcall_args += "&fcall_len" - - return template.substitute(ret_type=ret_type, RET_TYPE=ret_type.upper(), - arg_types=arg_types_str, - ARG_TYPES=arg_types_str.upper(), - args=args, fcall_args=fcall_args) - - -def gen_async_dfun_macro_list(): - from rpc_table import func_table - for item in func_table: - print gen_async_dfun_macro(item[0], item[1]) - if __name__ == "__main__": command = sys.argv[1] if command == "gen-marshal": @@ -389,12 +176,5 @@ if __name__ == "__main__": gen_marshal_register_function() elif command == "gen-signature": gen_signature_list() - elif command == "gen-fcall": - gen_fcall_list() - elif command == "gen-fcall-declare": - gen_fcall_declare_list() - elif command == "gen-dfun-macro": - gen_dfun_macro_list() - gen_async_dfun_macro_list() else: print "Unknown command %s" % (command) diff --git a/lib/rpc_table.py b/lib/rpc_table.py index d08d465..a706a84 100644 --- a/lib/rpc_table.py +++ b/lib/rpc_table.py @@ -17,8 +17,6 @@ func_table = [ [ "int", ["string", "string", "string"] ], [ "int", ["string", "string", "int", "int"] ], [ "int", ["string", "string", "string", "string"]], - [ "int64", [] ], - [ "int64", ["string"] ], [ "string", [] ], [ "string", ["int"] ], [ "string", ["string"] ], diff --git a/lib/searpc-client.c b/lib/searpc-client.c index 6542caf..1744928 100644 --- a/lib/searpc-client.c +++ b/lib/searpc-client.c @@ -32,11 +32,258 @@ searpc_client_transport_send (SearpcClient *client, fcall_len, ret_len); } +static char * +fcall_to_str (const char *fname, int n_params, va_list args, gsize *len) +{ + JsonArray *array; + + array = json_array_new (); + json_array_add_string_element (array, fname); + + int i = 0; + for (; i < n_params; i++) { + const char *type = va_arg(args, const char *); + void *value = va_arg(args, void *); + if (strcmp(type, "int") == 0) + json_array_add_int_element (array, (int)value); + else if (strcmp(type, "string") == 0) + json_array_add_string_or_null_element (array, (char *)value); + else { + g_warning ("unrecognized parameter type %s\n", type); + return NULL; + } + } + + gchar *data; + JsonGenerator *gen = json_generator_new (); + JsonNode *root; + + root = json_node_new (JSON_NODE_ARRAY); + json_node_take_array (root, array); + json_generator_set_root (gen, root); + + g_object_set (gen, "pretty", FALSE, NULL); + data = json_generator_to_data (gen, len); + + json_node_free (root); + g_object_unref (gen); + + return data; +} + +void +searpc_client_call (SearpcClient *client, const char *fname, + const char *ret_type, int gobject_type, + void *ret_ptr, GError **error, + int n_params, ...) +{ + g_return_if_fail (fname != NULL); + g_return_if_fail (ret_type != NULL); + + va_list args; + gsize len, ret_len; + char *fstr; + + va_start (args, n_params); + fstr = fcall_to_str (fname, n_params, args, &len); + va_end (args); + if (!fstr) { + 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); + g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); + return; + } + + if (strcmp(ret_type, "int") == 0) + *((int *)ret_ptr) = searpc_client_fret__int (fret, ret_len, error); + else if (strcmp(ret_type, "int64") == 0) + *((gint64 *)ret_ptr) = searpc_client_fret__int64 (fret, ret_len, error); + else if (strcmp(ret_type, "string") == 0) + *((char **)ret_ptr) = searpc_client_fret__string (fret, len, error); + else if (strcmp(ret_type, "object") == 0) + *((GObject **)ret_ptr) = searpc_client_fret__object (gobject_type, fret, + ret_len, error); + else if (strcmp(ret_type, "objlist") == 0) + *((GList **)ret_ptr) = searpc_client_fret__objlist (gobject_type, fret, + ret_len, error); + else + g_warning ("unrecognized return type %s\n", ret_type); + + g_free (fstr); + g_free (fret); +} + +int +searpc_client_call__int (SearpcClient *client, const char *fname, + GError **error, int n_params, ...) +{ + g_return_val_if_fail (fname != NULL, 0); + + va_list args; + gsize len, ret_len; + char *fstr; + + va_start (args, n_params); + fstr = fcall_to_str (fname, n_params, args, &len); + va_end (args); + if (!fstr) { + 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); + g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); + return 0; + } + + int ret = searpc_client_fret__int (fret, ret_len, error); + g_free (fstr); + g_free (fret); + return ret; +} + +gint64 +searpc_client_call__int64 (SearpcClient *client, const char *fname, + GError **error, int n_params, ...) +{ + g_return_val_if_fail (fname != NULL, 0); + + va_list args; + gsize len, ret_len; + char *fstr; + + va_start (args, n_params); + fstr = fcall_to_str (fname, n_params, args, &len); + va_end (args); + if (!fstr) { + 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); + g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); + return 0; + } + + gint64 ret = searpc_client_fret__int64 (fret, ret_len, error); + g_free (fstr); + g_free (fret); + return ret; +} + +char * +searpc_client_call__string (SearpcClient *client, const char *fname, + GError **error, int n_params, ...) +{ + g_return_val_if_fail (fname != NULL, NULL); + + va_list args; + gsize len, ret_len; + char *fstr; + + va_start (args, n_params); + fstr = fcall_to_str (fname, n_params, args, &len); + va_end (args); + if (!fstr) { + 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); + g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); + return NULL; + } + + char *ret = searpc_client_fret__string (fret, ret_len, error); + g_free (fstr); + g_free (fret); + return ret; +} + +GObject * +searpc_client_call__object (SearpcClient *client, const char *fname, + int object_type, + GError **error, int n_params, ...) +{ + g_return_val_if_fail (fname != NULL, NULL); + g_return_val_if_fail (object_type != 0, NULL); + + va_list args; + gsize len, ret_len; + char *fstr; + + va_start (args, n_params); + fstr = fcall_to_str (fname, n_params, args, &len); + va_end (args); + if (!fstr) { + 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); + g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); + return NULL; + } + + GObject *ret = searpc_client_fret__object (object_type, fret, ret_len, error); + g_free (fstr); + g_free (fret); + return ret; +} + +GList* +searpc_client_call__objlist (SearpcClient *client, const char *fname, + int object_type, + GError **error, int n_params, ...) +{ + g_return_val_if_fail (fname != NULL, NULL); + g_return_val_if_fail (object_type != 0, NULL); + + va_list args; + gsize len, ret_len; + char *fstr; + + va_start (args, n_params); + fstr = fcall_to_str (fname, n_params, args, &len); + va_end (args); + if (!fstr) { + 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); + g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); + return NULL; + } + + GList *ret = searpc_client_fret__objlist (object_type, fret, ret_len, error); + g_free (fstr); + g_free (fret); + return ret; +} + + typedef struct { SearpcClient *client; AsyncCallback callback; const gchar *ret_type; - int gtype; + int gtype; /* to specify the specific gobject type + if ret_type is object or objlist */ void *cbdata; } AsyncCallData; @@ -77,15 +324,24 @@ searpc_client_generic_callback (char *retstr, size_t len, g_free (data); } + int -searpc_client_async_call (SearpcClient *client, - gchar *fcall_str, - size_t fcall_len, - AsyncCallback callback, - const gchar *ret_type, - int gtype, - void *cbdata) +searpc_client_async_call_v (SearpcClient *client, + const char *fname, + AsyncCallback callback, + const gchar *ret_type, + int gtype, + void *cbdata, + int n_params, + va_list args) { + gsize len, ret_len; + char *fstr; + + fstr = fcall_to_str (fname, n_params, args, &len); + if (!fstr) + return -1; + int ret; AsyncCallData *data = g_new0(AsyncCallData, 1); data->client = client; @@ -94,7 +350,7 @@ searpc_client_async_call (SearpcClient *client, data->gtype = gtype; data->cbdata = cbdata; - ret = client->async_send (client->async_arg, fcall_str, fcall_len, data); + ret = client->async_send (client->async_arg, fstr, len, data); if (ret < 0) { g_free (data); return -1; @@ -102,30 +358,99 @@ searpc_client_async_call (SearpcClient *client, return 0; } -/* - * serialize function call from array to string - */ -static char * -fcall_common (JsonArray *array, gsize *len) +int +searpc_client_async_call__int (SearpcClient *client, + const char *fname, + AsyncCallback callback, void *cbdata, + int n_params, ...) { - gchar *data; - JsonGenerator *gen = json_generator_new (); - JsonNode *root; + g_return_val_if_fail (fname != NULL, -1); - root = json_node_new (JSON_NODE_ARRAY); - json_node_take_array (root, array); - json_generator_set_root (gen, root); + va_list args; + int ret; - g_object_set (gen, "pretty", FALSE, NULL); - data = json_generator_to_data (gen, len); - - json_node_free (root); - g_object_unref (gen); - - return data; + va_start (args, n_params); + ret = searpc_client_async_call_v (client, fname, callback, "int", 0, cbdata, + n_params, args); + va_end (args); + return ret; } -#include "fcall-impr.h" +int +searpc_client_async_call__int64 (SearpcClient *client, + const char *fname, + AsyncCallback callback, void *cbdata, + int n_params, ...) +{ + g_return_val_if_fail (fname != NULL, -1); + + va_list args; + int ret; + + va_start (args, n_params); + ret = searpc_client_async_call_v (client, fname, callback, "int64", 0, cbdata, + n_params, args); + va_end (args); + return ret; +} + +int +searpc_client_async_call__string (SearpcClient *client, + const char *fname, + AsyncCallback callback, void *cbdata, + int n_params, ...) +{ + g_return_val_if_fail (fname != NULL, -1); + + va_list args; + int ret; + + va_start (args, n_params); + ret = searpc_client_async_call_v (client, fname, callback, "string", 0, cbdata, + n_params, args); + va_end (args); + return ret; +} + +int +searpc_client_async_call__object (SearpcClient *client, + const char *fname, + AsyncCallback callback, + int object_type, void *cbdata, + int n_params, ...) +{ + g_return_val_if_fail (fname != NULL, -1); + + va_list args; + int ret; + + va_start (args, n_params); + ret = searpc_client_async_call_v (client, fname, callback, "object", + object_type, cbdata, + n_params, args); + va_end (args); + return ret; +} + +int +searpc_client_async_call__objlist (SearpcClient *client, + const char *fname, + AsyncCallback callback, + int object_type, void *cbdata, + int n_params, ...) +{ + g_return_val_if_fail (fname != NULL, -1); + + va_list args; + int ret; + + va_start (args, n_params); + ret = searpc_client_async_call_v (client, fname, callback, "objlist", + object_type, cbdata, + n_params, args); + va_end (args); + return ret; +} /* diff --git a/lib/searpc-client.h b/lib/searpc-client.h index 36e197f..064ad7d 100644 --- a/lib/searpc-client.h +++ b/lib/searpc-client.h @@ -34,28 +34,74 @@ SearpcClient *searpc_client_new (); void searpc_client_free (SearpcClient *client); +void +searpc_client_call (SearpcClient *client, const char *fname, + const char *ret_type, int gobject_type, + void *ret_ptr, GError **error, + int n_params, ...); + +int +searpc_client_call__int (SearpcClient *client, const char *fname, + GError **error, int n_params, ...); + +gint64 +searpc_client_call__int64 (SearpcClient *client, const char *fname, + GError **error, int n_params, ...); + +char * +searpc_client_call__string (SearpcClient *client, const char *fname, + GError **error, int n_params, ...); + +GObject * +searpc_client_call__object (SearpcClient *client, const char *fname, + int object_type, + GError **error, int n_params, ...); + +GList* +searpc_client_call__objlist (SearpcClient *client, const char *fname, + int object_type, + GError **error, int n_params, ...); + + char* searpc_client_transport_send (SearpcClient *client, const gchar *fcall_str, size_t fcall_len, size_t *ret_len); -/** - * Send the serialized function call to server. - * - * @fcall_str: the serialized function. - * @ret_type: the return type. - * @gtype: specify the type id if @ret_type is `object` or `objlist`, - * or 0 otherwise. - * @cbdata: the data that will be given to the callback. - */ -int searpc_client_async_call (SearpcClient *client, - gchar *fcall_str, - size_t fcall_len, - AsyncCallback callback, - const gchar *ret_type, - int gtype, - void *cbdata); + +int +searpc_client_async_call__int (SearpcClient *client, + const char *fname, + AsyncCallback callback, void *cbdata, + int n_params, ...); + +int +searpc_client_async_call__int64 (SearpcClient *client, + const char *fname, + AsyncCallback callback, void *cbdata, + int n_params, ...); + +int +searpc_client_async_call__string (SearpcClient *client, + const char *fname, + AsyncCallback callback, void *cbdata, + int n_params, ...); + +int +searpc_client_async_call__object (SearpcClient *client, + const char *fname, + AsyncCallback callback, + int object_type, void *cbdata, + int n_params, ...); + +int +searpc_client_async_call__objlist (SearpcClient *client, + const char *fname, + AsyncCallback callback, + int object_type, void *cbdata, + int n_params, ...); + /* called by the transport layer, the rpc layer should be able to * modify the str, but not take ownership of it */ @@ -65,7 +111,6 @@ searpc_client_generic_callback (char *retstr, size_t len, #include - char* searpc_client_fret__string (char *data, size_t len, GError **error); @@ -88,7 +133,5 @@ searpc_client_fret__objlist (GType gtype, char *data, #define TRANSPORT_ERROR "Transport Error" #define TRANSPORT_ERROR_CODE 500 -#include - #endif diff --git a/lib/searpc-server.c b/lib/searpc-server.c index 2c02f8d..045a26d 100644 --- a/lib/searpc-server.c +++ b/lib/searpc-server.c @@ -158,6 +158,29 @@ marshal_set_ret_common (JsonObject *object, gsize *len, GError *error) return data; } +static gchar * +error_to_json (int code, const char *msg, gsize *len) +{ + JsonObject *object = json_object_new (); + JsonNode *root = json_node_new (JSON_NODE_OBJECT); + JsonGenerator *generator = json_generator_new (); + gchar *data; + + json_object_set_int_member (object, "err_code", code); + json_object_set_string_or_null_member (object, "err_msg", msg); + + json_node_take_object (root, object); + json_generator_set_root (generator, root); + + g_object_set (generator, "pretty", FALSE, NULL); + data = json_generator_to_data (generator, len); + + json_node_free (root); + g_object_unref (generator); + + return data; +} + /* include the generated marshal functions */ #include "marshal.h" @@ -235,33 +258,34 @@ searpc_server_register_function (const char *svc_name, /* Called by RPC transport. */ gchar* searpc_server_call_function (const char *svc_name, - gchar *func, gsize len, gsize *ret_len, GError **error) + gchar *func, gsize len, gsize *ret_len) { SearpcService *service; JsonParser *parser; JsonNode *root; JsonArray *array; + gchar* ret; + GError *error = NULL; #ifdef PROFILE struct timeval start, end, intv; gettimeofday(&start, NULL); #endif - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - service = g_hash_table_lookup (service_table, svc_name); if (!service) { - g_warning ("[SeaRPC] cannot find service %s.\n", svc_name); - g_set_error (error, DFT_DOMAIN, 501, "cannot find service %s.", svc_name); - return NULL; + char buf[256]; + snprintf (buf, 255, "cannot find service %s.", svc_name); + return error_to_json (501, buf, ret_len); } parser = json_parser_new (); - if (!json_parser_load_from_data (parser, func, len, error)) { - g_warning ("[SeaRPC] failed to parse RPC call: %s\n", (*error)->message); - g_object_unref (parser); - return NULL; + if (!json_parser_load_from_data (parser, func, len, &error)) { + char buf[512]; + snprintf (buf, 511, "failed to parse RPC call: %s\n", error->message); + g_object_unref (parser); + return error_to_json (511, buf, ret_len); } root = json_parser_get_root (parser); @@ -270,12 +294,13 @@ searpc_server_call_function (const char *svc_name, const char *fname = json_array_get_string_element(array, 0); FuncItem *fitem = g_hash_table_lookup(service->func_table, fname); if (!fitem) { - g_warning ("[SeaRPC] cannot find function %s.\n", fname); - g_set_error (error, DFT_DOMAIN, 500, "cannot find function %s.", fname); - return NULL; + char buf[256]; + snprintf (buf, 255, "cannot find function %s.", fname); + g_object_unref (parser); + return error_to_json (500, buf, ret_len); } - gchar* ret = fitem->marshal->mfunc (fitem->func, array, ret_len); + ret = fitem->marshal->mfunc (fitem->func, array, ret_len); #ifdef PROFILE gettimeofday(&end, NULL); diff --git a/lib/searpc-server.h b/lib/searpc-server.h index e8fd45d..66438fc 100644 --- a/lib/searpc-server.h +++ b/lib/searpc-server.h @@ -78,8 +78,7 @@ gboolean searpc_server_register_function (const char *service, * Returns the serialized representatio of the returned value. */ gchar *searpc_server_call_function (const char *service, - gchar *func, gsize len, gsize *ret_len, - GError **error); + gchar *func, gsize len, gsize *ret_len); /** * searpc_compute_signature: diff --git a/pysearpc/Makefile.am b/pysearpc/Makefile.am index 0a0b508..b81efe8 100644 --- a/pysearpc/Makefile.am +++ b/pysearpc/Makefile.am @@ -1,33 +1,5 @@ -genrpc_files = pygencode.py rpc_table.py - -AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ - -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ - @GLIB_CFLAGS@ \ - -I/usr/include/python$(PYTHON_VERSION) \ - -I${top_builddir}/lib \ - -I${top_srcdir}/lib - - pysearpcdir=${pyexecdir}/pysearpc pysearpc_PYTHON = __init__.py client.py -BUILT_SOURCES = fcallfret.h - -# generating the fcallfret module -pysearpc_LTLIBRARIES = fcallfret.la - -fcallfret_la_LDFLAGS = -module -avoid-version -export-symbols-regex initfcallfret -no-undefined @SERVER_PKG_RPATH@ -fcallfret_la_SOURCES = fcallfret.c fcallfret.h -fcallfret_la_LIBADD = @GLIB_LIBS@ $(top_builddir)/lib/libsearpc.la @LIB_PYTHON@ - -EXTRA_DIST = ${genrpc_files} - -fcallfret.h: ${genrpc_files} - python pygencode.py > fcallfret.h - -rpc_table.py: ../lib/rpc_table.py - cp -f ../lib/rpc_table.py . - -DISTCLEANFILES = fcallfret.h rpc_table.py diff --git a/pysearpc/client.py b/pysearpc/client.py index bab8324..9333a5c 100644 --- a/pysearpc/client.py +++ b/pysearpc/client.py @@ -1,4 +1,3 @@ -import fcallfret import simplejson as json class SearpcError(Exception): @@ -9,6 +8,31 @@ class SearpcError(Exception): def __str__(self): return self.msg + +def _fret_int(ret_str): + try: + dicts = json.loads(ret_str) + except: + raise SearpcError('Invalid response format') + + if dicts.has_key('err_code'): + raise SearpcError(dicts['err_msg']) + + if dicts['ret']: + return dicts['ret'] + +def _fret_string(ret_str): + try: + dicts = json.loads(ret_str) + except: + raise SearpcError('Invalid response format') + + if dicts.has_key('err_code'): + raise SearpcError(dicts['err_msg']) + + if dicts['ret']: + return dicts['ret'] + class _SearpcObj(object): '''A compact class to emulate gobject.GObject ''' @@ -59,40 +83,33 @@ def _fret_objlist(ret_str): return l + def searpc_func(ret_type, param_types): + def decorate(func): - if len(param_types) == 0: - fcall = getattr(fcallfret, 'fcall__void') - else: - fcall = getattr(fcallfret, 'fcall__' + '_'.join(param_types)) if ret_type == "void": fret = None elif ret_type == "object": fret = _fret_obj elif ret_type == "objlist": fret = _fret_objlist + elif ret_type == "int": + fret = _fret_int + elif ret_type == "int64": + fret = _fret_int + elif ret_type == "string": + fret = _fret_string else: - fret = getattr(fcallfret, 'fret__' + ret_type) + raise SearpcError('Invial return type') def newfunc(self, *args): - fcall_str = fcall(func.__name__, *args) + array = [func.__name__] + list(args) + fcall_str = json.dumps(array) ret_str = self.call_remote_func_sync(fcall_str) if fret: - try: - return fret(ret_str) - except fcallfret.error, e: - raise SearpcError(str(e)) + return fret(ret_str) - def newfunc_obj(self, *args): - fcall_str = fcall(func.__name__, *args) - ret_str = self.call_remote_func_sync(fcall_str) - - return fret(ret_str) - - if ret_type == "objlist" or ret_type == "object": - return newfunc_obj - else: - return newfunc + return newfunc return decorate diff --git a/tests/test-searpc.c b/tests/test-searpc.c index 491b5b5..2de12d5 100644 --- a/tests/test-searpc.c +++ b/tests/test-searpc.c @@ -10,6 +10,7 @@ #include "searpc-client.h" +/* sample class */ #define MAMAN_TYPE_BAR (maman_bar_get_type ()) #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) @@ -58,12 +59,10 @@ maman_bar_set_property (GObject *object, case PROP_MAMAN_NAME: g_free (self->name); self->name = g_value_dup_string (value); - g_print ("maman: %s\n", self->name); break; case PROP_PAPA_NUMBER: self->papa_number = g_value_get_uchar (value); - g_print ("papa: %u\n", self->papa_number); break; default: @@ -145,13 +144,30 @@ maman_bar_init (MamanBar *self) } -/* test function define macro */ -SEARPC_CLIENT_DEFUN_INT__STRING(func4); -SEARPC_CLIENT_DEFUN_INT__STRING_STRING(func1); -SEARPC_CLIENT_DEFUN_STRING__VOID(func0); -SEARPC_CLIENT_DEFUN_OBJECT__STRING(func2, 0); -SEARPC_CLIENT_DEFUN_OBJLIST__STRING_INT(func3, 0); +/* sample client */ +SearpcClient *client; +char * +sample_transport(void *arg, const gchar *fcall_str, + size_t fcall_len, size_t *ret_len) +{ + g_assert (strcmp(arg, "test") == 0); + + char *ret; + /* directly call in memory, instead of send via network */ + gchar *temp = g_strdup(fcall_str); + ret = searpc_server_call_function ("test", temp, fcall_len, ret_len); + g_free (temp); + return ret; +} + +void +init_sample_client () +{ + client = searpc_client_new(); + client->transport = sample_transport; + client->arg = "test"; +} gchar * get_substring (const gchar *orig_str, int sub_len, GError **error) @@ -168,32 +184,35 @@ get_substring (const gchar *orig_str, int sub_len, GError **error) } void test_simple_call (void *fixture, const void *data) +{ + gchar* result; + GError *error = NULL; + + result = searpc_client_call__string (client, "get_substring", &error, + 2, "string", "hello", "int", 2); + g_assert (error == NULL); + g_assert (strcmp(result, "he") == 0); + g_free (result); + + /* error should return */ + result = NULL; + result = searpc_client_call__string (client, "get_substring", &error, + 2, "string", "hello", "int", 10); + g_assert (error->message); + g_free (result); +} + +void +test_invalid_call (void *fixture, const void *data) { char *fcall, *fret; gsize fcall_len, ret_len; gchar* result; GError *error = NULL; - fcall = searpc_client_fcall__string_int ("get_substring", "hello", 2, - &fcall_len); - fret = searpc_server_call_function ("test", fcall, fcall_len, &ret_len, &error); - g_assert (error == NULL); - result = searpc_client_fret__string (fret, ret_len, &error); - g_assert (strcmp(result, "he") == 0); - g_free (fcall); - g_free (fret); - g_free (result); - - /* error should return */ - result = NULL; - fcall = searpc_client_fcall__string_int ("get_substring", "hello", 7, - &fcall_len); - fret = searpc_server_call_function ("test", fcall, fcall_len, &ret_len, &error); - g_assert (error == NULL); - result = searpc_client_fret__string (fret, ret_len, &error); - g_assert (error->message); - g_free (fcall); - g_free (fret); + result = searpc_client_call__string (client, "nonexist_func", &error, + 2, "string", "hello", "int", 2); + g_assert (error != NULL); g_free (result); } @@ -205,23 +224,16 @@ get_maman_bar(const char *name, GError **error) void test_object_call (void *fixture, const void *data) { - char *fcall, *fret; - gsize fcall_len, ret_len; GObject *result; GError *error = NULL; - fcall = searpc_client_fcall__string ("get_maman_bar", "kitty", - &fcall_len); - fret = searpc_server_call_function ("test", fcall, fcall_len, &ret_len, &error); + result = searpc_client_call__object (client, "get_maman_bar", + MAMAN_TYPE_BAR, &error, + 1, "string", "kitty"); g_assert (error == NULL); - result = searpc_client_fret__object (MAMAN_TYPE_BAR, fret, ret_len, &error); - - g_free (fcall); - g_free (fret); g_object_unref (result); } - GList * get_maman_bar_list (const char *name, int num, GError **error) { @@ -251,30 +263,22 @@ get_maman_bar_list (const char *name, int num, GError **error) void test_objlist_call (void *fixture, const void *data) { - char *fcall, *fret; - gsize fcall_len, ret_len; GList *result, *ptr; GError *error = NULL; - fcall = searpc_client_fcall__string_int ("get_maman_bar_list", "kitty", 10, - &fcall_len); - fret = searpc_server_call_function ("test", fcall, fcall_len, &ret_len, &error); + result = searpc_client_call__objlist (client, "get_maman_bar_list", + MAMAN_TYPE_BAR, &error, + 2, "string", "kitty", "int", 10); g_assert (error == NULL); - result = searpc_client_fret__objlist (MAMAN_TYPE_BAR, fret, ret_len, &error); - g_free (fcall); - g_free (fret); for (ptr = result; ptr; ptr = ptr->next) g_object_unref (ptr->data); g_list_free (result); - fcall = searpc_client_fcall__string_int ("get_maman_bar_list", "kitty", 0, - &fcall_len); - fret = searpc_server_call_function ("test", fcall, fcall_len, &ret_len, &error); + result = searpc_client_call__objlist (client, "get_maman_bar_list", + MAMAN_TYPE_BAR, &error, + 2, "string", "kitty", "int", 0); g_assert (error == NULL); - result = searpc_client_fret__objlist (MAMAN_TYPE_BAR, fret, ret_len, &error); - g_free (fcall); - g_free (fret); for (ptr = result; ptr; ptr = ptr->next) g_object_unref (ptr->data); g_list_free (result); @@ -296,6 +300,9 @@ main (int argc, char *argv[]) searpc_server_register_function ("test", get_maman_bar_list, "get_maman_bar_list", searpc_signature_objlist__string_int()); + /* sample client */ + init_sample_client(); + g_test_add ("/searpc/simple", void, NULL, NULL, test_simple_call, NULL); @@ -303,6 +310,9 @@ main (int argc, char *argv[]) g_test_add ("/searpc/simple2", void, NULL, NULL, test_simple_call, NULL); + g_test_add ("/searpc/invalid_call", void, NULL, + NULL, test_invalid_call, NULL); + g_test_add ("/searpc/object", void, NULL, NULL, test_object_call, NULL); diff --git a/tests/test_pysearpc.py b/tests/test_pysearpc.py index c4a1dcc..302acb7 100644 --- a/tests/test_pysearpc.py +++ b/tests/test_pysearpc.py @@ -1,22 +1,17 @@ import sys -sys.path += ['..', '../pysearpc/.libs'] +sys.path += ['..'] from pysearpc import SearpcClient, searpc_func, SearpcError -import fcallfret class SampleRpcClient(SearpcClient): def call_remote_func_sync(self, fcall_str): return "" - @searpc_func("void", ["string"]) + @searpc_func("void", ["string", "int"]) def list_peers(self): pass -fcallfret.fcall__string("list", "hello") - client = SampleRpcClient() -client.list_peers("10") - - +client.list_peers("id", 10)