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 * 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"
78 #include "gw/wap_push_pap_compiler.h"
79
80 static long max_pushes = 1;
81 static int verbose = 1,
82 use_hardcoded = 0,
83 num_urls = 0,
84 use_headers = 0,
85 use_config = 0,
86 accept_binary = 0,
87 use_numeric = 0,
88 use_string = 0,
89 use_content_header = 0,
90 add_epilogue = 0,
91 add_preamble = 0,
92 use_dlr_mask = 0,
93 use_dlr_url = 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;
102 static Octstr *content_transfer_encoding = 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
109 enum { SSL_CONNECTION_OFF = 0,
110 DEFAULT_NUMBER_OF_RELOGS = 2};
111
112 /*
113 * Configuration variables
114 */
115 static int pi_ssl = SSL_CONNECTION_OFF;
116 static long retries = DEFAULT_NUMBER_OF_RELOGS;
117 static Octstr *ssl_client_certkey_file = NULL;
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
read_test_ppg_config(Octstr * name)124 static void read_test_ppg_config(Octstr *name)
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",
132 octstr_get_cstr(name));
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) {
139 ssl_client_certkey_file = cfg_get(grp,
140 octstr_imm("ssl-client-certkey-file"));
141 if (ssl_client_certkey_file != NULL) {
142 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
add_delimiter(Octstr ** content)162 static void add_delimiter(Octstr **content)
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
add_push_application_id(Octstr * appid_flag,Octstr ** content,int use_string)171 static void add_push_application_id(Octstr *appid_flag, Octstr **content,
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
add_dlr_mask(List ** push_headers,Octstr * value)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
add_dlr_url(List ** push_headers,Octstr * value)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
add_part_header(Octstr * content_keader,Octstr ** wap_content)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
add_content_type(Octstr * content_flag,Octstr ** content)224 static void add_content_type(Octstr *content_flag, Octstr **content)
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
add_content_transfer_encoding_type(Octstr * content_flag,Octstr * wap_content)241 static void add_content_transfer_encoding_type(Octstr *content_flag,
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
add_connection_header(List ** push_headers,Octstr * connection)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
transfer_encode(Octstr * cte,Octstr * content)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) {
270 octstr_binary_to_base64(content);
271 }
272 }
273
274
275 /*
276 * Add boundary value to the multipart header.
277 */
make_multipart_value(const char * boundary)278 static Octstr *make_multipart_value(const char *boundary)
279 {
280 Octstr *hos;
281
282 hos = octstr_format("%s", "multipart/related; boundary=");
283 octstr_append(hos, octstr_imm(boundary));
284 octstr_append(hos, octstr_imm("; type=\"application/xml\""));
285
286 return hos;
287 }
288
make_part_delimiter(Octstr * boundary)289 static Octstr *make_part_delimiter(Octstr *boundary)
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
make_close_delimiter(Octstr * boundary)302 static Octstr *make_close_delimiter(Octstr *boundary)
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
push_headers_create(size_t content_len)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",
328 octstr_get_cstr(mos = make_multipart_value(boundary)));
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",
342 octstr_get_cstr(initiator_uri));
343
344 return push_headers;
345 }
346
push_content_create(void)347 static Octstr *push_content_create(void)
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 {
401 add_push_application_id(appid_flag, &wap_content, use_string);
402 add_content_type(content_flag, &wap_content);
403 add_content_transfer_encoding_type(content_transfer_encoding,
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 =
409 octstr_read_file(octstr_get_cstr(content_file))) == NULL)
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 =
429 octstr_read_file(octstr_get_cstr(pap_file))) == NULL)
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,
442 bpos = make_part_delimiter(octstr_imm(boundary)));
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,
450 bcos = make_close_delimiter(octstr_imm(boundary)));
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
make_url(Octstr ** url)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
start_push(HTTPCaller * caller,long i)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);
492 http_start_request(caller, HTTP_METHOD_POST, push_url, push_headers,
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 */
receive_push_reply(HTTPCaller * caller)503 static int receive_push_reply(HTTPCaller *caller)
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);
622 wap_event_destroy(e);
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
633 parse_error:
634 octstr_destroy(reply_body);
635 http_destroy_headers(reply_headers);
636 wap_event_destroy(e);
637 return -1;
638 }
639
push_thread(void * arg)640 static void push_thread(void *arg)
641 {
642 HTTPCaller *caller;
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) {
654 i = counter_increase(counter);
655 if (i >= max_pushes)
656 goto receive_rest;
657 start_push(caller, i);
658 if (wait_seconds > 0)
659 gwthread_sleep(wait_seconds);
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
681 http_caller_destroy(caller);
682 info(0, "TEST_PPG: In thread %ld %ld succeeded, %ld failed",
683 (long) gwthread_self(), succeeded, failed);
684 }
685
help(void)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
main(int argc,char ** argv)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':
788 log_set_output_level(atoi(optarg));
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':
814 content_flag = octstr_create(optarg);
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) {
822 octstr_destroy(content_flag);
823 error(0, "TEST_PPG: Content type not known");
824 help();
825 exit(1);
826 }
827 break;
828
829 case 'a':
830 appid_flag = octstr_create(optarg);
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) {
836 octstr_destroy(appid_flag);
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':
848 appid_string = octstr_create(optarg);
849 use_string = 1;
850 break;
851
852 case 'S':
853 content_header = octstr_create(optarg);
854 use_content_header = 1;
855 break;
856
857 case 'e':
858 content_transfer_encoding = octstr_create(optarg);
859 if (octstr_compare(content_transfer_encoding, octstr_imm("base64")) != 0) {
860 octstr_destroy(content_transfer_encoding);
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':
869 connection = octstr_create(optarg);
870 if (octstr_compare(connection, octstr_imm("close")) != 0 &&
871 octstr_compare(connection, octstr_imm("keep-alive")) != 0) {
872 octstr_destroy(connection);
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':
892 delimiter = octstr_create(optarg);
893 if (octstr_compare(delimiter, octstr_imm("crlf")) != 0 &&
894 octstr_compare(delimiter, octstr_imm("lf")) != 0) {
895 octstr_destroy(delimiter);
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':
911 initiator_uri = octstr_create(optarg);
912 break;
913
914 case 'm':
915 use_dlr_mask = 1;
916 dlr_mask = octstr_create(optarg);
917 break;
918
919 case 'u':
920 use_dlr_url = 1;
921 dlr_url = octstr_create(optarg);
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");
976 read_test_ppg_config(fos = octstr_format("%s", push_data[0]));
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");
991 content_file = octstr_create(push_data[1]);
992 pap_file = octstr_create(push_data[2]);
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";
999 counter = counter_create();
1000
1001 time(&start);
1002 if (num_threads == 0)
1003 push_thread(http_caller_create());
1004 else {
1005 for (i = 0; i < num_threads; ++i)
1006 threads[i] = gwthread_create(push_thread, http_caller_create());
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
1015 octstr_destroy(content_flag);
1016 octstr_destroy(appid_flag);
1017 octstr_destroy(content_header);
1018 octstr_destroy(content_file);
1019 octstr_destroy(pap_file);
1020 octstr_destroy(ssl_client_certkey_file);
1021 octstr_destroy(username);
1022 octstr_destroy(password);
1023 octstr_destroy(push_url);
1024 octstr_destroy(connection);
1025 octstr_destroy(delimiter);
1026 octstr_destroy(dlr_mask);
1027 octstr_destroy(dlr_url);
1028 counter_destroy(counter);
1029 gwlib_shutdown();
1030
1031 exit(0);
1032 }
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042