/* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2005 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* A very simple push initiator for testing a push proxy gateway
*
* Read pap control content and push content from files, pack them into a PAP
* protocol MIME message and invoke push services specified by an url. Use a
* hardcoded message boundary (asdlfkjiurwgasf), for simpler command line
* interface.
* Repetitions and use of multiple threads can be requested, in addition of
* setting of some headers.
*
* By Aarno Syvänen for Wiral Ltd and Global Networks Inc.
*/
#define MAX_THREADS 1024
#define MAX_IN_QUEUE 128
#include
#include
#include
#include "gwlib/gwlib.h"
#include "gw/wap_push_pap_compiler.h"
static long max_pushes = 1;
static int verbose = 1,
use_hardcoded = 0,
num_urls = 0,
use_headers = 0,
use_config = 0,
accept_binary = 0,
use_numeric = 0,
use_string = 0,
use_content_header = 0,
add_epilogue = 0,
add_preamble = 0,
use_dlr_mask = 0,
use_dlr_url = 0;
static double wait_seconds = 0.0;
static Counter *counter = NULL;
static char **push_data = NULL;
static char *boundary = NULL;
static Octstr *content_flag = NULL;
static Octstr *appid_flag = NULL;
static Octstr *appid_string = NULL;
static Octstr *content_header = NULL;
static Octstr *content_transfer_encoding = NULL;
static Octstr *connection = NULL;
static Octstr *delimiter = NULL;
static Octstr *initiator_uri = NULL;
static Octstr *dlr_mask = NULL;
static Octstr *dlr_url = NULL;
enum { SSL_CONNECTION_OFF = 0,
DEFAULT_NUMBER_OF_RELOGS = 2};
/*
* Configuration variables
*/
static int pi_ssl = SSL_CONNECTION_OFF;
static long retries = DEFAULT_NUMBER_OF_RELOGS;
static Octstr *ssl_client_certkey_file = NULL;
static Octstr *push_url = NULL;
static Octstr *pap_file = NULL;
static Octstr *content_file = NULL;
static Octstr *username = NULL;
static Octstr *password = NULL;
static void read_test_ppg_config(Octstr *name)
{
Cfg *cfg;
CfgGroup *grp;
cfg = cfg_create(name);
if (cfg_read(cfg) == -1)
panic(0, "Cannot read a configuration file %s, exiting",
octstr_get_cstr(name));
cfg_dump(cfg);
grp = cfg_get_single_group(cfg, octstr_imm("test-ppg"));
cfg_get_integer(&retries, grp, octstr_imm("retries"));
cfg_get_bool(&pi_ssl, grp, octstr_imm("pi-ssl"));
#ifdef HAVE_LIBSSL
if (pi_ssl) {
ssl_client_certkey_file = cfg_get(grp,
octstr_imm("ssl-client-certkey-file"));
if (ssl_client_certkey_file != NULL) {
use_global_client_certkey_file(ssl_client_certkey_file);
} else {
error(0, "cannot set up SSL without client certkey file");
exit(1);
}
}
#endif
grp = cfg_get_single_group(cfg, octstr_imm("configuration"));
push_url = cfg_get(grp, octstr_imm("push-url"));
pap_file = cfg_get(grp, octstr_imm("pap-file"));
content_file = cfg_get(grp, octstr_imm("content-file"));
if (!use_hardcoded) {
username = cfg_get(grp, octstr_imm("username"));
password = cfg_get(grp, octstr_imm("password"));
}
cfg_destroy(cfg);
}
static void add_delimiter(Octstr **content)
{
if (octstr_compare(delimiter, octstr_imm("crlf")) == 0) {
octstr_format_append(*content, "%c", '\r');
}
octstr_format_append(*content, "%c", '\n');
}
static void add_push_application_id(List **push_headers, Octstr *appid_flag,
int use_string)
{
if (use_string) {
gwlist_append(*push_headers, appid_string);
return;
}
if (octstr_compare(appid_flag, octstr_imm("any")) == 0) {
if (!use_numeric)
http_header_add(*push_headers, "X-WAP-Application-Id",
"http://www.wiral.com:*");
else
http_header_add(*push_headers, "X-WAP-Application-Id", "0");
} else if (octstr_compare(appid_flag, octstr_imm("ua")) == 0) {
if (!use_numeric)
http_header_add(*push_headers, "X-WAP-Application-Id",
"http://www.wiral.com:wml.ua");
else
http_header_add(*push_headers, "X-WAP-Application-Id", "2");
} else if (octstr_compare(appid_flag, octstr_imm("mms")) == 0) {
if (!use_numeric)
http_header_add(*push_headers, "X-WAP-Application-Id",
"mms.ua");
else
http_header_add(*push_headers, "X-WAP-Application-Id", "4");
} else if (octstr_compare(appid_flag, octstr_imm("scrap")) == 0) {
if (!use_numeric)
http_header_add(*push_headers, "X-WAP-Application-Id",
"no appid at all");
else
http_header_add(*push_headers, "X-WAP-Application-Id",
"this is not a numeric header");
}
}
static void add_dlr_mask(List **push_headers, Octstr *value)
{
http_header_add(*push_headers, "X-Kannel-DLR-Mask",
octstr_get_cstr(value));
}
static void add_dlr_url(List **push_headers, Octstr *value)
{
http_header_add(*push_headers, "X-Kannel-DLR-Url",
octstr_get_cstr(value));
}
static void add_part_header(Octstr *content_keader, Octstr **wap_content)
{
if (use_content_header) {
octstr_append(*wap_content, content_header);
}
add_delimiter(wap_content);
}
static void add_content_type(Octstr *content_flag, Octstr **wap_content)
{
if (octstr_compare(content_flag, octstr_imm("wml")) == 0)
*wap_content = octstr_format("%s",
"Content-Type: text/vnd.wap.wml");
else if (octstr_compare(content_flag, octstr_imm("si")) == 0)
*wap_content = octstr_format("%s",
"Content-Type: text/vnd.wap.si");
else if (octstr_compare(content_flag, octstr_imm("sl")) == 0)
*wap_content = octstr_format("%s",
"Content-Type: text/vnd.wap.sl");
else if (octstr_compare(content_flag, octstr_imm("multipart")) == 0)
*wap_content = octstr_format("%s",
"Content-Type: multipart/related; boundary=fsahgwruijkfldsa");
else if (octstr_compare(content_flag, octstr_imm("mms")) == 0)
*wap_content = octstr_format("%s",
"Content-Type: application/vnd.wap.mms-message");
else if (octstr_compare(content_flag, octstr_imm("scrap")) == 0)
*wap_content = octstr_format("%s", "no type at all");
else if (octstr_compare(content_flag, octstr_imm("nil")) == 0)
*wap_content = octstr_create("");
if (octstr_len(*wap_content) > 0)
add_delimiter(wap_content);
}
static void add_content_transfer_encoding_type(Octstr *content_flag,
Octstr *wap_content)
{
if (!content_flag)
return;
if (octstr_compare(content_flag, octstr_imm("base64")) == 0)
octstr_append_cstr(wap_content, "Content-transfer-encoding: base64");
add_delimiter(&wap_content);
}
static void add_connection_header(List **push_headers, Octstr *connection)
{
if (!connection)
return;
if (octstr_compare(connection, octstr_imm("close")) == 0)
http_header_add(*push_headers, "Connection", "close");
else if (octstr_compare(connection, octstr_imm("keep-alive")) == 0)
http_header_add(*push_headers, "Connection", "keep-alive");
}
static void transfer_encode (Octstr *cte, Octstr *content)
{
if (!cte)
return;
if (octstr_compare(cte, octstr_imm("base64")) == 0) {
octstr_binary_to_base64(content);
}
}
/*
* Add boundary value to the multipart header.
*/
static Octstr *make_multipart_value(const char *boundary)
{
Octstr *hos;
hos = octstr_format("%s", "multipart/related; boundary=");
octstr_append(hos, octstr_imm(boundary));
octstr_append(hos, octstr_imm("; type=\"application/xml\""));
return hos;
}
static Octstr *make_part_delimiter(Octstr *boundary)
{
Octstr *part_delimiter;
part_delimiter = octstr_create("");
add_delimiter(&part_delimiter);
octstr_format_append(part_delimiter, "%s", "--");
octstr_append(part_delimiter, boundary);
add_delimiter(&part_delimiter);
return part_delimiter;
}
static Octstr *make_close_delimiter(Octstr *boundary)
{
Octstr *close_delimiter;
close_delimiter = octstr_create("");
add_delimiter(&close_delimiter);
octstr_format_append(close_delimiter, "%s", "--");
octstr_append(close_delimiter, boundary);
octstr_format_append(close_delimiter, "%s", "--");
/*add_delimiter(&close_delimiter);*/
return close_delimiter;
}
static List *push_headers_create(size_t content_len)
{
List *push_headers;
Octstr *mos;
mos = NULL;
push_headers = http_create_empty_headers();
if (use_hardcoded)
http_header_add(push_headers, "Content-Type", "multipart/related;"
" boundary=asdlfkjiurwgasf; type=\"application/xml\"");
else
http_header_add(push_headers, "Content-Type",
octstr_get_cstr(mos = make_multipart_value(boundary)));
if (use_headers)
http_add_basic_auth(push_headers, username, password);
add_push_application_id(&push_headers, appid_flag, use_string);
add_connection_header(&push_headers, connection);
if (use_dlr_mask)
add_dlr_mask(&push_headers, dlr_mask);
if (use_dlr_url)
add_dlr_url(&push_headers, dlr_url);
octstr_destroy(mos);
/* add initiator... */
if (initiator_uri)
http_header_add(push_headers, "X-Wap-Initiator-URI",
octstr_get_cstr(initiator_uri));
return push_headers;
}
static Octstr *push_content_create(void)
{
Octstr *push_content,
*wap_content;
Octstr *wap_file_content,
*pap_content,
*pap_file_content,
*bpos,
*bcos;
wap_content = NULL;
push_content = NULL;
if (use_hardcoded) {
push_content = octstr_create("\r\n\r\n"
"--asdlfkjiurwgasf\r\n"
"Content-Type: application/xml\r\n\r\n"
""
""
""
""
""
""
""
""
""
"\r\n\r\n"
"--asdlfkjiurwgasf\r\n"
"Content-Type: text/vnd.wap.si\r\n\r\n"
""
""
""
""
"Want to test a fetch?"
""
"\r\n\r\n"
"--asdlfkjiurwgasf--\r\n\r\n"
"");
} else {
add_content_type(content_flag, &wap_content);
add_content_transfer_encoding_type(content_transfer_encoding,
wap_content);
add_part_header(content_header, &wap_content);
/* Read the content file. (To be pushed)*/
if ((wap_file_content =
octstr_read_file(octstr_get_cstr(content_file))) == NULL)
panic(0, "Stopping");
if (accept_binary) {
octstr_delete_matching(wap_file_content, octstr_imm(" "));
octstr_delete_matching(wap_file_content, octstr_imm("\n"));
octstr_delete_matching(wap_file_content, octstr_imm("\r"));
if (!octstr_is_all_hex(wap_file_content))
panic(0, "non-hex chars in the content file, cannot continue");
octstr_hex_to_binary(wap_file_content);
}
transfer_encode(content_transfer_encoding, wap_file_content);
octstr_append(wap_content, wap_file_content);
octstr_destroy(wap_file_content);
/* Read the control file. (To control pushing)*/
pap_content = octstr_format("%s", "Content-Type: application/xml");
add_delimiter(&pap_content);
add_delimiter(&pap_content);
if ((pap_file_content =
octstr_read_file(octstr_get_cstr(pap_file))) == NULL)
panic(0, "Stopping");
octstr_append(pap_content, pap_file_content);
octstr_destroy(pap_file_content);
if (wap_content == NULL || pap_content == NULL)
panic(0, "Cannot open the push content files");
push_content = octstr_create("");
if (add_preamble)
octstr_append(push_content, octstr_imm("the parser should discard this"));
octstr_append(push_content,
bpos = make_part_delimiter(octstr_imm(boundary)));
/*octstr_append(push_content, octstr_imm("\r\n"));*/ /* Do we accept an additional
* clrf ? */
octstr_append(push_content, pap_content);
octstr_append(push_content, bpos);
octstr_destroy(bpos);
octstr_append(push_content, wap_content);
octstr_append(push_content,
bcos = make_close_delimiter(octstr_imm(boundary)));
if (add_epilogue) {
octstr_append(push_content, octstr_imm("\r\n"));
octstr_append(push_content, octstr_imm("the parser should discard this"));
}
octstr_destroy(bcos);
octstr_destroy(pap_content);
octstr_destroy(wap_content);
}
return push_content;
}
static void make_url(Octstr **url)
{
if (use_config && !use_headers) {
octstr_append(*url, octstr_imm("?username="));
octstr_append(*url, username ? username : octstr_imm("default"));
octstr_append(*url, octstr_imm("&password="));
octstr_append(*url, password ? password: octstr_imm("default"));
}
}
static void start_push(HTTPCaller *caller, long i)
{
List *push_headers;
Octstr *push_content;
long *id;
push_content = push_content_create();
push_headers = push_headers_create(octstr_len(push_content));
if (verbose) {
debug("test.ppg", 0, "we have push content");
octstr_dump(push_content, 0);
debug("test.ppg", 0, "and headers");
http_header_dump(push_headers);
}
id = gw_malloc(sizeof(long));
*id = i;
make_url(&push_url);
debug("test.ppg", 0, "TEST_PPG: starting to push job %ld", i);
http_start_request(caller, HTTP_METHOD_POST, push_url, push_headers,
push_content, 0, id, ssl_client_certkey_file);
debug("test.ppg", 0, "push done");
octstr_destroy(push_content);
http_destroy_headers(push_headers);
}
/*
* Try log in defined number of times, when got response 401 and authentica-
* tion info is in headers.
*/
static int receive_push_reply(HTTPCaller *caller)
{
void *id;
long *trid;
int http_status,
tries;
List *reply_headers;
Octstr *final_url,
*auth_url,
*reply_body,
*os,
*push_content,
*auth_reply_body;
WAPEvent *e;
List *retry_headers;
http_status = HTTP_UNAUTHORIZED;
tries = 0;
id = http_receive_result(caller, &http_status, &final_url, &reply_headers,
&reply_body);
if (id == NULL || http_status == -1 || final_url == NULL) {
error(0, "push failed, no reason found");
goto push_failed;
}
while (use_headers && http_status == HTTP_UNAUTHORIZED && tries < retries) {
debug("test.ppg", 0, "try number %d", tries);
debug("test.ppg", 0, "authentication failure, get a challenge");
http_destroy_headers(reply_headers);
push_content = push_content_create();
retry_headers = push_headers_create(octstr_len(push_content));
http_add_basic_auth(retry_headers, username, password);
trid = gw_malloc(sizeof(long));
*trid = tries;
http_start_request(caller, HTTP_METHOD_POST, final_url, retry_headers,
push_content, 0, trid, NULL);
debug("test.ppg ", 0, "TEST_PPG: doing response to %s",
octstr_get_cstr(final_url));
octstr_destroy(push_content);
http_destroy_headers(retry_headers);
trid = http_receive_result(caller, &http_status, &auth_url,
&reply_headers, &auth_reply_body);
if (trid == NULL || http_status == -1 || auth_url == NULL) {
error(0, "unable to send authorisation, no reason found");
goto push_failed;
}
debug("test.ppg", 0, "TEST_PPG: send authentication to %s, retry %ld",
octstr_get_cstr(auth_url), *(long *) trid);
gw_free(trid);
octstr_destroy(auth_reply_body);
octstr_destroy(auth_url);
++tries;
}
if (http_status == HTTP_NOT_FOUND) {
error(0, "push failed, service not found");
goto push_failed;
}
if (http_status == HTTP_FORBIDDEN) {
error(0, "push failed, service forbidden");
goto push_failed;
}
if (http_status == HTTP_UNAUTHORIZED) {
if (use_headers)
error(0, "tried %ld times, stopping", retries);
else
error(0, "push failed, authorisation failure");
goto push_failed;
}
debug("test.ppg", 0, "TEST_PPG: push %ld done: reply from, %s",
*(long *) id, octstr_get_cstr(final_url));
gw_free(id);
octstr_destroy(final_url);
if (verbose)
debug("test.ppg", 0, "TEST_PPG: reply headers were");
while ((os = gwlist_extract_first(reply_headers)) != NULL) {
if (verbose)
octstr_dump(os, 0);
octstr_destroy(os);
}
if (verbose) {
debug("test.ppg", 0, "TEST_PPG: reply body was");
octstr_dump(reply_body, 0);
}
e = NULL;
if (pap_compile(reply_body, &e) < 0) {
warning(0, "TEST_PPG: receive_push_reply: cannot compile pap message");
goto parse_error;
}
switch (e->type) {
case Push_Response:
debug("test.ppg", 0, "TEST_PPG: and type push response");
break;
case Bad_Message_Response:
debug("test.ppg", 0, "TEST_PPG: and type bad message response");
break;
default:
warning(0, "TEST_PPG: unknown event received from %s",
octstr_get_cstr(final_url));
break;
}
octstr_destroy(reply_body);
wap_event_destroy(e);
http_destroy_headers(reply_headers);
return 0;
push_failed:
gw_free(id);
octstr_destroy(final_url);
octstr_destroy(reply_body);
http_destroy_headers(reply_headers);
return -1;
parse_error:
octstr_destroy(reply_body);
http_destroy_headers(reply_headers);
wap_event_destroy(e);
return -1;
}
static void push_thread(void *arg)
{
HTTPCaller *caller;
long succeeded, failed, in_queue;
unsigned long i;
caller = arg;
succeeded = 0;
failed = 0;
in_queue = 0;
i = 0;
for (;;) {
while (in_queue < MAX_IN_QUEUE) {
i = counter_increase(counter);
if (i >= max_pushes)
goto receive_rest;
start_push(caller, i);
if (wait_seconds > 0)
gwthread_sleep(wait_seconds);
++in_queue;
}
while (in_queue >= MAX_IN_QUEUE) {
if (receive_push_reply(caller) == -1)
++failed;
else
++succeeded;
--in_queue;
}
}
receive_rest:
while (in_queue > 0) {
if (receive_push_reply(caller) == -1)
++failed;
else
++succeeded;
--in_queue;
}
http_caller_destroy(caller);
info(0, "TEST_PPG: In thread %ld %ld succeeded, %ld failed",
(long) gwthread_self(), succeeded, failed);
}
static void help(void)
{
info(0, "Usage: test_ppg [options] push_url [content_file pap_file]");
info(0, " or");
info(0, "Usage: test_ppg [options] [conf_file]");
info(0, "Implements push initiator for wap push. Push services are ");
info(0, "located in push_url, push content in the file content file.");
info(0, "File pap_file contains pap control document that controls");
info(0, "pushing");
info(0, "If option -H is not used, command line has either three or one");
info(0, "arguments:");
info(0, " a) the url of the push proxy gateway");
info(0, " b) a file containing the content to be pushed");
info(0, " c) a pap document controlling pushing");
info(0, " or");
info(0, " a) a test configuration file, containing all these");
info(0, "Option -H cannot be used with a configuration file. If it is");
info(0, "used, the push url is the only argument.");
info(0, "Options are:");
info(0, "-h");
info(0, "print this info");
info(0, "-c content qualifier");
info(0, "Define content type of the push content. Wml, multipart, nil,");
info(0, "scrap, sl, and si accepted. Si is default, nil (no content");
info(0, " type at all) and scrap (random string) are used for debugging");
info(0, "-a application id");
info(0, "Define the client application that will handle the push. Any,");
info(0, "ua, mms, nil and scrap accepted, default ua.");
info(0, "-n");
info(0, "if set, use numeric appid values instead of string ones. For");
info(0, "instance, '4' instead of 'mms.ua'. Default is off.");
info(0, "-s string");
info(0, "supply a message header as a plain string. For instance");
info(0, "-s x-wap-application-id:mms.ua equals -a ua. Default is");
info(0, "x-wap-application-id:mms.ua.");
info(0, "-I string");
info(0, "supply an initiator header as a plain string. For instance");
info(0, "-I x-wap-application-id:http://foo.bar equals -I http://foo.bar");
info(0, "-S string");
info(0, "supply an additional part header (for push content) as a string.");
info(0, "For instance, -S Content-Language: en. Default no additional part");
info(0, "headers.");
info(0, "-b");
info(0, "If true, send username/password in headers. Default false");
info(0, "-v number");
info(0, " Set log level for stderr logging. Default 0 (debug)");
info(0, "-q");
info(0, " Do not print debugging information");
info(0, "Default: print it");
info(0, "-r number");
info(0, " Make `number' requests. Default one request");
info(0, "-i seconds");
info(0, " Wait 'seconds' seconds between pushes. Default: do not wait");
info(0, "-e transfer encoding");
info(0, " use transfer encoding to send push contents.");
info(0, " Currently supported is base64.");
info(0, "-k connection header");
info(0, "Use the connection header. Keep-alive and close accepted,");
info(0, "default close");
info(0, "-H");
info(0, "Use hardcoded MIME message, containing a pap control document.");
info(0, "In addition, use hardcoded username/password in headers (if ");
info(0, "flag -b is set, too");
info(0, "Default: read components from files");
info(0, "-t");
info(0, "number of threads, maximum 1024, default 1");
info(0, "-B");
info(0, "accept binary push content. Default: off.");
info(0, "Binary content consist of hex numbers. In addition, crs, lfs and");
info(0, "spaces are accepted, and ignored.");
info(0, "-d value");
info(0, "set delimiter to be used. Accepted values crlf and lf. Default crlf.");
info(0, "-E");
info(0, "If set, add a hardcoded epilogue (epilogue is to be discarded anyway).");
info(0, "Default off.");
info(0, "-p");
info(0, "If set, add hardcoded preamble. Default is off.");
info(0, "-m value");
info(0, "If set, add push header X-Kannel-DLR-Mask: value");
info(0, "Default off.");
info(0, "-u value");
info(0, "If set, add push header X-Kannel-DLR-Url: value");
info(0, "Default off.");
}
int main(int argc, char **argv)
{
int opt,
num_threads;
time_t start,
end;
double run_time;
long threads[MAX_THREADS];
long i;
Octstr *fos;
gwlib_init();
num_threads = 1;
while ((opt = getopt(argc, argv, "HhBbnEpv:qr:t:c:a:i:e:k:d:s:S:I:m:u:")) != EOF) {
switch(opt) {
case 'v':
log_set_output_level(atoi(optarg));
break;
case 'q':
verbose = 0;
break;
case 'r':
max_pushes = atoi(optarg);
break;
case 'i':
wait_seconds = atof(optarg);
break;
case 't':
num_threads = atoi(optarg);
if (num_threads > MAX_THREADS)
num_threads = MAX_THREADS;
break;
case 'H':
use_hardcoded = 1;
break;
case 'c':
content_flag = octstr_create(optarg);
if (octstr_compare(content_flag, octstr_imm("wml")) != 0 &&
octstr_compare(content_flag, octstr_imm("si")) != 0 &&
octstr_compare(content_flag, octstr_imm("sl")) != 0 &&
octstr_compare(content_flag, octstr_imm("nil")) != 0 &&
octstr_compare(content_flag, octstr_imm("mms")) != 0 &&
octstr_compare(content_flag, octstr_imm("scrap")) != 0 &&
octstr_compare(content_flag, octstr_imm("multipart")) != 0) {
octstr_destroy(content_flag);
error(0, "TEST_PPG: Content type not known");
help();
exit(1);
}
break;
case 'a':
appid_flag = octstr_create(optarg);
if (octstr_compare(appid_flag, octstr_imm("any")) != 0 &&
octstr_compare(appid_flag, octstr_imm("ua")) != 0 &&
octstr_compare(appid_flag, octstr_imm("mms")) != 0 &&
octstr_compare(appid_flag, octstr_imm("nil")) != 0 &&
octstr_compare(appid_flag, octstr_imm("scrap")) != 0) {
octstr_destroy(appid_flag);
error(0, "TEST_PPG: Push application id not known");
help();
exit(1);
}
break;
case 'n':
use_numeric = 1;
break;
case 's':
appid_string = octstr_create(optarg);
use_string = 1;
break;
case 'S':
content_header = octstr_create(optarg);
use_content_header = 1;
break;
case 'e':
content_transfer_encoding = octstr_create(optarg);
if (octstr_compare(content_transfer_encoding, octstr_imm("base64")) != 0) {
octstr_destroy(content_transfer_encoding);
error(0, "TEST_PPG: unknown content transfer"
" encoding \"%s\"", octstr_get_cstr(content_transfer_encoding));
help();
exit(1);
}
break;
case 'k':
connection = octstr_create(optarg);
if (octstr_compare(connection, octstr_imm("close")) != 0 &&
octstr_compare(connection, octstr_imm("keep-alive")) != 0) {
octstr_destroy(connection);
error(0, "TEST_PPG: Connection-header unacceptable");
help();
exit(1);
}
break;
case 'h':
help();
exit(1);
case 'b':
use_headers = 1;
break;
case 'B':
accept_binary = 1;
break;
case 'd':
delimiter = octstr_create(optarg);
if (octstr_compare(delimiter, octstr_imm("crlf")) != 0 &&
octstr_compare(delimiter, octstr_imm("lf")) != 0) {
octstr_destroy(delimiter);
error(0, "illegal d value");
help();
exit(1);
}
break;
case 'E':
add_epilogue = 1;
break;
case 'p':
add_preamble = 1;
break;
case 'I':
initiator_uri = octstr_create(optarg);
break;
case 'm':
use_dlr_mask = 1;
dlr_mask = octstr_create(optarg);
break;
case 'u':
use_dlr_url = 1;
dlr_url = octstr_create(optarg);
break;
case '?':
default:
error(0, "TEST_PPG: Invalid option %c", opt);
help();
error(0, "Stopping");
exit(1);
}
}
if (optind == argc) {
help();
exit(1);
}
push_data = argv + optind;
num_urls = argc - optind;
if (content_flag == NULL)
content_flag = octstr_imm("si");
if (appid_flag == NULL)
appid_flag = octstr_imm("ua");
if (appid_string == NULL)
appid_string = octstr_imm("x-wap-application-id: wml.ua");
if (content_header == NULL)
use_content_header = 0;
if (dlr_mask == NULL)
use_dlr_mask = 0;
if (dlr_url == NULL)
use_dlr_url = 0;
if (delimiter == NULL)
delimiter = octstr_imm("crlf");
if (use_hardcoded) {
username = octstr_imm("troo");
password = octstr_imm("far");
}
if (push_data[0] == NULL) {
error(0, "No ppg address or config file, stopping");
exit(1);
}
use_config = 0;
if (!use_hardcoded) {
if (push_data[1] == NULL) {
info(0, "a configuration file input assumed");
read_test_ppg_config(fos = octstr_format("%s", push_data[0]));
octstr_destroy(fos);
use_config = 1;
}
}
if (!use_config)
push_url = octstr_format("%s", push_data[0]);
if (!use_hardcoded && !use_config && push_data[1] != NULL) {
if (push_data[2] == NULL) {
error(0, "no pap control document, stopping");
exit(1);
} else {
info(0, "an input without a configuration file assumed");
content_file = octstr_create(push_data[1]);
pap_file = octstr_create(push_data[2]);
debug("test.ppg", 0, "using %s as a content file", push_data[1]);
debug("test.ppg", 0, "using %s as a control file", push_data[2]);
}
}
boundary = "asdlfkjiurwghasf";
counter = counter_create();
time(&start);
if (num_threads == 0)
push_thread(http_caller_create());
else {
for (i = 0; i < num_threads; ++i)
threads[i] = gwthread_create(push_thread, http_caller_create());
for (i = 0; i < num_threads; ++i)
gwthread_join(threads[i]);
}
time(&end);
run_time = difftime(end, start);
info(0, "TEST_PPG: %ld requests in %f seconds, %f requests per second",
max_pushes, run_time, max_pushes / run_time);
octstr_destroy(content_flag);
octstr_destroy(appid_flag);
octstr_destroy(content_header);
octstr_destroy(content_file);
octstr_destroy(pap_file);
octstr_destroy(ssl_client_certkey_file);
octstr_destroy(username);
octstr_destroy(password);
octstr_destroy(push_url);
octstr_destroy(connection);
octstr_destroy(delimiter);
octstr_destroy(dlr_mask);
octstr_destroy(dlr_url);
counter_destroy(counter);
gwlib_shutdown();
exit(0);
}