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