00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 #define MAX_SEND (0)
00133
00134 static char usage[] = "\
00135 Usage: fakewap [options] url ...\n\
00136 \n\
00137 where options are:\n\
00138 \n\
00139 -h help\n\
00140 -v verbose\n\
00141 -g hostname hostname or IP number of gateway (default: localhost)\n\
00142 -p port port number of gateway (default: 9201)\n\
00143 -m max maximum number of requests fakewap will make (default: 1)\n\
00144 -i interval interval between requests (default: 1.0 seconds)\n\
00145 -c threads number of concurrent clients simulated (default: 1)\n\
00146 -V protoversion protocol version field, as an integer (default: 0)\n\
00147 -T pdu-type PDU type, as an integer (default: 1)\n\
00148 -t tcl transaction class, as an integer (default: 2)\n\
00149 -n set tid_new flag in packets, forces gateway to flush cache\n\
00150 (default: off)\n\
00151 -s test separation, by concatenating ack and disconnect pdus\n\
00152 (default: off)\n\
00153 -d difference difference between successive tid numbers (default: 1)\n\
00154 -F Accept failure and continue rather than exiting\n\
00155 -w Write/print received data (experimental)\n\
00156 \n\
00157 The urls are fetched in random order.\n\
00158 ";
00159
00160 #include <errno.h>
00161 #include <ctype.h>
00162 #include <math.h>
00163 #include <stdio.h>
00164 #include <stdlib.h>
00165 #include <string.h>
00166 #include <time.h>
00167 #include <unistd.h>
00168 #include <sys/time.h>
00169 #include <sys/types.h>
00170 #include <sys/socket.h>
00171 #include <netinet/in.h>
00172 #include <netdb.h>
00173 #include <sys/param.h>
00174 #include <math.h>
00175 #include <signal.h>
00176
00177 #include "gwlib/gwlib.h"
00178
00179 #define GET_WTP_PDU_TYPE(hdr) (hdr[0] >> 3)
00180 static int get_wtp_pdu_type(Octstr *hdr) {
00181 return octstr_get_char(hdr, 0) >> 3;
00182 }
00183
00184 #define WTP_PDU_INVOKE 1
00185 #define WTP_PDU_RESULT 2
00186 #define WTP_PDU_ACK 3
00187 #define WTP_PDU_ABORT 4
00188
00189
00190
00191
00192 char **urls;
00193 int num_urls;
00194
00195 Octstr *hostname = NULL;
00196 Octstr *gateway_addr = NULL;
00197 double interval = 1.0;
00198 unsigned short port = 9201;
00199 int max_send = 1;
00200 unsigned short tid_addition = 1;
00201 Mutex *mutex;
00202 int threads = 1;
00203 int num_sent = 0;
00204 time_t start_time, end_time;
00205 double totaltime = 0, besttime = 1000000L, worsttime = 0;
00206 int verbose = 0;
00207 int nofailexit = 0;
00208 int writedata = 0;
00209 int test_separation = 0;
00210
00211
00212
00213
00214
00215
00216 unsigned char WSP_Connect[] = {0x06, 0x00, 0x00, 0x00,
00217
00218 0x01,
00219 0x10,
00220 0x00,
00221 0x02,
00222
00223
00224 0x80, 0x80
00225 };
00226 unsigned char WSP_ConnectReply[] = {0x16, 0x80, 0x00, 0x02 };
00227 unsigned char WTP_Ack[] = {0x18, 0x00, 0x00 };
00228 unsigned char WTP_TidVe[] = {0x1C, 0x00, 0x00 };
00229 unsigned char WTP_Abort[] = {0x20, 0x00, 0x00, 0x00 };
00230 unsigned char WSP_Get[] = {0x0E, 0x00, 0x00, 0x02, 0x40 };
00231
00232
00233 unsigned char WSP_Reply[] = {0x16, 0x80, 0x00, 0x04, 0x20 };
00234 unsigned char WSP_Disconnect[] = {0x0E, 0x00, 0x00, 0x00, 0x05 };
00235 unsigned char WSP_Concat[] = {0x00, 0x03, 0x18, 0x00, 0x00, 0x05, 0x0E, 0x00, 0x00, 0x00, 0x05 };
00236
00237
00238
00239
00240 #define SET_GTR( hdr ) hdr[0] |= 0x04
00241 #define SET_TID( hdr, tid) \
00242 hdr[1] |= (0x7f & ((tid) >> 8)); \
00243 hdr[2] = (char)(tid)
00244 #define GET_TID( hdr ) (((hdr[1] & 0x7f) << 8) + hdr[2])
00245 #define CONSTRUCT_EXPECTED_REPLY_HDR( dest, template, tid ) \
00246 if (sizeof(dest) < sizeof(template)) panic(0,"buffer overflow.");\
00247 memcpy( dest, template, sizeof(template));\
00248 SET_TID( dest, tid )
00249
00250 static void set_tid(Octstr *hdr, int tid) {
00251 int c;
00252
00253 c = octstr_get_char(hdr, 1);
00254 c |= 0x7f & (tid >> 8);
00255 octstr_set_char(hdr, 1, c);
00256 octstr_set_char(hdr, 2, (unsigned char) tid);
00257 }
00258
00259
00260 static void set_tid_new(Octstr *hdr) {
00261 int c;
00262
00263 c = octstr_get_char(hdr, 3);
00264 c |= 0x40;
00265 octstr_set_char(hdr, 3, c);
00266 }
00267
00268
00269 #ifndef min
00270 #define min(a,b) (a < b ? a : b)
00271 #endif
00272
00273
00274
00275
00276
00277
00278 static void print_msg( const char * trace, unsigned char * msg,
00279 int msg_len ) {
00280 int i;
00281 if (verbose) {
00282 mutex_lock( mutex );
00283 printf( "%s (len %d): ", trace, msg_len );
00284 for (i = 0; i < msg_len && i < 16; i++) printf( "%02X ", msg[i] );
00285 printf( "\n");
00286 mutex_unlock( mutex );
00287 }
00288 }
00289
00290
00291
00292
00293 static void print_data( const char * trace, unsigned char * msg,
00294 int msg_len ) {
00295 int i;
00296
00297 if (verbose || writedata) {
00298 mutex_lock( mutex );
00299 printf( "%s (len %d): ", trace, msg_len );
00300 for (i = 0; i < msg_len && i < msg_len; i++)
00301 printf( "%c", isprint(msg[i]) ? msg[i] : '_');
00302 printf( "\n");
00303 mutex_unlock( mutex );
00304 }
00305 }
00306
00307
00308 static char *choose_message(char **urls, int num_urls) {
00309
00310 return urls[gw_rand() % num_urls];
00311 }
00312
00313
00314
00315
00316 static unsigned short next_tid(unsigned short old_tid) {
00317 return (old_tid + tid_addition) % (1 << 15);
00318 }
00319
00320
00321
00322
00323
00324
00325 static int StoreVarInt( unsigned char *buf, unsigned long varInt )
00326 {
00327 int i, len = 1, non_zero_bits = 7;
00328
00329
00330
00331
00332 while ((varInt >> non_zero_bits) != 0) {
00333 non_zero_bits += 7;
00334 len++;
00335 }
00336
00337
00338
00339 for (i = 0; i < len; i++)
00340 {
00341 buf[i] = ((unsigned char)(varInt >> (non_zero_bits-7)) & 0x7f) | 0x80;
00342 non_zero_bits -= 7;
00343 }
00344 buf[len-1] &= 0x7f;
00345 return len;
00346 }
00347
00348
00349
00350
00351
00352 static int ReadVarIntLen( const unsigned char *buf )
00353 {
00354 int len = 1;
00355
00356 while (buf[len-1] & 0x80) len++;
00357 return len;
00358 }
00359
00360
00361
00362
00363
00364 static int
00365 wap_msg_send( int fd, unsigned char * hdr,
00366 int hdr_len, unsigned short tid, int tid_new, unsigned char * data,
00367 int data_len )
00368 {
00369 int ret;
00370 Octstr *datagram;
00371
00372 datagram = octstr_create("");
00373 if (hdr != NULL)
00374 octstr_append_data(datagram, hdr, hdr_len);
00375
00376 set_tid(datagram, tid);
00377 if (get_wtp_pdu_type(datagram) == WTP_PDU_INVOKE) {
00378
00379 int c;
00380 c = octstr_get_char(datagram, 3);
00381 octstr_set_char(datagram, 3, c | 0x10);
00382 if (tid_new)
00383 set_tid_new(datagram);
00384 }
00385
00386 if (data != NULL)
00387 octstr_append_data(datagram, data, data_len);
00388
00389 #if 0
00390 debug("fakewap", 0, "Sending WDP datagram:");
00391 octstr_dump(datagram, 0);
00392 #endif
00393 ret = udp_sendto(fd, datagram, gateway_addr);
00394
00395 if (ret == -1) {
00396 error(0, "Sending to socket failed");
00397 return -1;
00398 }
00399
00400 if (verbose) {
00401 debug("", 0, "Sent packet:");
00402 octstr_dump(datagram, 0);
00403 }
00404 octstr_destroy(datagram);
00405 return ret;
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 static int
00417 wap_msg_recv( int fd, const char * hdr, int hdr_len,
00418 unsigned short tid, unsigned char * data, int data_len,
00419 int timeout )
00420 {
00421 int ret;
00422 unsigned char msg[1024*64];
00423 int msg_len = 0;
00424 int fResponderIsDead = 1;
00425 Octstr *datagram, *dummy;
00426
00427
00428
00429
00430 for (;;)
00431 {
00432 if (timeout != 0)
00433 {
00434 ret = read_available(fd, timeout * 1000 * 1000);
00435 if (ret <= 0) {
00436 info(0, "Timeout while receiving from socket.\n");
00437 if(nofailexit){
00438 continue;
00439 }else{
00440 return fResponderIsDead ? -1 : 0;
00441 }
00442
00443 }
00444 }
00445
00446 ret = udp_recvfrom(fd, &datagram, &dummy);
00447 if (ret == 0) {
00448 octstr_get_many_chars(msg, datagram, 0, octstr_len(datagram));
00449 msg_len = octstr_len(datagram);
00450 }
00451 octstr_destroy(datagram);
00452 octstr_destroy(dummy);
00453
00454 if (ret == -1) {
00455 error(0, "recv() from socket failed");
00456 return -1;
00457 }
00458
00459 if (hdr != NULL) {
00460
00461
00462
00463 if (msg_len >= hdr_len &&
00464 GET_WTP_PDU_TYPE(msg) == GET_WTP_PDU_TYPE(hdr) &&
00465 (hdr_len <= 3 || !memcmp( msg+3, hdr+3, hdr_len-3 ))) {
00466 break;
00467 }
00468
00469
00470
00471
00472
00473 else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_ACK &&
00474 GET_TID(msg) == tid) {
00475 print_msg( "Received tid verification", msg, msg_len );
00476 wap_msg_send( fd, WTP_TidVe, sizeof(WTP_TidVe), tid, 0,
00477 NULL, 0 );
00478 }
00479 else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_ABORT) {
00480 print_msg( "Received WTP Abort", msg, msg_len );
00481 }
00482 else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_RESULT) {
00483 break;
00484 }
00485 else {
00486 print_msg( "Received unexpected message", msg, msg_len );
00487 }
00488 fResponderIsDead = 0;
00489 }
00490 else {
00491 hdr_len = 0;
00492 break;
00493 }
00494 }
00495 print_msg( "Received packet", msg, msg_len );
00496 print_data( "Received data", msg, msg_len );
00497
00498 if (data != NULL && msg_len > hdr_len) {
00499 data_len = min( data_len, msg_len - hdr_len );
00500 memcpy( data, msg+hdr_len, data_len);
00501 }
00502 else data_len = 0;
00503 return data_len;
00504 }
00505
00506
00507 static int get_next_transaction(void) {
00508 int i_this;
00509 mutex_lock( mutex );
00510 i_this = num_sent + 1;
00511 if (max_send == MAX_SEND || num_sent < max_send) num_sent++;
00512 mutex_unlock( mutex );
00513 return i_this;
00514 }
00515
00516
00517
00518
00519
00520 static void client_session( void * arg)
00521 {
00522 int fd;
00523 int ret;
00524 int url_len = 0, url_off = 0;
00525 double nowsec, lastsec, tmp, sleepTime;
00526 long uSleepTime;
00527 struct timeval now;
00528 struct timezone tz;
00529 char * url;
00530 unsigned char sid[20];
00531 int sid_len = 0;
00532 unsigned char buf[64*1024];
00533 unsigned char reply_hdr[32];
00534 long timeout = 10;
00535 unsigned short tid = 0;
00536 unsigned short old_tid;
00537 int tid_new = 0;
00538 int connection_retries = 0;
00539 int i_this;
00540
00541 fd = udp_client_socket();
00542 if (fd == -1)
00543 panic(0, "Couldn't create socket.");
00544
00545
00546
00547
00548 for (;;) {
00549
00550
00551
00552 gettimeofday(&now, &tz);
00553 lastsec = (double) now.tv_sec + now.tv_usec / 1e6;
00554
00555
00556
00557
00558 i_this = get_next_transaction();
00559 if (max_send != MAX_SEND && i_this > max_send) break;
00560
00561
00562
00563
00564 old_tid = tid;
00565 tid = next_tid(old_tid);
00566 tid_new = (tid < old_tid);
00567 ret = wap_msg_send( fd, WSP_Connect, sizeof(WSP_Connect),
00568 tid, tid_new, NULL, 0 );
00569
00570 if (ret == -1) panic(0, "Send WSP_Connect failed");
00571
00572 CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WSP_ConnectReply, tid );
00573 ret = wap_msg_recv( fd, reply_hdr, sizeof(WSP_ConnectReply),
00574 tid, buf, sizeof(buf), timeout );
00575
00576 if (ret == -1) panic(0, "Receive WSP_ConnectReply failed");
00577
00578 if (ret > 2)
00579 {
00580 sid_len = ReadVarIntLen(buf);
00581 memcpy( sid, buf, sid_len);
00582 }
00583
00584
00585
00586 if (ret == 0) {
00587 if (connection_retries++ > 3) {
00588 panic(0, "Cannot connect WAP GW!");
00589 }
00590 wap_msg_send( fd, WTP_Abort, sizeof(WTP_Abort), tid, tid_new,
00591 NULL, 0 );
00592 continue;
00593 }
00594 else {
00595 connection_retries = 0;
00596 }
00597 ret = wap_msg_send( fd, WTP_Ack, sizeof(WTP_Ack), tid, tid_new,
00598 NULL, 0 );
00599
00600 if (ret == -1) panic(0, "Send WTP_Ack failed");
00601
00602
00603
00604
00605 old_tid = tid;
00606 tid = next_tid(old_tid);
00607 tid_new = (tid < old_tid);
00608 url = choose_message(urls, num_urls);
00609 url_len = strlen(url);
00610 url_off = StoreVarInt( buf, url_len );
00611 memcpy( buf+url_off, url, url_len );
00612 ret = wap_msg_send( fd, WSP_Get, sizeof(WSP_Get), tid, tid_new,
00613 buf, url_len+url_off );
00614 if (ret == -1) break;
00615
00616 CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WSP_Reply, tid );
00617 ret = wap_msg_recv( fd, reply_hdr, sizeof(WSP_Reply),
00618 tid, buf, sizeof(buf), timeout );
00619 if (ret == -1) break;
00620
00621
00622
00623
00624 if (test_separation){
00625 ret = wap_msg_send(fd, WSP_Concat, sizeof(WSP_Concat), tid, tid_new,
00626 sid, sid_len);
00627
00628 if (ret == -1) break;
00629 } else {
00630 ret = wap_msg_send( fd, WTP_Ack, sizeof(WTP_Ack), tid, tid_new,
00631 NULL, 0 );
00632
00633 if (ret == -1) break;
00634
00635
00636
00637
00638 ret = wap_msg_send( fd, WSP_Disconnect, sizeof(WSP_Disconnect),
00639 tid, tid_new, sid, sid_len );
00640
00641 if (ret == -1) break;
00642 }
00643
00644
00645
00646
00647 gettimeofday(&now, &tz);
00648 nowsec = (double) now.tv_sec + now.tv_usec / 1e6;
00649 tmp = nowsec - lastsec;
00650 sleepTime = interval-tmp;
00651 uSleepTime = sleepTime * 1e6;
00652
00653 mutex_lock( mutex );
00654 if (tmp < besttime) besttime = tmp;
00655 if (tmp > worsttime) worsttime = tmp;
00656 totaltime += tmp;
00657 mutex_unlock( mutex );
00658
00659 if (verbose == 1)
00660 {
00661 info(0, "fakewap: finished session # %d", i_this);
00662 }
00663
00664
00665
00666
00667 if (i_this >= max_send) break;
00668
00669 if (tmp < (double)interval) {
00670 usleep( uSleepTime );
00671 }
00672 }
00673 close(fd);
00674
00675
00676 mutex_lock( mutex );
00677 time(&end_time);
00678 mutex_unlock( mutex );
00679 }
00680
00681
00682 static void help(void) {
00683 info(0, "\n%s", usage);
00684 }
00685
00686
00687
00688
00689 int main(int argc, char **argv)
00690 {
00691 int i, opt;
00692 double delta;
00693 int proto_version, pdu_type, tcl, tid_new;
00694 #ifdef SunOS
00695 struct sigaction alrm;
00696
00697 alrm.sa_handler = SIG_IGN;
00698
00699 sigaction(SIGALRM,&alrm,NULL);
00700 #endif
00701 gwlib_init();
00702
00703 proto_version = 0;
00704 pdu_type = 1;
00705 tcl = 2;
00706 tid_new = 0;
00707
00708 hostname = octstr_create("localhost");
00709
00710 while ((opt = getopt(argc, argv, "Fhvc:g:p:P:m:i:t:V:T:t:nsd:w")) != EOF) {
00711 switch (opt) {
00712 case 'g':
00713 octstr_destroy(hostname);
00714 hostname = octstr_create(optarg);
00715 break;
00716
00717 case 'p':
00718 port = atoi(optarg);
00719 break;
00720
00721 case 'm':
00722 max_send = atoi(optarg);
00723 break;
00724
00725 case 'i':
00726 interval = atof(optarg);
00727 break;
00728
00729 case 'c':
00730 threads = atoi(optarg);
00731 break;
00732
00733 case 'V':
00734 proto_version = atoi(optarg);
00735 break;
00736
00737 case 'T':
00738 pdu_type = atoi(optarg);
00739 break;
00740
00741 case 't':
00742 tcl = atoi(optarg);
00743 break;
00744
00745 case 'n':
00746 tid_new = 1;
00747 break;
00748
00749 case 's':
00750 test_separation = 1;
00751 break;
00752
00753 case 'd':
00754 tid_addition = atoi(optarg);
00755 break;
00756
00757 case 'v':
00758 verbose = 1;
00759 break;
00760
00761 case 'h':
00762 help();
00763 exit(0);
00764 break;
00765
00766 case 'F':
00767 nofailexit=1;
00768 break;
00769
00770 case 'w':
00771 writedata = 1;
00772 break;
00773
00774 case '?':
00775 default:
00776 error(0, "Unknown option %c", opt);
00777 help();
00778 panic(0, "Stopping.");
00779 }
00780 }
00781
00782 time(&start_time);
00783
00784 if (optind >= argc)
00785 panic(0, "%s", usage);
00786
00787 if (verbose != 1)
00788 {
00789 log_set_output_level (GW_INFO);
00790 }
00791 WSP_Connect[3] += (proto_version&3)<<6;
00792 WSP_Connect[0] += (pdu_type&15)<<3;
00793 WSP_Connect[3] += tcl&3;
00794 WSP_Connect[3] += (tid_new&1)<<5;
00795
00796 gateway_addr = udp_create_address(hostname, port);
00797
00798 urls = argv + optind;
00799 num_urls = argc - optind;
00800
00801 srand((unsigned int) time(NULL));
00802
00803 mutex = mutex_create();
00804
00805 info(0, "fakewap starting");
00806
00807 if (threads < 1) threads = 1;
00808
00809
00810
00811
00812
00813 for (i = 1; i < threads; i++)
00814 gwthread_create(client_session, NULL);
00815 client_session(NULL);
00816
00817
00818 gwthread_join_every(client_session);
00819
00820 info(0, "fakewap complete.");
00821 info(0, "fakewap: %d client threads made total %d transactions.",
00822 threads, num_sent);
00823 delta = difftime(end_time, start_time);
00824 info( 0, "fakewap: total running time %.1f seconds", delta);
00825 info( 0, "fakewap: %.1f messages/seconds on average", num_sent / delta);
00826 info( 0, "fakewap: time of best, worst and average transaction: "
00827 "%.1f s, %.1f s, %.1f s",
00828 besttime, worsttime, totaltime / num_sent );
00829
00830 octstr_destroy(hostname);
00831 octstr_destroy(gateway_addr);
00832 mutex_destroy(mutex);
00833 gwlib_shutdown();
00834 return 0;
00835 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.