~ubuntu-branches/ubuntu/lucid/cmake/lucid

« back to all changes in this revision

Viewing changes to Utilities/cmxmlrpc/xmlrpc_client.c

  • Committer: Bazaar Package Importer
  • Author(s): Artur Rona
  • Date: 2009-12-16 11:11:54 UTC
  • mfrom: (3.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20091216111154-6accvv6yq86h2hkc
Tags: 2.8.0-5ubuntu1
* Merge from debian testing (LP: #497349). Remaining changes:
  - Keep the Replaces: on cmake-data to cover the Kubuntu version from
    Jaunty in case someone decides to do an (unsupported) Jaunty->Lucid
    upgrade.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
2
 
**
3
 
** Redistribution and use in source and binary forms, with or without
4
 
** modification, are permitted provided that the following conditions
5
 
** are met:
6
 
** 1. Redistributions of source code must retain the above copyright
7
 
**    notice, this list of conditions and the following disclaimer.
8
 
** 2. Redistributions in binary form must reproduce the above copyright
9
 
**    notice, this list of conditions and the following disclaimer in the
10
 
**    documentation and/or other materials provided with the distribution.
11
 
** 3. The name of the author may not be used to endorse or promote products
12
 
**    derived from this software without specific prior written permission. 
13
 
**  
14
 
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 
** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 
** SUCH DAMAGE. */
25
 
 
26
 
#include "xmlrpc_config.h"
27
 
 
28
 
#undef PACKAGE
29
 
#undef VERSION
30
 
 
31
 
#include <stddef.h>
32
 
#include <stdio.h>
33
 
#include <string.h>
34
 
#include <stdlib.h>
35
 
#include <assert.h>
36
 
#include <errno.h>
37
 
 
38
 
#include "bool.h"
39
 
#include "mallocvar.h"
40
 
#include "xmlrpc.h"
41
 
#include "xmlrpc_int.h"
42
 
#include "xmlrpc_client.h"
43
 
#include "xmlrpc_client_int.h"
44
 
/* transport_config.h defines XMLRPC_DEFAULT_TRANSPORT,
45
 
    MUST_BUILD_WININET_CLIENT, MUST_BUILD_CURL_CLIENT,
46
 
    MUST_BUILD_LIBWWW_CLIENT 
47
 
*/
48
 
#include "transport_config.h"
49
 
 
50
 
#if MUST_BUILD_WININET_CLIENT
51
 
#include "xmlrpc_wininet_transport.h"
52
 
#endif
53
 
#if MUST_BUILD_CURL_CLIENT
54
 
#include "xmlrpc_curl_transport.h"
55
 
#endif
56
 
#if MUST_BUILD_LIBWWW_CLIENT
57
 
#include "xmlrpc_libwww_transport.h"
58
 
#endif
59
 
 
60
 
struct xmlrpc_client {
61
 
/*----------------------------------------------------------------------------
62
 
   This represents a client object.
63
 
-----------------------------------------------------------------------------*/
64
 
    struct clientTransport * transportP;
65
 
};
66
 
 
67
 
 
68
 
 
69
 
typedef struct call_info
70
 
{
71
 
    /* These fields are used when performing asynchronous calls.
72
 
    ** The _asynch_data_holder contains server_url, method_name and
73
 
    ** param_array, so it's the only thing we need to free. */
74
 
    xmlrpc_value *_asynch_data_holder;
75
 
    char *server_url;
76
 
    char *method_name;
77
 
    xmlrpc_value *param_array;
78
 
    xmlrpc_response_handler callback;
79
 
    void *user_data;
80
 
 
81
 
    /* The serialized XML data passed to this call. We keep this around
82
 
    ** for use by our source_anchor field. */
83
 
    xmlrpc_mem_block *serialized_xml;
84
 
} call_info;
85
 
 
86
 
static bool clientInitialized = FALSE;
87
 
 
88
 
/*=========================================================================
89
 
**  Initialization and Shutdown
90
 
**=========================================================================
91
 
*/
92
 
 
93
 
static struct clientTransportOps clientTransportOps;
94
 
 
95
 
static struct xmlrpc_client client;
96
 
    /* Some day, we need to make this dynamically allocated, so there can
97
 
       be more than one client per program and just generally to provide
98
 
       a cleaner interface.
99
 
    */
100
 
 
101
 
extern void
102
 
xmlrpc_client_init(int          const flags,
103
 
                   const char * const appname,
104
 
                   const char * const appversion) {
105
 
 
106
 
    struct xmlrpc_clientparms clientparms;
107
 
 
108
 
    /* As our interface does not allow for failure, we just fail silently ! */
109
 
    
110
 
    xmlrpc_env env;
111
 
    xmlrpc_env_init(&env);
112
 
 
113
 
    clientparms.transport = XMLRPC_DEFAULT_TRANSPORT;
114
 
 
115
 
    xmlrpc_client_init2(&env, flags,
116
 
                        appname, appversion,
117
 
                        &clientparms, XMLRPC_CPSIZE(transport));
118
 
 
119
 
    xmlrpc_env_clean(&env);
120
 
}
121
 
 
122
 
 
123
 
 
124
 
const char * 
125
 
xmlrpc_client_get_default_transport(xmlrpc_env * const env ATTR_UNUSED) {
126
 
 
127
 
    return XMLRPC_DEFAULT_TRANSPORT;
128
 
}
129
 
 
130
 
 
131
 
 
132
 
static void
133
 
setupTransport(xmlrpc_env * const envP,
134
 
               const char * const transportName) {
135
 
 
136
 
    if (FALSE) {
137
 
    }
138
 
#if MUST_BUILD_WININET_CLIENT
139
 
    else if (strcmp(transportName, "wininet") == 0)
140
 
        clientTransportOps = xmlrpc_wininet_transport_ops;
141
 
#endif
142
 
#if MUST_BUILD_CURL_CLIENT
143
 
    else if (strcmp(transportName, "curl") == 0)
144
 
        clientTransportOps = xmlrpc_curl_transport_ops;
145
 
    else if (strcmp(transportName, "libcurl") == 0)
146
 
        clientTransportOps = xmlrpc_curl_transport_ops;
147
 
#endif
148
 
#if MUST_BUILD_LIBWWW_CLIENT
149
 
    else if (strcmp(transportName, "libwww") == 0)
150
 
        clientTransportOps = xmlrpc_libwww_transport_ops;
151
 
#endif
152
 
    else
153
 
        xmlrpc_env_set_fault_formatted(
154
 
            envP, XMLRPC_INTERNAL_ERROR, 
155
 
            "Unrecognized XML transport name '%s'", transportName);
156
 
}
157
 
 
158
 
 
159
 
 
160
 
void 
161
 
xmlrpc_client_init2(xmlrpc_env *                const envP,
162
 
                    int                         const flags,
163
 
                    const char *                const appname,
164
 
                    const char *                const appversion,
165
 
                    struct xmlrpc_clientparms * const clientparmsP,
166
 
                    unsigned int                const parm_size) {
167
 
 
168
 
    if (clientInitialized)
169
 
        xmlrpc_env_set_fault_formatted(
170
 
            envP, XMLRPC_INTERNAL_ERROR, 
171
 
            "Xmlrpc-c client instance has already been initialized "
172
 
            "(need to call xmlrpc_client_cleanup() before you can "
173
 
            "reinitialize).");
174
 
    else {
175
 
        const char * transportName;
176
 
 
177
 
        if (parm_size < XMLRPC_CPSIZE(transport) ||
178
 
            clientparmsP->transport == NULL) {
179
 
            /* He didn't specify a transport.  Use the default */
180
 
            transportName = xmlrpc_client_get_default_transport(envP);
181
 
        } else
182
 
            transportName = clientparmsP->transport;
183
 
 
184
 
        if (!envP->fault_occurred) {
185
 
            setupTransport(envP, transportName);
186
 
            if (!envP->fault_occurred) {
187
 
                clientTransportOps.create(envP, flags, appname, appversion,
188
 
                                          &client.transportP);
189
 
                if (!envP->fault_occurred)
190
 
                    clientInitialized = TRUE;
191
 
            }
192
 
        }
193
 
    }
194
 
}
195
 
 
196
 
 
197
 
 
198
 
void 
199
 
xmlrpc_client_cleanup() {
200
 
 
201
 
    XMLRPC_ASSERT(clientInitialized);
202
 
 
203
 
    clientTransportOps.destroy(client.transportP);
204
 
    
205
 
    clientInitialized = FALSE;
206
 
}
207
 
 
208
 
 
209
 
 
210
 
static void 
211
 
call_info_free(call_info * const callInfoP) {
212
 
 
213
 
    /* Assume the worst.. That only parts of the call_info are valid. */
214
 
 
215
 
    XMLRPC_ASSERT_PTR_OK(callInfoP);
216
 
 
217
 
    /* If this has been allocated, we're responsible for destroying it. */
218
 
    if (callInfoP->_asynch_data_holder)
219
 
        xmlrpc_DECREF(callInfoP->_asynch_data_holder);
220
 
 
221
 
    /* Now we can blow away the XML data. */
222
 
    if (callInfoP->serialized_xml)
223
 
         xmlrpc_mem_block_free(callInfoP->serialized_xml);
224
 
 
225
 
    free(callInfoP);
226
 
}
227
 
 
228
 
 
229
 
 
230
 
static void
231
 
call_info_new(xmlrpc_env *         const envP,
232
 
              xmlrpc_server_info * const server,
233
 
              const char *         const method_name,
234
 
              xmlrpc_value *       const argP,
235
 
              call_info **         const callInfoPP) {
236
 
/*----------------------------------------------------------------------------
237
 
   Create a call_info object.  A call_info object represents an XML-RPC
238
 
   call.
239
 
-----------------------------------------------------------------------------*/
240
 
    call_info * callInfoP;
241
 
 
242
 
    XMLRPC_ASSERT_PTR_OK(argP);
243
 
    XMLRPC_ASSERT_PTR_OK(callInfoPP);
244
 
 
245
 
    if (method_name == NULL)
246
 
        xmlrpc_env_set_fault_formatted(
247
 
            envP, XMLRPC_INTERNAL_ERROR,
248
 
            "method name argument is NULL pointer");
249
 
    else if (server == NULL)
250
 
        xmlrpc_env_set_fault_formatted(
251
 
            envP, XMLRPC_INTERNAL_ERROR,
252
 
            "server info argument is NULL pointer");
253
 
    else {
254
 
        MALLOCVAR(callInfoP);
255
 
        if (callInfoP == NULL)
256
 
            xmlrpc_env_set_fault_formatted(
257
 
                envP, XMLRPC_INTERNAL_ERROR,
258
 
                "Couldn't allocate memory for xmlrpc_call_info");
259
 
        else {
260
 
            xmlrpc_mem_block * callXmlP;
261
 
 
262
 
        /* Clear contents. */
263
 
            memset(callInfoP, 0, sizeof(*callInfoP));
264
 
        
265
 
            /* Make the XML for our call */
266
 
            callXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
267
 
            if (!envP->fault_occurred) {
268
 
                xmlrpc_serialize_call(envP, callXmlP, method_name, argP);
269
 
                if (!envP->fault_occurred) {
270
 
                    xmlrpc_traceXml("XML-RPC CALL", 
271
 
                                    XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP),
272
 
                                    (unsigned int)XMLRPC_MEMBLOCK_SIZE(char, callXmlP));
273
 
        
274
 
                    callInfoP->serialized_xml = callXmlP;
275
 
 
276
 
                    *callInfoPP = callInfoP;
277
 
                }
278
 
                if (envP->fault_occurred)
279
 
                    XMLRPC_MEMBLOCK_FREE(char, callXmlP);
280
 
            }
281
 
            if (envP->fault_occurred)
282
 
                free(callInfoP);
283
 
        }
284
 
    }
285
 
}
286
 
 
287
 
 
288
 
 
289
 
static void
290
 
clientCallServerParams(xmlrpc_env *             const envP,
291
 
                       struct clientTransport * const transportP,
292
 
                       xmlrpc_server_info *     const serverP,
293
 
                       const char *             const methodName,
294
 
                       xmlrpc_value *           const paramArrayP,
295
 
                       xmlrpc_value **          const resultPP) {
296
 
 
297
 
    call_info * callInfoP;
298
 
    
299
 
    if (!clientInitialized)
300
 
        xmlrpc_env_set_fault_formatted(
301
 
            envP, XMLRPC_INTERNAL_ERROR, 
302
 
            "Xmlrpc-c client instance has not been initialized "
303
 
            "(need to call xmlrpc_client_init2()).");
304
 
    else {
305
 
        call_info_new(envP, serverP, methodName, paramArrayP, &callInfoP);
306
 
        if (!envP->fault_occurred) {
307
 
            xmlrpc_mem_block * respXmlP;
308
 
        
309
 
            clientTransportOps.call(envP, transportP, serverP, 
310
 
                                    callInfoP->serialized_xml, callInfoP, 
311
 
                                    &respXmlP);
312
 
            if (!envP->fault_occurred) {
313
 
                xmlrpc_traceXml("XML-RPC RESPONSE", 
314
 
                                XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP),
315
 
                                (unsigned int)XMLRPC_MEMBLOCK_SIZE(char, respXmlP));
316
 
            
317
 
                *resultPP = xmlrpc_parse_response(
318
 
                    envP,
319
 
                    XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP),
320
 
                    XMLRPC_MEMBLOCK_SIZE(char, respXmlP));
321
 
                XMLRPC_MEMBLOCK_FREE(char, respXmlP);
322
 
            }                    
323
 
            call_info_free(callInfoP);
324
 
        }
325
 
    }
326
 
}
327
 
 
328
 
 
329
 
 
330
 
xmlrpc_value * 
331
 
xmlrpc_client_call_params(xmlrpc_env *   const envP,
332
 
                          const char *   const serverUrl,
333
 
                          const char *   const methodName,
334
 
                          xmlrpc_value * const paramArrayP) {
335
 
 
336
 
    xmlrpc_value *retval;
337
 
 
338
 
    XMLRPC_ASSERT_ENV_OK(envP);
339
 
    XMLRPC_ASSERT_PTR_OK(serverUrl);
340
 
 
341
 
    if (!clientInitialized)
342
 
        xmlrpc_env_set_fault_formatted(
343
 
            envP, XMLRPC_INTERNAL_ERROR, 
344
 
            "Xmlrpc-c client instance has not been initialized "
345
 
            "(need to call xmlrpc_client_init2()).");
346
 
    else {
347
 
        xmlrpc_server_info * serverP;
348
 
        
349
 
        /* Build a server info object and make our call. */
350
 
        serverP = xmlrpc_server_info_new(envP, serverUrl);
351
 
        if (!envP->fault_occurred) {
352
 
            clientCallServerParams(envP, client.transportP, serverP, 
353
 
                                   methodName, paramArrayP,
354
 
                                   &retval);
355
 
 
356
 
            xmlrpc_server_info_free(serverP);
357
 
        }
358
 
    }
359
 
        
360
 
    if (!envP->fault_occurred)
361
 
        XMLRPC_ASSERT_VALUE_OK(retval);
362
 
 
363
 
    return retval;
364
 
}
365
 
 
366
 
 
367
 
 
368
 
static xmlrpc_value * 
369
 
xmlrpc_client_call_va(xmlrpc_env * const envP,
370
 
                      const char * const server_url,
371
 
                      const char * const method_name,
372
 
                      const char * const format,
373
 
                      va_list            args) {
374
 
 
375
 
    xmlrpc_value * argP;
376
 
    xmlrpc_value * retval = 0;
377
 
    xmlrpc_env argenv;
378
 
    const char * suffix;
379
 
 
380
 
    XMLRPC_ASSERT_ENV_OK(envP);
381
 
    XMLRPC_ASSERT_PTR_OK(format);
382
 
 
383
 
    /* Build our argument value. */
384
 
    xmlrpc_env_init(&argenv);
385
 
    xmlrpc_build_value_va(&argenv, format, args, &argP, &suffix);
386
 
    if (argenv.fault_occurred) {
387
 
        xmlrpc_env_set_fault_formatted(
388
 
            envP, argenv.fault_code, "Invalid RPC arguments.  "
389
 
            "The format argument must indicate a single array, and the "
390
 
            "following arguments must correspond to that format argument.  "
391
 
            "The failure is: %s",
392
 
            argenv.fault_string);
393
 
        xmlrpc_env_clean(&argenv);
394
 
    } else {
395
 
        XMLRPC_ASSERT_VALUE_OK(argP);
396
 
        
397
 
        if (*suffix != '\0')
398
 
            xmlrpc_env_set_fault_formatted(
399
 
                envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
400
 
                "specifier: '%s'.  There must be exactly one arument.",
401
 
                suffix);
402
 
        else {
403
 
            /* Perform the actual XML-RPC call. */
404
 
            retval = xmlrpc_client_call_params(
405
 
                envP, server_url, method_name, argP);
406
 
            if (!envP->fault_occurred)
407
 
                XMLRPC_ASSERT_VALUE_OK(retval);
408
 
        }
409
 
        xmlrpc_DECREF(argP);
410
 
    }
411
 
    return retval;
412
 
}
413
 
 
414
 
 
415
 
 
416
 
xmlrpc_value * 
417
 
xmlrpc_client_call(xmlrpc_env * const envP,
418
 
                   const char *       const server_url,
419
 
                   const char *       const method_name,
420
 
                   const char *       const format,
421
 
                   ...) {
422
 
 
423
 
    xmlrpc_value * result;
424
 
    va_list args;
425
 
 
426
 
    va_start(args, format);
427
 
    result = xmlrpc_client_call_va(envP, server_url,
428
 
                                   method_name, format, args);
429
 
    va_end(args);
430
 
 
431
 
    return result;
432
 
}
433
 
 
434
 
 
435
 
 
436
 
xmlrpc_value * 
437
 
xmlrpc_client_call_server(xmlrpc_env *         const envP,
438
 
                          xmlrpc_server_info * const serverP,
439
 
                          const char *         const methodName,
440
 
                          const char *         const format, 
441
 
                          ...) {
442
 
 
443
 
    va_list args;
444
 
    xmlrpc_value * paramArrayP;
445
 
    xmlrpc_value * retval;
446
 
    const char * suffix;
447
 
 
448
 
    XMLRPC_ASSERT_ENV_OK(envP);
449
 
    XMLRPC_ASSERT_PTR_OK(format);
450
 
 
451
 
    /* Build our argument */
452
 
    va_start(args, format);
453
 
    xmlrpc_build_value_va(envP, format, args, &paramArrayP, &suffix);
454
 
    va_end(args);
455
 
 
456
 
    if (!envP->fault_occurred) {
457
 
        if (*suffix != '\0')
458
 
            xmlrpc_env_set_fault_formatted(
459
 
                envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
460
 
                "specifier: '%s'.  There must be exactly one arument.",
461
 
                suffix);
462
 
        else
463
 
            clientCallServerParams(envP, client.transportP, serverP, 
464
 
                                   methodName, paramArrayP, 
465
 
                                   &retval);
466
 
 
467
 
        xmlrpc_DECREF(paramArrayP);
468
 
    }
469
 
    return retval;
470
 
}
471
 
 
472
 
 
473
 
void 
474
 
xmlrpc_client_event_loop_finish_asynch(void) {
475
 
    XMLRPC_ASSERT(clientInitialized);
476
 
    clientTransportOps.finish_asynch(client.transportP, timeout_no, 0);
477
 
}
478
 
 
479
 
 
480
 
 
481
 
void 
482
 
xmlrpc_client_event_loop_finish_asynch_timeout(timeout_t const timeout) {
483
 
    XMLRPC_ASSERT(clientInitialized);
484
 
    clientTransportOps.finish_asynch(client.transportP, timeout_yes, timeout);
485
 
}
486
 
 
487
 
 
488
 
 
489
 
static void 
490
 
call_info_set_asynch_data(xmlrpc_env *   const env,
491
 
                          call_info *    const info,
492
 
                          const char *   const server_url,
493
 
                          const char *   const method_name,
494
 
                          xmlrpc_value * const argP,
495
 
                          xmlrpc_response_handler callback,
496
 
                          void *         const user_data) {
497
 
 
498
 
    xmlrpc_value *holder;
499
 
 
500
 
    XMLRPC_ASSERT_ENV_OK(env);
501
 
    XMLRPC_ASSERT_PTR_OK(info);
502
 
    XMLRPC_ASSERT(info->_asynch_data_holder == NULL);
503
 
    XMLRPC_ASSERT_PTR_OK(server_url);
504
 
    XMLRPC_ASSERT_PTR_OK(method_name);
505
 
    XMLRPC_ASSERT_VALUE_OK(argP);
506
 
 
507
 
    /* Install our callback and user_data.
508
 
    ** (We're not responsible for destroying the user_data.) */
509
 
    info->callback  = callback;
510
 
    info->user_data = user_data;
511
 
 
512
 
    /* Build an XML-RPC data structure to hold our other data. This makes
513
 
    ** copies of server_url and method_name, and increments the reference
514
 
    ** to the argument *argP. */
515
 
    holder = xmlrpc_build_value(env, "(ssV)",
516
 
                                server_url, method_name, argP);
517
 
    XMLRPC_FAIL_IF_FAULT(env);
518
 
 
519
 
    /* Parse the newly-allocated structure into our public member variables.
520
 
    ** This doesn't make any new references, so we can dispose of the whole
521
 
    ** thing by DECREF'ing the one master reference. Nifty, huh? */
522
 
    xmlrpc_parse_value(env, holder, "(ssV)",
523
 
                       &info->server_url,
524
 
                       &info->method_name,
525
 
                       &info->param_array);
526
 
    XMLRPC_FAIL_IF_FAULT(env);
527
 
 
528
 
    /* Hand over ownership of the holder to the call_info struct. */
529
 
    info->_asynch_data_holder = holder;
530
 
    holder = NULL;
531
 
 
532
 
 cleanup:
533
 
    if (env->fault_occurred) {
534
 
        if (holder)
535
 
            xmlrpc_DECREF(holder);
536
 
    }
537
 
}
538
 
 
539
 
/*=========================================================================
540
 
**  xmlrpc_server_info
541
 
**=========================================================================
542
 
*/
543
 
 
544
 
xmlrpc_server_info *
545
 
xmlrpc_server_info_new (xmlrpc_env * const env,
546
 
                        const char * const server_url) {
547
 
 
548
 
    xmlrpc_server_info *server;
549
 
    char *url_copy;
550
 
 
551
 
    /* Error-handling preconditions. */
552
 
    url_copy = NULL;
553
 
 
554
 
    XMLRPC_ASSERT_ENV_OK(env);
555
 
    XMLRPC_ASSERT_PTR_OK(server_url);
556
 
 
557
 
    /* Allocate our memory blocks. */
558
 
    server = (xmlrpc_server_info*) malloc(sizeof(xmlrpc_server_info));
559
 
    XMLRPC_FAIL_IF_NULL(server, env, XMLRPC_INTERNAL_ERROR,
560
 
                        "Couldn't allocate memory for xmlrpc_server_info");
561
 
    memset(server, 0, sizeof(xmlrpc_server_info));
562
 
    url_copy = (char*) malloc(strlen(server_url) + 1);
563
 
    XMLRPC_FAIL_IF_NULL(url_copy, env, XMLRPC_INTERNAL_ERROR,
564
 
                        "Couldn't allocate memory for server URL");
565
 
 
566
 
    /* Build our object. */
567
 
    strcpy(url_copy, server_url);
568
 
    server->_server_url = url_copy;
569
 
    server->_http_basic_auth = NULL;
570
 
 
571
 
 cleanup:
572
 
    if (env->fault_occurred) {
573
 
        if (url_copy)
574
 
            free(url_copy);
575
 
        if (server)
576
 
            free(server);
577
 
        return NULL;
578
 
    }
579
 
    return server;
580
 
}
581
 
 
582
 
xmlrpc_server_info * xmlrpc_server_info_copy(xmlrpc_env *env,
583
 
                                             xmlrpc_server_info *aserver)
584
 
{
585
 
    xmlrpc_server_info *server;
586
 
    char *url_copy, *auth_copy;
587
 
 
588
 
    XMLRPC_ASSERT_ENV_OK(env);
589
 
    XMLRPC_ASSERT_PTR_OK(aserver);
590
 
 
591
 
    /* Error-handling preconditions. */
592
 
    url_copy = NULL;
593
 
    auth_copy = NULL;
594
 
 
595
 
    /* Allocate our memory blocks. */
596
 
    server = (xmlrpc_server_info*) malloc(sizeof(xmlrpc_server_info));
597
 
    XMLRPC_FAIL_IF_NULL(server, env, XMLRPC_INTERNAL_ERROR,
598
 
                        "Couldn't allocate memory for xmlrpc_server_info");
599
 
    url_copy = (char*) malloc(strlen(aserver->_server_url) + 1);
600
 
    XMLRPC_FAIL_IF_NULL(url_copy, env, XMLRPC_INTERNAL_ERROR,
601
 
                        "Couldn't allocate memory for server URL");
602
 
    auth_copy = (char*) malloc(strlen(aserver->_http_basic_auth) + 1);
603
 
    XMLRPC_FAIL_IF_NULL(auth_copy, env, XMLRPC_INTERNAL_ERROR,
604
 
                        "Couldn't allocate memory for authentication info");
605
 
 
606
 
    /* Build our object. */
607
 
    strcpy(url_copy, aserver->_server_url);
608
 
    server->_server_url = url_copy;
609
 
    strcpy(auth_copy, aserver->_http_basic_auth);
610
 
    server->_http_basic_auth = auth_copy;
611
 
 
612
 
    cleanup:
613
 
    if (env->fault_occurred) {
614
 
        if (url_copy)
615
 
            free(url_copy);
616
 
        if (auth_copy)
617
 
            free(auth_copy);
618
 
        if (server)
619
 
            free(server);
620
 
        return NULL;
621
 
    }
622
 
    return server;
623
 
 
624
 
}
625
 
 
626
 
void xmlrpc_server_info_free (xmlrpc_server_info *server)
627
 
{
628
 
    XMLRPC_ASSERT_PTR_OK(server);
629
 
    XMLRPC_ASSERT(server->_server_url != XMLRPC_BAD_POINTER);
630
 
 
631
 
    if (server->_http_basic_auth)
632
 
        free(server->_http_basic_auth);
633
 
    free(server->_server_url);
634
 
    server->_server_url = XMLRPC_BAD_POINTER;
635
 
    free(server);
636
 
}
637
 
 
638
 
/*=========================================================================
639
 
**  xmlrpc_client_call_asynch
640
 
**=========================================================================
641
 
*/
642
 
 
643
 
void 
644
 
xmlrpc_client_call_asynch(const char * const serverUrl,
645
 
                          const char * const methodName,
646
 
                          xmlrpc_response_handler callback,
647
 
                          void *       const userData,
648
 
                          const char * const format,
649
 
                          ...) {
650
 
 
651
 
    xmlrpc_env env;
652
 
    va_list args;
653
 
    xmlrpc_value * paramArrayP;
654
 
    const char * suffix;
655
 
 
656
 
    xmlrpc_env_init(&env);
657
 
 
658
 
    XMLRPC_ASSERT_PTR_OK(serverUrl);
659
 
    XMLRPC_ASSERT_PTR_OK(format);
660
 
 
661
 
    /* Build our argument array. */
662
 
    va_start(args, format);
663
 
    xmlrpc_build_value_va(&env, format, args, &paramArrayP, &suffix);
664
 
    va_end(args);
665
 
    if (env.fault_occurred) {
666
 
        /* Unfortunately, we have no way to return an error and the
667
 
           regular callback for a failed RPC is designed to have the
668
 
           parameter array passed to it.  This was probably an oversight
669
 
           of the original asynch design, but now we have to be as
670
 
           backward compatible as possible, so we do this:
671
 
        */
672
 
        (*callback)(serverUrl, methodName, NULL, userData, &env, NULL);
673
 
    } else {
674
 
        if (*suffix != '\0')
675
 
            xmlrpc_env_set_fault_formatted(
676
 
                &env, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
677
 
                "specifier: '%s'.  There must be exactly one arument.",
678
 
                suffix);
679
 
        else {
680
 
            xmlrpc_server_info * serverP;
681
 
            serverP = xmlrpc_server_info_new(&env, serverUrl);
682
 
            if (!env.fault_occurred) {
683
 
                xmlrpc_client_call_server_asynch_params(
684
 
                    serverP, methodName, callback, userData, 
685
 
                    paramArrayP);
686
 
            }
687
 
            xmlrpc_server_info_free(serverP);
688
 
        }
689
 
        if (env.fault_occurred)
690
 
            (*callback)(serverUrl, methodName, paramArrayP, userData,
691
 
                        &env, NULL);
692
 
        xmlrpc_DECREF(paramArrayP);
693
 
    }
694
 
 
695
 
    xmlrpc_env_clean(&env);
696
 
}
697
 
 
698
 
 
699
 
 
700
 
void
701
 
xmlrpc_client_call_asynch_params(const char *   const serverUrl,
702
 
                                 const char *   const methodName,
703
 
                                 xmlrpc_response_handler callback,
704
 
                                 void *         const userData,
705
 
                                 xmlrpc_value * const paramArrayP) {
706
 
 
707
 
    xmlrpc_env env;
708
 
    xmlrpc_server_info *serverP;
709
 
 
710
 
    xmlrpc_env_init(&env);
711
 
 
712
 
    XMLRPC_ASSERT_PTR_OK(serverUrl);
713
 
 
714
 
    serverP = xmlrpc_server_info_new(&env, serverUrl);
715
 
    if (!env.fault_occurred) {
716
 
        xmlrpc_client_call_server_asynch_params(
717
 
            serverP, methodName, callback, userData, paramArrayP);
718
 
 
719
 
        xmlrpc_server_info_free(serverP);
720
 
    }
721
 
 
722
 
    if (env.fault_occurred)
723
 
        /* We have no way to return failure; we report the failure
724
 
           as it happened after we successfully started the RPC.
725
 
        */
726
 
        (*callback)(serverUrl, methodName, paramArrayP, userData,
727
 
                    &env, NULL);
728
 
 
729
 
    xmlrpc_env_clean(&env);
730
 
}
731
 
 
732
 
 
733
 
 
734
 
void 
735
 
xmlrpc_client_call_server_asynch(xmlrpc_server_info * const serverP,
736
 
                                 const char *         const methodName,
737
 
                                 xmlrpc_response_handler callback,
738
 
                                 void *               const userData,
739
 
                                 const char *         const format,
740
 
                                 ...) {
741
 
 
742
 
    xmlrpc_env env;
743
 
    va_list args;
744
 
    xmlrpc_value * paramArrayP;
745
 
    const char * suffix;
746
 
 
747
 
    xmlrpc_env_init(&env);
748
 
 
749
 
    XMLRPC_ASSERT_PTR_OK(format);
750
 
 
751
 
    /* Build our parameter array. */
752
 
    va_start(args, format);
753
 
    xmlrpc_build_value_va(&env, format, args, &paramArrayP, &suffix);
754
 
    va_end(args);
755
 
    if (env.fault_occurred) {
756
 
        /* Unfortunately, we have no way to return an error and the
757
 
           regular callback for a failed RPC is designed to have the
758
 
           parameter array passed to it.  This was probably an oversight
759
 
           of the original asynch design, but now we have to be as
760
 
           backward compatible as possible, so we do this:
761
 
        */
762
 
        (*callback)(serverP->_server_url, methodName, NULL, userData, 
763
 
                    &env, NULL);
764
 
    } else {
765
 
        if (*suffix != '\0')
766
 
            xmlrpc_env_set_fault_formatted(
767
 
                &env, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
768
 
                "specifier: '%s'.  There must be exactly one arument.",
769
 
                suffix);
770
 
        else {
771
 
            xmlrpc_client_call_server_asynch_params(
772
 
                serverP, methodName, callback, userData, paramArrayP);
773
 
        }
774
 
        xmlrpc_DECREF(paramArrayP);
775
 
    }
776
 
 
777
 
    if (env.fault_occurred)
778
 
        (*callback)(serverP->_server_url, methodName, paramArrayP, userData,
779
 
                    &env, NULL);
780
 
 
781
 
    xmlrpc_env_clean(&env);
782
 
}
783
 
 
784
 
 
785
 
 
786
 
static void
787
 
asynchComplete(call_info *        const callInfoP,
788
 
               xmlrpc_mem_block * const responseXmlP,
789
 
               xmlrpc_env         const transportEnv) {
790
 
/*----------------------------------------------------------------------------
791
 
   Complete an asynchronous XML-RPC call request.
792
 
 
793
 
   This includes calling the user's RPC completion routine.
794
 
 
795
 
   'transportEnv' describes the an error that the transport
796
 
   encountered in processing the call.  If the transport successfully
797
 
   sent the call to the server and processed the response but the
798
 
   server failed the call, 'transportEnv' indicates no error, and the
799
 
   response in *callInfoP might very well indicate that the server
800
 
   failed the request.
801
 
-----------------------------------------------------------------------------*/
802
 
    xmlrpc_env env;
803
 
    xmlrpc_value * responseP = 0;
804
 
 
805
 
    xmlrpc_env_init(&env);
806
 
 
807
 
    if (transportEnv.fault_occurred)
808
 
        xmlrpc_env_set_fault_formatted(
809
 
            &env, transportEnv.fault_code,
810
 
            "Client transport failed to execute the RPC.  %s",
811
 
            transportEnv.fault_string);
812
 
 
813
 
    if (!env.fault_occurred)
814
 
        responseP = xmlrpc_parse_response(
815
 
            &env,
816
 
            XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlP),
817
 
            XMLRPC_MEMBLOCK_SIZE(char, responseXmlP));
818
 
 
819
 
    /* Call the user's callback function with the result */
820
 
    (*callInfoP->callback)(callInfoP->server_url, 
821
 
                           callInfoP->method_name, 
822
 
                           callInfoP->param_array,
823
 
                           callInfoP->user_data, &env, responseP);
824
 
 
825
 
    if (!env.fault_occurred)
826
 
        xmlrpc_DECREF(responseP);
827
 
 
828
 
    call_info_free(callInfoP);
829
 
 
830
 
    xmlrpc_env_clean(&env);
831
 
}
832
 
 
833
 
 
834
 
 
835
 
static void
836
 
sendRequest(xmlrpc_env *             const envP,
837
 
            struct clientTransport * const transportP,
838
 
            xmlrpc_server_info *     const serverP,
839
 
            const char *             const methodName,
840
 
            xmlrpc_response_handler        responseHandler,
841
 
            void *                   const userData,
842
 
            xmlrpc_value *           const argP) {
843
 
 
844
 
    call_info * callInfoP;
845
 
 
846
 
    call_info_new(envP, serverP, methodName, argP, &callInfoP);
847
 
    if (!envP->fault_occurred) {
848
 
        call_info_set_asynch_data(envP, callInfoP, 
849
 
                                  serverP->_server_url, methodName,
850
 
                                  argP, responseHandler, userData);
851
 
        if (!envP->fault_occurred)
852
 
            clientTransportOps.send_request(
853
 
                envP, transportP, serverP, callInfoP->serialized_xml,
854
 
                &asynchComplete, callInfoP);
855
 
 
856
 
        if (envP->fault_occurred)
857
 
            call_info_free(callInfoP);
858
 
        else {
859
 
            /* asynchComplete() will free *callInfoP */
860
 
        }
861
 
    }
862
 
    if (envP->fault_occurred) {
863
 
        /* Transport did not start the call.  Report the call complete
864
 
           (with error) now.
865
 
        */
866
 
        (*responseHandler)(serverP->_server_url, methodName, argP, userData,
867
 
                           envP, NULL);
868
 
    } else {
869
 
        /* The transport will call *responseHandler() when it has completed
870
 
           the call
871
 
        */
872
 
    }
873
 
}
874
 
 
875
 
 
876
 
 
877
 
void 
878
 
xmlrpc_client_call_server_asynch_params(
879
 
    xmlrpc_server_info * const serverP,
880
 
    const char *         const methodName,
881
 
    xmlrpc_response_handler    responseHandler,
882
 
    void *               const userData,
883
 
    xmlrpc_value *       const argP) {
884
 
    xmlrpc_env env;
885
 
 
886
 
    xmlrpc_env_init(&env);
887
 
 
888
 
    XMLRPC_ASSERT_PTR_OK(serverP);
889
 
    XMLRPC_ASSERT_PTR_OK(methodName);
890
 
    XMLRPC_ASSERT_PTR_OK(responseHandler);
891
 
    XMLRPC_ASSERT_VALUE_OK(argP);
892
 
 
893
 
    if (!clientInitialized)
894
 
        xmlrpc_env_set_fault_formatted(
895
 
            &env, XMLRPC_INTERNAL_ERROR, 
896
 
            "Xmlrpc-c client instance has not been initialized "
897
 
            "(need to call xmlrpc_client_init2()).");
898
 
    else
899
 
        sendRequest(&env, client.transportP, serverP, 
900
 
                    methodName, responseHandler, userData, 
901
 
                    argP);
902
 
 
903
 
    xmlrpc_env_clean(&env);
904
 
}
905
 
 
906
 
 
907
 
 
908
 
void 
909
 
xmlrpc_server_info_set_basic_auth(xmlrpc_env *         const envP,
910
 
                                  xmlrpc_server_info * const serverP,
911
 
                                  const char *         const username,
912
 
                                  const char *         const password) {
913
 
 
914
 
    size_t username_len, password_len, raw_token_len;
915
 
    char *raw_token;
916
 
    xmlrpc_mem_block *token;
917
 
    char *token_data, *auth_type, *auth_header;
918
 
    size_t token_len, auth_type_len, auth_header_len;
919
 
 
920
 
    /* Error-handling preconditions. */
921
 
    token = NULL;
922
 
    auth_header = NULL;
923
 
 
924
 
    XMLRPC_ASSERT_ENV_OK(envP);
925
 
    XMLRPC_ASSERT_PTR_OK(serverP);
926
 
    XMLRPC_ASSERT_PTR_OK(username);
927
 
    XMLRPC_ASSERT_PTR_OK(password);
928
 
 
929
 
    /* Calculate some lengths. */
930
 
    username_len = strlen(username);
931
 
    password_len = strlen(password);
932
 
    raw_token_len = username_len + password_len + 1;
933
 
 
934
 
    /* Build a raw token of the form 'username:password'. */
935
 
    raw_token = (char*) malloc(raw_token_len + 1);
936
 
    XMLRPC_FAIL_IF_NULL(raw_token, envP, XMLRPC_INTERNAL_ERROR,
937
 
                        "Couldn't allocate memory for auth token");
938
 
    strcpy(raw_token, username);
939
 
    raw_token[username_len] = ':';
940
 
    strcpy(&raw_token[username_len + 1], password);
941
 
 
942
 
    /* Encode our raw token using Base64. */
943
 
    token = xmlrpc_base64_encode_without_newlines(envP, 
944
 
                                                  (unsigned char*) raw_token,
945
 
                                                  raw_token_len);
946
 
    XMLRPC_FAIL_IF_FAULT(envP);
947
 
    token_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, token);
948
 
    token_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, token);
949
 
 
950
 
    /* Build our actual header value. (I hate string processing in C.) */
951
 
    auth_type = "Basic ";
952
 
    auth_type_len = strlen(auth_type);
953
 
    auth_header_len = auth_type_len + token_len;
954
 
    auth_header = (char*) malloc(auth_header_len + 1);
955
 
    XMLRPC_FAIL_IF_NULL(auth_header, envP, XMLRPC_INTERNAL_ERROR,
956
 
                        "Couldn't allocate memory for auth header");
957
 
    memcpy(auth_header, auth_type, auth_type_len);
958
 
    memcpy(&auth_header[auth_type_len], token_data, token_len);
959
 
    auth_header[auth_header_len] = '\0';
960
 
 
961
 
    /* Clean up any pre-existing authentication information, and install
962
 
    ** the new value. */
963
 
    if (serverP->_http_basic_auth)
964
 
        free(serverP->_http_basic_auth);
965
 
    serverP->_http_basic_auth = auth_header;
966
 
 
967
 
 cleanup:
968
 
    if (raw_token)
969
 
        free(raw_token);
970
 
    if (token)
971
 
        xmlrpc_mem_block_free(token);
972
 
    if (envP->fault_occurred) {
973
 
        if (auth_header)
974
 
            free(auth_header);
975
 
    }
976
 
}
977