initial load of upstream version 1.06.32
[xmlrpc-c] / examples / xmlrpc_server_validatee.c
1 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 ** 1. Redistributions of source code must retain the above copyright
7 **    notice, this list of conditions and the following disclaimer.
8 ** 2. Redistributions in binary form must reproduce the above copyright
9 **    notice, this list of conditions and the following disclaimer in the
10 **    documentation and/or other materials provided with the distribution.
11 ** 3. The name of the author may not be used to endorse or promote products
12 **    derived from this software without specific prior written permission. 
13 **  
14 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 ** SUCH DAMAGE. */
25
26
27 /*============================================================================
28                               xmlrpc_server_validatee
29 ==============================================================================
30
31   This program runs an XMLRPC server, using the Xmlrpc-c libraries.
32
33   The server implements the methods that the Userland Validator1 test suite
34   invokes, which are supposed to exercise a broad range of XMLRPC server
35   function.
36
37   Coments here used to say you could get information about Validator1
38   from <http://validator.xmlrpc.com/>, but as of 2004.09.25, there's nothing
39   there (there's a web server, but it is not configured to serve that
40   particular URL).
41
42 ============================================================================*/
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include <xmlrpc-c/base.h>
49 #include <xmlrpc-c/server.h>
50 #include <xmlrpc-c/server_abyss.h>
51
52 #include "config.h"  /* information about this build environment */
53
54 #define RETURN_IF_FAULT(env) \
55     do { \
56         if ((env)->fault_occurred) \
57             return NULL; \
58     } while (0)
59         
60
61 /*=========================================================================
62 **  validator1.arrayOfStructsTest
63 **=========================================================================
64 */
65
66 static xmlrpc_value *
67 array_of_structs(xmlrpc_env *   const envP, 
68                  xmlrpc_value * const param_array, 
69                  void *         const user_data ATTR_UNUSED) {
70
71     xmlrpc_value * array;
72     xmlrpc_value * retval;
73
74     xmlrpc_decompose_value(envP, param_array, "(A)", &array);
75     if (envP->fault_occurred)
76         retval = NULL;
77     else {
78         /* Add up all the struct elements named "curly". */
79         size_t size;
80         size = xmlrpc_array_size(envP, array);
81         if (envP->fault_occurred)
82             retval = NULL;
83         else {
84             unsigned int sum;
85             unsigned int i;
86             sum = 0;
87             for (i = 0; i < size && !envP->fault_occurred; ++i) {
88                 xmlrpc_value * strct;
89                 strct = xmlrpc_array_get_item(envP, array, i);
90                 if (!envP->fault_occurred) {
91                     xmlrpc_int32 curly;
92                     xmlrpc_decompose_value(envP, strct, "{s:i,*}", 
93                                            "curly", &curly);
94                     if (!envP->fault_occurred)
95                         sum += curly;
96                 }
97             }
98             xmlrpc_DECREF(array);
99             if (envP->fault_occurred)
100                 retval = NULL;
101             else
102                 retval = xmlrpc_build_value(envP, "i", sum);
103         }
104     }
105     return retval;
106 }
107
108
109 /*=========================================================================
110 **  validator1.countTheEntities
111 **=========================================================================
112 */
113
114 static xmlrpc_value *
115 count_entities(xmlrpc_env *   const env, 
116                xmlrpc_value * const param_array, 
117                void *         const user_data ATTR_UNUSED) {
118     const char *str;
119     size_t len, i;
120     xmlrpc_int32 left, right, amp, apos, quote;
121
122     xmlrpc_decompose_value(env, param_array, "(s#)", &str, &len);
123     RETURN_IF_FAULT(env);
124
125     left = right = amp = apos = quote = 0;
126     for (i = 0; i < len; i++) {
127         switch (str[i]) {
128         case '<': left++; break;
129         case '>': right++; break;
130         case '&': amp++; break;
131         case '\'': apos++; break;
132         case '\"': quote++; break;
133         default: break;
134         }
135     }
136     free((void*)str);
137
138     return xmlrpc_build_value(env, "{s:i,s:i,s:i,s:i,s:i}",
139                               "ctLeftAngleBrackets", left,
140                               "ctRightAngleBrackets", right,
141                               "ctAmpersands", amp,
142                               "ctApostrophes", apos,
143                               "ctQuotes", quote);
144 }
145
146
147
148 /*=========================================================================
149 **  validator1.easyStructTest
150 **=========================================================================
151 */
152
153 static xmlrpc_value *
154 easy_struct(xmlrpc_env *   const env, 
155             xmlrpc_value * const param_array,
156             void *         const user_data ATTR_UNUSED) {
157
158     xmlrpc_int32 larry, moe, curly;
159
160     /* Parse our argument array and get the stooges. */
161     xmlrpc_decompose_value(env, param_array, "({s:i,s:i,s:i,*})",
162                            "larry", &larry,
163                            "moe", &moe,
164                            "curly", &curly);
165     RETURN_IF_FAULT(env);
166
167     /* Return our result. */
168     return xmlrpc_build_value(env, "i", larry + moe + curly);
169 }
170
171
172 /*=========================================================================
173 **  validator1.echoStructTest
174 **=========================================================================
175 */
176
177 static xmlrpc_value *
178 echo_struct(xmlrpc_env *   const env, 
179             xmlrpc_value * const param_array, 
180             void *         const user_data ATTR_UNUSED) {
181     xmlrpc_value *s;
182
183     /* Parse our argument array. */
184     xmlrpc_decompose_value(env, param_array, "(S)", &s);
185     RETURN_IF_FAULT(env);
186     
187     return s;  /* We transfer our reference on 's' to Caller */
188 }
189
190
191 /*=========================================================================
192 **  validator1.manyTypesTest
193 **=========================================================================
194 */
195
196 static xmlrpc_value *
197 many_types(xmlrpc_env *   const env ATTR_UNUSED, 
198            xmlrpc_value * const param_array, 
199            void *         const user_data ATTR_UNUSED) {
200
201     /* Create another reference to our argument array and return it as is. */
202     xmlrpc_INCREF(param_array);
203     return param_array;
204 }
205
206
207 /*=========================================================================
208 **  validator1.moderateSizeArrayCheck
209 **=========================================================================
210 */
211
212 static void
213 concatenate(xmlrpc_env *    const envP,
214             const char *    const str1,
215             size_t          const str1_len,
216             const char *    const str2,
217             size_t          const str2_len,
218             xmlrpc_value ** const resultP) {
219
220     /* Concatenate the two strings. */
221
222     char * buffer;
223
224     buffer = (char*) malloc(str1_len + str2_len);
225     if (!buffer) {
226         xmlrpc_env_set_fault(envP, 1, 
227                              "Couldn't allocate concatenated string");
228     } else {
229         memcpy(buffer, str1, str1_len);
230         memcpy(&buffer[str1_len], str2, str2_len);
231         *resultP = xmlrpc_build_value(envP, "s#", 
232                                       buffer, str1_len + str2_len);
233         free(buffer);
234     }
235 }
236
237
238
239 static xmlrpc_value *
240 moderate_array(xmlrpc_env *   const envP, 
241                xmlrpc_value * const param_array, 
242                void *         const user_data ATTR_UNUSED) {
243
244     xmlrpc_value * retval;
245     xmlrpc_value * arrayP;
246
247     /* Parse our argument array. */
248     xmlrpc_decompose_value(envP, param_array, "(A)", &arrayP);
249     if (!envP->fault_occurred) {
250         int const size = xmlrpc_array_size(envP, arrayP);
251         if (!envP->fault_occurred) {
252             /* Get our first string. */
253             xmlrpc_value * const firstItemP =
254                 xmlrpc_array_get_item(envP, arrayP, 0);
255             if (!envP->fault_occurred) {
256                 const char * str1;
257                 size_t str1_len;
258                 xmlrpc_read_string_lp(envP, firstItemP, &str1_len, &str1);
259                 if (!envP->fault_occurred) {
260                     /* Get our last string. */
261                     xmlrpc_value * const lastItemP =
262                         xmlrpc_array_get_item(envP, arrayP, size - 1);
263                     if (!envP->fault_occurred) {
264                         const char * str2;
265                         size_t str2_len;
266                         xmlrpc_read_string_lp(envP, lastItemP,
267                                               &str2_len, &str2);
268                         if (!envP->fault_occurred) {
269                             concatenate(envP, str1, str1_len, str2, str2_len,
270                                         &retval);
271                             free((char*)str2);
272                         }
273                     }
274                     free((char*)str1);
275                 }
276             }
277         }
278         xmlrpc_DECREF(arrayP);
279     }
280     return retval;
281 }
282
283
284 /*=========================================================================
285 **  validator1.nestedStructTest
286 **=========================================================================
287 */
288
289 static xmlrpc_value *
290 nested_struct(xmlrpc_env *   const envP,
291               xmlrpc_value * const param_array, 
292               void *         const user_data ATTR_UNUSED) {
293
294     xmlrpc_value * yearsP;
295     xmlrpc_value * retval;
296
297     /* Parse our argument array. */
298     xmlrpc_decompose_value(envP, param_array, "(S)", &yearsP);
299     if (envP->fault_occurred)
300         retval = NULL;
301     else {
302         /* Get values of larry, moe and curly for 2000-04-01. */
303         xmlrpc_int32 larry, moe, curly;
304         xmlrpc_decompose_value(envP, yearsP,
305                                "{s:{s:{s:{s:i,s:i,s:i,*},*},*},*}",
306                                "2000", "04", "01",
307                                "larry", &larry,
308                                "moe", &moe,
309                                "curly", &curly);               
310         if (envP->fault_occurred)
311             retval = NULL;
312         else
313             retval = xmlrpc_build_value(envP, "i", larry + moe + curly);
314
315         xmlrpc_DECREF(yearsP);
316     }
317     return retval;
318 }
319
320
321 /*=========================================================================
322 **  validator1.simpleStructReturnTest
323 **=========================================================================
324 */
325
326 static xmlrpc_value *
327 struct_return(xmlrpc_env *   const env, 
328               xmlrpc_value * const param_array, 
329               void *         const user_data ATTR_UNUSED) {
330
331     xmlrpc_int32 i;
332
333     xmlrpc_decompose_value(env, param_array, "(i)", &i);
334     RETURN_IF_FAULT(env);
335
336     return xmlrpc_build_value(env, "{s:i,s:i,s:i}",
337                               "times10", (xmlrpc_int32) i * 10,
338                               "times100", (xmlrpc_int32) i * 100,
339                               "times1000", (xmlrpc_int32) i * 1000);
340 }
341
342
343 /*=========================================================================
344 **  main
345 **=========================================================================
346 */
347
348 int main(int           const argc, 
349          const char ** const argv) {
350
351     xmlrpc_server_abyss_parms serverparm;
352     xmlrpc_registry * registryP;
353     xmlrpc_env env;
354
355     if (argc-1 != 1) {
356         fprintf(stderr, "You must specify 1 argument:  The TCP port "
357                 "number on which the server will accept connections "
358                 "for RPCs.  You specified %d arguments.\n",  argc-1);
359         exit(1);
360     }
361
362     xmlrpc_env_init(&env);
363
364     registryP = xmlrpc_registry_new(&env);
365
366     xmlrpc_registry_add_method(
367         &env, registryP, NULL, "validator1.arrayOfStructsTest", 
368         &array_of_structs, NULL);
369     xmlrpc_registry_add_method(
370         &env, registryP, NULL, "validator1.countTheEntities", 
371         &count_entities, NULL);
372     xmlrpc_registry_add_method(
373         &env, registryP, NULL, "validator1.easyStructTest", 
374         &easy_struct, NULL);
375     xmlrpc_registry_add_method(
376         &env, registryP, NULL, "validator1.echoStructTest", 
377         &echo_struct, NULL);
378     xmlrpc_registry_add_method(
379         &env, registryP, NULL, "validator1.manyTypesTest", 
380         &many_types, NULL);
381     xmlrpc_registry_add_method(
382         &env, registryP, NULL, "validator1.moderateSizeArrayCheck", 
383         &moderate_array, NULL);
384     xmlrpc_registry_add_method(
385         &env, registryP, NULL, "validator1.nestedStructTest", 
386         &nested_struct, NULL);
387     xmlrpc_registry_add_method(
388         &env, registryP, NULL, "validator1.simpleStructReturnTest", 
389         &struct_return, NULL);
390
391     serverparm.config_file_name = NULL;
392     serverparm.registryP = registryP;
393     serverparm.port_number = atoi(argv[1]);
394     serverparm.log_file_name = NULL;
395
396     printf("Running XML-RPC server...\n");
397
398     xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name));
399
400     /* This never gets executed. */
401     return 0;
402 }