1
/* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
3
** Redistribution and use in source and binary forms, with or without
4
** modification, are permitted provided that the following conditions
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.
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
26
#include "xmlrpc_config.h"
39
#include "mallocvar.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
48
#include "transport_config.h"
50
#if MUST_BUILD_WININET_CLIENT
51
#include "xmlrpc_wininet_transport.h"
53
#if MUST_BUILD_CURL_CLIENT
54
#include "xmlrpc_curl_transport.h"
56
#if MUST_BUILD_LIBWWW_CLIENT
57
#include "xmlrpc_libwww_transport.h"
60
struct xmlrpc_client {
61
/*----------------------------------------------------------------------------
62
This represents a client object.
63
-----------------------------------------------------------------------------*/
64
struct clientTransport * transportP;
69
typedef struct call_info
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;
77
xmlrpc_value *param_array;
78
xmlrpc_response_handler callback;
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;
86
static bool clientInitialized = FALSE;
88
/*=========================================================================
89
** Initialization and Shutdown
90
**=========================================================================
93
static struct clientTransportOps clientTransportOps;
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
102
xmlrpc_client_init(int const flags,
103
const char * const appname,
104
const char * const appversion) {
106
struct xmlrpc_clientparms clientparms;
108
/* As our interface does not allow for failure, we just fail silently ! */
111
xmlrpc_env_init(&env);
113
clientparms.transport = XMLRPC_DEFAULT_TRANSPORT;
115
xmlrpc_client_init2(&env, flags,
117
&clientparms, XMLRPC_CPSIZE(transport));
119
xmlrpc_env_clean(&env);
125
xmlrpc_client_get_default_transport(xmlrpc_env * const env ATTR_UNUSED) {
127
return XMLRPC_DEFAULT_TRANSPORT;
133
setupTransport(xmlrpc_env * const envP,
134
const char * const transportName) {
138
#if MUST_BUILD_WININET_CLIENT
139
else if (strcmp(transportName, "wininet") == 0)
140
clientTransportOps = xmlrpc_wininet_transport_ops;
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;
148
#if MUST_BUILD_LIBWWW_CLIENT
149
else if (strcmp(transportName, "libwww") == 0)
150
clientTransportOps = xmlrpc_libwww_transport_ops;
153
xmlrpc_env_set_fault_formatted(
154
envP, XMLRPC_INTERNAL_ERROR,
155
"Unrecognized XML transport name '%s'", transportName);
161
xmlrpc_client_init2(xmlrpc_env * const envP,
163
const char * const appname,
164
const char * const appversion,
165
struct xmlrpc_clientparms * const clientparmsP,
166
unsigned int const parm_size) {
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 "
175
const char * transportName;
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);
182
transportName = clientparmsP->transport;
184
if (!envP->fault_occurred) {
185
setupTransport(envP, transportName);
186
if (!envP->fault_occurred) {
187
clientTransportOps.create(envP, flags, appname, appversion,
189
if (!envP->fault_occurred)
190
clientInitialized = TRUE;
199
xmlrpc_client_cleanup() {
201
XMLRPC_ASSERT(clientInitialized);
203
clientTransportOps.destroy(client.transportP);
205
clientInitialized = FALSE;
211
call_info_free(call_info * const callInfoP) {
213
/* Assume the worst.. That only parts of the call_info are valid. */
215
XMLRPC_ASSERT_PTR_OK(callInfoP);
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);
221
/* Now we can blow away the XML data. */
222
if (callInfoP->serialized_xml)
223
xmlrpc_mem_block_free(callInfoP->serialized_xml);
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
239
-----------------------------------------------------------------------------*/
240
call_info * callInfoP;
242
XMLRPC_ASSERT_PTR_OK(argP);
243
XMLRPC_ASSERT_PTR_OK(callInfoPP);
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");
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");
260
xmlrpc_mem_block * callXmlP;
262
/* Clear contents. */
263
memset(callInfoP, 0, sizeof(*callInfoP));
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));
274
callInfoP->serialized_xml = callXmlP;
276
*callInfoPP = callInfoP;
278
if (envP->fault_occurred)
279
XMLRPC_MEMBLOCK_FREE(char, callXmlP);
281
if (envP->fault_occurred)
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) {
297
call_info * callInfoP;
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()).");
305
call_info_new(envP, serverP, methodName, paramArrayP, &callInfoP);
306
if (!envP->fault_occurred) {
307
xmlrpc_mem_block * respXmlP;
309
clientTransportOps.call(envP, transportP, serverP,
310
callInfoP->serialized_xml, callInfoP,
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));
317
*resultPP = xmlrpc_parse_response(
319
XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP),
320
XMLRPC_MEMBLOCK_SIZE(char, respXmlP));
321
XMLRPC_MEMBLOCK_FREE(char, respXmlP);
323
call_info_free(callInfoP);
331
xmlrpc_client_call_params(xmlrpc_env * const envP,
332
const char * const serverUrl,
333
const char * const methodName,
334
xmlrpc_value * const paramArrayP) {
336
xmlrpc_value *retval;
338
XMLRPC_ASSERT_ENV_OK(envP);
339
XMLRPC_ASSERT_PTR_OK(serverUrl);
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()).");
347
xmlrpc_server_info * serverP;
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,
356
xmlrpc_server_info_free(serverP);
360
if (!envP->fault_occurred)
361
XMLRPC_ASSERT_VALUE_OK(retval);
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,
376
xmlrpc_value * retval = 0;
380
XMLRPC_ASSERT_ENV_OK(envP);
381
XMLRPC_ASSERT_PTR_OK(format);
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);
395
XMLRPC_ASSERT_VALUE_OK(argP);
398
xmlrpc_env_set_fault_formatted(
399
envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
400
"specifier: '%s'. There must be exactly one arument.",
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);
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,
423
xmlrpc_value * result;
426
va_start(args, format);
427
result = xmlrpc_client_call_va(envP, server_url,
428
method_name, format, args);
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,
444
xmlrpc_value * paramArrayP;
445
xmlrpc_value * retval;
448
XMLRPC_ASSERT_ENV_OK(envP);
449
XMLRPC_ASSERT_PTR_OK(format);
451
/* Build our argument */
452
va_start(args, format);
453
xmlrpc_build_value_va(envP, format, args, ¶mArrayP, &suffix);
456
if (!envP->fault_occurred) {
458
xmlrpc_env_set_fault_formatted(
459
envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
460
"specifier: '%s'. There must be exactly one arument.",
463
clientCallServerParams(envP, client.transportP, serverP,
464
methodName, paramArrayP,
467
xmlrpc_DECREF(paramArrayP);
474
xmlrpc_client_event_loop_finish_asynch(void) {
475
XMLRPC_ASSERT(clientInitialized);
476
clientTransportOps.finish_asynch(client.transportP, timeout_no, 0);
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);
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) {
498
xmlrpc_value *holder;
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);
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;
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);
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)",
526
XMLRPC_FAIL_IF_FAULT(env);
528
/* Hand over ownership of the holder to the call_info struct. */
529
info->_asynch_data_holder = holder;
533
if (env->fault_occurred) {
535
xmlrpc_DECREF(holder);
539
/*=========================================================================
540
** xmlrpc_server_info
541
**=========================================================================
545
xmlrpc_server_info_new (xmlrpc_env * const env,
546
const char * const server_url) {
548
xmlrpc_server_info *server;
551
/* Error-handling preconditions. */
554
XMLRPC_ASSERT_ENV_OK(env);
555
XMLRPC_ASSERT_PTR_OK(server_url);
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");
566
/* Build our object. */
567
strcpy(url_copy, server_url);
568
server->_server_url = url_copy;
569
server->_http_basic_auth = NULL;
572
if (env->fault_occurred) {
582
xmlrpc_server_info * xmlrpc_server_info_copy(xmlrpc_env *env,
583
xmlrpc_server_info *aserver)
585
xmlrpc_server_info *server;
586
char *url_copy, *auth_copy;
588
XMLRPC_ASSERT_ENV_OK(env);
589
XMLRPC_ASSERT_PTR_OK(aserver);
591
/* Error-handling preconditions. */
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");
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;
613
if (env->fault_occurred) {
626
void xmlrpc_server_info_free (xmlrpc_server_info *server)
628
XMLRPC_ASSERT_PTR_OK(server);
629
XMLRPC_ASSERT(server->_server_url != XMLRPC_BAD_POINTER);
631
if (server->_http_basic_auth)
632
free(server->_http_basic_auth);
633
free(server->_server_url);
634
server->_server_url = XMLRPC_BAD_POINTER;
638
/*=========================================================================
639
** xmlrpc_client_call_asynch
640
**=========================================================================
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,
653
xmlrpc_value * paramArrayP;
656
xmlrpc_env_init(&env);
658
XMLRPC_ASSERT_PTR_OK(serverUrl);
659
XMLRPC_ASSERT_PTR_OK(format);
661
/* Build our argument array. */
662
va_start(args, format);
663
xmlrpc_build_value_va(&env, format, args, ¶mArrayP, &suffix);
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:
672
(*callback)(serverUrl, methodName, NULL, userData, &env, NULL);
675
xmlrpc_env_set_fault_formatted(
676
&env, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
677
"specifier: '%s'. There must be exactly one arument.",
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,
687
xmlrpc_server_info_free(serverP);
689
if (env.fault_occurred)
690
(*callback)(serverUrl, methodName, paramArrayP, userData,
692
xmlrpc_DECREF(paramArrayP);
695
xmlrpc_env_clean(&env);
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) {
708
xmlrpc_server_info *serverP;
710
xmlrpc_env_init(&env);
712
XMLRPC_ASSERT_PTR_OK(serverUrl);
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);
719
xmlrpc_server_info_free(serverP);
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.
726
(*callback)(serverUrl, methodName, paramArrayP, userData,
729
xmlrpc_env_clean(&env);
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,
744
xmlrpc_value * paramArrayP;
747
xmlrpc_env_init(&env);
749
XMLRPC_ASSERT_PTR_OK(format);
751
/* Build our parameter array. */
752
va_start(args, format);
753
xmlrpc_build_value_va(&env, format, args, ¶mArrayP, &suffix);
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:
762
(*callback)(serverP->_server_url, methodName, NULL, userData,
766
xmlrpc_env_set_fault_formatted(
767
&env, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
768
"specifier: '%s'. There must be exactly one arument.",
771
xmlrpc_client_call_server_asynch_params(
772
serverP, methodName, callback, userData, paramArrayP);
774
xmlrpc_DECREF(paramArrayP);
777
if (env.fault_occurred)
778
(*callback)(serverP->_server_url, methodName, paramArrayP, userData,
781
xmlrpc_env_clean(&env);
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.
793
This includes calling the user's RPC completion routine.
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
801
-----------------------------------------------------------------------------*/
803
xmlrpc_value * responseP = 0;
805
xmlrpc_env_init(&env);
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);
813
if (!env.fault_occurred)
814
responseP = xmlrpc_parse_response(
816
XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlP),
817
XMLRPC_MEMBLOCK_SIZE(char, responseXmlP));
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);
825
if (!env.fault_occurred)
826
xmlrpc_DECREF(responseP);
828
call_info_free(callInfoP);
830
xmlrpc_env_clean(&env);
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) {
844
call_info * callInfoP;
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);
856
if (envP->fault_occurred)
857
call_info_free(callInfoP);
859
/* asynchComplete() will free *callInfoP */
862
if (envP->fault_occurred) {
863
/* Transport did not start the call. Report the call complete
866
(*responseHandler)(serverP->_server_url, methodName, argP, userData,
869
/* The transport will call *responseHandler() when it has completed
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) {
886
xmlrpc_env_init(&env);
888
XMLRPC_ASSERT_PTR_OK(serverP);
889
XMLRPC_ASSERT_PTR_OK(methodName);
890
XMLRPC_ASSERT_PTR_OK(responseHandler);
891
XMLRPC_ASSERT_VALUE_OK(argP);
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()).");
899
sendRequest(&env, client.transportP, serverP,
900
methodName, responseHandler, userData,
903
xmlrpc_env_clean(&env);
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) {
914
size_t username_len, password_len, raw_token_len;
916
xmlrpc_mem_block *token;
917
char *token_data, *auth_type, *auth_header;
918
size_t token_len, auth_type_len, auth_header_len;
920
/* Error-handling preconditions. */
924
XMLRPC_ASSERT_ENV_OK(envP);
925
XMLRPC_ASSERT_PTR_OK(serverP);
926
XMLRPC_ASSERT_PTR_OK(username);
927
XMLRPC_ASSERT_PTR_OK(password);
929
/* Calculate some lengths. */
930
username_len = strlen(username);
931
password_len = strlen(password);
932
raw_token_len = username_len + password_len + 1;
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);
942
/* Encode our raw token using Base64. */
943
token = xmlrpc_base64_encode_without_newlines(envP,
944
(unsigned char*) raw_token,
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);
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';
961
/* Clean up any pre-existing authentication information, and install
963
if (serverP->_http_basic_auth)
964
free(serverP->_http_basic_auth);
965
serverP->_http_basic_auth = auth_header;
971
xmlrpc_mem_block_free(token);
972
if (envP->fault_occurred) {