1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 /*
58 * test_xmlrpc.c: A simple program to test XML-RPC parsing
59 *
60 * Stipe Tolj <stolj@wapme.de>
61 */
62
63
64 #include <string.h>
65 #include <stdlib.h>
66 #include <unistd.h>
67 #include <stdio.h>
68
69 #include "gwlib/gwlib.h"
70 #include "gwlib/http.h"
71 #include "gwlib/xmlrpc.h"
72
73 #define MAX_THREADS 1024
74 #define MAX_IN_QUEUE 128
75
76 static Counter *counter = NULL;
77 static long max_requests = 1;
78 /*static int verbose = 1;*/
79 static Octstr *auth_username = NULL;
80 static Octstr *auth_password = NULL;
81 static Octstr *ssl_client_certkey_file = NULL;
82 static Octstr *extra_headers = NULL;
83 static Octstr *content_file = NULL;
84 static Octstr *url = NULL;
85 static int file = 0;
86 static XMLRPCDocument *msg;
87
88
start_request(HTTPCaller * caller,List * reqh,long i)89 static void start_request(HTTPCaller *caller, List *reqh, long i)
90 {
91 long *id;
92
93 if ((i % 1000) == 0)
94 info(0, "Starting fetch %ld", i);
95 id = gw_malloc(sizeof(long));
96 *id = i;
97
98 /*
99 * not semd the XML-RPC document contained in msg to
100 * the URL 'url' using the POST method
101 */
102 xmlrpc_send_call(msg, caller, url, reqh, id);
103
104 debug("", 0, "Started request %ld.", *id);
105 /*
106 debug("", 0, "Started request %ld with url:", *id);
107 octstr_url_decode(url);
108 octstr_dump(url, 0);
109 */
110 }
111
112
receive_reply(HTTPCaller * caller)113 static int receive_reply(HTTPCaller *caller)
114 {
115 void *id;
116 int ret;
117 Octstr *final_url;
118 List *replyh;
119 Octstr *replyb;
120 Octstr *output;
121 XMLRPCDocument *xrdoc;
122 /*
123 Octstr *type, *os_xrdoc, *os;
124 Octstr *charset;
125 */
126
127 id = http_receive_result(caller, &ret, &final_url, &replyh, &replyb);
128 octstr_destroy(final_url);
129 if (id == NULL || ret == -1) {
130 error(0, "http POST failed");
131 gw_free(id);
132 return -1;
133 }
134 debug("", 0, "Done with request %ld", *(long *) id);
135 gw_free(id);
136
137 /*
138 http_header_get_content_type(replyh, &type, &charset);
139 debug("", 0, "Content-type is <%s>, charset is <%s>",
140 octstr_get_cstr(type), octstr_get_cstr(charset));
141 octstr_destroy(type);
142 octstr_destroy(charset);
143 if (verbose)
144 debug("", 0, "Reply headers:");
145 while ((os = gwlist_extract_first(replyh)) != NULL) {
146 if (verbose)
147 octstr_dump(os, 1);
148 octstr_destroy(os);
149 }
150 if (verbose) {
151 debug("", 0, "Reply body:");
152 octstr_dump(replyb, 1);
153 }
154 */
155 xrdoc = xmlrpc_parse_response(replyb);
156 debug("", 0, "Parsed xmlrpc");
157
158 if ((xmlrpc_parse_status(xrdoc) != XMLRPC_COMPILE_OK) &&
159 ((output = xmlrpc_parse_error(xrdoc)) != NULL)) {
160 /* parse failure */
161 error(0, "%s", octstr_get_cstr(output));
162 octstr_destroy(output);
163 return -1;
164 } else {
165 /*parse proper xmlrpc */
166 if (xmlrpc_is_fault(xrdoc)) {
167 Octstr *fstring = xmlrpc_get_faultstring(xrdoc);
168 debug("xr", 0, "Got fault response with code:%ld and description: %s",
169 xmlrpc_get_faultcode(xrdoc),
170 octstr_get_cstr(fstring));
171 octstr_destroy(fstring);
172 http_destroy_headers(replyh);
173 octstr_destroy(replyb);
174 return -1;
175 }
176 /*
177 os_xrdoc = xmlrpc_print_response(xrdoc);
178 debug("xr", 0, "XMLRPC response:");
179 octstr_dump(os_xrdoc, 0);
180 */
181 }
182 http_destroy_headers(replyh);
183 octstr_destroy(replyb);
184 return 0;
185 }
186
187
client_thread(void * arg)188 static void client_thread(void *arg)
189 {
190 List *reqh;
191 long i, succeeded, failed;
192 HTTPCaller *caller;
193 char buf[1024];
194 long in_queue;
195
196 caller = arg;
197 succeeded = 0;
198 failed = 0;
199 reqh = gwlist_create();
200
201 sprintf(buf, "%ld", (long) gwthread_self());
202 http_header_add(reqh, "X-Thread", buf);
203 if (auth_username != NULL && auth_password != NULL)
204 http_add_basic_auth(reqh, auth_username, auth_password);
205
206 in_queue = 0;
207
208 for (;;) {
209 while (in_queue < MAX_IN_QUEUE) {
210 i = counter_increase(counter);
211 if (i >= max_requests)
212 goto receive_rest;
213 start_request(caller, reqh, i);
214 #if 1
215 gwthread_sleep(0.1);
216 #endif
217 ++in_queue;
218 }
219 while (in_queue >= MAX_IN_QUEUE) {
220 if (receive_reply(caller) == -1)
221 ++failed;
222 else
223 ++succeeded;
224 --in_queue;
225 }
226 }
227
228 receive_rest:
229 while (in_queue > 0) {
230 if (receive_reply(caller) == -1)
231 ++failed;
232 else
233 ++succeeded;
234 --in_queue;
235 }
236
237 http_caller_destroy(caller);
238 info(0, "This thread: %ld succeeded, %ld failed.", succeeded, failed);
239 }
240
241
help(void)242 static void help(void)
243 {
244 info(0, "Usage: test_xmlrpc [options] xml_source");
245 info(0, "where options are:");
246 info(0, "-u URL");
247 info(0, " send XML-RPC source as POST HTTP request to URL");
248 info(0, "-v number");
249 info(0, " set log level for stderr logging");
250 info(0, "-q");
251 info(0, " don't print the body or headers of the HTTP response");
252 info(0, "-r number");
253 info(0, " make `number' requests, repeating URLs as necessary");
254 info(0, "-p domain.name");
255 info(0, " use `domain.name' as a proxy");
256 info(0, "-P portnumber");
257 info(0, " connect to proxy at port `portnumber'");
258 info(0, "-S");
259 info(0, " use HTTPS scheme to access SSL-enabled proxy server");
260 info(0, "-e domain1:domain2:...");
261 info(0, " set exception list for proxy use");
262 info(0, "-s");
263 info(0, " use HTTPS scheme to access SSL-enabled HTTP server");
264 info(0, "-c ssl_client_cert_key_file");
265 info(0, " use this file as the SSL certificate and key file");
266 }
267
268
main(int argc,char ** argv)269 int main(int argc, char **argv)
270 {
271 int i, opt, num_threads;
272 Octstr *proxy;
273 List *exceptions;
274 long proxy_port;
275 int proxy_ssl = 0;
276 Octstr *proxy_username;
277 Octstr *proxy_password;
278 Octstr *exceptions_regex;
279 char *p;
280 long threads[MAX_THREADS];
281 time_t start, end;
282 double run_time;
283 Octstr *output, *xml_doc;
284 int ssl = 0;
285
286 gwlib_init();
287
288 proxy = NULL;
289 proxy_port = -1;
290 exceptions = gwlist_create();
291 proxy_username = NULL;
292 proxy_password = NULL;
293 exceptions_regex = NULL;
294 num_threads = 0;
295 file = 0;
296
297 while ((opt = getopt(argc, argv, "hvr:t:p:u:P:Se:a:sc:")) != EOF) {
298 switch (opt) {
299 case 'h':
300 help();
301 exit(1);
302 break;
303
304 case 'v':
305 log_set_output_level(atoi(optarg));
306 break;
307
308 case 'r':
309 max_requests = atoi(optarg);
310 break;
311
312 case 't':
313 num_threads = atoi(optarg);
314 if (num_threads > MAX_THREADS)
315 num_threads = MAX_THREADS;
316 break;
317
318 case 'p':
319 proxy = octstr_create(optarg);
320 break;
321
322 case 'u':
323 url = octstr_create(optarg);
324 break;
325
326 case 'P':
327 proxy_port = atoi(optarg);
328 break;
329
330 case 'S':
331 proxy_ssl = 1;
332 break;
333
334 case 'e':
335 p = strtok(optarg, ":");
336 while (p != NULL) {
337 gwlist_append(exceptions, octstr_create(p));
338 p = strtok(NULL, ":");
339 }
340 break;
341
342 case 'E':
343 exceptions_regex = octstr_create(optarg);
344 break;
345
346 case 'a':
347 p = strtok(optarg, ":");
348 if (p != NULL) {
349 auth_username = octstr_create(p);
350 p = strtok(NULL, "");
351 if (p != NULL)
352 auth_password = octstr_create(p);
353 }
354 break;
355
356 case 's':
357 ssl = 1;
358 break;
359
360 case 'c':
361 octstr_destroy(ssl_client_certkey_file);
362 ssl_client_certkey_file = octstr_create(optarg);
363 break;
364
365 case '?':
366 default:
367 error(0, "Invalid option %c", opt);
368 help();
369 panic(0, "Stopping");
370 break;
371 }
372 }
373
374 if (optind >= argc) {
375 error(0, "Missing arguments");
376 help();
377 panic(0, "Stopping");
378 }
379
380 #ifdef HAVE_LIBSSL
381 /*
382 * check if we are doing a SSL-enabled client version here
383 * load the required cert and key file
384 */
385 if (ssl || proxy_ssl) {
386 if (ssl_client_certkey_file != NULL) {
387 use_global_client_certkey_file(ssl_client_certkey_file);
388 } else {
389 panic(0, "client certkey file need to be given!");
390 }
391 }
392 #endif
393
394 if (proxy != NULL && proxy_port > 0) {
395 http_use_proxy(proxy, proxy_port, proxy_ssl, exceptions,
396 proxy_username, proxy_password,
397 exceptions_regex);
398 }
399 octstr_destroy(proxy);
400 octstr_destroy(proxy_username);
401 octstr_destroy(proxy_password);
402 octstr_destroy(exceptions_regex);
403 gwlist_destroy(exceptions, octstr_destroy_item);
404
405 counter = counter_create();
406
407 xml_doc = octstr_read_file(argv[optind]);
408 if (xml_doc == NULL)
409 panic(0, "Cannot read the XML document");
410
411 /*
412 * parse the XML source
413 */
414 msg = xmlrpc_parse_call(xml_doc);
415
416 if ((xmlrpc_parse_status(msg) != XMLRPC_COMPILE_OK) &&
417 ((output = xmlrpc_parse_error(msg)) != NULL)) {
418 /* parse failure */
419 error(0, "%s", octstr_get_cstr(output));
420 octstr_destroy(output);
421 }
422
423 /*
424 * if no POST is desired then dump the re-formated XML
425 */
426 if (url != NULL) {
427
428 time(&start);
429 if (num_threads == 0)
430 client_thread(http_caller_create());
431 else {
432 for (i = 0; i < num_threads; ++i)
433 threads[i] = gwthread_create(client_thread, http_caller_create());
434 for (i = 0; i < num_threads; ++i)
435 gwthread_join(threads[i]);
436 }
437 time(&end);
438
439
440 run_time = difftime(end, start);
441 info(0, "%ld requests in %f seconds, %f requests/s.",
442 max_requests, run_time, max_requests / run_time);
443
444 octstr_destroy(url);
445
446 } else {
447 output = xmlrpc_print_call(msg);
448 if (output != NULL) {
449 octstr_print(stderr, output);
450 octstr_destroy(output);
451 }
452 }
453
454 counter_destroy(counter);
455 octstr_destroy(auth_username);
456 octstr_destroy(auth_password);
457 octstr_destroy(ssl_client_certkey_file);
458 octstr_destroy(extra_headers);
459 octstr_destroy(content_file);
460
461
462 xmlrpc_destroy_call(msg);
463 octstr_destroy(xml_doc);
464
465 gwlib_shutdown();
466
467 return 0;
468 }
469
470