aboutsummaryrefslogtreecommitdiff
path: root/vendor/voclient/libsamp/libxrpc/xrClient.c
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /vendor/voclient/libsamp/libxrpc/xrClient.c
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'vendor/voclient/libsamp/libxrpc/xrClient.c')
-rw-r--r--vendor/voclient/libsamp/libxrpc/xrClient.c955
1 files changed, 955 insertions, 0 deletions
diff --git a/vendor/voclient/libsamp/libxrpc/xrClient.c b/vendor/voclient/libsamp/libxrpc/xrClient.c
new file mode 100644
index 00000000..53680307
--- /dev/null
+++ b/vendor/voclient/libsamp/libxrpc/xrClient.c
@@ -0,0 +1,955 @@
+/**
+ * XRCLIENT.C
+ *
+ * Client-side procedures used by an application to make a call to a
+ * remote service. In this interface, the calling application must
+ * first initialize a client context for a specific service, then
+ * create a parameter array of arguments before invoking the function
+ * either synchronously or asynchronously. Once the call completes,
+ * API procedures are used to extract the result values.
+ *
+ * Client methods:
+ * // call services
+ * cnum = xr_initClient (char *url, char *name, char *version)
+ * xr_callSync (cnum, char *name)
+ * xr_callASync (cnum, char *name, void *func, .....)
+ * xr_closeClient (cnum)
+ *
+ * xr_initParam (cnum) // init params
+ * xr_setVerbose (verbose) // verbose flag
+ * xr_setDebug (debug) // debug flag
+ *
+ * xr_setIntInParam (cnum, int ival) // scalar param
+ * xr_setDoubleInParam (cnum, double dval)
+ * xr_setBoolInParam (cnum, int bval)
+ * xr_setStringInParam (cnum, char *str)
+ * xr_setDatetimeInParam (cnum, char *date)
+ * xr_setStructInParam (cnum, int snum)
+ * xr_setArrayInParam (cnum, int anum)
+ *
+ * stat = xr_getIntFromResult (cnum, int *ival) // get results
+ * stat = xr_getDoubleFromResult (cnum, double *dval)
+ * stat = xr_getBoolFromResult (cnum, int *bval)
+ * stat = xr_getStringFromResult (cnum, char **value)
+ * stat = xr_getDatetimeFromResult (cnum, char **date)
+ * stat = xr_getStructFromResult (cnum)
+ * stat = xr_getArrayFromResult (cnum)
+ *
+ * xr_envClean (cnum) // cleanup
+ * xr_freeParam (cnum)
+ * xr_freeResult (cnum)
+ * xr_clientCleanup (cnum)
+ *
+ *
+ * stat = xr_resultArrayInt (int anum, int index, int *value)
+ * stat = xr_resultArrayDouble (int anum, int index, int *value)
+ * stat = xr_resultArrayBool (int anum, int index, int *value)
+ * stat = xr_resultArrayString (int anum, int index, char **value)
+ * stat = xr_resultArrayDatetime (int anum, int index, char **value)
+ * stat = xr_resultArrayStruct (int anum, int index, int *value)
+ *
+ *
+ * @brief Client-side procedures
+ *
+ * @file xrClient.c
+ * @author Mike Fitzpatrick
+ * @date 6/10/09
+ */
+
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#include <xmlrpc-c/base.h>
+#include <xmlrpc-c/client.h>
+#include <xmlrpc-c/server.h>
+#include <xmlrpc-c/server_abyss.h>
+
+#include "xrpcP.h"
+
+#define DEBUG 0
+/*
+#define REUSE_CLIENT 1
+*/
+#define USE_DEFAULT_TRANSPORT 1
+#define CLIENT_START 0 /* slot zero reserved for monitor */
+
+
+int client_errstat = OK;
+int num_asynch_threads = 0;
+int client_debug = 0;
+int client_verbose = 0;
+
+
+
+pthread_mutex_t async_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static Client clientArray[MAX_CLIENTS];
+static int nclients = -1;
+
+int global_init = 0;
+
+typedef struct {
+ int cnum;
+ char *name;
+ Client *client;
+ xmlrpc_value *param;
+ xmlrpc_value *result;
+ void *ret_handler;
+} ASynch, *ASynchP;
+
+
+static void *xr_asynchRunner (void *arg);
+
+static void xr_defaultAsynchHandler (char *serverUrl, char *methodName,
+ xmlrpc_value *paramArrayP, void *user_data, xmlrpc_env *faultP,
+ xmlrpc_value *resultP);
+
+
+
+
+/* ***********************************************************************
+** INITCLIENT - Initialize the client-side environment
+*************************************************************************/
+
+int
+xr_newASync (int cnum)
+{
+ int aclient;
+ ClientP client = &clientArray[cnum];
+
+ aclient = xr_initClient (client->url, "async", "v1.0");
+ xr_initParam (aclient);
+
+ return (aclient);
+}
+
+
+int
+xr_setClient (int cnum, char *url)
+{
+ ClientP client = &clientArray[cnum];
+
+ memset (client, 0, sizeof(Client));
+ strcpy (client->url, url);
+
+ return (cnum);
+}
+
+
+int
+xr_initClient (char *url, char *name, char *version)
+{
+ int client_num = CLIENT_START;
+ ClientP client;
+ struct xmlrpc_clientparms clientParms;
+
+
+ /* Initialize XML-RPC interface. We create a private client object so
+ ** we can use asynchronous calls to get the response.
+ */
+ memset (&clientParms, 0, sizeof(clientParms));
+ for (client_num=CLIENT_START; client_num < MAX_CLIENTS; client_num++) {
+ client = &clientArray[client_num];
+
+#ifdef REUSE_CLIENT
+ /* If we've already seen this client before, we've already created
+ * the RPC client.
+ */
+ if (client->url[0] && strcmp (url, client->url) == 0) {
+ client->in_use = 1;
+ client_errstat = OK;
+ return (client_num);
+ }
+#endif
+ if (! client->in_use) {
+ memset (client, 0, sizeof (Client) );
+ break;
+ }
+ }
+
+
+ xmlrpc_env_init (&client->env);
+ if (! global_init++)
+ xmlrpc_client_setup_global_const (&client->env);
+ die_on_error (&client->env);
+
+#ifdef USE_DEFAULT_TRANSPORT
+ xmlrpc_client_create (&client->env, XMLRPC_CLIENT_NO_FLAGS, name, version,
+ &clientParms, 0,
+ &client->rpc_client);
+#else
+ clientParms.transport = "curl";
+ xmlrpc_client_create (&client->env, XMLRPC_CLIENT_NO_FLAGS, name, version,
+ &clientParms, XMLRPC_CPSIZE(transport),
+ &client->rpc_client);
+#endif
+ die_on_error (&client->env);
+
+ client->in_use++; /* increment counters */
+ nclients++;
+ strcpy (client->url, url); /* save the service url */
+ client_errstat = OK;
+
+ return (client_num);
+}
+
+
+int
+xr_closeClient (int cnum)
+{
+ ClientP client = &clientArray[cnum];
+
+
+ if (cnum < 0)
+ return (ERR);
+
+ xr_freeParam (cnum);
+ xr_freeResult (cnum);
+
+ /* Clean up our error-handling environment.
+ */
+ xmlrpc_env_init (&client->env);
+ xmlrpc_env_clean (&client->env);
+
+ /* Close down the client.
+ xmlrpc_client_destroy (client->rpc_client);
+ */
+ /*
+ xmlrpc_client_teardown_global_const ();
+ global_init = 0;
+ */
+
+ /*
+ */
+ memset (client, 0, sizeof(Client));
+ nclients--;
+
+ return (OK);
+}
+
+
+int xr_pause () { int i = 0; i++; return (i); }
+
+
+/* CALLSYNC -- Make a synchronous service call. The result value is parsed
+** in the caller via the API and using the 'result' pointer gotten here.
+*/
+int
+xr_callSync (int cnum, char *method_name)
+{
+ xmlrpc_value *result = (xmlrpc_value *) NULL;
+ ClientP client = &clientArray[cnum];
+#ifdef DTS
+ int ntries = 0;
+#endif
+
+ xmlrpc_server_info *serverInfoP =
+ xmlrpc_server_info_new (&client->env, client->url);
+
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ client_errstat = OK;
+ xmlrpc_env_init (&client->env);
+
+#ifdef DTS
+try_again_:
+#endif
+ xmlrpc_client_call2 (&client->env, client->rpc_client, serverInfoP,
+ method_name, client->param, &result);
+
+ if (client->env.fault_occurred) {
+ client_errstat = ERR;
+ if (client_verbose)
+ warn_on_error (&client->env);
+
+#ifdef DTS
+ if (strcmp (method_name, "ping") != 0 &&
+ strcmp (method_name, "poke") != 0 &&
+ strcmp (method_name, "dtslog") != 0) {
+ xr_pause();
+ xmlrpc_env_init (&client->env);
+ if (ntries++ < 30) {
+ sleep (3);
+ fprintf (stderr, "retry ....\n");
+ goto try_again_;
+ }
+ }
+#endif
+ } else {
+/*
+ strcpy (client->faultString, client->env.fault_string);
+*/
+ client_errstat = OK;
+ }
+
+
+ /* The result is a <params> array with a single <param> entry whose
+ ** <value> will be one of the base XML-RPC types. In the case of an
+ ** <array> or <struct> we need to extract data from those sepearately.
+ */
+ client->result = result;
+
+ /* We have the call results, so free the parameters.
+ xr_freeParam (cnum);
+ */
+ xmlrpc_server_info_free (serverInfoP); /* clean up */
+
+ return (client_errstat);
+}
+
+
+
+/* CALLASYNC -- Make an asynchronous service call. We do this by spawning
+** a thread to make the call and handle the result. Treat each asynch
+** message as a new client connection.
+*/
+
+int
+xr_callASync (int cnum, char *name, void *ret_handler)
+{
+ ClientP client = &clientArray[cnum];
+ pthread_attr_t attr; /* wait thread attribute */
+ pthread_t tnum; /* wait thread */
+ ASynch *as = calloc (1, sizeof(ASynch));
+
+
+ /* Get a new client connection for the thread.
+
+ tcnum = xr_initClient (client->url, "xrASync", "v1.0");
+ tclient = &clientArray[tcnum];
+
+ bcopy (&clientArray[cnum], &clientArray[tcnum], sizeof(Client) );
+ xmlrpc_INCREF (tclient->param);
+ */
+
+
+ /* Create a detatched thread in which to run.
+ */
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+ as->name = name;
+ as->cnum = cnum;
+ as->client = client;
+ as->ret_handler = ret_handler;
+
+ /* Start the asynch wait thread.
+ */
+ num_asynch_threads++;
+ if (pthread_create (&tnum, &attr, (void *)xr_asynchRunner, (void *)as)) {
+ perror ("Cannot start asynch wait thread");
+ exit (-1);
+ }
+
+ return (OK);
+}
+
+
+static void *
+xr_asynchRunner ( void *arg )
+{
+ xmlrpc_env env;
+ xmlrpc_value *result = (xmlrpc_value *) NULL;
+ xmlrpc_server_info *serverInfoP;
+ xmlrpc_client *clientP;
+
+ ASynch *as = (ASynch *)(arg);
+ ClientP client = as->client;
+ int client_num = as->cnum;
+ char *url = as->client->url;
+
+
+ xmlrpc_env_init (&env);
+ serverInfoP = xmlrpc_server_info_new (&env, url);
+
+ /* Setup.
+ */
+ xmlrpc_client_setup_global_const (&env);
+ xmlrpc_client_create (&env, XMLRPC_CLIENT_NO_FLAGS, XR_NAME, XR_VERSION,
+ NULL, 0, &clientP);
+
+ client_errstat = OK;
+ as->client->handlerFunc = as->ret_handler;
+
+ /* Make the asynchronous call and send it off by calling the finish
+ ** routine.
+ */
+ xmlrpc_env_init (&env);
+ xmlrpc_client_start_rpc (&env, clientP, serverInfoP,
+ as->name, client->param,
+ (xmlrpc_response_handler) xr_defaultAsynchHandler,
+ (void *)&client_num);
+
+ if (env.fault_occurred) {
+ client_errstat = ERR;
+ if (client_verbose)
+ warn_on_error (&client->env);
+ xmlrpc_env_init (&client->env);
+ }
+
+ xmlrpc_client_event_loop_finish (clientP);
+
+ /*
+ ** The result is a <params> array with a single <param> entry whose
+ ** <value> will be one of the base XML-RPC types. In the case of an
+ ** <array> or <struct> we need to extract data from those sepearately.
+ */
+ as->client->result = as->result = result;
+
+ xmlrpc_server_info_free (serverInfoP); /* clean up */
+ client->in_use = 0;
+ xr_closeClient (client_num);
+
+ free ((void *)as);
+
+ pthread_exit (&client_errstat); /* exit the thread */
+}
+
+
+/* Default asynchronous response handler.
+*/
+static void
+xr_defaultAsynchHandler (char *serverUrl, char *methodName,
+ xmlrpc_value *paramArrayP,
+ void *user_data,
+ xmlrpc_env *faultP,
+ xmlrpc_value *resultP)
+{
+ int *cnum = (int *)user_data;
+ ClientP client = &clientArray[*cnum];
+ int lock;
+
+
+ if (resultP) {
+ xmlrpc_INCREF(resultP);
+ client->result = resultP;
+
+ if ( (*(PFI)(client->handlerFunc))((void *)cnum) )
+ fprintf (stderr, "Error calling asynch handler function\n");
+
+ } else if (faultP->fault_occurred) {
+ fprintf (stderr, "Error in asynch (%s): %s\n",
+ methodName, faultP->fault_string);
+ client->env = *faultP;
+ }
+
+ /* Decrement the open thread counter.
+ */
+ lock = pthread_mutex_lock (&async_mutex);
+ num_asynch_threads--;
+ if (num_asynch_threads < 0)
+ num_asynch_threads = 0;
+ lock = pthread_mutex_unlock (&async_mutex);
+}
+
+
+/* XR_ASYNCWAIT -- Wait for all pending asyncronous requests to complete.
+**
+*/
+int
+xr_asyncWait ()
+{
+ register int wait = 0;
+
+
+ while (1) {
+ pthread_mutex_lock (&async_mutex);
+ wait = num_asynch_threads;
+ pthread_mutex_unlock (&async_mutex);
+
+ if (wait)
+ sleep (1);
+ else
+ break;
+ }
+
+ return (OK);
+}
+
+
+
+
+/***************************************************************************
+** Set parameter values. This code is used by the programming calling
+** the service, i.e. the 'Client'. As such we 'set' the parameters for the
+** call. It is in the method implementation on the server side that we
+** 'get' the params from the call.
+****************************************************************************/
+
+/* Initialize the parameter calling array.
+**
+*/
+void
+xr_initParam (int cnum)
+{
+ ClientP client = &clientArray[cnum];
+
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ /* If we're initializing the calling parameters, free up an previous
+ ** params, results or status flags.
+ */
+ if ( client->param )
+ xr_freeParam ( cnum );
+ if ( client->result )
+ xr_freeResult ( cnum );
+ client_errstat = OK;
+
+
+ /* Allocate an array for the parameters.
+ */
+ xmlrpc_env_init (&client->env);
+ client->param = xmlrpc_array_new (&client->env);
+
+ if (client_verbose)
+ warn_on_error (&client->env);
+}
+
+
+/*
+** Flag utilities.
+*/
+void xr_setVerbose (int verbose) { client_verbose = verbose; }
+void xr_setDebug (int debug ) { client_debug = debug; }
+
+
+
+/* Set parameters of various types. If the param was initialized as an
+** an array simply append the new value, otherwise overwrite the param
+** with the specified value after freeing it.
+*/
+void
+xr_setIntInParam (int cnum, int value)
+{
+ ClientP client = &clientArray[cnum];
+ xmlrpc_value *v = (xmlrpc_value *) NULL;
+
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ xmlrpc_env_init (&client->env); /* initialize env */
+ v = xmlrpc_int_new (&client->env, value);
+
+ if (! client->param )
+ client->param = xmlrpc_array_new (&client->env);
+
+ xmlrpc_array_append_item (&client->env, client->param, v);
+ if (client_verbose)
+ warn_on_error (&client->env);
+ xmlrpc_DECREF(v); /* free temp value */
+}
+
+
+void
+xr_setDoubleInParam (int cnum, double value)
+{
+ ClientP client = &clientArray[cnum];
+ xmlrpc_value *v = (xmlrpc_value *) NULL;
+
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ xmlrpc_env_init (&client->env);
+ v = xmlrpc_double_new (&client->env, value);
+
+ if (! client->param) /* safety initialization */
+ client->param = xmlrpc_array_new (&client->env);
+
+ xmlrpc_array_append_item (&client->env, client->param, v);
+ if (client_verbose)
+ warn_on_error (&client->env);
+ xmlrpc_DECREF(v);
+}
+
+void
+xr_setBoolInParam (int cnum, int value)
+{
+ ClientP client = &clientArray[cnum];
+ xmlrpc_value *v = (xmlrpc_value *) NULL;
+
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ xmlrpc_env_init (&client->env);
+ v = xmlrpc_bool_new (&client->env, (xmlrpc_bool) value);
+
+ if (! client->param) /* safety initialization */
+ client->param = xmlrpc_array_new (&client->env);
+
+ xmlrpc_array_append_item (&client->env, client->param, v);
+ if (client_verbose)
+ warn_on_error (&client->env);
+ xmlrpc_DECREF(v);
+}
+
+void
+xr_setStringInParam (int cnum, char *str)
+{
+ ClientP client = &clientArray[cnum];
+ xmlrpc_value *v = (xmlrpc_value *) NULL;
+
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ xmlrpc_env_init (&client->env);
+ v = xmlrpc_string_new (&client->env, (str ? str : ""));
+
+ if (! client->param) /* safety initialization */
+ client->param = xmlrpc_array_new (&client->env);
+
+ xmlrpc_array_append_item (&client->env, client->param, v);
+ if (client_verbose)
+ warn_on_error (&client->env);
+ xmlrpc_DECREF(v);
+}
+
+void
+xr_setDatetimeInParam (int cnum, char *str)
+{
+ ClientP client = &clientArray[cnum];
+ xmlrpc_value *v = (xmlrpc_value *) NULL;
+
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ xmlrpc_env_init (&client->env);
+ v = xmlrpc_datetime_new_str (&client->env, (const char *)str);
+
+ if (! client->param) /* safety initialization */
+ client->param = xmlrpc_array_new (&client->env);
+
+ xmlrpc_array_append_item (&client->env, client->param, v);
+ if (client_verbose)
+ warn_on_error (&client->env);
+ xmlrpc_DECREF(v);
+}
+
+
+void
+xr_setStructInParam (int cnum, int snum)
+{
+ ClientP client = &clientArray[cnum];
+
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (! client->param) /* safety initialization */
+ client->param = xmlrpc_array_new (&client->env);
+
+ xmlrpc_env_init (&client->env);
+ xmlrpc_array_append_item (&client->env, client->param, xr_getSParam(snum));
+ if (client_verbose)
+ warn_on_error (&client->env);
+}
+
+void
+xr_setArrayInParam (int cnum, int anum)
+{
+ ClientP client = &clientArray[cnum];
+
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (! client->param) /* safety initialization */
+ client->param = xmlrpc_array_new (&client->env);
+
+ xmlrpc_env_init (&client->env);
+ xmlrpc_array_append_item (&client->env, client->param,
+ xr_getAElement(anum));
+ if (client_verbose)
+ warn_on_error (&client->env);
+}
+
+
+
+
+/***************************************************************************
+** Get/Set result values.
+****************************************************************************/
+
+int
+xr_getIntFromResult (int cnum, int *value)
+{
+ ClientP client = &clientArray[cnum];
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (client_errstat == OK) {
+ xmlrpc_env_init (&client->env);
+ xmlrpc_read_int (&client->env, client->result, value);
+
+ return (client->env.fault_occurred ? ERR : OK);
+ } else
+ return (ERR);
+}
+
+
+int
+xr_getDoubleFromResult (int cnum, double *value)
+{
+ ClientP client = &clientArray[cnum];
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (client_errstat == OK) {
+ xmlrpc_read_double (&client->env, client->result, value);
+ return (client->env.fault_occurred ? ERR : OK);
+ } else
+ return (ERR);
+}
+
+
+int
+xr_getBoolFromResult (int cnum, int *value)
+{
+ ClientP client = &clientArray[cnum];
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (client_errstat == OK) {
+ xmlrpc_env_init (&client->env);
+ xmlrpc_read_bool (&client->env, client->result, (xmlrpc_bool *) value);
+ return (client->env.fault_occurred ? ERR : OK);
+ } else
+ return (ERR);
+}
+
+int
+xr_getStringFromResult (int cnum, char **value)
+{
+ ClientP client = &clientArray[cnum];
+ const char *str = (char *) NULL;
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (client_errstat == OK) {
+ xmlrpc_env_init (&client->env);
+ xmlrpc_read_string (&client->env, client->result, &str);
+ if (str) {
+ if (*value)
+ strcpy (*value, str);
+ else
+ *value = strdup (str);
+ free ((char *) str);
+ }
+ return (client->env.fault_occurred ? ERR : OK);
+
+ } else
+ return (ERR);
+}
+
+int
+xr_getDatetimeFromResult (int cnum, char **date)
+{
+ ClientP client = &clientArray[cnum];
+ const char *str = (char *) NULL;
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (client_errstat == OK) {
+ xmlrpc_env_init (&client->env);
+ xmlrpc_read_datetime_str (&client->env, client->result, &str);
+ strcpy (*date, str);
+ if (str) free ((char *) str);
+ return (client->env.fault_occurred ? ERR : OK);
+
+ } else
+ return (ERR);
+}
+
+int
+xr_getStructFromResult (int cnum, int *snum)
+{
+ ClientP client = &clientArray[cnum];
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ *snum = 0;
+ if (client_errstat == OK) {
+ *snum = xr_newStruct (); /* FIXME */
+ xr_setSParam (*snum, client->result);
+
+ return (client->env.fault_occurred ? ERR : OK);
+ } else
+ return (ERR);
+}
+
+int
+xr_getArrayFromResult (int cnum, int *anum)
+{
+ ClientP client = &clientArray[cnum];
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (client_errstat == OK) {
+ *anum = xr_newArray ();
+ xr_setAElement (*anum, client->result);
+
+ return (client->env.fault_occurred ? ERR : OK);
+ } else
+ return (ERR);
+}
+
+
+/***************************************************************************
+** Utility procedures.
+****************************************************************************/
+
+/**
+ * XR_GETERRMSG -- Get the error message from the last call.
+ */
+char *
+xr_getErrMsg (int cnum)
+{
+ ClientP client = &clientArray[cnum];
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ return (client->env.fault_string);
+}
+
+
+/**
+ * XR_GETERRCODE -- Get the error code from the last call.
+ */
+int
+xr_getErrCode (int cnum)
+{
+ ClientP client = &clientArray[cnum];
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ return (client->env.fault_occurred);
+}
+
+
+
+/***************************************************************************
+** Cleanup procedures.
+****************************************************************************/
+
+/**
+ * XR_ENVCLEAN -- Clean the environment of the specified client.
+ */
+void
+xr_envClean (int cnum)
+{
+ ClientP client = &clientArray[cnum];
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ xmlrpc_env_clean (&client->env); /* cleanup error-handling env */
+}
+
+
+/**
+ * XR_FREEPARAM -- Free the Client parameter xmlrpc_value.
+ */
+void
+xr_freeParam (int cnum)
+{
+ ClientP client = &clientArray[cnum];
+ int refcount = 0;
+ extern int xmlrpc_refcount();
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (client->param) {
+ /*
+ int len = xmlrpc_array_size (&client->env, client->param);
+ xmlrpc_value *v;
+
+ while (len >= 0) {
+ xmlrpc_array_read_item (&client->env, client->param, --len, &v);
+ warn_on_error (&client->env);
+ xmlrpc_DECREF (v);
+ }
+ */
+ refcount = xmlrpc_refcount (client->param) - 1;
+ xmlrpc_DECREF (client->param);
+#ifdef CLEAN_ENV
+ xmlrpc_env_clean(&client->env);
+#endif
+ }
+
+ if (refcount == 0)
+ client->param = (xmlrpc_value *) NULL;
+}
+
+
+/**
+ * Free the Client result xmlrpc_value.
+ */
+void
+xr_freeResult (int cnum)
+{
+ ClientP client = &clientArray[cnum];
+ int refcount = 0;
+ extern int xmlrpc_refcount();
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ if (client->result) {
+ /*
+ int len = xmlrpc_array_size (&client->env, client->result);
+ xmlrpc_value *v;
+
+ while (len >= 0) {
+ xmlrpc_array_read_item (&client->env, client->result, --len, &v);
+ warn_on_error (&client->env);
+ xmlrpc_DECREF (v);
+ }
+ */
+ refcount = xmlrpc_refcount (client->result) - 1;
+ if (refcount)
+ xmlrpc_DECREF (client->result);
+#ifdef CLEAN_ENV
+ xmlrpc_env_clean(&client->env);
+#endif
+ }
+
+ if (refcount == 0)
+ client->result = (xmlrpc_value *) NULL;
+}
+
+
+/**
+ * Shutdown our XML-RPC client library.
+ */
+void
+xr_clientCleanup (int cnum)
+{
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+/*
+ if (client->rpc_client)
+ xmlrpc_client_cleanup ();
+*/
+ xr_envClean (cnum); /* cleanup error-handling env */
+}
+
+
+void
+printClient (int cnum)
+{
+ ClientP client = &clientArray[cnum];
+
+ assert (cnum < MAX_CLIENTS); /* validate the client number */
+
+ fprintf (stderr, "Client %d\n", cnum);
+ fprintf (stderr, " url = '%s'\n", client->url);
+ fprintf (stderr, " param = 0x%lx\n", (long) client->param);
+ fprintf (stderr, " result = 0x%lx\n", (long) client->result);
+ fprintf (stderr, " client = 0x%lx\n", (long) client->rpc_client);
+ fprintf (stderr, " in_use = %d\n", client->in_use);
+}
+
+