| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983 |
- /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
- **
- ** Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions
- ** are met:
- ** 1. Redistributions of source code must retain the above copyright
- ** notice, this list of conditions and the following disclaimer.
- ** 2. Redistributions in binary form must reproduce the above copyright
- ** notice, this list of conditions and the following disclaimer in the
- ** documentation and/or other materials provided with the distribution.
- ** 3. The name of the author may not be used to endorse or promote products
- ** derived from this software without specific prior written permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- ** SUCH DAMAGE. */
- #include "xmlrpc_config.h"
- #undef PACKAGE
- #undef VERSION
- #include <stddef.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <errno.h>
- #include "bool.h"
- #include "mallocvar.h"
- #include "xmlrpc.h"
- #include "xmlrpc_int.h"
- #include "xmlrpc_client.h"
- #include "xmlrpc_client_int.h"
- /* transport_config.h defines XMLRPC_DEFAULT_TRANSPORT,
- MUST_BUILD_WININET_CLIENT, MUST_BUILD_CURL_CLIENT,
- MUST_BUILD_LIBWWW_CLIENT
- */
- #include "transport_config.h"
- #if MUST_BUILD_WININET_CLIENT
- #include "xmlrpc_wininet_transport.h"
- #endif
- #if MUST_BUILD_CURL_CLIENT
- #include "xmlrpc_curl_transport.h"
- #endif
- #if MUST_BUILD_LIBWWW_CLIENT
- #include "xmlrpc_libwww_transport.h"
- #endif
- struct xmlrpc_client {
- /*----------------------------------------------------------------------------
- This represents a client object.
- -----------------------------------------------------------------------------*/
- struct clientTransport * transportP;
- };
- typedef struct call_info
- {
- /* These fields are used when performing asynchronous calls.
- ** The _asynch_data_holder contains server_url, method_name and
- ** param_array, so it's the only thing we need to free. */
- xmlrpc_value *_asynch_data_holder;
- char *server_url;
- char *method_name;
- xmlrpc_value *param_array;
- xmlrpc_response_handler callback;
- void *user_data;
- /* The serialized XML data passed to this call. We keep this around
- ** for use by our source_anchor field. */
- xmlrpc_mem_block *serialized_xml;
- } call_info;
- static bool clientInitialized = FALSE;
- /*=========================================================================
- ** Initialization and Shutdown
- **=========================================================================
- */
- static struct clientTransportOps clientTransportOps;
- static struct xmlrpc_client client;
- /* Some day, we need to make this dynamically allocated, so there can
- be more than one client per program and just generally to provide
- a cleaner interface.
- */
- extern void
- xmlrpc_client_init(int const flags,
- const char * const appname,
- const char * const appversion) {
- struct xmlrpc_clientparms clientparms;
- /* As our interface does not allow for failure, we just fail silently ! */
-
- xmlrpc_env env;
- xmlrpc_env_init(&env);
- clientparms.transport = XMLRPC_DEFAULT_TRANSPORT;
- xmlrpc_client_init2(&env, flags,
- appname, appversion,
- &clientparms, XMLRPC_CPSIZE(transport));
- xmlrpc_env_clean(&env);
- }
- const char *
- xmlrpc_client_get_default_transport(xmlrpc_env * const env ATTR_UNUSED) {
- return XMLRPC_DEFAULT_TRANSPORT;
- }
- static void
- setupTransport(xmlrpc_env * const envP,
- const char * const transportName) {
- if (FALSE) {
- }
- #if MUST_BUILD_WININET_CLIENT
- else if (strcmp(transportName, "wininet") == 0)
- clientTransportOps = xmlrpc_wininet_transport_ops;
- #endif
- #if MUST_BUILD_CURL_CLIENT
- else if (strcmp(transportName, "curl") == 0)
- clientTransportOps = xmlrpc_curl_transport_ops;
- else if (strcmp(transportName, "libcurl") == 0)
- clientTransportOps = xmlrpc_curl_transport_ops;
- #endif
- #if MUST_BUILD_LIBWWW_CLIENT
- else if (strcmp(transportName, "libwww") == 0)
- clientTransportOps = xmlrpc_libwww_transport_ops;
- #endif
- else
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR,
- "Unrecognized XML transport name '%s'", transportName);
- }
- void
- xmlrpc_client_init2(xmlrpc_env * const envP,
- int const flags,
- const char * const appname,
- const char * const appversion,
- struct xmlrpc_clientparms * const clientparmsP,
- unsigned int const parm_size) {
- if (clientInitialized)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR,
- "Xmlrpc-c client instance has already been initialized "
- "(need to call xmlrpc_client_cleanup() before you can "
- "reinitialize).");
- else {
- const char * transportName;
- if (parm_size < XMLRPC_CPSIZE(transport) ||
- clientparmsP->transport == NULL) {
- /* He didn't specify a transport. Use the default */
- transportName = xmlrpc_client_get_default_transport(envP);
- } else
- transportName = clientparmsP->transport;
- if (!envP->fault_occurred) {
- setupTransport(envP, transportName);
- if (!envP->fault_occurred) {
- clientTransportOps.create(envP, flags, appname, appversion,
- &client.transportP);
- if (!envP->fault_occurred)
- clientInitialized = TRUE;
- }
- }
- }
- }
- void
- xmlrpc_client_cleanup() {
- XMLRPC_ASSERT(clientInitialized);
- clientTransportOps.destroy(client.transportP);
-
- clientInitialized = FALSE;
- }
- static void
- call_info_free(call_info * const callInfoP) {
- /* Assume the worst.. That only parts of the call_info are valid. */
- XMLRPC_ASSERT_PTR_OK(callInfoP);
- /* If this has been allocated, we're responsible for destroying it. */
- if (callInfoP->_asynch_data_holder)
- xmlrpc_DECREF(callInfoP->_asynch_data_holder);
- /* Now we can blow away the XML data. */
- if (callInfoP->serialized_xml)
- xmlrpc_mem_block_free(callInfoP->serialized_xml);
- free(callInfoP);
- }
- static void
- call_info_new(xmlrpc_env * const envP,
- xmlrpc_server_info * const server,
- const char * const method_name,
- xmlrpc_value * const argP,
- call_info ** const callInfoPP) {
- /*----------------------------------------------------------------------------
- Create a call_info object. A call_info object represents an XML-RPC
- call.
- -----------------------------------------------------------------------------*/
- call_info * callInfoP;
- XMLRPC_ASSERT_PTR_OK(argP);
- XMLRPC_ASSERT_PTR_OK(callInfoPP);
- if (method_name == NULL)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR,
- "method name argument is NULL pointer");
- else if (server == NULL)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR,
- "server info argument is NULL pointer");
- else {
- MALLOCVAR(callInfoP);
- if (callInfoP == NULL)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR,
- "Couldn't allocate memory for xmlrpc_call_info");
- else {
- xmlrpc_mem_block * callXmlP;
- /* Clear contents. */
- memset(callInfoP, 0, sizeof(*callInfoP));
-
- /* Make the XML for our call */
- callXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
- if (!envP->fault_occurred) {
- xmlrpc_serialize_call(envP, callXmlP, method_name, argP);
- if (!envP->fault_occurred) {
- xmlrpc_traceXml("XML-RPC CALL",
- XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP),
- XMLRPC_MEMBLOCK_SIZE(char, callXmlP));
-
- callInfoP->serialized_xml = callXmlP;
- *callInfoPP = callInfoP;
- }
- if (envP->fault_occurred)
- XMLRPC_MEMBLOCK_FREE(char, callXmlP);
- }
- if (envP->fault_occurred)
- free(callInfoP);
- }
- }
- }
- static void
- clientCallServerParams(xmlrpc_env * const envP,
- struct clientTransport * const transportP,
- xmlrpc_server_info * const serverP,
- const char * const methodName,
- xmlrpc_value * const paramArrayP,
- xmlrpc_value ** const resultPP) {
- call_info * callInfoP;
-
- if (!clientInitialized)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR,
- "Xmlrpc-c client instance has not been initialized "
- "(need to call xmlrpc_client_init2()).");
- else {
- call_info_new(envP, serverP, methodName, paramArrayP, &callInfoP);
- if (!envP->fault_occurred) {
- xmlrpc_mem_block * respXmlP;
-
- clientTransportOps.call(envP, transportP, serverP,
- callInfoP->serialized_xml, callInfoP,
- &respXmlP);
- if (!envP->fault_occurred) {
- xmlrpc_traceXml("XML-RPC RESPONSE",
- XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP),
- XMLRPC_MEMBLOCK_SIZE(char, respXmlP));
-
- *resultPP = xmlrpc_parse_response(
- envP,
- XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP),
- XMLRPC_MEMBLOCK_SIZE(char, respXmlP));
- XMLRPC_MEMBLOCK_FREE(char, respXmlP);
- }
- call_info_free(callInfoP);
- }
- }
- }
- xmlrpc_value *
- xmlrpc_client_call_params(xmlrpc_env * const envP,
- const char * const serverUrl,
- const char * const methodName,
- xmlrpc_value * const paramArrayP) {
- xmlrpc_value *retval;
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_PTR_OK(serverUrl);
- if (!clientInitialized)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR,
- "Xmlrpc-c client instance has not been initialized "
- "(need to call xmlrpc_client_init2()).");
- else {
- xmlrpc_server_info * serverP;
-
- /* Build a server info object and make our call. */
- serverP = xmlrpc_server_info_new(envP, serverUrl);
- if (!envP->fault_occurred) {
- clientCallServerParams(envP, client.transportP, serverP,
- methodName, paramArrayP,
- &retval);
- xmlrpc_server_info_free(serverP);
- }
- }
-
- if (!envP->fault_occurred)
- XMLRPC_ASSERT_VALUE_OK(retval);
- return retval;
- }
- static xmlrpc_value *
- xmlrpc_client_call_va(xmlrpc_env * const envP,
- const char * const server_url,
- const char * const method_name,
- const char * const format,
- va_list args) {
- xmlrpc_value * argP;
- xmlrpc_value * retval;
- xmlrpc_env argenv;
- const char * suffix;
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_PTR_OK(format);
- /* Build our argument value. */
- xmlrpc_env_init(&argenv);
- xmlrpc_build_value_va(&argenv, format, args, &argP, &suffix);
- if (argenv.fault_occurred) {
- xmlrpc_env_set_fault_formatted(
- envP, argenv.fault_code, "Invalid RPC arguments. "
- "The format argument must indicate a single array, and the "
- "following arguments must correspond to that format argument. "
- "The failure is: %s",
- argenv.fault_string);
- xmlrpc_env_clean(&argenv);
- } else {
- XMLRPC_ASSERT_VALUE_OK(argP);
-
- if (*suffix != '\0')
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
- "specifier: '%s'. There must be exactly one arument.",
- suffix);
- else {
- /* Perform the actual XML-RPC call. */
- retval = xmlrpc_client_call_params(
- envP, server_url, method_name, argP);
- if (!envP->fault_occurred)
- XMLRPC_ASSERT_VALUE_OK(retval);
- }
- xmlrpc_DECREF(argP);
- }
- return retval;
- }
- xmlrpc_value *
- xmlrpc_client_call(xmlrpc_env * const envP,
- const char * const server_url,
- const char * const method_name,
- const char * const format,
- ...) {
- xmlrpc_value * result;
- va_list args;
- va_start(args, format);
- result = xmlrpc_client_call_va(envP, server_url,
- method_name, format, args);
- va_end(args);
- return result;
- }
- xmlrpc_value *
- xmlrpc_client_call_server(xmlrpc_env * const envP,
- xmlrpc_server_info * const serverP,
- const char * const methodName,
- const char * const format,
- ...) {
- va_list args;
- xmlrpc_value * paramArrayP;
- xmlrpc_value * retval;
- const char * suffix;
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_PTR_OK(format);
- /* Build our argument */
- va_start(args, format);
- xmlrpc_build_value_va(envP, format, args, ¶mArrayP, &suffix);
- va_end(args);
- if (!envP->fault_occurred) {
- if (*suffix != '\0')
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
- "specifier: '%s'. There must be exactly one arument.",
- suffix);
- else
- clientCallServerParams(envP, client.transportP, serverP,
- methodName, paramArrayP,
- &retval);
- xmlrpc_DECREF(paramArrayP);
- }
- return retval;
- }
- void
- xmlrpc_client_event_loop_finish_asynch(void) {
- XMLRPC_ASSERT(clientInitialized);
- clientTransportOps.finish_asynch(client.transportP, timeout_no, 0);
- }
- void
- xmlrpc_client_event_loop_finish_asynch_timeout(timeout_t const timeout) {
- XMLRPC_ASSERT(clientInitialized);
- clientTransportOps.finish_asynch(client.transportP, timeout_yes, timeout);
- }
- static void
- call_info_set_asynch_data(xmlrpc_env * const env,
- call_info * const info,
- const char * const server_url,
- const char * const method_name,
- xmlrpc_value * const argP,
- xmlrpc_response_handler callback,
- void * const user_data) {
- xmlrpc_value *holder;
- /* Error-handling preconditions. */
- holder = NULL;
- XMLRPC_ASSERT_ENV_OK(env);
- XMLRPC_ASSERT_PTR_OK(info);
- XMLRPC_ASSERT(info->_asynch_data_holder == NULL);
- XMLRPC_ASSERT_PTR_OK(server_url);
- XMLRPC_ASSERT_PTR_OK(method_name);
- XMLRPC_ASSERT_VALUE_OK(argP);
- /* Install our callback and user_data.
- ** (We're not responsible for destroying the user_data.) */
- info->callback = callback;
- info->user_data = user_data;
- /* Build an XML-RPC data structure to hold our other data. This makes
- ** copies of server_url and method_name, and increments the reference
- ** to the argument *argP. */
- holder = xmlrpc_build_value(env, "(ssV)",
- server_url, method_name, argP);
- XMLRPC_FAIL_IF_FAULT(env);
- /* Parse the newly-allocated structure into our public member variables.
- ** This doesn't make any new references, so we can dispose of the whole
- ** thing by DECREF'ing the one master reference. Nifty, huh? */
- xmlrpc_parse_value(env, holder, "(ssV)",
- &info->server_url,
- &info->method_name,
- &info->param_array);
- XMLRPC_FAIL_IF_FAULT(env);
- /* Hand over ownership of the holder to the call_info struct. */
- info->_asynch_data_holder = holder;
- holder = NULL;
- cleanup:
- if (env->fault_occurred) {
- if (holder)
- xmlrpc_DECREF(holder);
- }
- }
- /*=========================================================================
- ** xmlrpc_server_info
- **=========================================================================
- */
- xmlrpc_server_info *
- xmlrpc_server_info_new (xmlrpc_env * const env,
- const char * const server_url) {
- xmlrpc_server_info *server;
- char *url_copy;
- /* Error-handling preconditions. */
- server = NULL;
- url_copy = NULL;
- XMLRPC_ASSERT_ENV_OK(env);
- XMLRPC_ASSERT_PTR_OK(server_url);
- /* Allocate our memory blocks. */
- server = (xmlrpc_server_info*) malloc(sizeof(xmlrpc_server_info));
- XMLRPC_FAIL_IF_NULL(server, env, XMLRPC_INTERNAL_ERROR,
- "Couldn't allocate memory for xmlrpc_server_info");
- memset(server, 0, sizeof(xmlrpc_server_info));
- url_copy = (char*) malloc(strlen(server_url) + 1);
- XMLRPC_FAIL_IF_NULL(url_copy, env, XMLRPC_INTERNAL_ERROR,
- "Couldn't allocate memory for server URL");
- /* Build our object. */
- strcpy(url_copy, server_url);
- server->_server_url = url_copy;
- server->_http_basic_auth = NULL;
- cleanup:
- if (env->fault_occurred) {
- if (url_copy)
- free(url_copy);
- if (server)
- free(server);
- return NULL;
- }
- return server;
- }
- xmlrpc_server_info * xmlrpc_server_info_copy(xmlrpc_env *env,
- xmlrpc_server_info *aserver)
- {
- xmlrpc_server_info *server;
- char *url_copy, *auth_copy;
- XMLRPC_ASSERT_ENV_OK(env);
- XMLRPC_ASSERT_PTR_OK(aserver);
- /* Error-handling preconditions. */
- server = NULL;
- url_copy = NULL;
- auth_copy = NULL;
- /* Allocate our memory blocks. */
- server = (xmlrpc_server_info*) malloc(sizeof(xmlrpc_server_info));
- XMLRPC_FAIL_IF_NULL(server, env, XMLRPC_INTERNAL_ERROR,
- "Couldn't allocate memory for xmlrpc_server_info");
- url_copy = (char*) malloc(strlen(aserver->_server_url) + 1);
- XMLRPC_FAIL_IF_NULL(url_copy, env, XMLRPC_INTERNAL_ERROR,
- "Couldn't allocate memory for server URL");
- auth_copy = (char*) malloc(strlen(aserver->_http_basic_auth) + 1);
- XMLRPC_FAIL_IF_NULL(auth_copy, env, XMLRPC_INTERNAL_ERROR,
- "Couldn't allocate memory for authentication info");
- /* Build our object. */
- strcpy(url_copy, aserver->_server_url);
- server->_server_url = url_copy;
- strcpy(auth_copy, aserver->_http_basic_auth);
- server->_http_basic_auth = auth_copy;
- cleanup:
- if (env->fault_occurred) {
- if (url_copy)
- free(url_copy);
- if (auth_copy)
- free(auth_copy);
- if (server)
- free(server);
- return NULL;
- }
- return server;
- }
- void xmlrpc_server_info_free (xmlrpc_server_info *server)
- {
- XMLRPC_ASSERT_PTR_OK(server);
- XMLRPC_ASSERT(server->_server_url != XMLRPC_BAD_POINTER);
- if (server->_http_basic_auth)
- free(server->_http_basic_auth);
- free(server->_server_url);
- server->_server_url = XMLRPC_BAD_POINTER;
- free(server);
- }
- /*=========================================================================
- ** xmlrpc_client_call_asynch
- **=========================================================================
- */
- void
- xmlrpc_client_call_asynch(const char * const serverUrl,
- const char * const methodName,
- xmlrpc_response_handler callback,
- void * const userData,
- const char * const format,
- ...) {
- xmlrpc_env env;
- va_list args;
- xmlrpc_value * paramArrayP;
- const char * suffix;
- xmlrpc_env_init(&env);
- XMLRPC_ASSERT_PTR_OK(serverUrl);
- XMLRPC_ASSERT_PTR_OK(format);
- /* Build our argument array. */
- va_start(args, format);
- xmlrpc_build_value_va(&env, format, args, ¶mArrayP, &suffix);
- va_end(args);
- if (env.fault_occurred) {
- /* Unfortunately, we have no way to return an error and the
- regular callback for a failed RPC is designed to have the
- parameter array passed to it. This was probably an oversight
- of the original asynch design, but now we have to be as
- backward compatible as possible, so we do this:
- */
- (*callback)(serverUrl, methodName, NULL, userData, &env, NULL);
- } else {
- if (*suffix != '\0')
- xmlrpc_env_set_fault_formatted(
- &env, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
- "specifier: '%s'. There must be exactly one arument.",
- suffix);
- else {
- xmlrpc_server_info * serverP;
- serverP = xmlrpc_server_info_new(&env, serverUrl);
- if (!env.fault_occurred) {
- xmlrpc_client_call_server_asynch_params(
- serverP, methodName, callback, userData,
- paramArrayP);
- }
- xmlrpc_server_info_free(serverP);
- }
- if (env.fault_occurred)
- (*callback)(serverUrl, methodName, paramArrayP, userData,
- &env, NULL);
- xmlrpc_DECREF(paramArrayP);
- }
- xmlrpc_env_clean(&env);
- }
- void
- xmlrpc_client_call_asynch_params(const char * const serverUrl,
- const char * const methodName,
- xmlrpc_response_handler callback,
- void * const userData,
- xmlrpc_value * const paramArrayP) {
- xmlrpc_env env;
- xmlrpc_server_info *serverP;
- xmlrpc_env_init(&env);
- XMLRPC_ASSERT_PTR_OK(serverUrl);
- serverP = xmlrpc_server_info_new(&env, serverUrl);
- if (!env.fault_occurred) {
- xmlrpc_client_call_server_asynch_params(
- serverP, methodName, callback, userData, paramArrayP);
- xmlrpc_server_info_free(serverP);
- }
- if (env.fault_occurred)
- /* We have no way to return failure; we report the failure
- as it happened after we successfully started the RPC.
- */
- (*callback)(serverUrl, methodName, paramArrayP, userData,
- &env, NULL);
- xmlrpc_env_clean(&env);
- }
- void
- xmlrpc_client_call_server_asynch(xmlrpc_server_info * const serverP,
- const char * const methodName,
- xmlrpc_response_handler callback,
- void * const userData,
- const char * const format,
- ...) {
- xmlrpc_env env;
- va_list args;
- xmlrpc_value * paramArrayP;
- const char * suffix;
- xmlrpc_env_init(&env);
- XMLRPC_ASSERT_PTR_OK(format);
- /* Build our parameter array. */
- va_start(args, format);
- xmlrpc_build_value_va(&env, format, args, ¶mArrayP, &suffix);
- va_end(args);
- if (env.fault_occurred) {
- /* Unfortunately, we have no way to return an error and the
- regular callback for a failed RPC is designed to have the
- parameter array passed to it. This was probably an oversight
- of the original asynch design, but now we have to be as
- backward compatible as possible, so we do this:
- */
- (*callback)(serverP->_server_url, methodName, NULL, userData,
- &env, NULL);
- } else {
- if (*suffix != '\0')
- xmlrpc_env_set_fault_formatted(
- &env, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
- "specifier: '%s'. There must be exactly one arument.",
- suffix);
- else {
- xmlrpc_client_call_server_asynch_params(
- serverP, methodName, callback, userData, paramArrayP);
- }
- xmlrpc_DECREF(paramArrayP);
- }
- if (env.fault_occurred)
- (*callback)(serverP->_server_url, methodName, paramArrayP, userData,
- &env, NULL);
- xmlrpc_env_clean(&env);
- }
- static void
- asynchComplete(call_info * const callInfoP,
- xmlrpc_mem_block * const responseXmlP,
- xmlrpc_env const transportEnv) {
- /*----------------------------------------------------------------------------
- Complete an asynchronous XML-RPC call request.
- This includes calling the user's RPC completion routine.
- 'transportEnv' describes the an error that the transport
- encountered in processing the call. If the transport successfully
- sent the call to the server and processed the response but the
- server failed the call, 'transportEnv' indicates no error, and the
- response in *callInfoP might very well indicate that the server
- failed the request.
- -----------------------------------------------------------------------------*/
- xmlrpc_env env;
- xmlrpc_value * responseP;
- xmlrpc_env_init(&env);
- if (transportEnv.fault_occurred)
- xmlrpc_env_set_fault_formatted(
- &env, transportEnv.fault_code,
- "Client transport failed to execute the RPC. %s",
- transportEnv.fault_string);
- if (!env.fault_occurred)
- responseP = xmlrpc_parse_response(
- &env,
- XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlP),
- XMLRPC_MEMBLOCK_SIZE(char, responseXmlP));
- /* Call the user's callback function with the result */
- (*callInfoP->callback)(callInfoP->server_url,
- callInfoP->method_name,
- callInfoP->param_array,
- callInfoP->user_data, &env, responseP);
- if (!env.fault_occurred)
- xmlrpc_DECREF(responseP);
- call_info_free(callInfoP);
- xmlrpc_env_clean(&env);
- }
- static void
- sendRequest(xmlrpc_env * const envP,
- struct clientTransport * const transportP,
- xmlrpc_server_info * const serverP,
- const char * const methodName,
- xmlrpc_response_handler responseHandler,
- void * const userData,
- xmlrpc_value * const argP) {
- call_info * callInfoP;
- call_info_new(envP, serverP, methodName, argP, &callInfoP);
- if (!envP->fault_occurred) {
- call_info_set_asynch_data(envP, callInfoP,
- serverP->_server_url, methodName,
- argP, responseHandler, userData);
- if (!envP->fault_occurred)
- clientTransportOps.send_request(
- envP, transportP, serverP, callInfoP->serialized_xml,
- &asynchComplete, callInfoP);
- if (envP->fault_occurred)
- call_info_free(callInfoP);
- else {
- /* asynchComplete() will free *callInfoP */
- }
- }
- if (envP->fault_occurred) {
- /* Transport did not start the call. Report the call complete
- (with error) now.
- */
- (*responseHandler)(serverP->_server_url, methodName, argP, userData,
- envP, NULL);
- } else {
- /* The transport will call *responseHandler() when it has completed
- the call
- */
- }
- }
- void
- xmlrpc_client_call_server_asynch_params(
- xmlrpc_server_info * const serverP,
- const char * const methodName,
- xmlrpc_response_handler responseHandler,
- void * const userData,
- xmlrpc_value * const argP) {
- xmlrpc_env env;
- xmlrpc_env_init(&env);
- XMLRPC_ASSERT_PTR_OK(serverP);
- XMLRPC_ASSERT_PTR_OK(methodName);
- XMLRPC_ASSERT_PTR_OK(responseHandler);
- XMLRPC_ASSERT_VALUE_OK(argP);
- if (!clientInitialized)
- xmlrpc_env_set_fault_formatted(
- &env, XMLRPC_INTERNAL_ERROR,
- "Xmlrpc-c client instance has not been initialized "
- "(need to call xmlrpc_client_init2()).");
- else
- sendRequest(&env, client.transportP, serverP,
- methodName, responseHandler, userData,
- argP);
- xmlrpc_env_clean(&env);
- }
- void
- xmlrpc_server_info_set_basic_auth(xmlrpc_env * const envP,
- xmlrpc_server_info * const serverP,
- const char * const username,
- const char * const password) {
- size_t username_len, password_len, raw_token_len;
- char *raw_token;
- xmlrpc_mem_block *token;
- char *token_data, *auth_type, *auth_header;
- size_t token_len, auth_type_len, auth_header_len;
- /* Error-handling preconditions. */
- raw_token = NULL;
- token = NULL;
- token_data = auth_type = auth_header = NULL;
- XMLRPC_ASSERT_ENV_OK(envP);
- XMLRPC_ASSERT_PTR_OK(serverP);
- XMLRPC_ASSERT_PTR_OK(username);
- XMLRPC_ASSERT_PTR_OK(password);
- /* Calculate some lengths. */
- username_len = strlen(username);
- password_len = strlen(password);
- raw_token_len = username_len + password_len + 1;
- /* Build a raw token of the form 'username:password'. */
- raw_token = (char*) malloc(raw_token_len + 1);
- XMLRPC_FAIL_IF_NULL(raw_token, envP, XMLRPC_INTERNAL_ERROR,
- "Couldn't allocate memory for auth token");
- strcpy(raw_token, username);
- raw_token[username_len] = ':';
- strcpy(&raw_token[username_len + 1], password);
- /* Encode our raw token using Base64. */
- token = xmlrpc_base64_encode_without_newlines(envP,
- (unsigned char*) raw_token,
- raw_token_len);
- XMLRPC_FAIL_IF_FAULT(envP);
- token_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, token);
- token_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, token);
- /* Build our actual header value. (I hate string processing in C.) */
- auth_type = "Basic ";
- auth_type_len = strlen(auth_type);
- auth_header_len = auth_type_len + token_len;
- auth_header = (char*) malloc(auth_header_len + 1);
- XMLRPC_FAIL_IF_NULL(auth_header, envP, XMLRPC_INTERNAL_ERROR,
- "Couldn't allocate memory for auth header");
- memcpy(auth_header, auth_type, auth_type_len);
- memcpy(&auth_header[auth_type_len], token_data, token_len);
- auth_header[auth_header_len] = '\0';
- /* Clean up any pre-existing authentication information, and install
- ** the new value. */
- if (serverP->_http_basic_auth)
- free(serverP->_http_basic_auth);
- serverP->_http_basic_auth = auth_header;
- cleanup:
- if (raw_token)
- free(raw_token);
- if (token)
- xmlrpc_mem_block_free(token);
- if (envP->fault_occurred) {
- if (auth_header)
- free(auth_header);
- }
- }
|