test_ppg.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:26k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * A very simple push initiator for testing a push proxy gateway
  3.  *
  4.  * Read pap control content and push content from files, pack them into a PAP
  5.  * protocol MIME message and invoke push services specified by an url. Use a 
  6.  * hardcoded message boundary (asdlfkjiurwgasf), for simpler command line 
  7.  * interface.
  8.  * Repetitions and use of multiple threads can be requested, in addition of 
  9.  * setting of some headers. 
  10.  *
  11.  * By Aarno Syv鋘en for Wiral Ltd and Global Networks Inc.
  12.  */
  13. #define MAX_THREADS 1024
  14. #define MAX_IN_QUEUE 128
  15. #include <unistd.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include "gwlib/gwlib.h"
  19. #include "gw/wap_push_pap_compiler.h"
  20. static long max_pushes = 1;
  21. static int verbose = 1,
  22.            use_hardcoded = 0,
  23.            num_urls = 0,
  24.            wait = 0,
  25.            use_headers = 0,
  26.            use_config = 0;
  27. static double wait_seconds = 0.0;
  28. static Counter *counter = NULL;
  29. static char **push_data = NULL;
  30. static char *boundary = NULL;
  31. static Octstr *content_flag = NULL;
  32. static Octstr *appid_flag = NULL;
  33. static Octstr *content_transfer_encoding = NULL;
  34. static Octstr *connection = NULL;
  35. enum { SSL_CONNECTION_OFF = 0,
  36.        DEFAULT_NUMBER_OF_RELOGS = 2};
  37. /*
  38.  * Configuration variables
  39.  */
  40. static int pi_ssl = SSL_CONNECTION_OFF;
  41. static long retries = DEFAULT_NUMBER_OF_RELOGS;
  42. static Octstr *ssl_client_certkey_file = NULL;
  43. static Octstr *push_url = NULL;
  44. static Octstr *pap_file = NULL;
  45. static Octstr *content_file = NULL;
  46. static Octstr *username = NULL;
  47. static Octstr *password = NULL;
  48. static void read_test_ppg_config(Octstr *name)
  49. {
  50.     Cfg *cfg;
  51.     CfgGroup *grp;
  52.     cfg = cfg_create(name);
  53.     if (cfg_read(cfg) == -1)
  54.         panic(0, "Cannot read a configuration file %s, exiting",
  55.               octstr_get_cstr(name));
  56.     cfg_dump(cfg);
  57.     grp = cfg_get_single_group(cfg, octstr_imm("test-ppg"));
  58.     cfg_get_integer(&retries, grp, octstr_imm("retries"));
  59.     cfg_get_bool(&pi_ssl, grp, octstr_imm("pi-ssl"));
  60. #ifdef HAVE_LIBSSL    
  61.     if (pi_ssl) {
  62.         ssl_client_certkey_file = cfg_get(grp, 
  63.             octstr_imm("ssl-client-certkey-file"));
  64.         if (ssl_client_certkey_file != NULL) {
  65.             use_global_client_certkey_file(ssl_client_certkey_file);
  66.         } else { 
  67.             error(0, "cannot set up SSL without client certkey file");
  68.             exit(1);
  69.         }
  70.     }
  71. #endif
  72.     grp = cfg_get_single_group(cfg, octstr_imm("configuration"));
  73.     push_url = cfg_get(grp, octstr_imm("push-url"));
  74.     pap_file =  cfg_get(grp, octstr_imm("pap-file"));
  75.     content_file =  cfg_get(grp, octstr_imm("content-file"));
  76.     if (!use_hardcoded) {
  77.         username = cfg_get(grp, octstr_imm("username"));
  78.         password = cfg_get(grp, octstr_imm("password"));
  79.     }
  80.     cfg_destroy(cfg);
  81. }
  82. static void add_push_application_id(List **push_headers, Octstr *appid_flag)
  83. {
  84.     if (octstr_compare(appid_flag, octstr_imm("any")) == 0)
  85.         http_header_add(*push_headers, "X-WAP-Application-Id", 
  86.                         "http://www.wiral.com:*");
  87.     else if (octstr_compare(appid_flag, octstr_imm("ua")) == 0)
  88.         http_header_add(*push_headers, "X-WAP-Application-Id", 
  89.                         "http://www.wiral.com:wml.ua");
  90.     else if (octstr_compare(appid_flag, octstr_imm("mms")) == 0)
  91.         http_header_add(*push_headers, "X-WAP-Application-Id", 
  92.                         "mms.ua");
  93.     else if (octstr_compare(appid_flag, octstr_imm("scrap")) == 0)
  94.         http_header_add(*push_headers, "X-WAP-Application-Id", 
  95.                         "no appid at all");
  96. }
  97. static void add_content_type(Octstr *content_flag, Octstr **wap_content)
  98. {
  99.     if (octstr_compare(content_flag, octstr_imm("wml")) == 0)
  100.         *wap_content = octstr_format("%s", 
  101.             "Content-Type: text/vnd.wap.wmlrn");
  102.     else if (octstr_compare(content_flag, octstr_imm("si")) == 0)
  103.     *wap_content = octstr_format("%s",
  104.             "Content-Type: text/vnd.wap.sirn");
  105.     else if (octstr_compare(content_flag, octstr_imm("sl")) == 0)
  106.     *wap_content = octstr_format("%s",
  107.             "Content-Type: text/vnd.wap.slrn");
  108.     else if (octstr_compare(content_flag, octstr_imm("multipart")) == 0)
  109.         *wap_content = octstr_format("%s",
  110.             "Content-Type: multipart/related; boundary=fsahgwruijkfldsarn");
  111.     else if (octstr_compare(content_flag, octstr_imm("mms")) == 0) 
  112.         *wap_content = octstr_format("%s", 
  113.             "Content-Type: application/vnd.wap.mms-messagern"); 
  114.     else if (octstr_compare(content_flag, octstr_imm("scrap")) == 0)
  115.         *wap_content = octstr_format("%s", "no type at allrn"); 
  116.     else if (octstr_compare(content_flag, octstr_imm("nil")) == 0)
  117.         *wap_content = octstr_create("");
  118. }
  119. static void add_content_transfer_encoding_type(Octstr *content_flag, 
  120.                                                Octstr *wap_content)
  121. {
  122.     if (!content_flag)
  123.      return;
  124.     if (octstr_compare(content_flag, octstr_imm("base64")) == 0)
  125.     octstr_append_cstr(wap_content, "Content-transfer-encoding: base64rn");
  126. }
  127. static void add_connection_header(Octstr *connection, Octstr *wap_content)
  128. {
  129.     if (!connection)
  130.         return;
  131.     if (octstr_compare(connection, octstr_imm("close")) == 0)
  132.         octstr_format_append(wap_content, "%s", "Connection: closern");
  133.     else if (octstr_compare(connection, octstr_imm("keep-alive")) == 0) 
  134.         octstr_format_append(wap_content, "%s", "Connection: keep-alivern");
  135. }
  136. static void transfer_encode (Octstr *cte, Octstr *content)
  137. {
  138.     if (!cte)
  139.     return;
  140.     
  141.     if (octstr_compare(cte, octstr_imm("base64")) == 0) {
  142.     octstr_binary_to_base64(content);
  143.     }
  144. }
  145. /*
  146.  * Add boundary value to the multipart header.
  147.  */
  148. static Octstr *make_multipart_value(const char *boundary)
  149. {
  150.     Octstr *hos;
  151.     
  152.     hos = octstr_format("%s", "multipart/related; boundary=");
  153.     octstr_append(hos, octstr_imm(boundary));
  154.     octstr_append(hos, octstr_imm("; type="application/xml""));
  155.     
  156.     return hos;
  157. }
  158. static Octstr *make_part_delimiter(Octstr *boundary)
  159. {
  160.     Octstr *part_delimiter;
  161.     part_delimiter = octstr_create("");
  162.     octstr_format_append(part_delimiter, "%c", 'r');
  163.     octstr_format_append(part_delimiter, "%c", 'n');
  164.     octstr_format_append(part_delimiter, "%s", "--");
  165.     octstr_append(part_delimiter, boundary);
  166.     octstr_format_append(part_delimiter, "%c", 'r');
  167.     octstr_format_append(part_delimiter, "%c", 'n');
  168.     
  169.     return part_delimiter;
  170. }
  171. static Octstr *make_close_delimiter(Octstr *boundary)
  172. {
  173.     Octstr *close_delimiter;
  174.     close_delimiter = octstr_create("");
  175.     octstr_format_append(close_delimiter, "%c", 'r');
  176.     octstr_format_append(close_delimiter, "%c", 'n');
  177.     octstr_format_append(close_delimiter, "%s", "--");
  178.     octstr_append(close_delimiter, boundary);
  179.     octstr_format_append(close_delimiter, "%s", "--");
  180.     octstr_format_append(close_delimiter, "%c", 'r');
  181.     octstr_format_append(close_delimiter, "%c", 'n');
  182.     
  183.     return close_delimiter;
  184. }
  185. static List *push_headers_create(size_t content_len)
  186. {
  187.     List *push_headers;
  188.     Octstr *mos;
  189.     mos = NULL;
  190.     push_headers = http_create_empty_headers();
  191.     if (use_hardcoded)
  192.         http_header_add(push_headers, "Content-Type", "multipart/related;" 
  193.                         " boundary=asdlfkjiurwgasf; type="application/xml"");
  194.     else
  195.         http_header_add(push_headers, "Content-Type", 
  196.                         octstr_get_cstr(mos = make_multipart_value(boundary)));
  197.     if (use_headers)
  198.         http_add_basic_auth(push_headers, username, password);
  199.     add_push_application_id(&push_headers, appid_flag);
  200.     octstr_destroy(mos);
  201.     return push_headers;
  202. }
  203. static Octstr *push_content_create(void)
  204. {
  205.     Octstr *push_content, 
  206.            *wap_content;
  207.     Octstr *wap_file_content,
  208.            *pap_content,
  209.            *pap_file_content,
  210.            *bpos,
  211.            *bcos;
  212.     wap_content = NULL;
  213.     push_content = NULL;
  214.     if (use_hardcoded) {
  215.         push_content = octstr_create("rnrn"
  216.                   "--asdlfkjiurwgasfrn"
  217.                   "Content-Type: application/xmlrnrn"
  218.                   "<?xml version="1.0"?>"
  219.                   "<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP//EN""
  220.                              " "http://www.wapforum.org/DTD/pap_1.0.dtd">"
  221.                   "<pap>"
  222.                         "<push-message push-id="9fjeo39jf084@pi.com""
  223.                           " deliver-before-timestamp="2002-11-01T06:45:00Z""
  224.                           " deliver-after-timestamp="2000-02-27T06:45:00Z""
  225.                           " progress-notes-requested="false">"
  226.      "<address address-value="WAPPUSH=+358408676001/"
  227.   "TYPE=PLMN@ppg.carrier.com">"
  228.                              "</address>"
  229.                              "<quality-of-service"
  230.                                " priority="low""
  231.                                " delivery-method="unconfirmed""
  232.                                " network-required="true""
  233.                                " network="GSM""
  234.                                " bearer-required="true""
  235.                                " bearer="SMS">"
  236.                              "</quality-of-service>"
  237.                         "</push-message>"
  238.                   "</pap>rnrn"         
  239.                   "--asdlfkjiurwgasfrn"
  240.                   "Content-Type: text/vnd.wap.sirnrn"
  241.                   "<?xml version="1.0"?>"
  242.                   "<!DOCTYPE si PUBLIC "-//WAPFORUM//DTD SI 1.0//EN" "
  243.                     " "http://www.wapforum.org/DTD/si.dtd">"
  244.                   "<si>"
  245.                       "<indication href="http://wap.iobox.fi""
  246.                           " si-id="1@wiral.com""
  247.                           " action="signal-high""
  248.                           " created="1999-06-25T15:23:15Z""
  249.                           " si-expires="2002-12-30T00:00:00Z">"
  250.                           "Want to test a fetch?"
  251.                       "</indication>"
  252.                    "</si>rnrn"
  253.                  "--asdlfkjiurwgasf--rnrn"
  254.                  "");
  255.     } else {
  256.         add_content_type(content_flag, &wap_content);
  257.         add_content_transfer_encoding_type(content_transfer_encoding, 
  258.                                            wap_content);
  259.         add_connection_header(connection, wap_content);
  260.         if ((wap_file_content = 
  261.                 octstr_read_file(octstr_get_cstr(content_file))) == NULL)
  262.          panic(0, "Stopping");
  263.     transfer_encode (content_transfer_encoding, wap_file_content);
  264.         octstr_append(wap_content, wap_file_content);
  265.         octstr_destroy(wap_file_content);
  266.         pap_content = octstr_format("%s", "Content-Type: application/xmlrn");
  267.         if ((pap_file_content = 
  268.                 octstr_read_file(octstr_get_cstr(pap_file))) ==  NULL)
  269.         panic(0, "Stopping");
  270.         octstr_append(pap_content, pap_file_content);
  271.         octstr_destroy(pap_file_content);
  272.         if (wap_content == NULL || pap_content == NULL)
  273.         panic(0, "Cannot open the push content files");
  274.         push_content = octstr_create("");
  275.         octstr_append(push_content, 
  276.             bpos = make_part_delimiter(octstr_imm(boundary)));
  277.         octstr_append(push_content, pap_content);
  278.         octstr_append(push_content, bpos);
  279.         octstr_destroy(bpos);
  280.         octstr_append(push_content, wap_content);
  281.         octstr_append(push_content, 
  282.             bcos = make_close_delimiter(octstr_imm(boundary)));
  283.         octstr_destroy(bcos);
  284.         octstr_destroy(pap_content);
  285.         octstr_destroy(wap_content);
  286.     }
  287.     return push_content;
  288. }
  289. static void make_url(Octstr **url)
  290. {
  291.     if (use_config && !use_headers) {
  292.         octstr_append(*url, octstr_imm("?username="));
  293.         octstr_append(*url, username ? username : octstr_imm("default"));
  294.         octstr_append(*url, octstr_imm("&password="));
  295.         octstr_append(*url, password ? password: octstr_imm("default"));
  296.     }
  297. }
  298. static void start_push(HTTPCaller *caller, long i)   
  299. {
  300.     List *push_headers;
  301.     Octstr *push_content;
  302.     long *id;
  303.     
  304.     push_content = push_content_create();
  305.     push_headers = push_headers_create(octstr_len(push_content));
  306.     if (verbose) {
  307.        debug("test.ppg", 0, "we have push content");
  308.        octstr_dump(push_content, 0);
  309.        debug("test.ppg", 0, "and headers");
  310.        http_header_dump(push_headers);
  311.     }
  312.     id = gw_malloc(sizeof(long));
  313.     *id = i;
  314.     make_url(&push_url);
  315.     debug("test.ppg", 0, "TEST_PPG: starting to push job %ld", i);
  316.     http_start_request(caller, HTTP_METHOD_POST, push_url, push_headers, 
  317.                        push_content, 0, id, ssl_client_certkey_file);
  318.     debug("test.ppg", 0, "push done");
  319.     octstr_destroy(push_content);
  320.     http_destroy_headers(push_headers);
  321. }
  322. /*
  323.  * Try log in defined number of times, when got response 401 and authentica-
  324.  * tion info is in headers.
  325.  */
  326. static int receive_push_reply(HTTPCaller *caller)
  327. {
  328.     void *id;
  329.     long *trid;
  330.     int http_status,
  331.         tries;
  332.     List *reply_headers;
  333.     Octstr *final_url,
  334.            *auth_url,
  335.            *reply_body,
  336.            *os,
  337.            *push_content,
  338.            *auth_reply_body;
  339.     WAPEvent *e;
  340.     List *retry_headers;
  341.     
  342.     http_status = HTTP_UNAUTHORIZED;
  343.     tries = 0;
  344.     id = http_receive_result(caller, &http_status, &final_url, &reply_headers,
  345.                              &reply_body);
  346.     if (id == NULL || http_status == -1 || final_url == NULL) {
  347.         error(0, "push failed, no reason found");
  348.         goto push_failed;
  349.     }
  350.     while (use_headers && http_status == HTTP_UNAUTHORIZED && tries < retries) {
  351.         debug("test.ppg", 0, "try number %d", tries);
  352.         debug("test.ppg", 0, "authentication failure, get a challenge");
  353.         http_destroy_headers(reply_headers);
  354.         push_content = push_content_create();
  355.         retry_headers = push_headers_create(octstr_len(push_content));
  356.         http_add_basic_auth(retry_headers, username, password);
  357.         trid = gw_malloc(sizeof(long));
  358.         *trid = tries;
  359.         http_start_request(caller, HTTP_METHOD_POST, final_url, retry_headers, 
  360.                            push_content, 0, trid, NULL);
  361.         debug("test.ppg ", 0, "TEST_PPG: doing response to %s", 
  362.               octstr_get_cstr(final_url));
  363.         octstr_destroy(push_content);
  364.         http_destroy_headers(retry_headers);
  365.         
  366.         trid = http_receive_result(caller, &http_status, &auth_url, 
  367.                                    &reply_headers, &auth_reply_body);
  368.         if (trid == NULL || http_status == -1 || auth_url == NULL) {
  369.             error(0, "unable to send authorisation, no reason found");
  370.             goto push_failed;
  371.         }   
  372.         debug("test.ppg", 0, "TEST_PPG: send authentication to %s, retry %ld", 
  373.                octstr_get_cstr(auth_url), *(long *) trid);
  374.         gw_free(trid);
  375.         octstr_destroy(auth_reply_body);
  376.         octstr_destroy(auth_url);
  377.         ++tries;
  378.     }
  379.     if (http_status == HTTP_NOT_FOUND) {
  380.         error(0, "push failed, service not found");
  381.         goto push_failed;
  382.     }
  383.     if (http_status == HTTP_FORBIDDEN) {
  384.         error(0, "push failed, service forbidden");
  385.         goto push_failed;
  386.     }
  387.     if (http_status == HTTP_UNAUTHORIZED) {
  388.         if (use_headers)
  389.             error(0, "tried %ld times, stopping", retries);
  390.         else
  391.         error(0, "push failed, authorisation failure");
  392.         goto push_failed;
  393.     }
  394.         
  395.     debug("test.ppg", 0, "TEST_PPG: push %ld done: reply from,  %s", 
  396.           *(long *) id, octstr_get_cstr(final_url));
  397.     gw_free(id);
  398.     octstr_destroy(final_url);
  399.     if (verbose)
  400.         debug("test.ppg", 0, "TEST_PPG: reply headers were");
  401.     while ((os = list_extract_first(reply_headers)) != NULL) {
  402.         if (verbose)
  403.             octstr_dump(os, 0); 
  404.         octstr_destroy(os);
  405.     }
  406.     if (verbose) {
  407.         debug("test.ppg", 0, "TEST_PPG: reply body was");
  408.         octstr_dump(reply_body, 0);
  409.     }
  410.     e = NULL;
  411.     if (pap_compile(reply_body, &e) < 0) {
  412.         warning(0, "TEST_PPG: receive_push_reply: cannot compile pap message");
  413.         goto parse_error;
  414.     }
  415.     switch (e->type) {
  416.         case Push_Response:
  417.         debug("test.ppg", 0, "TEST_PPG: and type push response");
  418.     break;
  419.         case Bad_Message_Response:
  420.         debug("test.ppg", 0, "TEST_PPG: and type bad message response");
  421.         break;
  422.         default:
  423.             warning(0, "TEST_PPG: unknown event received from %s", 
  424.                     octstr_get_cstr(final_url));
  425.         break;
  426.     }
  427.     octstr_destroy(reply_body);
  428.     wap_event_destroy(e);
  429.     http_destroy_headers(reply_headers);
  430.     return 0;
  431. push_failed:
  432.     gw_free(id);
  433.     octstr_destroy(final_url);
  434.     octstr_destroy(reply_body);
  435.     http_destroy_headers(reply_headers);
  436.     return -1;
  437. parse_error:
  438.     octstr_destroy(reply_body);
  439.     http_destroy_headers(reply_headers);
  440.     wap_event_destroy(e);
  441.     return -1;
  442. }
  443. static void push_thread(void *arg)
  444. {
  445.     HTTPCaller *caller;
  446.     long succeeded, failed, in_queue;
  447.     unsigned long i;
  448.     caller = arg;
  449.     succeeded = 0;
  450.     failed = 0;   
  451.     in_queue = 0;
  452.     i = 0;
  453.     for (;;) {
  454.         while (in_queue < MAX_IN_QUEUE) {
  455.         i = counter_increase(counter);
  456.             if (i >= max_pushes)
  457.             goto receive_rest;
  458.             start_push(caller, i);
  459.             if (wait)
  460.                 gwthread_sleep(wait_seconds);
  461.             ++in_queue;
  462.         }
  463.         while (in_queue >= MAX_IN_QUEUE) {
  464.         if (receive_push_reply(caller) == -1)
  465.             ++failed;
  466.             else
  467.             ++succeeded;
  468.             --in_queue;
  469.         }
  470.     }
  471. receive_rest:
  472.     while (in_queue > 0) {
  473.         if (receive_push_reply(caller) == -1)
  474.         ++failed;
  475.         else
  476.         ++succeeded;
  477.         --in_queue;
  478.     }
  479.     http_caller_destroy(caller);
  480.     info(0, "TEST_PPG: In thread %ld %ld succeeded, %ld failed", 
  481.          (long) gwthread_self(), succeeded, failed);
  482. }
  483. static void help(void) 
  484. {
  485.     info(0, "Usage: test_ppg [options] push_url [content_file pap_file]");
  486.     info(0, "      or");
  487.     info(0, "Usage: test_ppg [options] [conf_file]");
  488.     info(0, "Implements push initiator for wap push. Push services are ");
  489.     info(0, "located in push_url, push content in the file content file.");
  490.     info(0, "File pap_file contains pap control document that controls");
  491.     info(0, "pushing");
  492.     info(0, "If option -H is not used, command line has either three or one");
  493.     info(0, "arguments:");
  494.     info(0, "      a) the url of the push proxy gateway");
  495.     info(0, "      b) a file containing the content to be pushed");
  496.     info(0, "      c) a pap document controlling pushing");
  497.     info(0, "     or");
  498.     info(0, "      a) a test configuration file, containing all these");
  499.     info(0, "Option -H cannot be used with a configuration file. If it is");
  500.     info(0, "used, the push url is the only argument.");
  501.     info(0, "Options are:");
  502.     info(0, "-h");
  503.     info(0, "print this info");
  504.     info(0, "-c content qualifier");
  505.     info(0, "Define content type of the push content. Wml, multipart, nil,"); 
  506.     info(0, "scrap, sl, and si accepted. Si is default, nil (no content"); 
  507.     info(0, " type at all) and scrap (random string) are used for debugging");
  508.     info(0, "-a application id");
  509.     info(0, "Define the client application that will handle the push. Any,"); 
  510.     info(0, "ua, mms, nil and scrap accepted, default ua.");
  511.     info(0, "-b");
  512.     info(0, "If true, send username/password in headers. Default false");
  513.     info(0, "-v number");
  514.     info(0, "    Set log level for stderr logging. Default 0 (debug)");
  515.     info(0, "-q");
  516.     info(0, "    Do not print debugging information");
  517.     info(0, "Default: print it");
  518.     info(0, "-r number");
  519.     info(0, "    Make `number' requests. Default one request");
  520.     info(0, "-i seconds");
  521.     info(0, "    Wait 'seconds' seconds between pushes. Default: do not wait");
  522.     info(0, "-e transfer encoding");
  523.     info(0, "    use transfer encoding to send push contents.");
  524.     info(0, "    Currently supported is base64.");
  525.     info(0, "-k connection header");
  526.     info(0, "Use the connection header. Keep-alive and close accepted,");
  527.     info(0, "default close");
  528.     info(0, "-H");
  529.     info(0, "Use hardcoded MIME message, containing a pap control document.");
  530.     info(0, "In addition, use hardcoded username/password in headers (if ");
  531.     info(0, "flag -b is set, too");
  532.     info(0, "Default: read components from files");
  533.     info(0, "-t");
  534.     info(0, "number of threads, maximum 1024, default 1");
  535. }
  536. int main(int argc, char **argv)
  537. {
  538.     int opt,
  539.         num_threads;
  540.     time_t start,
  541.            end;
  542.     double run_time;
  543.     long threads[MAX_THREADS];
  544.     long i;
  545.     Octstr *fos;
  546.     gwlib_init();
  547.     num_threads = 1;
  548.     while ((opt = getopt(argc, argv, "Hhbv:qr:t:c:a:i:e:k:")) != EOF) {
  549.         switch(opt) {
  550.     case 'v':
  551.         log_set_output_level(atoi(optarg));
  552.     break;
  553.     case 'q': 
  554.         verbose = 0;
  555.     break;  
  556.     case 'r':
  557.         max_pushes = atoi(optarg);      
  558.     break; 
  559.             
  560.     case 'i': 
  561.         wait = 1;
  562.             wait_seconds = atof(optarg);
  563.     break;
  564.         case 't': 
  565.         num_threads = atoi(optarg);
  566.             if (num_threads > MAX_THREADS)
  567.         num_threads = MAX_THREADS;
  568.     break;
  569.     case 'H': 
  570.         use_hardcoded = 1;
  571.     break;
  572.     case 'c':
  573.         content_flag = octstr_create(optarg);
  574.             if (octstr_compare(content_flag, octstr_imm("wml")) != 0 && 
  575.                     octstr_compare(content_flag, octstr_imm("si")) != 0 &&
  576.                     octstr_compare(content_flag, octstr_imm("sl")) != 0 &&
  577.                     octstr_compare(content_flag, octstr_imm("nil")) != 0 &&
  578.                     octstr_compare(content_flag, octstr_imm("mms")) != 0 &&
  579.                     octstr_compare(content_flag, octstr_imm("scrap")) != 0 &&
  580.                     octstr_compare(content_flag, 
  581.                     octstr_imm("multipart")) != 0){
  582.         octstr_destroy(content_flag);
  583.         error(0, "TEST_PPG: Content type not known");
  584.         help();
  585.                 exit(1);
  586.             }
  587.     break;
  588.     case 'a':
  589.         appid_flag = octstr_create(optarg);
  590.             if (octstr_compare(appid_flag, octstr_imm("any")) != 0 && 
  591.                     octstr_compare(appid_flag, octstr_imm("ua")) != 0 &&
  592.                     octstr_compare(appid_flag, octstr_imm("mms")) != 0 &&
  593.                     octstr_compare(appid_flag, octstr_imm("nil")) != 0 &&
  594.                     octstr_compare(appid_flag, octstr_imm("scrap")) != 0) {
  595.         octstr_destroy(appid_flag);
  596.         error(0, "TEST_PPG: Push application id not known");
  597.         help();
  598.                 exit(1);
  599.            }
  600.     break;
  601.     case 'e':
  602.     content_transfer_encoding = octstr_create(optarg);
  603.             if (octstr_compare(content_transfer_encoding, 
  604.                                octstr_imm("base64")) != 0) {
  605.         octstr_destroy(content_transfer_encoding);
  606.         error(0, "TEST_PPG: unknown content transfer" 
  607.                       " encoding "%s"",
  608.           octstr_get_cstr(content_transfer_encoding));
  609.         help();
  610.                 exit(1);
  611.     }
  612.     break;
  613.     case 'k':
  614.         connection = octstr_create(optarg);
  615.             if (octstr_compare(connection, octstr_imm("close")) != 0 && 
  616.                     octstr_compare(connection, 
  617.                         octstr_imm("keep-alive")) != 0) {
  618.         octstr_destroy(connection);
  619.         error(0, "TEST_PPG: Connection-header unacceptable");
  620.         help();
  621.                 exit(1);
  622.            }
  623.     break;
  624.     case 'h':
  625.         help();
  626.             exit(1);
  627.     case 'b':
  628.         use_headers = 1;
  629.     break;
  630.     case '?':
  631.     default:
  632.         error(0, "TEST_PPG: Invalid option %c", opt);
  633.             help();
  634.             error(0, "Stopping");
  635.             exit(1);
  636.         }
  637.     }
  638.     if (optind == argc) {
  639.         help();
  640.         exit(1);
  641.     }
  642.     
  643.     push_data = argv + optind;
  644.     num_urls = argc - optind;
  645.     if (content_flag == NULL)
  646.         content_flag = octstr_imm("si");
  647.     if (appid_flag == NULL)
  648.         appid_flag = octstr_imm("ua");
  649.     if (use_hardcoded) {
  650.         username = octstr_imm("troo");
  651.         password = octstr_imm("far");
  652.     }
  653.     if (push_data[0] == NULL) {
  654.         error(0, "No ppg address or config file, stopping");
  655.         exit(1);
  656.     }
  657.            
  658.     use_config = 0;
  659.     if (!use_hardcoded) {
  660.         if (push_data[1] == NULL) {
  661.             info(0, "a configuration file input assumed");
  662.             read_test_ppg_config(fos = octstr_format("%s", push_data[0]));
  663.             octstr_destroy(fos);
  664.             use_config = 1;
  665.         }
  666.     }
  667.     if (!use_config)
  668.         push_url = octstr_format("%s", push_data[0]);
  669.     if (!use_hardcoded && !use_config && push_data[1] != NULL) {
  670.         if (push_data[2] == NULL) {
  671.         error(0, "no pap control document, stopping");
  672.             exit(1);
  673.         } else {
  674.            info(0, "an input without a configuration file assumed");
  675.            content_file = octstr_create(push_data[1]);
  676.            pap_file = octstr_create(push_data[2]);
  677.            debug("test.ppg", 0, "using %s as a content file", push_data[1]);
  678.            debug("test.ppg", 0, "using %s as a control file", push_data[2]);
  679.         }
  680.     }
  681.     boundary = "asdlfkjiurwghasf";
  682.     counter = counter_create();
  683.     time(&start);
  684.     if (num_threads == 0)
  685.         push_thread(http_caller_create());
  686.     else {
  687.         for (i = 0; i < num_threads; ++i)
  688.         threads[i] = gwthread_create(push_thread, http_caller_create());
  689.     for (i = 0; i < num_threads; ++i)
  690.         gwthread_join(threads[i]);
  691.     }
  692.     time(&end);
  693.     run_time = difftime(end, start);
  694.     info(0, "TEST_PPG: %ld requests in %f seconds, %f requests per second",
  695.          max_pushes, run_time, max_pushes / run_time);
  696.     octstr_destroy(content_flag);
  697.     octstr_destroy(appid_flag);
  698.     octstr_destroy(content_file);
  699.     octstr_destroy(pap_file);
  700.     octstr_destroy(ssl_client_certkey_file);
  701.     octstr_destroy(username);
  702.     octstr_destroy(password);
  703.     octstr_destroy(push_url);
  704.     octstr_destroy(connection);
  705.     counter_destroy(counter);
  706.     gwlib_shutdown();
  707.     exit(0);
  708. }