Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

fakewap.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * fakewap.c - simulate wap clients talking directly to wap gw.
00059  *
00060  * This module can be built also in Windows where you should
00061  * add unzipped ".\wininc" to your include directories.
00062  *
00063  * The protocol:
00064  *
00065  *
00066  *    A)    Fakewap -> Gateway
00067  *
00068  *        WTP: Invoke PDU
00069  *        WSP: Connect PDU
00070  *
00071  *    B)    Gateway -> Fakewap
00072  *
00073  *        WTP: Result PDU
00074  *        WSP: ConnectReply PDU
00075  *
00076  *    C)    Fakewap -> Gateway
00077  *
00078  *        WTP: Ack PDU
00079  *
00080  *    D)    Fakewap -> Gateway
00081  *
00082  *        WTP: Invoke PDU
00083  *        WSP: Get PDU (data: URL)
00084  *
00085  *    E)    Gateway -> Fakewap
00086  *
00087  *        WTP: Result PDU (data: WML page)
00088  *        WSP: Reply PDU
00089  *
00090  *    F)    Fakewap -> Gateway
00091  *
00092  *        WTP: Ack PDU
00093  *
00094  *    G)    Fakewap -> Gateway
00095  *
00096  *        WTP: Invoke PDU
00097  *        WSP: Disconnect PDU
00098  *
00099  *
00100  *    Packets A-C open a WAP session. Packets D-F fetch a WML page.
00101  *    Packet G closes the session.
00102  *
00103  * The test terminates when all packets have been sent.
00104  *
00105  * Tid verification uses following protocol (at WTP level only):
00106  *
00107  *    A)   Fakewap -> Gateway
00108  *
00109  *         Either WSP Connect PDU with tid_new flag set on or same PDU with a 
00110  *         *seriously* wrapped up tid (only WTP header affected). Seriously
00111  *         means tid being out of the window:
00112  *
00113  *         |----------------------------|
00114  *                  tid space
00115  *
00116  *         |-------------|
00117  *          wrapping up
00118  *          tid window
00119  *
00120  *    B)   Gateway -> Fakewap
00121  *
00122  *         Ack PDU, tid verification flag set on.
00123  *
00124  *    C)   Fakewap -> Gateway
00125  *
00126  *         Ack PDU, tid verification flag set on (this means a positive 
00127  *         answer). 
00128  *
00129  * Antti Saarenheimo for WapIT Ltd.
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 **  Common parameters
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  * PDU type, version number and transaction class are supplied by a 
00213  * command line argument. WSP_Concat is a concatenation of WTP_Ack and 
00214  * WSP_Disconnect PDUs.
00215  */
00216 unsigned char WSP_Connect[] = {0x06, 0x00, 0x00, 0x00, 
00217                 /* WSP part */
00218                 0x01, /* PDU type */
00219                 0x10, /* Version 1.0 */
00220                 0x00, /* Capability length */
00221                 0x02, /* Headers length = 2*/
00222                 /* Capabilities */
00223                 /* Headers */
00224                 0x80, 0x80 /* Accept: *\* */
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 /* This used to also expect a content-type of 0x94, but that's too difficult
00232  * to check now that Kannel does full header encoding. */
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 **  In this case it does not matter what is the byte order
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 /* Use this only on Invoke packets, the others have no tid_new field */
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 **  if -v option has been defined, function prints the trace message and
00276 **  the first bytes in the message header
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 **  if -w option has been defined, function prints the trace message and
00291 **  the first bytes in the message header
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 /* Choose a random message from a table of messages. */
00308 static char *choose_message(char **urls, int num_urls) {
00309     /* the following doesn't give an even distribution, but who cares */
00310     return urls[gw_rand() % num_urls];
00311 }
00312 
00313 
00314 /* returns next tid, given current tid.  Every thread has its own
00315  * port, so has its own tid space. */
00316 static unsigned short next_tid(unsigned short old_tid) { 
00317     return (old_tid + tid_addition) % (1 << 15);
00318 }
00319 
00320 
00321 /*
00322 **  Function stores WAP/WSP variable length integer to buffer and returns 
00323 **  actual len
00324 */
00325 static int StoreVarInt( unsigned char *buf, unsigned long varInt )
00326 {
00327     int i, len = 1, non_zero_bits = 7;
00328 
00329     /*
00330     **    Skip all zero high bits
00331     */
00332     while ((varInt >> non_zero_bits) != 0) {
00333         non_zero_bits += 7;
00334         len++;
00335     }
00336     /*
00337     **    Read the higest bits first.
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 **  Function length of WAP/WSP variable length integer in the buffer
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 **  Function sends message to WAP GW
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     /* request ack every time */
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 **  Function receives a wap wtl/wsp message. If the headers has been
00410 **  given, it must match with the received message.
00411 **  Return value:
00412 **      >  0 => length of received data
00413 **      == 0 => got acknowlengement or abort but not the expected data
00414 **      < 0  => error,
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;  /* assume this by default */
00425     Octstr *datagram, *dummy;
00426 
00427     /*
00428     **  Loop until we get the expected response or do timeout
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         /* continue if we got ack? */
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             **  Ignore extra header bits, WAP GWs return different values
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             **  Handle TID test, the answer is: Yes, we have an outstanding
00470             **  transaction with this tid. We must turn on TID_OK-flag, too.
00471             **  We have a separate tid verification PDU.
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 **  Function (or thread) sets up a dgram socket.  Then it loops: WTL/WSP
00518 **  Connect, Get a url and Disconnect until all requests are have been done.
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;  /* wap gw is broken if no input */
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     **  Loop until all URLs have been requested
00547     */
00548     for (;;) {
00549         /*
00550          ** Get start time of this request
00551          */
00552         gettimeofday(&now, &tz);
00553         lastsec = (double) now.tv_sec + now.tv_usec / 1e6;
00554 
00555         /*
00556         **  Get next transaction number or exit if too many transactions
00557         */
00558         i_this = get_next_transaction();
00559         if (max_send != MAX_SEND  && i_this > max_send) break;
00560 
00561         /*
00562         **  Connect, save sid from reply and finally ack the reply
00563         */
00564     old_tid = tid;
00565         tid = next_tid(old_tid);
00566     tid_new = (tid < old_tid);  /* Did we wrap? */
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         **  Send abort and continue if we get an unexpected reply
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         **  Request WML page with the given URL
00604         */
00605     old_tid = tid;
00606         tid = next_tid(old_tid);
00607     tid_new = (tid < old_tid);  /* Did we wrap? */
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     ** If we are testing separation, we concatenate WTP_Ack and 
00622         ** WSP_Disconnect messages.
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         **  Finally disconnect with the sid returned by connect reply
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          ** Get end time of the request
00646          */
00647         gettimeofday(&now, &tz);
00648         nowsec = (double) now.tv_sec + now.tv_usec / 1e6;
00649         tmp = nowsec - lastsec; /* Duration of request */
00650         sleepTime = interval-tmp;   /* Amount of time left to sleep */
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          ** If we've done all the requests, then don't bother to sleep
00666          */
00667         if (i_this >= max_send) break;
00668 
00669         if (tmp < (double)interval) {
00670             usleep( uSleepTime );
00671         }
00672     }
00673     close(fd);
00674 
00675     /* The last end_time stays */
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 /* The main program. */
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     **  Start 'extra' client threads and finally execute the
00811     **  session of main thread
00812     */
00813     for (i = 1; i < threads; i++)
00814         gwthread_create(client_session, NULL);
00815     client_session(NULL);
00816 
00817     /* Wait for the other sessions to complete */
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.