RE: wap client with SAR
Piotr Galecki <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <2C515BE8694C6F4B9B6A578BCAC32E2F024E964C@MBX021-W3-CA-1.exch021.domain.local> |
Hi Stipe, Here is the patch with my latest changes: - added WSP GET result reassembly - added WSP POST - options -P, -C, -w - added source address (-I) option - send Nack for lost segments, reassembly fixes Let me know your comments. There are a few more changes coming: - wtp segm invoke retry if wtp ack is not received - do not write wsp header to the output file Thanks, Piotr -----Original Message----- From: Stipe Tolj [mailto:[email protected]] Sent: Monday, March 04, 2013 5:54 PM Cc: Piotr Galecki Subject: Re: wap client with SAR Am 09.01.2013 15:57, schrieb Stipe Tolj: > > thanks a lot for contributing to the Kannel WAP 1 stack and the SAR > part. We're definitely interested. > > Kindly please provide a patchset in 'diff -u' against current SVN > trunk to review and commit. > > It would be great if we can move the discussion to the devel@ list, > which is more suited for this. Kindly subscribe and send the patchset > to the devel@ list. Hi Piotr, I haven't seen any update here from your side. Kindly, please let us know if you can still provide the patch for the WAP client SAR support? Kind Regards, Stipe -- ------------------------------------------------------------------- Kölner Landstrasse 419 40589 Düsseldorf, NRW, Germany tolj.org system architecture Kannel Software Foundation (KSF) http://www.tolj.org/ http://www.kannel.org/ mailto:st_{at}_tolj.org mailto:stolj_{at}_kannel.org -------------------------------------------------------------------
fakewap_sar_post.patch
(application/octet-stream, 23.2 KB)
Index: test/fakewap.c
===================================================================
--- test/fakewap.c (revision 5026)
+++ test/fakewap.c (working copy)
@@ -80,7 +80,7 @@
* D) Fakewap -> Gateway
*
* WTP: Invoke PDU
- * WSP: Get PDU (data: URL)
+ * WSP: Get/Post PDU (data: URL)
*
* E) Gateway -> Fakewap
*
@@ -131,7 +131,13 @@
#define MAX_SEND (0)
+// Versions:
+// v1.0 - added WSP GET result reassembly
+// v1.1 - added WSP POST - options -P, -C, -w
+// v1.2 - added source address (-I) option
+// v1.3 - send Nack for lost segments, reassembly fixes
static char usage[] = "\
+fakewap version 1.3\n\
Usage: fakewap [options] url ...\n\
\n\
where options are:\n\
@@ -152,7 +158,10 @@
(default: off)\n\
-d difference difference between successive tid numbers (default: 1)\n\
-F Accept failure and continue rather than exiting\n\
--w Write/print received data (experimental)\n\
+-w out-file Write received data to file\n\
+-P in-file Post data from file\n\
+-C content-type Specify content type: text, mms\n\
+-I addr[:port] Specify source address\n\
\n\
The urls are fetched in random order.\n\
";
@@ -174,17 +183,23 @@
#include <math.h>
#include <signal.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
#include "gwlib/gwlib.h"
-#define GET_WTP_PDU_TYPE(hdr) (hdr[0] >> 3)
-static int get_wtp_pdu_type(Octstr *hdr) {
- return octstr_get_char(hdr, 0) >> 3;
+#define GET_WTP_PDU_TYPE(hdr) ((hdr[0] >> 3) & 0x0f)
+static int get_wtp_pdu_type(Octstr *hdr)
+{
+ return (octstr_get_char(hdr, 0) >> 3) & 0x0f;
}
#define WTP_PDU_INVOKE 1
#define WTP_PDU_RESULT 2
#define WTP_PDU_ACK 3
#define WTP_PDU_ABORT 4
+#define WTP_PDU_SEGM_INVOKE 5
+#define WTP_PDU_SEGM_RESULT 6
/*
** Common parameters
@@ -207,6 +222,10 @@
int nofailexit = 0;
int writedata = 0;
int test_separation = 0;
+char* infile = NULL;
+char* outfile = NULL;
+const char* content_type;
+struct sockaddr_in src_addr;
/*
* PDU type, version number and transaction class are supplied by a
@@ -214,14 +233,17 @@
* WSP_Disconnect PDUs.
*/
unsigned char WSP_Connect[] = {0x06, 0x00, 0x00, 0x00,
- /* WSP part */
- 0x01, /* PDU type */
- 0x10, /* Version 1.0 */
- 0x00, /* Capability length */
- 0x02, /* Headers length = 2*/
- /* Capabilities */
- /* Headers */
- 0x80, 0x80 /* Accept: *\* */
+ /* WSP part */
+ 0x01, /* PDU type */
+ 0x10, /* Version 1.0 */
+ 0x0a, /* Capability length */
+ 0x0d, /* Headers length = 13 */
+ /* Capabilities */
+ 0x04, 0x80, 0xc0, 0x80, 0x00, /* Client SDU */
+ 0x04, 0x81, 0xc0, 0x80, 0x00, /* Server SDU */
+ /* Headers */
+ 0x80, 0x80, /* Accept: *\* */
+ 0xa7, 'f', 'a', 'k', 'e', 'w', 'a', 'p', 0, /* User-Agent: fakewap */
};
unsigned char WSP_ConnectReply[] = {0x16, 0x80, 0x00, 0x02 };
unsigned char WTP_Ack[] = {0x18, 0x00, 0x00 };
@@ -233,6 +255,13 @@
unsigned char WSP_Reply[] = {0x16, 0x80, 0x00, 0x04, 0x20 };
unsigned char WSP_Disconnect[] = {0x0E, 0x00, 0x00, 0x00, 0x05 };
unsigned char WSP_Concat[] = {0x00, 0x03, 0x18, 0x00, 0x00, 0x05, 0x0E, 0x00, 0x00, 0x00, 0x05 };
+unsigned char WTP_Result[] = {0x10, 0x80, 0x00 };
+unsigned char WTP_Segm_Result[] = {0x30, 0x80, 0x00 };
+unsigned char WTP_Segm_Ack[] = {0x98, 0x00, 0x00, 0x19, 0x00 };
+unsigned char WTP_Nack[] = { /* wtp nack */ 0x38, /* tid */ 0x00, 0x00, /*num missing*/ 0x00 };
+unsigned char WSP_Post[] = { /* wtp invoke */ 0x0E, /* tid */ 0x00, 0x00, /* ack/class2: */ 0x12,
+ /* tti max-group: 4200 */ 0x13, 0x04, 0x10, 0x68, /* wsp post */ 0x60 };
+unsigned char WTP_Segm_Invoke[] = { /* wtp segm invoke*/ 0x28, /* tid */ 0x00, 0x00, /* psn */ 0x00 };
/*
** In this case it does not matter what is the byte order
@@ -243,7 +272,7 @@
hdr[2] = (char)(tid)
#define GET_TID( hdr ) (((hdr[1] & 0x7f) << 8) + hdr[2])
#define CONSTRUCT_EXPECTED_REPLY_HDR( dest, template, tid ) \
- if (sizeof(dest) < sizeof(template)) panic(0,"buffer overflow.");\
+ if (sizeof(dest) < sizeof(template)) panic(0,"fakewap: buffer overflow.");\
memcpy( dest, template, sizeof(template));\
SET_TID( dest, tid )
@@ -294,7 +323,8 @@
int msg_len ) {
int i;
- if (verbose || writedata) {
+ if (verbose)
+ {
mutex_lock( mutex );
printf( "%s (len %d): ", trace, msg_len );
for (i = 0; i < msg_len && i < msg_len; i++)
@@ -357,6 +387,21 @@
return len;
}
+/*
+** Retrieve value of WAP/WSP variable length integer in the buffer
+*/
+static int ReadVarIntVal( const unsigned char *buf )
+{
+ int len = 1;
+ int value = buf[0] & 0x7F;
+ while (buf[len-1] & 0x80)
+ {
+ len++;
+ value <<= 7;
+ value |= buf[len-1] & 0x7F;
+ }
+ return value;
+}
/*
** Function sends message to WAP GW
@@ -371,7 +416,7 @@
datagram = octstr_create("");
if (hdr != NULL)
- octstr_append_data(datagram, hdr, hdr_len);
+ octstr_append_data(datagram, (char*)hdr, hdr_len);
set_tid(datagram, tid);
if (get_wtp_pdu_type(datagram) == WTP_PDU_INVOKE) {
@@ -384,7 +429,7 @@
}
if (data != NULL)
- octstr_append_data(datagram, data, data_len);
+ octstr_append_data(datagram, (char*)data, data_len);
#if 0
debug("fakewap", 0, "Sending WDP datagram:");
@@ -393,12 +438,26 @@
ret = udp_sendto(fd, datagram, gateway_addr);
if (ret == -1) {
- error(0, "Sending to socket failed");
+ error(0, "fakewap: Sending to socket failed");
return -1;
}
if (verbose) {
- debug("", 0, "Sent packet:");
+ switch (get_wtp_pdu_type(datagram))
+ {
+ case WTP_PDU_INVOKE:
+ debug("fakewap", 0, "Sent WTP_INVOKE packet");
+ break;
+ case WTP_PDU_ACK:
+ debug("fakewap", 0, "Sent WTP_ACK packet");
+ break;
+ case WTP_PDU_ABORT:
+ debug("fakewap", 0, "Sent WTP_ABORT packet");
+ break;
+ default:
+ debug("fakewap", 0, "Sent ??? packet");
+ break;
+ }
octstr_dump(datagram, 0);
}
octstr_destroy(datagram);
@@ -433,7 +492,7 @@
{
ret = read_available(fd, timeout * 1000 * 1000);
if (ret <= 0) {
- info(0, "Timeout while receiving from socket.\n");
+ info(0, "fakewap: Timeout while receiving from socket.\n");
if(nofailexit){
continue;
}else{
@@ -452,7 +511,7 @@
octstr_destroy(dummy);
if (ret == -1) {
- error(0, "recv() from socket failed");
+ error(0, "fakewap: recv() from socket failed");
return -1;
}
@@ -461,7 +520,8 @@
** Ignore extra header bits, WAP GWs return different values
*/
if (msg_len >= hdr_len &&
- GET_WTP_PDU_TYPE(msg) == GET_WTP_PDU_TYPE(hdr) &&
+ (GET_WTP_PDU_TYPE(msg) == GET_WTP_PDU_TYPE(hdr) ||
+ (GET_WTP_PDU_TYPE(hdr)==WTP_PDU_RESULT && GET_WTP_PDU_TYPE(msg)==WTP_PDU_SEGM_RESULT)) &&
(hdr_len <= 3 || !memcmp( msg+3, hdr+3, hdr_len-3 ))) {
break;
}
@@ -482,6 +542,9 @@
else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_RESULT) {
break;
}
+ else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_SEGM_RESULT) {
+ break;
+ }
else {
print_msg( "Received unexpected message", msg, msg_len );
}
@@ -496,8 +559,8 @@
print_data( "Received data", msg, msg_len );
if (data != NULL && msg_len > hdr_len) {
- data_len = min( data_len, msg_len - hdr_len );
- memcpy( data, msg+hdr_len, data_len);
+ data_len = min( data_len, msg_len );
+ memcpy( data, msg, data_len);
}
else data_len = 0;
return data_len;
@@ -513,6 +576,159 @@
return i_this;
}
+int send_post(int fd, unsigned short tid, int tid_new, char* url)
+{
+#define SAR_SEGM_SIZE 1200
+#define SAR_GROUP_LEN 4
+ char msgbuf[1500];
+ char useragent[] = { 0xa9, 'a', 'n', 'f', 'a', 'k', 'e', 'w', 'a', 'p', 0 };
+ char contentlen_buf[8];
+ unsigned char reply_hdr[32];
+ long timeout = 10; /* wap gw is broken if no input */
+
+ // open post input file
+ int infd = open(infile, O_RDONLY);
+ if (infd < 0)
+ panic(0, "fakewap: failed to open input file %s, errno %d", infile, errno);
+
+ // get size of input file
+ struct stat fstats;
+ int ret = fstat(infd, &fstats);
+ if (ret)
+ panic(0, "fakewap: failed to get file stats, errno %d", errno);
+ if (fstats.st_size == 0)
+ panic(0, "fakewap: input file is empty");
+ if (fstats.st_size > 256*SAR_SEGM_SIZE)
+ panic(0, "fakewap: input file size (%ld) is too large", fstats.st_size);
+
+ int nsegs = (fstats.st_size-1) / SAR_SEGM_SIZE;
+ int tpi, gtr, ttr;
+ int psn = 0;
+
+ // build initial WSP POST message
+ Octstr *postmsg;
+ postmsg = octstr_create("");
+
+ memcpy(msgbuf, WSP_Post, sizeof(WSP_Post));
+ tpi = 1;
+ ttr = (nsegs==0) ? 1 : 0;
+ gtr = (ttr) ? 0 : 1;
+ msgbuf[0] = (tpi << 7) | (WTP_PDU_INVOKE << 3) | (gtr << 2) | (ttr << 1);
+ octstr_append_data(postmsg, msgbuf, sizeof(WSP_Post));
+
+ // add uri, content type, user agent, content length
+ int url_len = strlen(url);
+ int off = StoreVarInt( msgbuf, url_len );
+ int content_type_len = strlen(content_type) + 1; // +1 for eos
+ int contentlen_len;
+ contentlen_buf[0] = 0x8d; // hdr type - content-length
+ if (fstats.st_size <= 127)
+ {
+ contentlen_buf[1] = 0x80 | (char)fstats.st_size;
+ contentlen_len = 2;
+ } else
+ {
+ contentlen_buf[1] = 2;
+ contentlen_buf[2] = (char)(fstats.st_size >> 8);
+ contentlen_buf[3] = (char)(fstats.st_size);
+ contentlen_len = 4;
+ }
+ off += StoreVarInt( &msgbuf[off], content_type_len+sizeof(useragent)+contentlen_len );
+ memcpy( &msgbuf[off], url, url_len );
+ off += url_len;
+ memcpy( &msgbuf[off], content_type, content_type_len );
+ off += content_type_len;
+ memcpy( &msgbuf[off], useragent, sizeof(useragent) );
+ off += sizeof(useragent);
+ memcpy( &msgbuf[off], contentlen_buf, contentlen_len );
+ off += contentlen_len;
+ octstr_append_data(postmsg, msgbuf, off);
+
+ // add payload
+ ret = read(infd, msgbuf, SAR_SEGM_SIZE);
+ if (ret <= 0)
+ panic(0, "fakewap: input file read error, errno %d", errno);
+
+ debug("fakewap", 0, "Sending WSP_POST, url %s, Content-Type %s, User-Agent %s, Content-Length %lu",
+ url, content_type, &useragent[1], fstats.st_size );
+
+ ret = wap_msg_send( fd, octstr_get_cstr(postmsg), octstr_len(postmsg),
+ tid, tid_new, msgbuf, ret );
+ if (ret == -1)
+ {
+ error(0, "fakewap: failure sending wtp invoke");
+ goto send_post_exit;
+ }
+
+ // receive invoke ack
+ CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Ack, tid );
+ ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Ack),
+ tid, msgbuf, sizeof(msgbuf), timeout );
+ if (ret == -1)
+ {
+ error(0, "fakewap: failure receiving wtp ack");
+ goto send_post_exit;
+ }
+ debug("fakewap", 0, "Received WTP_ACK, psn 0");
+
+ while (!ttr)
+ {
+ psn++;
+
+ // create message with WTP Segmented Invoke headers
+ Octstr *segm_msg;
+ segm_msg = octstr_create("");
+ memcpy(msgbuf, WTP_Segm_Invoke, sizeof(WTP_Segm_Invoke));
+ tpi = 0;
+ ttr = (nsegs==psn) ? 1 : 0;
+ gtr = ttr ? 0 : (psn+1)%SAR_GROUP_LEN ? 0 : 1;
+ msgbuf[0] = (tpi << 7) | (WTP_PDU_SEGM_INVOKE << 3) | (gtr << 2) | (ttr << 1);
+ msgbuf[3] = psn;
+ octstr_append_data(segm_msg, msgbuf, sizeof(WTP_Segm_Invoke));
+
+ // read payload from file
+ int payload_len = read(infd, msgbuf, SAR_SEGM_SIZE);
+ if (payload_len <= 0)
+ panic(0, "fakewap: input file read error, errno %d", errno);
+
+ // send WTP Segmented Invoke message
+ ret = wap_msg_send( fd, octstr_get_cstr(segm_msg), octstr_len(segm_msg),
+ tid, tid_new, msgbuf, payload_len );
+ if (ret == -1)
+ {
+ error(0, "fakewap: failure sending wtp invoke");
+ goto send_post_exit;
+ }
+ debug("fakewap", 0, "Sending WTP_SEGM_INVOKE, psn %u, payload len %d", psn, payload_len);
+
+ // receive ack for the group
+ if (gtr)
+ {
+ // receive segm invoke ack
+ CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Segm_Ack, tid );
+ reply_hdr[4] = psn;
+ ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Segm_Ack),
+ tid, msgbuf, sizeof(msgbuf), timeout );
+ if (ret == -1)
+ {
+ error(0, "fakewap: failure receiving WTP Segm Ack, psn %u", psn);
+ octstr_destroy(segm_msg);
+ segm_msg = NULL;
+ break;
+ }
+ debug("fakewap", 0, "Received WTP_ACK, psn %d", psn);
+ }
+
+ octstr_destroy(segm_msg);
+ segm_msg = NULL;
+ }
+
+send_post_exit:
+ octstr_destroy(postmsg);
+ close(infd);
+ return ret;
+}
+
/*
** Function (or thread) sets up a dgram socket. Then it loops: WTL/WSP
** Connect, Get a url and Disconnect until all requests are have been done.
@@ -540,8 +756,12 @@
fd = udp_client_socket();
if (fd == -1)
- panic(0, "Couldn't create socket.");
+ panic(0, "fakewap: Couldn't create socket.");
+ if (src_addr.sin_addr.s_addr!=INADDR_ANY || src_addr.sin_port!=0)
+ if (bind(fd, (const struct sockaddr *)&src_addr, (int)sizeof(src_addr)) == -1)
+ panic(0, "fakewap: Couldn't bind socket, errno %d", errno);
+
/*
** Loop until all URLs have been requested
*/
@@ -567,25 +787,26 @@
ret = wap_msg_send( fd, WSP_Connect, sizeof(WSP_Connect),
tid, tid_new, NULL, 0 );
- if (ret == -1) panic(0, "Send WSP_Connect failed");
+ if (ret == -1) panic(0, "fakewap: Send WSP_Connect failed");
CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WSP_ConnectReply, tid );
ret = wap_msg_recv( fd, reply_hdr, sizeof(WSP_ConnectReply),
tid, buf, sizeof(buf), timeout );
- if (ret == -1) panic(0, "Receive WSP_ConnectReply failed");
+ if (ret == -1) panic(0, "fakewap: Receive WSP_ConnectReply failed");
if (ret > 2)
{
- sid_len = ReadVarIntLen(buf);
- memcpy( sid, buf, sid_len);
+ sid_len = ReadVarIntLen(&buf[4]);
+ memcpy( sid, &buf[4], sid_len);
+ debug("fakewap", 0, "Received WSP_ConnectReply, SessID %d", ReadVarIntVal(&buf[4]));
}
/*
** Send abort and continue if we get an unexpected reply
*/
if (ret == 0) {
if (connection_retries++ > 3) {
- panic(0, "Cannot connect WAP GW!");
+ panic(0, "fakewap: Cannot connect WAP GW!");
}
wap_msg_send( fd, WTP_Abort, sizeof(WTP_Abort), tid, tid_new,
NULL, 0 );
@@ -597,7 +818,7 @@
ret = wap_msg_send( fd, WTP_Ack, sizeof(WTP_Ack), tid, tid_new,
NULL, 0 );
- if (ret == -1) panic(0, "Send WTP_Ack failed");
+ if (ret == -1) panic(0, "fakewap: Send WTP_Ack failed");
/*
** Request WML page with the given URL
@@ -609,32 +830,115 @@
url_len = strlen(url);
url_off = StoreVarInt( buf, url_len );
memcpy( buf+url_off, url, url_len );
- ret = wap_msg_send( fd, WSP_Get, sizeof(WSP_Get), tid, tid_new,
- buf, url_len+url_off );
- if (ret == -1) break;
- CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WSP_Reply, tid );
- ret = wap_msg_recv( fd, reply_hdr, sizeof(WSP_Reply),
- tid, buf, sizeof(buf), timeout );
- if (ret == -1) break;
- /*
- ** If we are testing separation, we concatenate WTP_Ack and
- ** WSP_Disconnect messages.
- */
- if (test_separation){
- ret = wap_msg_send(fd, WSP_Concat, sizeof(WSP_Concat), tid, tid_new,
- sid, sid_len);
-
- if (ret == -1) break;
- } else {
- ret = wap_msg_send( fd, WTP_Ack, sizeof(WTP_Ack), tid, tid_new,
- NULL, 0 );
+ // send WSP Post if an input file is specified
+ if (infile)
+ {
+ send_post(fd, tid, tid_new, url);
+ }
+ else // send WSP Get
+ {
+ ret = wap_msg_send( fd, WSP_Get, sizeof(WSP_Get), tid, tid_new,
+ buf, url_len+url_off );
+ if (ret == -1) break;
+ }
- if (ret == -1) break;
+ int gtr = 0, ttr = 0, psn, gtr_psn = -1;
+ unsigned char segment_data[256][1500];
+ int segment_len[256];
+ memset(segment_len, 0, sizeof(segment_len));
+ while (!ttr)
+ {
+ CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Result, tid );
+ ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Result),
+ tid, buf, sizeof(buf), timeout );
+ if (ret == -1) break;
+ gtr = (buf[0] & 0x04) ? 1 : 0;
+ ttr = (buf[0] & 0x02) ? 1 : 0;
+ if (GET_WTP_PDU_TYPE(buf) == WTP_PDU_RESULT)
+ {
+ psn = 0;
+ debug("fakewap", 0, "Received WTP_RESULT pdu, gtr %d, ttr %d", gtr, ttr);
+ }
+ else // segmented result
+ {
+ psn = buf[3];
+ debug("fakewap", 0, "Received WTP_SEGM_RESULT pdu, psn %d, gtr %d, ttr %d", psn, gtr, ttr);
+ }
+ segment_len[psn] = ret;
+ if (ret > 1500)
+ panic(0, "fakewap: Segment 0 exceeds 1500 bytes!?!");
+ memcpy(segment_data[psn], buf, ret);
+
+ if (gtr || ttr)
+ gtr_psn = psn;
+ if (gtr || ttr || (psn < gtr_psn))
+ {
+ // check for lost segments and send NACK
+ char lost_segs[256];
+ int i, num_lost = 0;
+ for (i = 0; i <= gtr_psn; i++)
+ if (!segment_len[i])
+ lost_segs[num_lost++] = i;
+ if (num_lost > 0)
+ {
+ // send NACK since some segments got lost
+ WTP_Nack[3] = num_lost;
+ debug("fakewap", 0, "Sending WTP_NACK pdu, num_lost %d, lost_seg0 %d", num_lost, lost_segs[0]);
+ ret = wap_msg_send( fd, WTP_Nack, sizeof(WTP_Nack), tid, tid_new, lost_segs, num_lost );
+ ttr = 0;
+ }
+ else if (psn > 0)
+ {
+ // send WTP Ack for a group of segments
+ WTP_Segm_Ack[4] = gtr_psn;
+ debug("fakewap", 0, "Sending WTP_ACK pdu, gtr_psn %d", gtr_psn);
+ ret = wap_msg_send( fd, WTP_Segm_Ack, sizeof(WTP_Segm_Ack), tid, tid_new, NULL, 0 );
+ }
+ else
+ {
+ // send regular WTP Ack for first segment
+ debug("fakewap", 0, "Sending WTP_ACK pdu, psn 0");
+ ret = wap_msg_send( fd, WTP_Ack, sizeof(WTP_Ack), tid, tid_new, NULL, 0 );
+ }
+ if (ret == -1)
+ break;
+ gtr = 0;
+ }
+ }
+ if (!ttr)
+ {
+ panic(0, "fakewap: Failed to receive entire message!?!");
+ break;
+ }
+
+ // if output file specified write received msg to file
+ if (outfile)
+ {
+ int outfd = open(outfile, O_CREAT | O_WRONLY);
+ if (outfd < 0)
+ panic(0, "fakewap: failed to open output file %s, errno %d", outfile, errno);
+
+ int iter, size = 0;
+ for (iter = 0; iter < 256; iter++)
+ {
+ if (segment_len[iter] > 0)
+ {
+ ret = write(outfd, segment_data[iter], segment_len[iter]);
+ if (ret < 0)
+ panic(0, "fakewap: failed to write to output file %s, errno %d", outfile, errno);
+ size += segment_len[iter];
+ }
+ }
+ close(outfd);
+ debug("fakewap", 0, "Wrote %d bytes of response payload to output file %s", size, outfile);
+ }
+
/*
** Finally disconnect with the sid returned by connect reply
*/
+ {
ret = wap_msg_send( fd, WSP_Disconnect, sizeof(WSP_Disconnect),
tid, tid_new, sid, sid_len );
@@ -698,6 +1002,7 @@
sigaction(SIGALRM,&alrm,NULL);
#endif
+
gwlib_init();
proto_version = 0;
@@ -707,7 +1012,13 @@
hostname = octstr_create("localhost");
- while ((opt = getopt(argc, argv, "Fhvc:g:p:P:m:i:t:V:T:t:nsd:w")) != EOF) {
+ content_type = "text/plain";
+ src_addr.sin_family = AF_INET;
+ src_addr.sin_addr.s_addr = INADDR_ANY;
+ src_addr.sin_port = 0;
+
+ while ((opt = getopt(argc, argv, "Fhvc:g:p:m:i:t:V:T:t:nsd:w:P:C:I:")) != EOF)
+ {
switch (opt) {
case 'g':
octstr_destroy(hostname);
@@ -769,13 +1080,37 @@
case 'w':
writedata = 1;
+ outfile = optarg;
break;
+ case 'P':
+ infile = optarg;
+ break;
+
+ case 'C':
+ if (!strcmp("mms", optarg))
+ content_type = "application/vnd.wap.mms-message";
+ else
+ content_type = "text/plain";
+ break;
+
+ case 'I':
+ {
+ unsigned int byte0, byte1, byte2, byte3, srcport;
+ int ret = sscanf(optarg, "%u.%u.%u.%u:%u", &byte0, &byte1, &byte2, &byte3, &srcport);
+ if (ret!=4 && ret!=5)
+ panic(0, "fakewap: invalid source address %s", optarg);
+ src_addr.sin_addr.s_addr = htonl(byte0<<24 | byte1<<16 | byte2<<8 | byte3);
+ if (ret==5)
+ src_addr.sin_port = htons(srcport);
+ break;
+ }
+
case '?':
default:
- error(0, "Unknown option %c", opt);
+ error(0, "fakewap: Unknown option %c", opt);
help();
- panic(0, "Stopping.");
+ panic(0, "fakewap: Stopping.");
}
}
@@ -802,7 +1137,7 @@
mutex = mutex_create();
- info(0, "fakewap starting");
+ info(0, "fakewap: starting");
if (threads < 1) threads = 1;
@@ -817,7 +1152,7 @@
/* Wait for the other sessions to complete */
gwthread_join_every(client_session);
- info(0, "fakewap complete.");
+ info(0, "fakewap: complete.");
info(0, "fakewap: %d client threads made total %d transactions.",
threads, num_sent);
delta = difftime(end_time, start_time);
@@ -830,6 +1165,7 @@
octstr_destroy(hostname);
octstr_destroy(gateway_addr);
mutex_destroy(mutex);
+
gwlib_shutdown();
return 0;
}