1 /* An XML-RPC client program written in C, as an example of using
2    compound XML-RPC values.
3 
4    For a simple client program that just deals with integer values,
5    see xmlrpc_sample_add_client.c.  This example focuses just on the
6    compound XML-RPC values and not the client functions.
7 
8    This client invokes the example.divide XML-RPC method that the example
9    server program compound_value_server.c provides.  That method takes a
10    list of pairs of numbers and returns the list of their quotients.
11 
12    Compound XML-RPC values are arrays and structures.  We call them compound
13    because they are made up of other XML-RPC values (e.g. an array of XML-RPC
14    integers).
15 
16    The arguments to the example.divide method are specified as follows:
17 
18    There are two arguments:
19 
20      Argument 0: Integer.  Version number of this argument protocol.  Must
21                  be 1.
22 
23      Argument 1: Array.  One element for each pair of numbers you want the
24                  server to divide.  Each element is structure, with these
25                  members:
26 
27                  KEY: "dividend"
28                  VALUE: floating point number.  The dividend.
29 
30                  KEY: "divisor"
31                  VALUE: floating point number.  The divisor.
32 
33    The result of the method is an array.  It has one member for each pair of
34    numbers in the arguments (So it is the same size as Argument 1).  That
35    member is a floating point number.  It is the quotient of the numbers
36    in the corresponding element of Argument 1.
37 
38    The client sends the RPC to the server running on the local system
39    ("localhost"), HTTP Port 8080.
40 */
41 
42 #include <stdlib.h>
43 #include <stdio.h>
44 
45 #include <xmlrpc-c/base.h>
46 #include <xmlrpc-c/client.h>
47 
48 #include "config.h"  /* information about this build environment */
49 
50 #define NAME "Xmlrpc-c Test Client"
51 #define VERSION "1.0"
52 
53 static void
dieIfFaultOccurred(xmlrpc_env * const envP)54 dieIfFaultOccurred (xmlrpc_env * const envP) {
55     if (envP->fault_occurred) {
56         fprintf(stderr, "ERROR: %s (%d)\n",
57                 envP->fault_string, envP->fault_code);
58         exit(1);
59     }
60 }
61 
62 
63 
64 struct ratio {
65     double dividend;
66     double divisor;
67 };
68 
69 
70 
71 int
main(int const argc,const char ** const argv)72 main(int           const argc,
73      const char ** const argv) {
74 
75     const char * const serverUrl = "http://localhost:8080/RPC2";
76     const char * const methodName = "example.divide";
77     unsigned int const argVersion = 1;
78     struct ratio const data[] = {{1,2},{12,3},{10,3},{89,3000}};
79     xmlrpc_env env;
80     xmlrpc_value * resultP;
81     unsigned int i;
82     xmlrpc_value * ratioArrayP;
83     unsigned int quotientCt;
84 
85     if (argc-1 > 0) {
86         fprintf(stderr, "This program has no arguments\n");
87         exit(1);
88     }
89 
90     xmlrpc_env_init(&env);
91 
92     xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0);
93     dieIfFaultOccurred(&env);
94 
95     /* Build the 2nd method argument: the array of ratios */
96 
97     ratioArrayP = xmlrpc_array_new(&env);
98     dieIfFaultOccurred(&env);
99 
100     for (i = 0; i < 4; ++i) {
101         xmlrpc_value * dividendP;
102         xmlrpc_value * divisorP;
103         xmlrpc_value * ratioP;
104 
105         dividendP = xmlrpc_double_new(&env, data[i].dividend);
106         dieIfFaultOccurred(&env);
107         divisorP  = xmlrpc_double_new(&env, data[i].divisor);
108         dieIfFaultOccurred(&env);
109 
110         ratioP = xmlrpc_struct_new(&env);
111         dieIfFaultOccurred(&env);
112 
113         xmlrpc_struct_set_value(&env, ratioP, "DIVIDEND", dividendP);
114         dieIfFaultOccurred(&env);
115         xmlrpc_struct_set_value(&env, ratioP, "DIVISOR",  divisorP);
116         dieIfFaultOccurred(&env);
117 
118         xmlrpc_array_append_item(&env, ratioArrayP, ratioP);
119         dieIfFaultOccurred(&env);
120 
121         xmlrpc_DECREF(ratioP);
122         xmlrpc_DECREF(divisorP);
123         xmlrpc_DECREF(dividendP);
124     }
125 
126     /* Make the call */
127 
128     resultP = xmlrpc_client_call(&env, serverUrl, methodName, "(iA)",
129                                  (xmlrpc_int32) argVersion, ratioArrayP);
130     dieIfFaultOccurred(&env);
131 
132     /* Print out the quotients returned */
133 
134     quotientCt = xmlrpc_array_size(&env, resultP);
135     dieIfFaultOccurred(&env);
136 
137     for (i = 0; i < quotientCt; ++i) {
138         xmlrpc_value * quotientP;
139         xmlrpc_double quotient;
140 
141         xmlrpc_array_read_item(&env, resultP, i, &quotientP);
142         dieIfFaultOccurred(&env);
143 
144         xmlrpc_read_double(&env, quotientP, &quotient);
145         dieIfFaultOccurred(&env);
146 
147         printf("Server says quotient %u is %f\n", i, quotient);
148 
149         xmlrpc_DECREF(quotientP);
150     }
151 
152     xmlrpc_DECREF(resultP);
153 
154     xmlrpc_env_clean(&env);
155 
156     xmlrpc_client_cleanup();
157 
158     return 0;
159 }
160 
161