Kannel: Open Source WAP and SMS gateway  svn-r5335
test_ppg.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  * A very simple push initiator for testing a push proxy gateway
59  *
60  * Read pap control content and push content from files, pack them into a PAP
61  * protocol MIME message and invoke push services specified by an url. Use a
62  * hardcoded message boundary (asdlfkjiurwgasf), for simpler command line
63  * interface.
64  * Repetitions and use of multiple threads can be requested, in addition of
65  * setting of some headers.
66  *
67  * By Aarno Syv�nen for Wiral Ltd and Global Networks Inc.
68  */
69 
70 #define MAX_THREADS 1024
71 #define MAX_IN_QUEUE 128
72 
73 #include <unistd.h>
74 #include <stdlib.h>
75 #include <string.h>
76 
77 #include "gwlib/gwlib.h"
79 
80 static long max_pushes = 1;
81 static int verbose = 1,
83  num_urls = 0,
94 static double wait_seconds = 0.0;
95 static Counter *counter = NULL;
96 static char **push_data = NULL;
97 static char *boundary = NULL;
98 static Octstr *content_flag = NULL;
99 static Octstr *appid_flag = NULL;
100 static Octstr *appid_string = NULL;
101 static Octstr *content_header = NULL;
103 static Octstr *connection = NULL;
104 static Octstr *delimiter = NULL;
105 static Octstr *initiator_uri = NULL;
106 static Octstr *dlr_mask = NULL;
107 static Octstr *dlr_url = NULL;
108 
111 
112 /*
113  * Configuration variables
114  */
118 static Octstr *push_url = NULL;
119 static Octstr *pap_file = NULL;
120 static Octstr *content_file = NULL;
121 static Octstr *username = NULL;
122 static Octstr *password = NULL;
123 
125 {
126  Cfg *cfg;
127  CfgGroup *grp;
128 
129  cfg = cfg_create(name);
130  if (cfg_read(cfg) == -1)
131  panic(0, "Cannot read a configuration file %s, exiting",
133  cfg_dump(cfg);
134  grp = cfg_get_single_group(cfg, octstr_imm("test-ppg"));
135  cfg_get_integer(&retries, grp, octstr_imm("retries"));
136  cfg_get_bool(&pi_ssl, grp, octstr_imm("pi-ssl"));
137 #ifdef HAVE_LIBSSL
138  if (pi_ssl) {
140  octstr_imm("ssl-client-certkey-file"));
141  if (ssl_client_certkey_file != NULL) {
142  conn_use_global_client_certkey_file(ssl_client_certkey_file);
143  } else {
144  error(0, "cannot set up SSL without client certkey file");
145  exit(1);
146  }
147  }
148 #endif
149 
150  grp = cfg_get_single_group(cfg, octstr_imm("configuration"));
151  push_url = cfg_get(grp, octstr_imm("push-url"));
152  pap_file = cfg_get(grp, octstr_imm("pap-file"));
153  content_file = cfg_get(grp, octstr_imm("content-file"));
154  if (!use_hardcoded) {
155  username = cfg_get(grp, octstr_imm("username"));
156  password = cfg_get(grp, octstr_imm("password"));
157  }
158 
159  cfg_destroy(cfg);
160 }
161 
163 {
164  if (octstr_compare(delimiter, octstr_imm("crlf")) == 0) {
165  octstr_format_append(*content, "%c", '\r');
166  }
167 
168  octstr_format_append(*content, "%c", '\n');
169 }
170 
172  int use_string)
173 {
174  if (use_string) {
175  *content = octstr_format("%S\r\n", appid_string);
176  return;
177  }
178 
179  if (octstr_compare(appid_flag, octstr_imm("any")) == 0) {
180  if (!use_numeric)
181  *content = octstr_create("X-WAP-Application-Id: http://www.wiral.com:*\r\n");
182  else
183  *content = octstr_create("X-WAP-Application-Id: 0\r\n");
184  } else if (octstr_compare(appid_flag, octstr_imm("ua")) == 0) {
185  if (!use_numeric)
186  *content = octstr_create("X-WAP-Application-Id: http://www.wiral.com:wml.ua\r\n");
187  else
188  *content = octstr_create("X-WAP-Application-Id: 2\r\n");
189  } else if (octstr_compare(appid_flag, octstr_imm("mms")) == 0) {
190  if (!use_numeric)
191  *content = octstr_create("X-WAP-Application-Id: mms.ua\r\n");
192  else
193  *content = octstr_create("X-WAP-Application-Id: 4\r\n");
194  } else if (octstr_compare(appid_flag, octstr_imm("scrap")) == 0) {
195  if (!use_numeric)
196  *content = octstr_create("X-WAP-Application-Id: no appid at all\r\n");
197  else
198  *content = octstr_create("X-WAP-Application-Id: this is not a numeric header\r\n");
199  }
200 }
201 
202 static void add_dlr_mask(List **push_headers, Octstr *value)
203 {
204  http_header_add(*push_headers, "X-Kannel-DLR-Mask",
205  octstr_get_cstr(value));
206 }
207 
208 static void add_dlr_url(List **push_headers, Octstr *value)
209 {
210  http_header_add(*push_headers, "X-Kannel-DLR-Url",
211  octstr_get_cstr(value));
212 }
213 
214 static void add_part_header(Octstr *content_keader, Octstr **wap_content)
215 {
216  if (use_content_header) {
217  octstr_append(*wap_content, content_header);
218  }
219 
220  add_delimiter(wap_content);
221 }
222 
223 
225 {
226  if (*content == NULL)
227  *content = octstr_create("");
228 
229  if (octstr_compare(content_flag, octstr_imm("wml")) == 0)
230  octstr_append_cstr(*content, "Content-Type: text/vnd.wap.wml\r\n");
231  else if (octstr_compare(content_flag, octstr_imm("si")) == 0)
232  octstr_append_cstr(*content, "Content-Type: text/vnd.wap.si\r\n");
233  else if (octstr_compare(content_flag, octstr_imm("sl")) == 0)
234  octstr_append_cstr(*content, "Content-Type: text/vnd.wap.sl\r\n");
235  else if (octstr_compare(content_flag, octstr_imm("multipart")) == 0)
236  octstr_append_cstr(*content, "Content-Type: multipart/related; boundary=fsahgwruijkfldsa\r\n");
237  else if (octstr_compare(content_flag, octstr_imm("mms")) == 0)
238  octstr_append_cstr(*content, "Content-Type: application/vnd.wap.mms-message\r\n");
239 }
240 
242  Octstr *wap_content)
243 {
244  if (!content_flag)
245  return;
246 
247  if (octstr_compare(content_flag, octstr_imm("base64")) == 0)
248  octstr_append_cstr(wap_content, "Content-transfer-encoding: base64");
249 
250  add_delimiter(&wap_content);
251 }
252 
253 static void add_connection_header(List **push_headers, Octstr *connection)
254 {
255  if (!connection)
256  return;
257 
258  if (octstr_compare(connection, octstr_imm("close")) == 0)
259  http_header_add(*push_headers, "Connection", "close");
260  else if (octstr_compare(connection, octstr_imm("keep-alive")) == 0)
261  http_header_add(*push_headers, "Connection", "keep-alive");
262 }
263 
264 static void transfer_encode (Octstr *cte, Octstr *content)
265 {
266  if (!cte)
267  return;
268 
269  if (octstr_compare(cte, octstr_imm("base64")) == 0) {
271  }
272 }
273 
274 
275 /*
276  * Add boundary value to the multipart header.
277  */
279 {
280  Octstr *hos;
281 
282  hos = octstr_format("%s", "multipart/related; boundary=");
284  octstr_append(hos, octstr_imm("; type=\"application/xml\""));
285 
286  return hos;
287 }
288 
290 {
291  Octstr *part_delimiter;
292 
293  part_delimiter = octstr_create("");
294  add_delimiter(&part_delimiter);
295  octstr_format_append(part_delimiter, "%s", "--");
296  octstr_append(part_delimiter, boundary);
297  add_delimiter(&part_delimiter);
298 
299  return part_delimiter;
300 }
301 
303 {
304  Octstr *close_delimiter;
305 
306  close_delimiter = octstr_create("");
307  add_delimiter(&close_delimiter);
308  octstr_format_append(close_delimiter, "%s", "--");
309  octstr_append(close_delimiter, boundary);
310  octstr_format_append(close_delimiter, "%s", "--");
311  /*add_delimiter(&close_delimiter);*/
312 
313  return close_delimiter;
314 }
315 
316 static List *push_headers_create(size_t content_len)
317 {
318  List *push_headers;
319  Octstr *mos;
320 
321  mos = NULL;
322  push_headers = http_create_empty_headers();
323  if (use_hardcoded)
324  http_header_add(push_headers, "Content-Type", "multipart/related;"
325  " boundary=asdlfkjiurwgasf; type=\"application/xml\"");
326  else
327  http_header_add(push_headers, "Content-Type",
329  if (use_headers)
330  http_add_basic_auth(push_headers, username, password);
331  add_connection_header(&push_headers, connection);
332  if (use_dlr_mask)
333  add_dlr_mask(&push_headers, dlr_mask);
334  if (use_dlr_url)
335  add_dlr_url(&push_headers, dlr_url);
336 
337  octstr_destroy(mos);
338 
339  /* add initiator... */
340  if (initiator_uri)
341  http_header_add(push_headers, "X-Wap-Initiator-URI",
343 
344  return push_headers;
345 }
346 
348 {
349  Octstr *push_content,
350  *wap_content;
351  Octstr *wap_file_content,
352  *pap_content,
353  *pap_file_content,
354  *bpos,
355  *bcos;
356 
357  wap_content = NULL;
358  push_content = NULL;
359  if (use_hardcoded) {
360  push_content = octstr_create("\r\n\r\n"
361  "--asdlfkjiurwgasf\r\n"
362  "Content-Type: application/xml\r\n\r\n"
363  "<?xml version=\"1.0\"?>"
364  "<!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP//EN\""
365  " \"http://www.wapforum.org/DTD/pap_1.0.dtd\">"
366  "<pap>"
367  "<push-message push-id=\"9fjeo39jf084@pi.com\""
368  " deliver-before-timestamp=\"2002-11-01T06:45:00Z\""
369  " deliver-after-timestamp=\"2000-02-27T06:45:00Z\""
370  " progress-notes-requested=\"false\">"
371  "<address address-value=\"WAPPUSH=+358408676001/"
372  "TYPE=PLMN@ppg.carrier.com\">"
373  "</address>"
374  "<quality-of-service"
375  " priority=\"low\""
376  " delivery-method=\"unconfirmed\""
377  " network-required=\"true\""
378  " network=\"GSM\""
379  " bearer-required=\"true\""
380  " bearer=\"SMS\">"
381  "</quality-of-service>"
382  "</push-message>"
383  "</pap>\r\n\r\n"
384  "--asdlfkjiurwgasf\r\n"
385  "Content-Type: text/vnd.wap.si\r\n\r\n"
386  "<?xml version=\"1.0\"?>"
387  "<!DOCTYPE si PUBLIC \"-//WAPFORUM//DTD SI 1.0//EN\" "
388  " \"http://www.wapforum.org/DTD/si.dtd\">"
389  "<si>"
390  "<indication href=\"http://wap.iobox.fi\""
391  " si-id=\"1@wiral.com\""
392  " action=\"signal-high\""
393  " created=\"1999-06-25T15:23:15Z\""
394  " si-expires=\"2002-12-30T00:00:00Z\">"
395  "Want to test a fetch?"
396  "</indication>"
397  "</si>\r\n\r\n"
398  "--asdlfkjiurwgasf--\r\n\r\n"
399  "");
400  } else {
402  add_content_type(content_flag, &wap_content);
404  wap_content);
405  add_part_header(content_header, &wap_content);
406 
407  /* Read the content file. (To be pushed)*/
408  if ((wap_file_content =
410  panic(0, "Stopping");
411  if (accept_binary) {
412  octstr_delete_matching(wap_file_content, octstr_imm(" "));
413  octstr_delete_matching(wap_file_content, octstr_imm("\n"));
414  octstr_delete_matching(wap_file_content, octstr_imm("\r"));
415  if (!octstr_is_all_hex(wap_file_content))
416  panic(0, "non-hex chars in the content file, cannot continue");
417  octstr_hex_to_binary(wap_file_content);
418  }
419 
420  transfer_encode(content_transfer_encoding, wap_file_content);
421  octstr_append(wap_content, wap_file_content);
422  octstr_destroy(wap_file_content);
423 
424  /* Read the control file. (To control pushing)*/
425  pap_content = octstr_format("%s", "Content-Type: application/xml");
426  add_delimiter(&pap_content);
427  add_delimiter(&pap_content);
428  if ((pap_file_content =
430  panic(0, "Stopping");
431 
432  octstr_append(pap_content, pap_file_content);
433  octstr_destroy(pap_file_content);
434 
435  if (wap_content == NULL || pap_content == NULL)
436  panic(0, "Cannot open the push content files");
437 
438  push_content = octstr_create("");
439  if (add_preamble)
440  octstr_append(push_content, octstr_imm("the parser should discard this"));
441  octstr_append(push_content,
443  /*octstr_append(push_content, octstr_imm("\r\n"));*/ /* Do we accept an additional
444  * clrf ? */
445  octstr_append(push_content, pap_content);
446  octstr_append(push_content, bpos);
447  octstr_destroy(bpos);
448  octstr_append(push_content, wap_content);
449  octstr_append(push_content,
451  if (add_epilogue) {
452  octstr_append(push_content, octstr_imm("\r\n"));
453  octstr_append(push_content, octstr_imm("the parser should discard this"));
454  }
455  octstr_destroy(bcos);
456  octstr_destroy(pap_content);
457  octstr_destroy(wap_content);
458  }
459 
460  return push_content;
461 }
462 
463 static void make_url(Octstr **url)
464 {
465  if (use_config && !use_headers) {
466  octstr_append(*url, octstr_imm("?username="));
467  octstr_append(*url, username ? username : octstr_imm("default"));
468  octstr_append(*url, octstr_imm("&password="));
469  octstr_append(*url, password ? password: octstr_imm("default"));
470  }
471 }
472 
473 static void start_push(HTTPCaller *caller, long i)
474 {
475  List *push_headers;
476  Octstr *push_content;
477  long *id;
478 
479  push_content = push_content_create();
480  push_headers = push_headers_create(octstr_len(push_content));
481  if (verbose) {
482  debug("test.ppg", 0, "we have push content");
483  octstr_dump(push_content, 0);
484  debug("test.ppg", 0, "and headers");
485  http_header_dump(push_headers);
486  }
487 
488  id = gw_malloc(sizeof(long));
489  *id = i;
490  make_url(&push_url);
491  debug("test.ppg", 0, "TEST_PPG: starting to push job %ld", i);
493  push_content, 0, id, ssl_client_certkey_file);
494  debug("test.ppg", 0, "push done");
495  octstr_destroy(push_content);
496  http_destroy_headers(push_headers);
497 }
498 
499 /*
500  * Try log in defined number of times, when got response 401 and authentica-
501  * tion info is in headers.
502  */
504 {
505  void *id;
506  long *trid;
507  int http_status,
508  tries;
509  List *reply_headers;
510  Octstr *final_url,
511  *auth_url,
512  *reply_body,
513  *os,
514  *push_content,
515  *auth_reply_body;
516  WAPEvent *e;
517  List *retry_headers;
518 
519  http_status = HTTP_UNAUTHORIZED;
520  tries = 0;
521 
522  id = http_receive_result(caller, &http_status, &final_url, &reply_headers,
523  &reply_body);
524 
525  if (id == NULL || http_status == -1 || final_url == NULL) {
526  error(0, "push failed, no reason found");
527  goto push_failed;
528  }
529 
530  while (use_headers && http_status == HTTP_UNAUTHORIZED && tries < retries) {
531  debug("test.ppg", 0, "try number %d", tries);
532  debug("test.ppg", 0, "authentication failure, get a challenge");
533  http_destroy_headers(reply_headers);
534  push_content = push_content_create();
535  retry_headers = push_headers_create(octstr_len(push_content));
536  http_add_basic_auth(retry_headers, username, password);
537  trid = gw_malloc(sizeof(long));
538  *trid = tries;
539  http_start_request(caller, HTTP_METHOD_POST, final_url, retry_headers,
540  push_content, 0, trid, NULL);
541  debug("test.ppg ", 0, "TEST_PPG: doing response to %s",
542  octstr_get_cstr(final_url));
543 
544  octstr_destroy(push_content);
545  http_destroy_headers(retry_headers);
546 
547  trid = http_receive_result(caller, &http_status, &auth_url,
548  &reply_headers, &auth_reply_body);
549 
550  if (trid == NULL || http_status == -1 || auth_url == NULL) {
551  error(0, "unable to send authorisation, no reason found");
552  goto push_failed;
553  }
554 
555  debug("test.ppg", 0, "TEST_PPG: send authentication to %s, retry %ld",
556  octstr_get_cstr(auth_url), *(long *) trid);
557  gw_free(trid);
558  octstr_destroy(auth_reply_body);
559  octstr_destroy(auth_url);
560  ++tries;
561  }
562 
563  if (http_status == HTTP_NOT_FOUND) {
564  error(0, "push failed, service not found");
565  goto push_failed;
566  }
567 
568  if (http_status == HTTP_FORBIDDEN) {
569  error(0, "push failed, service forbidden");
570  goto push_failed;
571  }
572 
573  if (http_status == HTTP_UNAUTHORIZED) {
574  if (use_headers)
575  error(0, "tried %ld times, stopping", retries);
576  else
577  error(0, "push failed, authorisation failure");
578  goto push_failed;
579  }
580 
581  debug("test.ppg", 0, "TEST_PPG: push %ld done: reply from, %s",
582  *(long *) id, octstr_get_cstr(final_url));
583  gw_free(id);
584  octstr_destroy(final_url);
585 
586  if (verbose)
587  debug("test.ppg", 0, "TEST_PPG: reply headers were");
588 
589  while ((os = gwlist_extract_first(reply_headers)) != NULL) {
590  if (verbose)
591  octstr_dump(os, 0);
592  octstr_destroy(os);
593  }
594 
595  if (verbose) {
596  debug("test.ppg", 0, "TEST_PPG: reply body was");
597  octstr_dump(reply_body, 0);
598  }
599 
600  e = NULL;
601  if (pap_compile(reply_body, &e) < 0) {
602  warning(0, "TEST_PPG: receive_push_reply: cannot compile pap message");
603  goto parse_error;
604  }
605 
606  switch (e->type) {
607  case Push_Response:
608  debug("test.ppg", 0, "TEST_PPG: and type push response");
609  break;
610 
611  case Bad_Message_Response:
612  debug("test.ppg", 0, "TEST_PPG: and type bad message response");
613  break;
614 
615  default:
616  warning(0, "TEST_PPG: unknown event received from %s",
617  octstr_get_cstr(final_url));
618  break;
619  }
620 
621  octstr_destroy(reply_body);
623  http_destroy_headers(reply_headers);
624  return 0;
625 
626 push_failed:
627  gw_free(id);
628  octstr_destroy(final_url);
629  octstr_destroy(reply_body);
630  http_destroy_headers(reply_headers);
631  return -1;
632 
634  octstr_destroy(reply_body);
635  http_destroy_headers(reply_headers);
637  return -1;
638 }
639 
640 static void push_thread(void *arg)
641 {
643  long succeeded, failed, in_queue;
644  unsigned long i;
645 
646  caller = arg;
647  succeeded = 0;
648  failed = 0;
649  in_queue = 0;
650  i = 0;
651 
652  for (;;) {
653  while (in_queue < MAX_IN_QUEUE) {
655  if (i >= max_pushes)
656  goto receive_rest;
657  start_push(caller, i);
658  if (wait_seconds > 0)
660  ++in_queue;
661  }
662 
663  while (in_queue >= MAX_IN_QUEUE) {
664  if (receive_push_reply(caller) == -1)
665  ++failed;
666  else
667  ++succeeded;
668  --in_queue;
669  }
670  }
671 
672 receive_rest:
673  while (in_queue > 0) {
674  if (receive_push_reply(caller) == -1)
675  ++failed;
676  else
677  ++succeeded;
678  --in_queue;
679  }
680 
682  info(0, "TEST_PPG: In thread %ld %ld succeeded, %ld failed",
683  (long) gwthread_self(), succeeded, failed);
684 }
685 
686 static void help(void)
687 {
688  info(0, "Usage: test_ppg [options] push_url [content_file pap_file]");
689  info(0, " or");
690  info(0, "Usage: test_ppg [options] [conf_file]");
691  info(0, "Implements push initiator for wap push. Push services are ");
692  info(0, "located in push_url, push content in the file content file.");
693  info(0, "File pap_file contains pap control document that controls");
694  info(0, "pushing");
695  info(0, "If option -H is not used, command line has either three or one");
696  info(0, "arguments:");
697  info(0, " a) the url of the push proxy gateway");
698  info(0, " b) a file containing the content to be pushed");
699  info(0, " c) a pap document controlling pushing");
700  info(0, " or");
701  info(0, " a) a test configuration file, containing all these");
702  info(0, "Option -H cannot be used with a configuration file. If it is");
703  info(0, "used, the push url is the only argument.");
704  info(0, "Options are:");
705  info(0, "-h");
706  info(0, "print this info");
707  info(0, "-c content qualifier");
708  info(0, "Define content type of the push content. Wml, multipart, nil,");
709  info(0, "scrap, sl, and si accepted. Si is default, nil (no content");
710  info(0, " type at all) and scrap (random string) are used for debugging");
711  info(0, "-a application id");
712  info(0, "Define the client application that will handle the push. Any,");
713  info(0, "ua, mms, nil and scrap accepted, default ua.");
714  info(0, "-n");
715  info(0, "if set, use numeric appid values instead of string ones. For");
716  info(0, "instance, '4' instead of 'mms.ua'. Default is off.");
717  info(0, "-s string");
718  info(0, "supply a message header as a plain string. For instance");
719  info(0, "-s x-wap-application-id:mms.ua equals -a ua. Default is");
720  info(0, "x-wap-application-id:mms.ua.");
721  info(0, "-I string");
722  info(0, "supply an initiator header as a plain string. For instance");
723  info(0, "-I x-wap-application-id:http://foo.bar equals -I http://foo.bar");
724  info(0, "-S string");
725  info(0, "supply an additional part header (for push content) as a string.");
726  info(0, "For instance, -S Content-Language: en. Default no additional part");
727  info(0, "headers.");
728  info(0, "-b");
729  info(0, "If true, send username/password in headers. Default false");
730  info(0, "-v number");
731  info(0, " Set log level for stderr logging. Default 0 (debug)");
732  info(0, "-q");
733  info(0, " Do not print debugging information");
734  info(0, "Default: print it");
735  info(0, "-r number");
736  info(0, " Make `number' requests. Default one request");
737  info(0, "-i seconds");
738  info(0, " Wait 'seconds' seconds between pushes. Default: do not wait");
739  info(0, "-e transfer encoding");
740  info(0, " use transfer encoding to send push contents.");
741  info(0, " Currently supported is base64.");
742  info(0, "-k connection header");
743  info(0, "Use the connection header. Keep-alive and close accepted,");
744  info(0, "default close");
745  info(0, "-H");
746  info(0, "Use hardcoded MIME message, containing a pap control document.");
747  info(0, "In addition, use hardcoded username/password in headers (if ");
748  info(0, "flag -b is set, too");
749  info(0, "Default: read components from files");
750  info(0, "-t");
751  info(0, "number of threads, maximum 1024, default 1");
752  info(0, "-B");
753  info(0, "accept binary push content. Default: off.");
754  info(0, "Binary content consist of hex numbers. In addition, crs, lfs and");
755  info(0, "spaces are accepted, and ignored.");
756  info(0, "-d value");
757  info(0, "set delimiter to be used. Accepted values crlf and lf. Default crlf.");
758  info(0, "-E");
759  info(0, "If set, add a hardcoded epilogue (epilogue is to be discarded anyway).");
760  info(0, "Default off.");
761  info(0, "-p");
762  info(0, "If set, add hardcoded preamble. Default is off.");
763  info(0, "-m value");
764  info(0, "If set, add push header X-Kannel-DLR-Mask: value");
765  info(0, "Default off.");
766  info(0, "-u value");
767  info(0, "If set, add push header X-Kannel-DLR-Url: value");
768  info(0, "Default off.");
769 }
770 
771 int main(int argc, char **argv)
772 {
773  int opt,
774  num_threads;
775  time_t start,
776  end;
777  double run_time;
778  long threads[MAX_THREADS];
779  long i;
780  Octstr *fos;
781 
782  gwlib_init();
783  num_threads = 1;
784 
785  while ((opt = getopt(argc, argv, "HhBbnEpv:qr:t:c:a:i:e:k:d:s:S:I:m:u:")) != EOF) {
786  switch(opt) {
787  case 'v':
789  break;
790 
791  case 'q':
792  verbose = 0;
793  break;
794 
795  case 'r':
796  max_pushes = atoi(optarg);
797  break;
798 
799  case 'i':
800  wait_seconds = atof(optarg);
801  break;
802 
803  case 't':
804  num_threads = atoi(optarg);
805  if (num_threads > MAX_THREADS)
806  num_threads = MAX_THREADS;
807  break;
808 
809  case 'H':
810  use_hardcoded = 1;
811  break;
812 
813  case 'c':
815  if (octstr_compare(content_flag, octstr_imm("wml")) != 0 &&
816  octstr_compare(content_flag, octstr_imm("si")) != 0 &&
817  octstr_compare(content_flag, octstr_imm("sl")) != 0 &&
818  octstr_compare(content_flag, octstr_imm("nil")) != 0 &&
819  octstr_compare(content_flag, octstr_imm("mms")) != 0 &&
820  octstr_compare(content_flag, octstr_imm("scrap")) != 0 &&
821  octstr_compare(content_flag, octstr_imm("multipart")) != 0) {
823  error(0, "TEST_PPG: Content type not known");
824  help();
825  exit(1);
826  }
827  break;
828 
829  case 'a':
831  if (octstr_compare(appid_flag, octstr_imm("any")) != 0 &&
832  octstr_compare(appid_flag, octstr_imm("ua")) != 0 &&
833  octstr_compare(appid_flag, octstr_imm("mms")) != 0 &&
834  octstr_compare(appid_flag, octstr_imm("nil")) != 0 &&
835  octstr_compare(appid_flag, octstr_imm("scrap")) != 0) {
837  error(0, "TEST_PPG: Push application id not known");
838  help();
839  exit(1);
840  }
841  break;
842 
843  case 'n':
844  use_numeric = 1;
845  break;
846 
847  case 's':
849  use_string = 1;
850  break;
851 
852  case 'S':
854  use_content_header = 1;
855  break;
856 
857  case 'e':
859  if (octstr_compare(content_transfer_encoding, octstr_imm("base64")) != 0) {
861  error(0, "TEST_PPG: unknown content transfer"
862  " encoding \"%s\"", octstr_get_cstr(content_transfer_encoding));
863  help();
864  exit(1);
865  }
866  break;
867 
868  case 'k':
870  if (octstr_compare(connection, octstr_imm("close")) != 0 &&
871  octstr_compare(connection, octstr_imm("keep-alive")) != 0) {
873  error(0, "TEST_PPG: Connection-header unacceptable");
874  help();
875  exit(1);
876  }
877  break;
878 
879  case 'h':
880  help();
881  exit(1);
882 
883  case 'b':
884  use_headers = 1;
885  break;
886 
887  case 'B':
888  accept_binary = 1;
889  break;
890 
891  case 'd':
893  if (octstr_compare(delimiter, octstr_imm("crlf")) != 0 &&
894  octstr_compare(delimiter, octstr_imm("lf")) != 0) {
896  error(0, "illegal d value");
897  help();
898  exit(1);
899  }
900  break;
901 
902  case 'E':
903  add_epilogue = 1;
904  break;
905 
906  case 'p':
907  add_preamble = 1;
908  break;
909 
910  case 'I':
912  break;
913 
914  case 'm':
915  use_dlr_mask = 1;
917  break;
918 
919  case 'u':
920  use_dlr_url = 1;
922  break;
923 
924  case '?':
925  default:
926  error(0, "TEST_PPG: Invalid option %c", opt);
927  help();
928  error(0, "Stopping");
929  exit(1);
930  }
931  }
932 
933  if (optind == argc) {
934  help();
935  exit(1);
936  }
937 
938  push_data = argv + optind;
939  num_urls = argc - optind;
940 
941  if (content_flag == NULL)
942  content_flag = octstr_imm("si");
943 
944  if (appid_flag == NULL)
945  appid_flag = octstr_imm("ua");
946 
947  if (appid_string == NULL)
948  appid_string = octstr_imm("x-wap-application-id: wml.ua");
949 
950  if (content_header == NULL)
951  use_content_header = 0;
952 
953  if (dlr_mask == NULL)
954  use_dlr_mask = 0;
955 
956  if (dlr_url == NULL)
957  use_dlr_url = 0;
958 
959  if (delimiter == NULL)
960  delimiter = octstr_imm("crlf");
961 
962  if (use_hardcoded) {
963  username = octstr_imm("troo");
964  password = octstr_imm("far");
965  }
966 
967  if (push_data[0] == NULL) {
968  error(0, "No ppg address or config file, stopping");
969  exit(1);
970  }
971 
972  use_config = 0;
973  if (!use_hardcoded) {
974  if (push_data[1] == NULL) {
975  info(0, "a configuration file input assumed");
977  octstr_destroy(fos);
978  use_config = 1;
979  }
980  }
981 
982  if (!use_config)
983  push_url = octstr_format("%s", push_data[0]);
984 
985  if (!use_hardcoded && !use_config && push_data[1] != NULL) {
986  if (push_data[2] == NULL) {
987  error(0, "no pap control document, stopping");
988  exit(1);
989  } else {
990  info(0, "an input without a configuration file assumed");
993  debug("test.ppg", 0, "using %s as a content file", push_data[1]);
994  debug("test.ppg", 0, "using %s as a control file", push_data[2]);
995  }
996  }
997 
998  boundary = "asdlfkjiurwghasf";
1000 
1001  time(&start);
1002  if (num_threads == 0)
1004  else {
1005  for (i = 0; i < num_threads; ++i)
1007  for (i = 0; i < num_threads; ++i)
1008  gwthread_join(threads[i]);
1009  }
1010  time(&end);
1011  run_time = difftime(end, start);
1012  info(0, "TEST_PPG: %ld requests in %f seconds, %f requests per second",
1013  max_pushes, run_time, max_pushes / run_time);
1014 
1029  gwlib_shutdown();
1030 
1031  exit(0);
1032 }
1033 
1034 
1035 
1036 
1037 
1038 
1039 
1040 
1041 
static Octstr * dlr_mask
Definition: test_ppg.c:106
static void add_part_header(Octstr *content_keader, Octstr **wap_content)
Definition: test_ppg.c:214
static int add_epilogue
Definition: test_ppg.c:90
void error(int err, const char *fmt,...)
Definition: log.c:648
static Octstr * delimiter
Definition: test_ppg.c:104
void info(int err, const char *fmt,...)
Definition: log.c:672
static void push_thread(void *arg)
Definition: test_ppg.c:640
static Octstr * initiator_uri
Definition: test_ppg.c:105
long gwthread_self(void)
static char ** push_data
Definition: test_ppg.c:96
static int use_headers
Definition: test_ppg.c:84
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2886
int threads
Definition: fakewap.c:239
void counter_destroy(Counter *counter)
Definition: counter.c:110
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1504
static double wait_seconds
Definition: test_ppg.c:94
void gwthread_join(long thread)
static Octstr * pap_file
Definition: test_ppg.c:119
static int use_string
Definition: test_ppg.c:88
static HTTPCaller * caller
Definition: smsbox.c:442
static int accept_binary
Definition: test_ppg.c:86
static Octstr * connection
Definition: test_ppg.c:103
static void make_url(Octstr **url)
Definition: test_ppg.c:463
static int use_dlr_mask
Definition: test_ppg.c:92
void http_add_basic_auth(List *headers, Octstr *username, Octstr *password)
Definition: http.c:3515
static char * boundary
Definition: test_ppg.c:97
static int use_config
Definition: test_ppg.c:85
int optind
Definition: attgetopt.c:80
#define cfg_get(grp, varname)
Definition: cfg.h:86
void octstr_binary_to_base64(Octstr *ostr)
Definition: octstr.c:542
static int use_hardcoded
Definition: test_ppg.c:82
static void add_content_transfer_encoding_type(Octstr *content_flag, Octstr *wap_content)
Definition: test_ppg.c:241
static Octstr * ssl_client_certkey_file
Definition: test_ppg.c:117
static Octstr * push_content_create(void)
Definition: test_ppg.c:347
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1511
static Cfg * cfg
Definition: opensmppbox.c:95
int main(int argc, char **argv)
Definition: test_ppg.c:771
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
unsigned long counter_increase(Counter *counter)
Definition: counter.c:123
static void add_push_application_id(Octstr *appid_flag, Octstr **content, int use_string)
Definition: test_ppg.c:171
static long max_pushes
Definition: test_ppg.c:80
static Octstr * appid_flag
Definition: test_ppg.c:99
static void add_dlr_url(List **push_headers, Octstr *value)
Definition: test_ppg.c:208
static void read_test_ppg_config(Octstr *name)
Definition: test_ppg.c:124
Cfg * cfg_create(Octstr *filename)
Definition: cfg.c:318
static Octstr * content_transfer_encoding
Definition: test_ppg.c:102
static Octstr * push_url
Definition: test_ppg.c:118
static Octstr * username
Definition: test_ppg.c:121
int cfg_read(Cfg *cfg)
Definition: cfg.c:452
void http_destroy_headers(List *headers)
Definition: http.c:2879
static void add_dlr_mask(List **push_headers, Octstr *value)
Definition: test_ppg.c:202
static Octstr * content_header
Definition: test_ppg.c:101
int getopt(int argc, char **argv, char *opts)
Definition: attgetopt.c:84
void http_start_request(HTTPCaller *caller, int method, Octstr *url, List *headers, Octstr *body, int follow, void *id, Octstr *certkeyfile)
Definition: http.c:1760
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
Definition: cfg.c:164
Counter * counter_create(void)
Definition: counter.c:94
void cfg_destroy(Cfg *cfg)
Definition: cfg.c:331
void * gwlist_extract_first(List *list)
Definition: list.c:305
void log_set_output_level(enum output_level level)
Definition: log.c:253
static Octstr * dlr_url
Definition: test_ppg.c:107
List * http_create_empty_headers(void)
Definition: http.c:2872
static long retries
Definition: test_ppg.c:116
void cfg_dump(Cfg *cfg)
Definition: cfg.c:835
#define MAX_THREADS
Definition: test_ppg.c:70
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
static void help(void)
Definition: test_ppg.c:686
char * name
Definition: smsc_cimd2.c:212
static int receive_push_reply(HTTPCaller *caller)
Definition: test_ppg.c:503
void warning(int err, const char *fmt,...)
Definition: log.c:660
static int verbose
Definition: test_ppg.c:81
static void add_delimiter(Octstr **content)
Definition: test_ppg.c:162
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
static Octstr * content_flag
Definition: test_ppg.c:98
static int pi_ssl
Definition: test_ppg.c:115
static Octstr * appid_string
Definition: test_ppg.c:100
void gwthread_sleep(double seconds)
#define MAX_IN_QUEUE
Definition: test_ppg.c:71
static Octstr * content_file
Definition: test_ppg.c:120
int octstr_is_all_hex(Octstr *os)
Definition: octstr.c:2717
#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 List * push_headers_create(size_t content_len)
Definition: test_ppg.c:316
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:759
Definition: octstr.c:118
static Octstr * password
Definition: test_ppg.c:122
static int use_dlr_url
Definition: test_ppg.c:93
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:742
char * optarg
Definition: attgetopt.c:82
#define panic
Definition: log.h:87
Definition: cfg.c:73
int octstr_hex_to_binary(Octstr *ostr)
Definition: octstr.c:494
static void add_content_type(Octstr *content_flag, Octstr **content)
Definition: test_ppg.c:224
WAPEventName type
Definition: wap_events.h:88
HTTPCaller * http_caller_create(void)
Definition: http.c:897
void octstr_format_append(Octstr *os, const char *fmt,...)
Definition: octstr.c:2507
void gwlib_shutdown(void)
Definition: gwlib.c:94
static Octstr * make_multipart_value(const char *boundary)
Definition: test_ppg.c:278
static Octstr * make_close_delimiter(Octstr *boundary)
Definition: test_ppg.c:302
static int add_preamble
Definition: test_ppg.c:91
static void start_push(HTTPCaller *caller, long i)
Definition: test_ppg.c:473
static int num_urls
Definition: test_ppg.c:83
void http_caller_destroy(HTTPCaller *caller)
Definition: http.c:907
void gwlib_init(void)
Definition: gwlib.c:78
int parse_error(ParseContext *context)
Definition: parse.c:100
static void add_connection_header(List **push_headers, Octstr *connection)
Definition: test_ppg.c:253
CfgGroup * cfg_get_single_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:639
static void transfer_encode(Octstr *cte, Octstr *content)
Definition: test_ppg.c:264
static Octstr * url
Definition: test_xmlrpc.c:84
static Counter * counter
Definition: test_ppg.c:95
static int use_content_header
Definition: test_ppg.c:89
Definition: list.c:102
int pap_compile(Octstr *pap_content, WAPEvent **e)
static int start
void http_header_dump(List *headers)
Definition: http.c:3427
static Octstr * make_part_delimiter(Octstr *boundary)
Definition: test_ppg.c:289
static int use_numeric
Definition: test_ppg.c:87
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:871
void octstr_delete_matching(Octstr *haystack, Octstr *needle)
Definition: octstr.c:2702
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.