From fb8d223f5431ffe813efe43fb82cd6a17fa47fac Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 3 Jun 2015 13:49:28 +0200 Subject: [PATCH] Improve XML-RPC API. - Handle XML-RPC request returning a string response - Allow creating a request adding the arguments one at a time (useful for automatically generated wrappers where variable args functions can be an issue) --- coreapi/private.h | 10 +++- coreapi/sipwizard.c | 15 +++--- coreapi/xmlrpc.c | 112 +++++++++++++++++++++++++++++++------------- coreapi/xmlrpc.h | 48 ++++++++++++++++--- 4 files changed, 138 insertions(+), 47 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index 48b448f67..e5e3e0400 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -983,6 +983,14 @@ BELLE_SIP_DECLARE_VPTR(LinphoneBuffer); * XML-RPC interface * ****************************************************************************/ +typedef struct _LinphoneXmlRpcArg { + LinphoneXmlRpcArgType type; + union { + int i; + char *s; + } data; +} LinphoneXmlRpcArg; + struct _LinphoneXmlRpcRequest { belle_sip_object_t base; void *user_data; @@ -990,7 +998,7 @@ struct _LinphoneXmlRpcRequest { char *content; /**< The string representation of the XML-RPC request */ char *method; LinphoneXmlRpcStatus status; - int response; + LinphoneXmlRpcArg response; }; BELLE_SIP_DECLARE_VPTR(LinphoneXmlRpcRequest); diff --git a/coreapi/sipwizard.c b/coreapi/sipwizard.c index 7c1e4d1bb..54b03fcfb 100644 --- a/coreapi/sipwizard.c +++ b/coreapi/sipwizard.c @@ -50,19 +50,17 @@ static int do_simple_xmlrpc_request(SipSetupContext *ctx, LinphoneXmlRpcRequest if (!request) { ms_error("Fail to create XML-RPC request!"); return -1; - } else { - ms_message("This is the XML-RPC request we are going to send:\n%s\n", linphone_xml_rpc_request_get_content(request)); } if (ctx->xmlrpc_session == NULL) { ctx->xmlrpc_session = linphone_xml_rpc_session_new(ctx->cfg->lc, XMLRPC_URL); } if (linphone_xml_rpc_session_send_request(ctx->xmlrpc_session, request) == LinphoneXmlRpcStatusOk) { - ret = linphone_xml_rpc_request_get_response(request); + ret = linphone_xml_rpc_request_get_int_response(request); } linphone_xml_rpc_request_unref(request); - return ret; + return ret; } /* @@ -71,21 +69,24 @@ static int do_simple_xmlrpc_request(SipSetupContext *ctx, LinphoneXmlRpcRequest * -1 if information isn't available */ static int sip_wizard_account_exists(SipSetupContext *ctx, const char *identity) { - LinphoneXmlRpcRequest *request = linphone_xml_rpc_request_new("check_account", + LinphoneXmlRpcRequest *request = linphone_xml_rpc_request_new_with_args("check_account", + LinphoneXmlRpcArgInt, LinphoneXmlRpcArgString, identity, LinphoneXmlRpcArgNone); return do_simple_xmlrpc_request(ctx, request); } static int sip_wizard_account_validated(SipSetupContext *ctx, const char *identity) { - LinphoneXmlRpcRequest *request = linphone_xml_rpc_request_new("check_account_validated", + LinphoneXmlRpcRequest *request = linphone_xml_rpc_request_new_with_args("check_account_validated", + LinphoneXmlRpcArgInt, LinphoneXmlRpcArgString, identity, LinphoneXmlRpcArgNone); return do_simple_xmlrpc_request(ctx, request); } static int sip_wizard_create_account(SipSetupContext *ctx, const char *identity, const char *passwd, const char *email, int subscribe) { - LinphoneXmlRpcRequest *request = linphone_xml_rpc_request_new("create_account", + LinphoneXmlRpcRequest *request = linphone_xml_rpc_request_new_with_args("create_account", + LinphoneXmlRpcArgInt, LinphoneXmlRpcArgString, identity, LinphoneXmlRpcArgString, passwd, LinphoneXmlRpcArgString, email, diff --git a/coreapi/xmlrpc.c b/coreapi/xmlrpc.c index 89f16f10d..1e5731535 100644 --- a/coreapi/xmlrpc.c +++ b/coreapi/xmlrpc.c @@ -26,14 +26,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -typedef struct _LinphoneXmlRpcArg { - LinphoneXmlRpcArgType type; - union { - int i; - char *s; - } data; -} LinphoneXmlRpcArg; - static void format_request(LinphoneXmlRpcRequest *request) { char si[64]; belle_sip_list_t *arg_ptr = request->arg_list; @@ -41,6 +33,11 @@ static void format_request(LinphoneXmlRpcRequest *request) { xmlTextWriterPtr writer; int err; + if (request->content != NULL) { + belle_sip_free(request->content); + request->content = NULL; + } + buf = xmlBufferCreate(); if (buf == NULL) { ms_error("Error creating the XML buffer"); @@ -140,10 +137,23 @@ static void parse_valid_xml_rpc_response(LinphoneXmlRpcSession *session, const c if (xml_ctx->doc != NULL) { const char *response_str; if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end; - response_str = linphone_get_xml_text_content(xml_ctx, "/methodResponse/params/param/value/int"); - if (response_str != NULL) { - session->request->response = atoi(response_str); - session->request->status = LinphoneXmlRpcStatusOk; + switch (session->request->response.type) { + case LinphoneXmlRpcArgInt: + response_str = linphone_get_xml_text_content(xml_ctx, "/methodResponse/params/param/value/int"); + if (response_str != NULL) { + session->request->response.data.i = atoi(response_str); + session->request->status = LinphoneXmlRpcStatusOk; + } + break; + case LinphoneXmlRpcArgString: + response_str = linphone_get_xml_text_content(xml_ctx, "/methodResponse/params/param/value/string"); + if (response_str != NULL) { + session->request->response.data.s = belle_sip_strdup(response_str); + session->request->status = LinphoneXmlRpcStatusOk; + } + break; + default: + break; } linphone_free_xml_text_content(response_str); } else { @@ -182,13 +192,39 @@ static void process_response_from_post_xml_rpc_request(void *data, const belle_h } -static void linphone_xml_rpc_request_destroy(LinphoneXmlRpcRequest *request) { +static LinphoneXmlRpcRequest * _linphone_xml_rpc_request_new(const char *method, LinphoneXmlRpcArgType return_type) { + LinphoneXmlRpcRequest *request = belle_sip_object_new(LinphoneXmlRpcRequest); + belle_sip_object_ref(request); + request->status = LinphoneXmlRpcStatusPending; + request->response.type = return_type; + request->method = belle_sip_strdup(method); + return request; +} + +static void _linphone_xml_rpc_request_add_int_arg(LinphoneXmlRpcRequest *request, int value) { + LinphoneXmlRpcArg *arg = belle_sip_malloc0(sizeof(LinphoneXmlRpcArg)); + arg->type = LinphoneXmlRpcArgInt; + arg->data.i = value; + request->arg_list = belle_sip_list_append(request->arg_list, arg); +} + +static void _linphone_xml_rpc_request_add_string_arg(LinphoneXmlRpcRequest *request, const char *value) { + LinphoneXmlRpcArg *arg = belle_sip_malloc0(sizeof(LinphoneXmlRpcArg)); + arg->type = LinphoneXmlRpcArgString; + arg->data.s = belle_sip_strdup(value); + request->arg_list = belle_sip_list_append(request->arg_list, arg); +} + +static void _linphone_xml_rpc_request_destroy(LinphoneXmlRpcRequest *request) { belle_sip_list_free_with_data(request->arg_list, (void (*)(void*))free_arg); + if ((request->response.type == LinphoneXmlRpcArgString) && (request->response.data.s != NULL)) { + belle_sip_free(request->response.data.s); + } if (request->content) belle_sip_free(request->content); belle_sip_free(request->method); } -static void linphone_xml_rpc_session_destroy(LinphoneXmlRpcSession *session) { +static void _linphone_xml_rpc_session_destroy(LinphoneXmlRpcSession *session) { belle_sip_free(session->url); ms_cond_destroy(&session->cond); ms_mutex_destroy(&session->cond_mutex); @@ -199,31 +235,33 @@ BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneXmlRpcRequest); BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneXmlRpcSession); BELLE_SIP_INSTANCIATE_VPTR(LinphoneXmlRpcRequest, belle_sip_object_t, - (belle_sip_object_destroy_t)linphone_xml_rpc_request_destroy, + (belle_sip_object_destroy_t)_linphone_xml_rpc_request_destroy, NULL, // clone NULL, // marshal TRUE ); BELLE_SIP_INSTANCIATE_VPTR(LinphoneXmlRpcSession, belle_sip_object_t, - (belle_sip_object_destroy_t)linphone_xml_rpc_session_destroy, + (belle_sip_object_destroy_t)_linphone_xml_rpc_session_destroy, NULL, // clone NULL, // marshal TRUE ); -LinphoneXmlRpcRequest * linphone_xml_rpc_request_new(const char *method, ...) { +LinphoneXmlRpcRequest * linphone_xml_rpc_request_new(const char *method, LinphoneXmlRpcArgType return_type) { + LinphoneXmlRpcRequest *request = _linphone_xml_rpc_request_new(method, return_type); + format_request(request); + return request; +} + +LinphoneXmlRpcRequest * linphone_xml_rpc_request_new_with_args(const char *method, LinphoneXmlRpcArgType return_type, ...) { bool_t cont = TRUE; va_list args; LinphoneXmlRpcArgType arg_type; LinphoneXmlRpcArg *arg = NULL; - LinphoneXmlRpcRequest *request = belle_sip_object_new(LinphoneXmlRpcRequest); - belle_sip_object_ref(request); - request->status = LinphoneXmlRpcStatusPending; - request->response = -1; - request->method = belle_sip_strdup(method); - va_start(args, method); + LinphoneXmlRpcRequest *request = _linphone_xml_rpc_request_new(method, return_type); + va_start(args, return_type); while (cont) { arg_type = va_arg(args, LinphoneXmlRpcArgType); switch (arg_type) { @@ -231,16 +269,10 @@ LinphoneXmlRpcRequest * linphone_xml_rpc_request_new(const char *method, ...) { cont = FALSE; break; case LinphoneXmlRpcArgInt: - arg = belle_sip_malloc0(sizeof(LinphoneXmlRpcArg)); - arg->type = LinphoneXmlRpcArgInt; - arg->data.i = va_arg(args, int); - request->arg_list = belle_sip_list_append(request->arg_list, arg); + _linphone_xml_rpc_request_add_int_arg(request, va_arg(args, int)); break; case LinphoneXmlRpcArgString: - arg = belle_sip_malloc0(sizeof(LinphoneXmlRpcArg)); - arg->type = LinphoneXmlRpcArgString; - arg->data.s = belle_sip_strdup(va_arg(args, char *)); - request->arg_list = belle_sip_list_append(request->arg_list, arg); + _linphone_xml_rpc_request_add_string_arg(request, va_arg(args, char *)); break; } } @@ -266,6 +298,16 @@ void linphone_xml_rpc_request_set_user_data(LinphoneXmlRpcRequest *request, void request->user_data = ud; } +void linphone_xml_rpc_request_add_int_arg(LinphoneXmlRpcRequest *request, int value) { + _linphone_xml_rpc_request_add_int_arg(request, value); + format_request(request); +} + +void linphone_xml_rpc_request_add_string_arg(LinphoneXmlRpcRequest *request, const char *value) { + _linphone_xml_rpc_request_add_string_arg(request, value); + format_request(request); +} + const char * linphone_xml_rpc_request_get_content(const LinphoneXmlRpcRequest *request) { return request->content; } @@ -274,8 +316,12 @@ LinphoneXmlRpcStatus linphone_xml_rpc_request_get_status(const LinphoneXmlRpcReq return request->status; } -int linphone_xml_rpc_request_get_response(const LinphoneXmlRpcRequest *request) { - return request->response; +int linphone_xml_rpc_request_get_int_response(const LinphoneXmlRpcRequest *request) { + return request->response.data.i; +} + +const char * linphone_xml_rpc_request_get_string_response(const LinphoneXmlRpcRequest *request) { + return request->response.data.s; } diff --git a/coreapi/xmlrpc.h b/coreapi/xmlrpc.h index 34141be89..fd98f16bc 100644 --- a/coreapi/xmlrpc.h +++ b/coreapi/xmlrpc.h @@ -31,12 +31,18 @@ extern "C" { * @{ */ +/** +* Enum describing the types of argument for LinphoneXmlRpcRequest. +**/ typedef enum _LinphoneXmlRpcArgType { LinphoneXmlRpcArgNone, LinphoneXmlRpcArgInt, LinphoneXmlRpcArgString } LinphoneXmlRpcArgType; +/** +* Enum describing the status of a LinphoneXmlRpcRequest. +**/ typedef enum _LinphoneXmlRpcStatus { LinphoneXmlRpcStatusPending, LinphoneXmlRpcStatusOk, @@ -55,11 +61,20 @@ typedef struct _LinphoneXmlRpcSession LinphoneXmlRpcSession; /** - * Create a new LinphoneXmlRpcRequest object. +* Create a new LinphoneXmlRpcRequest object. +* @param[in] method The XML-RPC method to call. +* @param[in] return_type The expected XML-RPC response type. +* @return A new LinphoneXmlRpcRequest object. +**/ +LINPHONE_PUBLIC LinphoneXmlRpcRequest * linphone_xml_rpc_request_new(const char *method, LinphoneXmlRpcArgType return_type); + +/** + * Create a new LinphoneXmlRpcRequest object giving the arguments to the method call. * @param[in] method The XML-RPC method to call. + * @param[in] return_type The expected XML-RPC response type. * @return A new LinphoneXmlRpcRequest object. - */ -LINPHONE_PUBLIC LinphoneXmlRpcRequest * linphone_xml_rpc_request_new(const char *method, ...); +**/ +LINPHONE_PUBLIC LinphoneXmlRpcRequest * linphone_xml_rpc_request_new_with_args(const char *method, LinphoneXmlRpcArgType return_type, ...); /** * Acquire a reference to the XML-RPC request. @@ -88,6 +103,20 @@ LINPHONE_PUBLIC void *linphone_xml_rpc_request_get_user_data(const LinphoneXmlRp **/ LINPHONE_PUBLIC void linphone_xml_rpc_request_set_user_data(LinphoneXmlRpcRequest *request, void *ud); +/** + * Add an integer argument to an XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. + * @param[in] value The integer value of the added argument. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_request_add_int_arg(LinphoneXmlRpcRequest *request, int value); + +/** + * Add a string argument to an XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. + * @param[in] value The string value of the added argument. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_request_add_string_arg(LinphoneXmlRpcRequest *request, const char *value); + /** * Get the content of the XML-RPC request. * @param[in] request LinphoneXmlRpcRequest object. @@ -103,11 +132,18 @@ LINPHONE_PUBLIC const char * linphone_xml_rpc_request_get_content(const Linphone LINPHONE_PUBLIC LinphoneXmlRpcStatus linphone_xml_rpc_request_get_status(const LinphoneXmlRpcRequest *request); /** - * Get the response to an XML-RPC request sent with linphone_xml_rpc_session_send_request(). + * Get the response to an XML-RPC request sent with linphone_xml_rpc_session_send_request() and returning an integer response. * @param[in] request LinphoneXmlRpcRequest object. - * @return The response to the XML-RPC request. + * @return The integer response to the XML-RPC request. **/ -LINPHONE_PUBLIC int linphone_xml_rpc_request_get_response(const LinphoneXmlRpcRequest *request); +LINPHONE_PUBLIC int linphone_xml_rpc_request_get_int_response(const LinphoneXmlRpcRequest *request); + +/** +* Get the response to an XML-RPC request sent with linphone_xml_rpc_session_send_request() and returning a string response. +* @param[in] request LinphoneXmlRpcRequest object. +* @return The string response to the XML-RPC request. +**/ +LINPHONE_PUBLIC const char * linphone_xml_rpc_request_get_string_response(const LinphoneXmlRpcRequest *request); /** * Create a new LinphoneXmlRpcSession object.