Kannel: Open Source WAP and SMS gateway  svn-r5335
test_xmlrpc.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 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;
82 static Octstr *extra_headers = NULL;
83 static Octstr *content_file = NULL;
84 static Octstr *url = NULL;
85 static int file = 0;
87 
88 
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 
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 
188 static void client_thread(void *arg)
189 {
190  List *reqh;
191  long i, succeeded, failed;
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)
205 
206  in_queue = 0;
207 
208  for (;;) {
209  while (in_queue < MAX_IN_QUEUE) {
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 
238  info(0, "This thread: %ld succeeded, %ld failed.", succeeded, failed);
239 }
240 
241 
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 
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;
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':
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':
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) {
350  p = strtok(NULL, "");
351  if (p != NULL)
353  }
354  break;
355 
356  case 's':
357  ssl = 1;
358  break;
359 
360  case 'c':
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  conn_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,
397  exceptions_regex);
398  }
399  octstr_destroy(proxy);
402  octstr_destroy(exceptions_regex);
403  gwlist_destroy(exceptions, octstr_destroy_item);
404 
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 
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)
431  else {
432  for (i = 0; i < num_threads; ++i)
434  for (i = 0; i < num_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 
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 
460 
461 
463  octstr_destroy(xml_doc);
464 
465  gwlib_shutdown();
466 
467  return 0;
468 }
469 
void error(int err, const char *fmt,...)
Definition: log.c:648
void info(int err, const char *fmt,...)
Definition: log.c:672
static int receive_reply(HTTPCaller *caller)
Definition: test_xmlrpc.c:113
#define xmlrpc_send_call(call, http_ref, url, headers, ref)
Definition: xmlrpc.h:197
long gwthread_self(void)
int xmlrpc_is_fault(XMLRPCDocument *response)
Definition: xmlrpc.c:1317
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2886
int threads
Definition: fakewap.c:239
int ssl
void counter_destroy(Counter *counter)
Definition: counter.c:110
void gwlist_append(List *list, void *item)
Definition: list.c:179
void gwthread_join(long thread)
static HTTPCaller * caller
Definition: smsbox.c:442
static Octstr * content_file
Definition: test_xmlrpc.c:83
void http_add_basic_auth(List *headers, Octstr *username, Octstr *password)
Definition: http.c:3515
int optind
Definition: attgetopt.c:80
static Octstr * ssl_client_certkey_file
Definition: test_xmlrpc.c:81
int octstr_print(FILE *f, Octstr *ostr)
Definition: octstr.c:1191
static int proxy_ssl
Definition: http.c:202
long xmlrpc_get_faultcode(XMLRPCDocument *faultresponse)
Definition: xmlrpc.c:1325
#define xmlrpc_parse_response(post_body)
Definition: xmlrpc.h:216
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static void help(void)
Definition: test_xmlrpc.c:242
int xmlrpc_parse_status(XMLRPCDocument *xrdoc)
Definition: xmlrpc.c:1348
unsigned long counter_increase(Counter *counter)
Definition: counter.c:123
Octstr * xmlrpc_get_faultstring(XMLRPCDocument *faultresponse)
Definition: xmlrpc.c:1335
int main(int argc, char **argv)
Definition: test_xmlrpc.c:269
#define MAX_IN_QUEUE
Definition: test_xmlrpc.c:74
void http_destroy_headers(List *headers)
Definition: http.c:2879
int getopt(int argc, char **argv, char *opts)
Definition: attgetopt.c:84
#define xmlrpc_parse_call(post_body)
Definition: xmlrpc.h:161
Counter * counter_create(void)
Definition: counter.c:94
void log_set_output_level(enum output_level level)
Definition: log.c:253
static Counter * counter
Definition: test_xmlrpc.c:76
static int proxy_port
Definition: http.c:201
static long max_requests
Definition: test_xmlrpc.c:77
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
static Octstr * proxy_username
Definition: http.c:203
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:336
static void client_thread(void *arg)
Definition: test_xmlrpc.c:188
void gwthread_sleep(double seconds)
#define http_receive_result(caller, status, final_url, headers, body)
Definition: http.h:394
Octstr * octstr_read_file(const char *filename)
Definition: octstr.c:1548
static Octstr * auth_username
Definition: test_xmlrpc.c:79
static int file
Definition: test_xmlrpc.c:85
Definition: octstr.c:118
void http_use_proxy(Octstr *hostname, int port, int ssl, List *exceptions, Octstr *username, Octstr *password, Octstr *exceptions_regex)
Definition: http.c:268
#define xmlrpc_destroy_call(call)
Definition: xmlrpc.h:165
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
char * optarg
Definition: attgetopt.c:82
#define panic
Definition: log.h:87
HTTPCaller * http_caller_create(void)
Definition: http.c:897
void gwlib_shutdown(void)
Definition: gwlib.c:94
#define gwlist_create()
Definition: list.h:136
static Octstr * auth_password
Definition: test_xmlrpc.c:80
#define MAX_THREADS
Definition: test_xmlrpc.c:73
void http_caller_destroy(HTTPCaller *caller)
Definition: http.c:907
void gwlib_init(void)
Definition: gwlib.c:78
#define xmlrpc_print_call(call)
Definition: xmlrpc.h:187
static Octstr * url
Definition: test_xmlrpc.c:84
static void start_request(HTTPCaller *caller, List *reqh, long i)
Definition: test_xmlrpc.c:89
Definition: list.c:102
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static int start
static Octstr * extra_headers
Definition: test_xmlrpc.c:82
Octstr * xmlrpc_parse_error(XMLRPCDocument *xrdoc)
Definition: xmlrpc.c:1356
static Octstr * proxy_password
Definition: http.c:204
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.