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
) {