144 fakewap version 1.6\n\ 145 Usage: fakewap [options] url ...\n\ 147 where options are:\n\ 150 -g hostname hostname or IP number of gateway (default: localhost)\n\ 151 -p port port number of gateway (default: 9201)\n\ 152 -m max maximum number of requests fakewap will make (default: 1)\n\ 153 -i interval interval between requests (default: 1.0 seconds)\n\ 154 -c threads number of concurrent clients simulated (default: 1)\n\ 155 -V protoversion protocol version field, as an integer (default: 0)\n\ 156 -T pdu-type PDU type, as an integer (default: 1)\n\ 157 -t tcl transaction class, as an integer (default: 2)\n\ 158 -n set tid_new flag in packets, forces gateway to flush cache\n\ 160 -s test separation, by concatenating ack and disconnect pdus\n\ 162 -d difference difference between successive tid numbers (default: 1)\n\ 163 -F Accept failure and continue rather than exiting\n\ 164 -A agent user agent\n\ 165 -C content-type Specify content type: text, mms\n\ 166 -D level debug level (0=none(default), 1=brief, 2=verbose\n\ 167 -I addr[:port] Specify source address\n\ 168 -M mode Transaction mode: 0=connectionless, 1=connection-oriented\n\ 169 -P in-file Post data from file\n\ 170 -w out-file Write received data to file\n\ 171 -l loss-precent Simulate packet loss\n\ 173 The urls are fetched in random order.\n\ 184 #include <sys/time.h> 185 #include <sys/types.h> 186 #include <sys/socket.h> 187 #include <netinet/in.h> 189 #include <sys/param.h> 193 #include <sys/stat.h> 198 #define GET_WTP_PDU_TYPE(hdr) ((hdr[0] >> 3) & 0x0f) 204 #define WTP_PDU_INVOKE 1 205 #define WTP_PDU_RESULT 2 206 #define WTP_PDU_ACK 3 207 #define WTP_PDU_ABORT 4 208 #define WTP_PDU_SEGM_INVOKE 5 209 #define WTP_PDU_SEGM_RESULT 6 210 #define WTP_PDU_NACK 7 212 #define WSP_PDU_CONNECT 1 213 #define WSP_PDU_REPLY 4 214 #define WSP_PDU_DISCONNECT 5 215 #define WSP_PDU_GET 0x40 216 #define WSP_PDU_POST 0x60 218 #define TXN_MODE_CONNECTION_LESS 0 219 #define TXN_MODE_CONNECTION_ORIENTED 1 221 #define SAR_SEGM_SIZE 1200 222 #define SAR_GROUP_LEN 4 223 #define SAR_MAX_RETRIES 3 224 #define WAP_MSG_RECEIVE_TIMEOUT 10 266 0x04, 0x80, 0xc0, 0x80, 0x00,
267 0x04, 0x81, 0xc0, 0x80, 0x00,
275 unsigned char WSP_Reply[] = {0x16, 0x80, 0x00, 0x04, 0x20 };
278 unsigned char WSP_Concat[] = {0x00, 0x03, 0x18, 0x00, 0x00, 0x05, 0x0E, 0x00, 0x00, 0x00, 0x05 };
280 unsigned char WTP_Ack[] = {0x18, 0x00, 0x00 };
286 0x13, 0x04, 0x10, 0x68 };
290 unsigned char WTP_Nack[] = { 0x38, 0x00, 0x00, 0x00 };
296 #define SET_GTR( hdr ) hdr[0] |= 0x04 297 #define SET_TID( hdr, tid) \ 298 hdr[1] |= (0x7f & ((tid) >> 8)); \ 300 #define GET_TID( hdr ) (((hdr[1] & 0x7f) << 8) + hdr[2]) 301 #define CONSTRUCT_EXPECTED_REPLY_HDR( dest, template, tid ) \ 302 if (sizeof(dest) < sizeof(template)) panic(0,"fakewap: buffer overflow.");\ 303 memcpy( dest, template, sizeof(template));\ 310 c |= 0x7f & (tid >> 8);
326 #define min(a,b) (a < b ? a : b) 339 printf(
"%s (len %d): ", trace, msg_len );
340 for (i = 0; i < msg_len && i < 16; i++) printf(
"%02X ",
msg[i] );
355 printf(
"%s (len %d): ", trace, msg_len );
356 for (i = 0; i < msg_len && i < msg_len; i++)
357 printf(
"%c", isprint(
msg[i]) ?
msg[i] :
'_');
372 static unsigned short next_tid(
unsigned short old_tid) {
381 static int StoreVarInt(
unsigned char *buf,
unsigned long varInt )
383 int i, len = 1, non_zero_bits = 7;
388 while ((varInt >> non_zero_bits) != 0) {
395 for (i = 0; i < len; i++)
397 buf[i] = ((
unsigned char)(varInt >> (non_zero_bits-7)) & 0x7f) | 0x80;
412 while (buf[len-1] & 0x80) len++;
422 int value = buf[0] & 0x7F;
423 while (buf[len-1] & 0x80)
427 value |= buf[len-1] & 0x7F;
436 wap_msg_send(
int fd,
unsigned char* wtp_hdr,
int wtp_hdr_len,
unsigned short tid,
int tid_new,
437 unsigned char* wsp_hdr,
int wsp_hdr_len,
unsigned char* data,
int data_len )
443 if (wtp_hdr != NULL) {
464 debug(
"fakewap", 0,
"Sending WDP datagram:");
470 error(0,
"fakewap: Sending to socket failed");
484 debug(
"fakewap", 0,
"Sent WSP_CONNECT packet");
487 debug(
"fakewap", 0,
"Sent WSP_DISCONNECT packet");
490 debug(
"fakewap", 0,
"Sent WSP_GET packet");
493 debug(
"fakewap", 0,
"Sent WSP_POST packet");
496 debug(
"fakewap", 0,
"Sent WSP ??? packet");
504 debug(
"fakewap", 0,
"Sent WTP_INVOKE packet");
507 debug(
"fakewap", 0,
"Sent WTP_ACK packet");
510 debug(
"fakewap", 0,
"Sent WTP_ABORT packet");
513 debug(
"fakewap", 0,
"Sent WTP_SEGM_INVOKE packet");
516 debug(
"fakewap", 0,
"Sent WTP_NACK packet");
519 debug(
"fakewap", 0,
"Sent ??? packet");
541 unsigned short tid,
unsigned char * data,
int data_len,
542 int timeout,
int udp_flags )
545 unsigned char msg[1024*64];
547 int fResponderIsDead = 1;
562 info(0,
"fakewap: Timeout while receiving from socket.\n");
566 return fResponderIsDead ? -1 : 0;
582 timeout -= (int)(currtime - calltime);
583 debug(
"fakewap", 0,
"Dropped packet, new timeout %d", timeout);
594 error(0,
"fakewap: recv() from socket failed");
602 if ((msg_len >= hdr_len) &&
604 (hdr_len <= 3 || !memcmp(
msg+3, hdr+3, hdr_len-3 ))) {
627 print_msg(
"Received unexpected message",
msg, msg_len );
629 fResponderIsDead = 0;
639 if (data != NULL && msg_len > hdr_len) {
640 data_len =
min( data_len, msg_len );
641 memcpy( data,
msg, data_len);
659 unsigned char wtphdr[32];
660 unsigned char msgbuf[32*1024];
661 unsigned char contentlen_buf[8];
662 unsigned char reply_hdr[32];
666 int infd = open(
infile, O_RDONLY);
668 panic(0,
"fakewap: failed to open input file %s, errno %d",
infile, errno);
672 int ret = fstat(infd, &fstats);
674 panic(0,
"fakewap: failed to get file stats, errno %d", errno);
675 if (fstats.st_size == 0)
676 panic(0,
"fakewap: input file is empty");
679 panic(0,
"fakewap: input file size (%ld) is too large", (
long) fstats.st_size);
688 ttr = (nsegs==0) ? 1 : 0;
691 wtphdr[0] = (tpi << 7) | (
WTP_PDU_INVOKE << 3) | (gtr << 2) | (ttr << 1);
704 int url_len = strlen(
url);
708 char acceptAll[] = { 0x80, 0x80 };
709 contentlen_buf[0] = 0x8d;
710 if (fstats.st_size <= 127)
712 contentlen_buf[1] = 0x80 | (char)fstats.st_size;
716 contentlen_buf[1] = 2;
717 contentlen_buf[2] = (char)(fstats.st_size >> 8);
718 contentlen_buf[3] = (char)(fstats.st_size);
722 memcpy( &msgbuf[off],
url, url_len );
725 off += content_type_len;
728 memcpy( &msgbuf[off], contentlen_buf, contentlen_len );
729 off += contentlen_len;
730 memcpy( &msgbuf[off], acceptAll,
sizeof(acceptAll) );
731 off +=
sizeof(acceptAll);
736 ret = read(infd, msgbuf,
sizeof(msgbuf));
741 panic(0,
"fakewap: input file read error, errno %d", errno);
743 debug(
"fakewap", 0,
"Sending WSP_POST, url %s, Content-Type %s, User-Agent %s, Content-Length %lu",
751 error(0,
"fakewap: failure sending connection-less wtp invoke");
762 error(0,
"fakewap: failure sending connection-oriented wtp invoke");
768 tid, msgbuf,
sizeof(msgbuf), timeout, 0 );
772 error(0,
"fakewap: failure receiving WTP Ack, psn %u, giving up", psn);
775 warning(0,
"fakewap: timeout receiving WTP Ack, resend wtp invoke");
778 debug(
"fakewap", 0,
"Received WTP_ACK, psn 0");
802 ttr = (nsegs==psn) ? 1 : 0;
804 grpwtphdr[grppktnum][0] = (tpi << 7) | (
WTP_PDU_SEGM_INVOKE << 3) | (gtr << 2) | (ttr << 1);
805 grpwtphdr[grppktnum][3] = psn;
808 grpmsglen[grppktnum] = read(infd, (
char*)grpmsgbuf[grppktnum],
SAR_SEGM_SIZE);
809 if (grpmsglen[grppktnum] <= 0)
810 panic(0,
"fakewap: input file read error, errno %d", errno);
820 for (grppktnum = 0; grppktnum < grpsize; grppktnum++)
822 debug(
"fakewap", 0,
"Sending WTP_SEGM_INVOKE, psn %u, payload len %d",
823 psn-grpsize+grppktnum+1, grpmsglen[grppktnum]);
825 NULL, 0, grpmsgbuf[grppktnum], grpmsglen[grppktnum] );
828 error(0,
"fakewap: failure sending wtp invoke");
837 tid, msgbuf,
sizeof(msgbuf), timeout, MSG_PEEK );
843 tid, msgbuf,
sizeof(msgbuf), timeout, 0 );
848 error(0,
"fakewap: failure receiving WTP Segm Ack, psn %u, giving up", psn);
851 warning(0,
"fakewap: failure receiving WTP Segm Ack, psn %u, retrying", psn);
856 debug(
"fakewap", 0,
"Received WTP_RESULT");
858 debug(
"fakewap", 0,
"Received WTP_ACK, psn %d", psn);
879 int url_len = 0, url_off = 0;
880 double nowsec, lastsec, tmp, sleepTime;
885 unsigned char sid[20];
887 unsigned char buf[64*1024];
888 unsigned char reply_hdr[32];
890 static unsigned short tid = 0;
891 unsigned short old_tid;
893 int connection_retries = 0;
898 panic(0,
"fakewap: Couldn't create socket.");
901 if (bind(fd, (
const struct sockaddr *)&
src_addr, (
int)
sizeof(
src_addr)) == -1)
902 panic(0,
"fakewap: Couldn't bind socket, errno %d", errno);
911 gettimeofday(&now, &tz);
912 lastsec = (double) now.tv_sec + now.tv_usec / 1e6;
926 tid_new = (tid < old_tid);
933 if (ret == -1)
panic(0,
"fakewap: Send WSP_Connect failed");
937 tid, buf,
sizeof(buf), timeout, 0 );
938 if (ret == -1)
panic(0,
"fakewap: Receive WSP_ConnectReply failed");
943 memcpy( sid, &buf[4], sid_len);
951 if (connection_retries++ > 3) {
952 panic(0,
"fakewap: Cannot connect WAP GW!");
958 connection_retries = 0;
962 if (ret == -1)
panic(0,
"fakewap: Send WTP_Ack failed");
970 tid_new = (tid < old_tid);
972 url_len = strlen(
url);
974 memcpy( buf+url_off,
url, url_len );
975 buf[url_len+url_off] = 0x80;
976 buf[url_len+url_off+1] = 0x80;
986 unsigned char wsphdr[32];
990 wsphdr,
sizeof(
WSP_Get)+1, buf, url_len+url_off+2 );
995 if (ret == -1)
break;
1004 tid, buf,
sizeof(buf), timeout, 0 );
1005 if (ret == -1)
break;
1012 int gtr = 0, ttr = 0, psn, gtr_psn = -1, ttr_psn = -1;
1013 unsigned char segment_data[256][1500];
1014 int segment_len[256];
1016 memset(segment_len, 0,
sizeof(segment_len));
1021 tid, buf,
sizeof(buf), timeout, 0 );
1023 if (ret == -1)
break;
1025 gtr = (buf[0] & 0x04) ? 1 : 0;
1026 ttr = (buf[0] & 0x02) ? 1 : 0;
1031 debug(
"fakewap", 0,
"Received WTP_RESULT pdu, gtr %d, ttr %d, payload len %d", gtr, ttr, ret - data_offset);
1037 debug(
"fakewap", 0,
"Received WTP_SEGM_RESULT pdu, psn %d, gtr %d, ttr %d, payload len %d", psn, gtr, ttr, ret - data_offset);
1039 segment_len[psn] = ret - data_offset;
1040 if (segment_len[psn] > 1500)
1041 panic(0,
"fakewap: Segment %d exceeds 1500 bytes!?!", psn);
1042 memcpy(segment_data[psn], &buf[data_offset], segment_len[psn]);
1044 if (gtr || ttr || (psn < gtr_psn))
1052 unsigned char lost_segs[256];
1053 int i, num_lost = 0;
1054 for (i = 0; i <= gtr_psn; i++)
1055 if (!segment_len[i])
1056 lost_segs[num_lost++] = i;
1062 memcpy(buf+
sizeof(
WTP_Nack), lost_segs, num_lost);
1063 debug(
"fakewap", 0,
"Sending WTP_NACK pdu, num_lost %d, lost_seg0 %d", num_lost, lost_segs[0]);
1071 debug(
"fakewap", 0,
"Sending WTP_ACK pdu, gtr_psn %d", gtr_psn);
1077 debug(
"fakewap", 0,
"Sending WTP_ACK pdu, psn 0");
1082 if ((ttr_psn >= 0) && (num_lost==0)) {
1089 panic(0,
"fakewap: Failed to receive entire message!?!");
1093 for (psn = 0; psn <= gtr_psn; psn++)
1101 panic(0,
"fakewap: Failed to unpack wsp message!?!");
1102 if (wsppdu->
type != Reply) {
1103 error(0,
"fakewap: Received WSP message type %u is not Reply!?!",
octstr_get_char(wspreply, 0));
1107 struct Reply* wspreply = &wsppdu->
u.Reply;
1109 if (wspreply->status <= 0x4f)
1110 status = (wspreply->status >> 4) * 100 + (wspreply->status & 0x0f);
1111 else if ((wspreply->status & 0xf0) == 0x50)
1112 status = 431 + (wspreply->status & 0x0f);
1114 status = (wspreply->status >> 4) * 100 - 100 + (wspreply->status & 0x0f);
1116 warning(0,
"fakewap: Warning - received reply with status %d",
status);
1118 info(0,
"fakewap: Received WSP Reply with status code 200OK");
1124 int outfd = creat(
outfile, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
1126 panic(0,
"fakewap: failed to create output file %s, errno %d",
outfile, errno);
1131 panic(0,
"fakewap: failed to write to output file %s, errno %d",
outfile, errno);
1135 debug(
"fakewap", 0,
"Wrote %d bytes of response payload to output file %s", ret,
outfile);
1147 if (ret == -1)
break;
1154 gettimeofday(&now, &tz);
1155 nowsec = (double) now.tv_sec + now.tv_usec / 1e6;
1156 tmp = nowsec - lastsec;
1158 uSleepTime = sleepTime * 1e6;
1168 info(0,
"fakewap: finished session # %d", i_this);
1177 usleep( uSleepTime );
1200 int proto_version, tcl, tid_new;
1202 struct sigaction alrm;
1204 alrm.sa_handler = SIG_IGN;
1206 sigaction(SIGALRM,&alrm,NULL);
1237 src_addr.sin_addr.s_addr = INADDR_ANY;
1243 const char firstchar[] = {0xa9, 0};
1249 while ((opt =
getopt(argc, argv,
"Fhc:g:p:m:i:t:V:t:nsd:A:C:D:I:M:P:w:l:")) != EOF)
1274 proto_version = atoi(
optarg);
1322 if (!strcmp(
"mms",
optarg))
1330 unsigned int byte0, byte1, byte2, byte3, srcport;
1331 int ret = sscanf(
optarg,
"%u.%u.%u.%u:%u", &byte0, &byte1, &byte2, &byte3, &srcport);
1332 if (ret!=4 && ret!=5)
1333 panic(0,
"fakewap: invalid source address %s",
optarg);
1334 src_addr.sin_addr.s_addr = htonl(byte0<<24 | byte1<<16 | byte2<<8 | byte3);
1336 src_addr.sin_port = htons(srcport);
1343 error(0,
"fakewap: invalid transaction mode %s",
optarg);
1355 error(0,
"fakewap: invalid packet loss rate %s, expect 0-99",
optarg);
1362 error(0,
"fakewap: Unknown option %c", opt);
1364 panic(0,
"fakewap: Stopping.");
1395 srand((
unsigned int) time(NULL));
1399 info(0,
"fakewap: starting");
1414 info(0,
"fakewap: complete.");
1415 info(0,
"fakewap: %d client threads made total %d transactions.",
1418 info( 0,
"fakewap: total running time %.1f seconds", delta);
1419 info( 0,
"fakewap: %.1f messages/seconds on average",
num_sent / delta);
1420 info( 0,
"fakewap: time of best, worst and average transaction: " 1421 "%.1f s, %.1f s, %.1f s",
static char * choose_message(char **urls, int num_urls)
void error(int err, const char *fmt,...)
void info(int err, const char *fmt,...)
static unsigned short next_tid(unsigned short old_tid)
unsigned char WSP_ConnectReply[]
static void set_tid_new(Octstr *hdr)
void octstr_append_data(Octstr *ostr, const char *data, long len)
unsigned char WTP_Segm_Invoke[]
unsigned char WTP_Segm_Result[]
static void print_data(const char *trace, unsigned char *msg, int msg_len)
#define GET_WTP_PDU_TYPE(hdr)
unsigned char WSP_Reply[]
unsigned char WTP_Invoke_Cl2[]
static int get_next_transaction(void)
static int wap_msg_send(int fd, unsigned char *wtp_hdr, int wtp_hdr_len, unsigned short tid, int tid_new, unsigned char *wsp_hdr, int wsp_hdr_len, unsigned char *data, int data_len)
#define TXN_MODE_CONNECTION_LESS
static void print_msg(const char *trace, unsigned char *msg, int msg_len)
static int wap_msg_recv(int fd, const unsigned char *hdr, int hdr_len, unsigned short tid, unsigned char *data, int data_len, int timeout, int udp_flags)
unsigned char WTP_Abort[]
#define octstr_get_cstr(ostr)
int send_post(int fd, unsigned short tid, int tid_new, char *url)
void gwthread_join_every(gwthread_func_t *func)
unsigned char WSP_Concat[]
static void set_tid(Octstr *hdr, int tid)
unsigned short tid_addition
int getopt(int argc, char **argv, char *opts)
struct sockaddr_in src_addr
#define WAP_MSG_RECEIVE_TIMEOUT
#define TXN_MODE_CONNECTION_ORIENTED
unsigned char WSP_Connect[]
int udp_recvfrom_flags(int s, Octstr **datagram, Octstr **addr, int sockrcvflags)
int udp_client_socket(void)
void log_set_output_level(enum output_level level)
static int ReadVarIntVal(const unsigned char *buf)
#define WSP_PDU_DISCONNECT
#define octstr_dump(ostr, level,...)
void warning(int err, const char *fmt,...)
void octstr_destroy(Octstr *ostr)
#define gwthread_create(func, arg)
#define octstr_create(cstr)
void mutex_destroy(Mutex *mutex)
const char * content_type
unsigned char WTP_Invoke_Cl2MaxGrp[]
static void client_session(void *arg)
unsigned char WTP_TidVe[]
long octstr_len(const Octstr *ostr)
unsigned char WTP_Result[]
int read_available(int fd, long wait_usec)
void debug(const char *place, int err, const char *fmt,...)
static int StoreVarInt(unsigned char *buf, unsigned long varInt)
static int ReadVarIntLen(const unsigned char *buf)
void gwlib_shutdown(void)
int main(int argc, char **argv)
int udp_sendto(int s, Octstr *datagram, Octstr *addr)
#define CONSTRUCT_EXPECTED_REPLY_HDR(dest, template, tid)
static int get_wtp_pdu_type(Octstr *hdr)
unsigned char WTP_Segm_Ack[]
unsigned char WTP_Invoke_Cl0[]
void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len)
int octstr_get_char(const Octstr *ostr, long pos)
void octstr_set_char(Octstr *ostr, long pos, int ch)
unsigned char WSP_Disconnect[]
static XMLRPCDocument * msg
#define WTP_PDU_SEGM_INVOKE
WSP_PDU * wsp_pdu_unpack(Octstr *data)
Octstr * udp_create_address(Octstr *host_or_ip, int port)
#define WTP_PDU_SEGM_RESULT