Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
fakewap.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * fakewap.c - simulate wap clients talking directly to wap gw.
59  *
60  * This module can be built also in Windows where you should
61  * add unzipped ".\wininc" to your include directories.
62  *
63  * The protocol:
64  *
65  *
66  * A) Fakewap -> Gateway
67  *
68  * WTP: Invoke PDU
69  * WSP: Connect PDU
70  *
71  * B) Gateway -> Fakewap
72  *
73  * WTP: Result PDU
74  * WSP: ConnectReply PDU
75  *
76  * C) Fakewap -> Gateway
77  *
78  * WTP: Ack PDU
79  *
80  * D) Fakewap -> Gateway
81  *
82  * WTP: Invoke PDU
83  * WSP: Get/Post PDU (data: URL)
84  *
85  * E) Gateway -> Fakewap
86  *
87  * WTP: Result PDU (data: WML page)
88  * WSP: Reply PDU
89  *
90  * F) Fakewap -> Gateway
91  *
92  * WTP: Ack PDU
93  *
94  * G) Fakewap -> Gateway
95  *
96  * WTP: Invoke PDU
97  * WSP: Disconnect PDU
98  *
99  *
100  * Packets A-C open a WAP session. Packets D-F fetch a WML page.
101  * Packet G closes the session.
102  *
103  * The test terminates when all packets have been sent.
104  *
105  * Tid verification uses following protocol (at WTP level only):
106  *
107  * A) Fakewap -> Gateway
108  *
109  * Either WSP Connect PDU with tid_new flag set on or same PDU with a
110  * *seriously* wrapped up tid (only WTP header affected). Seriously
111  * means tid being out of the window:
112  *
113  * |----------------------------|
114  * tid space
115  *
116  * |-------------|
117  * wrapping up
118  * tid window
119  *
120  * B) Gateway -> Fakewap
121  *
122  * Ack PDU, tid verification flag set on.
123  *
124  * C) Fakewap -> Gateway
125  *
126  * Ack PDU, tid verification flag set on (this means a positive
127  * answer).
128  *
129  * Antti Saarenheimo for WapIT Ltd.
130  */
131 
132 #define MAX_SEND (0)
133 
134 /* Versions:
135  * v1.0 - added WSP GET result reassembly
136  * v1.1 - added WSP POST - options -P, -C, -w
137  * v1.2 - added source address (-I) option
138  * v1.3 - send Nack for lost segments, reassembly fixes
139  * v1.4 - parse WSP message and save only the received payload to the output file
140  * v1.5 - support for connectionless get/post
141  * v1.6 - robustness fixes for Post (resend group segments if no ack), packet loss simulation
142  */
143 static char usage[] = "\
144 fakewap version 1.6\n\
145 Usage: fakewap [options] url ...\n\
146 \n\
147 where options are:\n\
148 \n\
149 -h help\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\
159  (default: off)\n\
160 -s test separation, by concatenating ack and disconnect pdus\n\
161  (default: off)\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\
172 \n\
173 The urls are fetched in random order.\n\
174 ";
175 
176 #include <errno.h>
177 #include <ctype.h>
178 #include <math.h>
179 #include <stdio.h>
180 #include <stdlib.h>
181 #include <string.h>
182 #include <time.h>
183 #include <unistd.h>
184 #include <sys/time.h>
185 #include <sys/types.h>
186 #include <sys/socket.h>
187 #include <netinet/in.h>
188 #include <netdb.h>
189 #include <sys/param.h>
190 #include <math.h>
191 #include <signal.h>
192 #include <fcntl.h>
193 #include <sys/stat.h>
194 
195 #include "gwlib/gwlib.h"
196 #include "wap/wsp_pdu.h"
197 
198 #define GET_WTP_PDU_TYPE(hdr) ((hdr[0] >> 3) & 0x0f)
199 static int get_wtp_pdu_type(Octstr *hdr)
200 {
201  return (octstr_get_char(hdr, 0) >> 3) & 0x0f;
202 }
203 
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
211 
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
217 
218 #define TXN_MODE_CONNECTION_LESS 0
219 #define TXN_MODE_CONNECTION_ORIENTED 1
220 
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
225 
226 /*
227 ** Common parameters
228 */
229 char **urls;
231 
232 Octstr *hostname = NULL;
234 double interval = 1.0;
235 unsigned short port = 0;
236 int max_send = 1;
237 unsigned short tid_addition = 1;
239 int threads = 1;
240 int num_sent = 0;
242 double totaltime = 0, besttime = 1000000L, worsttime = 0;
243 int brief; /* enable brief debug */
244 int verbose = 0;
245 int nofailexit = 0;
247 char* infile;
248 char* outfile;
249 const char* content_type;
250 struct sockaddr_in src_addr;
252 int packet_loss; /* packet loss rate 0-99 */
254 
255 /*
256  * PDU type, version number and transaction class are supplied by a
257  * command line argument. WSP_Concat is a concatenation of WTP_Ack and
258  * WSP_Disconnect PDUs.
259  */
260 unsigned char WSP_Connect[] = { /* WSP part */
261  0x01, /* PDU type */
262  0x10, /* Version 1.0 */
263  0x0a, /* Capability length */
264  0x0d, /* Headers length = 13 */
265  /* Capabilities */
266  0x04, 0x80, 0xc0, 0x80, 0x00, /* Client SDU */
267  0x04, 0x81, 0xc0, 0x80, 0x00, /* Server SDU */
268  /* Headers */
269  0x80, 0x80, /* Accept: *\* */
270  };
271 unsigned char WSP_ConnectReply[] = {0x16, 0x80, 0x00, 0x02 };
272 unsigned char WSP_Get[] = {0x40};
273 /* This used to also expect a content-type of 0x94, but that's too difficult
274  * to check now that Kannel does full header encoding. */
275 unsigned char WSP_Reply[] = {0x16, 0x80, 0x00, 0x04, 0x20 };
276 unsigned char WSP_Disconnect[] = {0x05};
277 unsigned char WSP_Post[] = { /* wsp post */ 0x60 };
278 unsigned char WSP_Concat[] = {0x00, 0x03, 0x18, 0x00, 0x00, 0x05, 0x0E, 0x00, 0x00, 0x00, 0x05 };
279 
280 unsigned char WTP_Ack[] = {0x18, 0x00, 0x00 };
281 unsigned char WTP_TidVe[] = {0x1C, 0x00, 0x00 };
282 unsigned char WTP_Abort[] = {0x20, 0x00, 0x00, 0x00 };
283 unsigned char WTP_Invoke_Cl0[] = { /*wtp invoke,ttr*/ 0x0a, /*tid*/ 0x00, 0x00, /*ack+class0*/ 0x10 };
284 unsigned char WTP_Invoke_Cl2[] = { /*wtp invoke,ttr*/ 0x0a, /*tid*/ 0x00, 0x00, /*ack+class2*/ 0x12 };
285 unsigned char WTP_Invoke_Cl2MaxGrp[] = { /*wtp invoke*/ 0x0E, /*tid*/ 0x00, 0x00, /*ack/class2:*/ 0x12,
286  /*tti max-group: 4200*/ 0x13, 0x04, 0x10, 0x68 };
287 unsigned char WTP_Result[] = {0x10, 0x80, 0x00 };
288 unsigned char WTP_Segm_Result[] = {0x30, 0x80, 0x00 };
289 unsigned char WTP_Segm_Ack[] = {0x98, 0x00, 0x00, 0x19, 0x00 };
290 unsigned char WTP_Nack[] = { /* wtp nack */ 0x38, /* tid */ 0x00, 0x00, /*num missing*/ 0x00 };
291 unsigned char WTP_Segm_Invoke[] = { /* wtp segm invoke*/ 0x28, /* tid */ 0x00, 0x00, /* psn */ 0x00 };
292 
293 /*
294 ** In this case it does not matter what is the byte order
295 */
296 #define SET_GTR( hdr ) hdr[0] |= 0x04
297 #define SET_TID( hdr, tid) \
298  hdr[1] |= (0x7f & ((tid) >> 8)); \
299  hdr[2] = (char)(tid)
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));\
304  SET_TID( dest, tid )
305 
306 static void set_tid(Octstr *hdr, int tid) {
307  int c;
308 
309  c = octstr_get_char(hdr, 1);
310  c |= 0x7f & (tid >> 8);
311  octstr_set_char(hdr, 1, c);
312  octstr_set_char(hdr, 2, (unsigned char) tid);
313 }
314 
315 /* Use this only on Invoke packets, the others have no tid_new field */
316 static void set_tid_new(Octstr *hdr) {
317  int c;
318 
319  c = octstr_get_char(hdr, 3);
320  c |= 0x40;
321  octstr_set_char(hdr, 3, c);
322 }
323 
324 
325 #ifndef min
326 #define min(a,b) (a < b ? a : b)
327 #endif
328 
329 
330 /*
331 ** if -v option has been defined, function prints the trace message and
332 ** the first bytes in the message header
333 */
334 static void print_msg( const char * trace, unsigned char * msg,
335  int msg_len ) {
336  int i;
337  if (verbose) {
338  mutex_lock( mutex );
339  printf( "%s (len %d): ", trace, msg_len );
340  for (i = 0; i < msg_len && i < 16; i++) printf( "%02X ", msg[i] );
341  printf( "\n");
342  mutex_unlock( mutex );
343  }
344 }
345 /*
346 ** function prints the trace message and the first bytes in the message header
347 */
348 static void print_data( const char * trace, unsigned char * msg,
349  int msg_len ) {
350  int i;
351 
352  if (verbose)
353  {
354  mutex_lock( mutex );
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] : '_');
358  printf( "\n");
359  mutex_unlock( mutex );
360  }
361 }
362 
363 /* Choose a random message from a table of messages. */
364 static char *choose_message(char **urls, int num_urls) {
365  /* the following doesn't give an even distribution, but who cares */
366  return urls[gw_rand() % num_urls];
367 }
368 
369 
370 /* returns next tid, given current tid. Every thread has its own
371  * port, so has its own tid space. */
372 static unsigned short next_tid(unsigned short old_tid) {
373  return (old_tid + tid_addition) % (1 << 15);
374 }
375 
376 
377 /*
378 ** Function stores WAP/WSP variable length integer to buffer and returns
379 ** actual len
380 */
381 static int StoreVarInt( unsigned char *buf, unsigned long varInt )
382 {
383  int i, len = 1, non_zero_bits = 7;
384 
385  /*
386  ** Skip all zero high bits
387  */
388  while ((varInt >> non_zero_bits) != 0) {
389  non_zero_bits += 7;
390  len++;
391  }
392  /*
393  ** Read the higest bits first.
394  */
395  for (i = 0; i < len; i++)
396  {
397  buf[i] = ((unsigned char)(varInt >> (non_zero_bits-7)) & 0x7f) | 0x80;
398  non_zero_bits -= 7;
399  }
400  buf[len-1] &= 0x7f;
401  return len;
402 }
403 
404 
405 /*
406 ** Function length of WAP/WSP variable length integer in the buffer
407 */
408 static int ReadVarIntLen( const unsigned char *buf )
409 {
410  int len = 1;
411 
412  while (buf[len-1] & 0x80) len++;
413  return len;
414 }
415 
416 /*
417 ** Retrieve value of WAP/WSP variable length integer in the buffer
418 */
419 static int ReadVarIntVal( const unsigned char *buf )
420 {
421  int len = 1;
422  int value = buf[0] & 0x7F;
423  while (buf[len-1] & 0x80)
424  {
425  len++;
426  value <<= 7;
427  value |= buf[len-1] & 0x7F;
428  }
429  return value;
430 }
431 
432 /*
433 ** Function sends message to WAP GW
434 */
435 static int
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 )
438 {
439  int ret;
440  Octstr *datagram;
441 
442  datagram = octstr_create("");
443  if (wtp_hdr != NULL) {
444  octstr_append_data(datagram, (char*)wtp_hdr, wtp_hdr_len);
445 
446  set_tid(datagram, tid);
447  if (get_wtp_pdu_type(datagram) == WTP_PDU_INVOKE) {
448  /* request ack every time */
449  int c;
450  c = octstr_get_char(datagram, 3);
451  octstr_set_char(datagram, 3, c | 0x10);
452  if (tid_new)
453  set_tid_new(datagram);
454  }
455  }
456 
457  if (wsp_hdr != NULL)
458  octstr_append_data(datagram, (char*)wsp_hdr, wsp_hdr_len);
459 
460  if (data != NULL)
461  octstr_append_data(datagram, (char*)data, data_len);
462 
463 #if 0
464  debug("fakewap", 0, "Sending WDP datagram:");
465  octstr_dump(datagram, 0);
466 #endif
467  ret = udp_sendto(fd, datagram, gateway_addr);
468 
469  if (ret == -1) {
470  error(0, "fakewap: Sending to socket failed");
471  return -1;
472  }
473 
474  if (brief) {
475  if (wsp_hdr!=NULL) {
476  int wsp_pdu;
478  wsp_pdu = wsp_hdr[0];
479  else
480  wsp_pdu = wsp_hdr[1];
481  switch (wsp_pdu)
482  {
483  case WSP_PDU_CONNECT:
484  debug("fakewap", 0, "Sent WSP_CONNECT packet");
485  break;
486  case WSP_PDU_DISCONNECT:
487  debug("fakewap", 0, "Sent WSP_DISCONNECT packet");
488  break;
489  case WSP_PDU_GET:
490  debug("fakewap", 0, "Sent WSP_GET packet");
491  break;
492  case WSP_PDU_POST:
493  debug("fakewap", 0, "Sent WSP_POST packet");
494  break;
495  default:
496  debug("fakewap", 0, "Sent WSP ??? packet");
497  break;
498  }
499  }
500  else {
501  switch (get_wtp_pdu_type(datagram))
502  {
503  case WTP_PDU_INVOKE:
504  debug("fakewap", 0, "Sent WTP_INVOKE packet");
505  break;
506  case WTP_PDU_ACK:
507  debug("fakewap", 0, "Sent WTP_ACK packet");
508  break;
509  case WTP_PDU_ABORT:
510  debug("fakewap", 0, "Sent WTP_ABORT packet");
511  break;
512  case WTP_PDU_SEGM_INVOKE:
513  debug("fakewap", 0, "Sent WTP_SEGM_INVOKE packet");
514  break;
515  case WTP_PDU_NACK:
516  debug("fakewap", 0, "Sent WTP_NACK packet");
517  break;
518  default:
519  debug("fakewap", 0, "Sent ??? packet");
520  break;
521  }
522  }
523  }
524  if (verbose) {
525  octstr_dump(datagram, 0);
526  }
527  octstr_destroy(datagram);
528  return ret;
529 }
530 
531 /*
532 ** Function receives a wap wtl/wsp message. If the headers has been
533 ** given, it must match with the received message.
534 ** Return value:
535 ** > 0 => length of received data
536 ** == 0 => got acknowlengement or abort but not the expected data
537 ** < 0 => error,
538 */
539 static int
540 wap_msg_recv( int fd, const unsigned char* hdr, int hdr_len,
541  unsigned short tid, unsigned char * data, int data_len,
542  int timeout, int udp_flags )
543 {
544  int ret;
545  unsigned char msg[1024*64];
546  int msg_len = 0;
547  int fResponderIsDead = 1; /* assume this by default */
548  Octstr *datagram, *dummy;
549 
550  /*
551  ** Loop until we get the expected response or do timeout
552  */
553  for (;;)
554  {
555  time_t calltime;
556  time(&calltime);
557 
558  if (timeout != 0)
559  {
560  ret = read_available(fd, timeout * 1000 * 1000);
561  if (ret <= 0) {
562  info(0, "fakewap: Timeout while receiving from socket.\n");
563  if(nofailexit){
564  continue;
565  }else{
566  return fResponderIsDead ? -1 : 0;
567  }
568  /* continue if we got ack? */
569  }
570  }
571 
572  ret = udp_recvfrom_flags(fd, &datagram, &dummy, udp_flags);
573 
574  /* drop packet if packet loss simulation is enabled
575  */
576  if ((packet_loss > 0) && !(udp_flags&MSG_PEEK) && ((gw_rand() % 100) < packet_loss))
577  {
578  time_t currtime;
579  time(&currtime);
580  octstr_destroy(datagram);
581  octstr_destroy(dummy);
582  timeout -= (int)(currtime - calltime);
583  debug("fakewap", 0, "Dropped packet, new timeout %d", timeout);
584  continue;
585  }
586  if (ret == 0) {
587  octstr_get_many_chars((char*)msg, datagram, 0, octstr_len(datagram));
588  msg_len = octstr_len(datagram);
589  }
590  octstr_destroy(datagram);
591  octstr_destroy(dummy);
592 
593  if (ret == -1) {
594  error(0, "fakewap: recv() from socket failed");
595  return -1;
596  }
597 
598  if (hdr != NULL) {
599  /*
600  ** Ignore extra header bits, WAP GWs return different values
601  */
602  if ((msg_len >= hdr_len) &&
603  (GET_WTP_PDU_TYPE(msg) == GET_WTP_PDU_TYPE(hdr)) &&
604  (hdr_len <= 3 || !memcmp( msg+3, hdr+3, hdr_len-3 ))) {
605  break;
606  }
607  /*
608  ** Handle TID test, the answer is: Yes, we have an outstanding
609  ** transaction with this tid. We must turn on TID_OK-flag, too.
610  ** We have a separate tid verification PDU.
611  */
612  else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_ACK &&
613  GET_TID(msg) == tid) {
614  print_msg( "Received tid verification", msg, msg_len );
615  wap_msg_send( fd, WTP_TidVe, sizeof(WTP_TidVe), tid, 0, NULL, 0, NULL, 0 );
616  }
617  else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_ABORT) {
618  print_msg( "Received WTP Abort", msg, msg_len );
619  }
620  else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_RESULT) {
621  break;
622  }
623  else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_SEGM_RESULT) {
624  break;
625  }
626  else {
627  print_msg( "Received unexpected message", msg, msg_len );
628  }
629  fResponderIsDead = 0;
630  }
631  else {
632  hdr_len = 0;
633  break;
634  }
635  }
636  print_msg( "Received packet", msg, msg_len );
637  print_data( "Received data", msg, msg_len );
638 
639  if (data != NULL && msg_len > hdr_len) {
640  data_len = min( data_len, msg_len );
641  memcpy( data, msg, data_len);
642  }
643  else data_len = 0;
644  return data_len;
645 }
646 
647 
648 static int get_next_transaction(void) {
649  int i_this;
650  mutex_lock( mutex );
651  i_this = num_sent + 1;
652  if (max_send == MAX_SEND || num_sent < max_send) num_sent++;
653  mutex_unlock( mutex );
654  return i_this;
655 }
656 
657 int send_post(int fd, unsigned short tid, int tid_new, char* url)
658 {
659  unsigned char wtphdr[32];
660  unsigned char msgbuf[32*1024];
661  unsigned char contentlen_buf[8];
662  unsigned char reply_hdr[32];
663  long timeout = WAP_MSG_RECEIVE_TIMEOUT; /* wap gw is broken if no input */
664 
665  /* open post input file */
666  int infd = open(infile, O_RDONLY);
667  if (infd < 0)
668  panic(0, "fakewap: failed to open input file %s, errno %d", infile, errno);
669 
670  /* get size of input file */
671  struct stat fstats;
672  int ret = fstat(infd, &fstats);
673  if (ret)
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");
677  if (((transaction_mode==TXN_MODE_CONNECTION_LESS) && (fstats.st_size > (int)sizeof(msgbuf))) ||
678  ((transaction_mode==TXN_MODE_CONNECTION_ORIENTED) && (fstats.st_size > 256*SAR_SEGM_SIZE))) {
679  panic(0, "fakewap: input file size (%ld) is too large", fstats.st_size);
680  }
681 
682  int nsegs = (fstats.st_size-1) / SAR_SEGM_SIZE;
683  int tpi, gtr, ttr;
684  int psn = 0;
685 
686  /* build WTP header */
687  tpi = 1;
688  ttr = (nsegs==0) ? 1 : 0;
689  gtr = (ttr) ? 0 : 1;
690  memcpy(wtphdr, WTP_Invoke_Cl2MaxGrp, sizeof(WTP_Invoke_Cl2MaxGrp));
691  wtphdr[0] = (tpi << 7) | (WTP_PDU_INVOKE << 3) | (gtr << 2) | (ttr << 1);
692 
693  /* build WSP POST message */
694  Octstr *postmsg;
695  postmsg = octstr_create("");
697  msgbuf[0] = tid;
698  octstr_append_data(postmsg, (char*)msgbuf, 1);
699  }
700  memcpy(msgbuf, WSP_Post, sizeof(WSP_Post));
701  octstr_append_data(postmsg, (char*)msgbuf, sizeof(WSP_Post));
702 
703  /* add uri, content type, user agent, content length, accept */
704  int url_len = strlen(url);
705  int off = StoreVarInt( msgbuf, url_len );
706  int content_type_len = strlen(content_type) + 1; /* +1 for eos */
707  int contentlen_len;
708  char acceptAll[] = { 0x80, 0x80 };
709  contentlen_buf[0] = 0x8d; /* hdr type - content-length */
710  if (fstats.st_size <= 127)
711  {
712  contentlen_buf[1] = 0x80 | (char)fstats.st_size;
713  contentlen_len = 2;
714  } else
715  {
716  contentlen_buf[1] = 2;
717  contentlen_buf[2] = (char)(fstats.st_size >> 8);
718  contentlen_buf[3] = (char)(fstats.st_size);
719  contentlen_len = 4;
720  }
721  off += StoreVarInt( &msgbuf[off], content_type_len+octstr_len(useragent)+contentlen_len+sizeof(acceptAll) );
722  memcpy( &msgbuf[off], url, url_len );
723  off += url_len;
724  memcpy( &msgbuf[off], content_type, content_type_len );
725  off += content_type_len;
726  memcpy( &msgbuf[off], octstr_get_cstr(useragent), octstr_len(useragent) );
727  off += octstr_len(useragent);
728  memcpy( &msgbuf[off], contentlen_buf, contentlen_len );
729  off += contentlen_len;
730  memcpy( &msgbuf[off], acceptAll, sizeof(acceptAll) );
731  off += sizeof(acceptAll);
732  octstr_append_data(postmsg, (char*)msgbuf, off);
733 
734  /* add payload */
736  ret = read(infd, msgbuf, sizeof(msgbuf));
737  } else {
738  ret = read(infd, msgbuf, SAR_SEGM_SIZE);
739  }
740  if (ret <= 0)
741  panic(0, "fakewap: input file read error, errno %d", errno);
742 
743  debug("fakewap", 0, "Sending WSP_POST, url %s, Content-Type %s, User-Agent %s, Content-Length %lu",
744  url, content_type, octstr_get_cstr(useragent) + 1, fstats.st_size );
745 
747  ret = wap_msg_send( fd, NULL, 0, tid, tid_new,
748  (unsigned char*)octstr_get_cstr(postmsg), octstr_len(postmsg), msgbuf, ret );
749  if (ret == -1)
750  {
751  error(0, "fakewap: failure sending connection-less wtp invoke");
752  goto send_post_exit;
753  }
754  } else {
755  int retry = 0;
756  while (retry++ < SAR_MAX_RETRIES)
757  {
758  ret = wap_msg_send( fd, wtphdr, sizeof(WTP_Invoke_Cl2MaxGrp), tid, tid_new,
759  (unsigned char*)octstr_get_cstr(postmsg), octstr_len(postmsg), msgbuf, ret );
760  if (ret == -1)
761  {
762  error(0, "fakewap: failure sending connection-oriented wtp invoke");
763  goto send_post_exit;
764  }
765  /* receive invoke ack */
766  CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Ack, tid );
767  ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Ack),
768  tid, msgbuf, sizeof(msgbuf), timeout, 0 );
769  if (ret < 0)
770  {
771  if (retry>=SAR_MAX_RETRIES) {
772  error(0, "fakewap: failure receiving WTP Ack, psn %u, giving up", psn);
773  goto send_post_exit;
774  }
775  warning(0, "fakewap: timeout receiving WTP Ack, resend wtp invoke");
776  continue;
777  }
778  debug("fakewap", 0, "Received WTP_ACK, psn 0");
779  break;
780  }
781  }
782 
784 
785  while (!ttr)
786  {
787  int grppktnum = 0; /* packet in the group */
788  unsigned char grpwtphdr[SAR_GROUP_LEN][32];
789  unsigned char grpmsgbuf[SAR_GROUP_LEN][SAR_SEGM_SIZE];
790  int grpmsglen[SAR_GROUP_LEN];
791  int grpsize = 0;
792 
793  /* build segments for a new group */
794  gtr = 0;
795  while (!gtr && !ttr)
796  {
797  psn++;
798 
799  /* create wtp header */
800  memcpy(grpwtphdr[grppktnum], WTP_Segm_Invoke, sizeof(WTP_Segm_Invoke));
801  tpi = 0;
802  ttr = (nsegs==psn) ? 1 : 0;
803  gtr = ttr ? 0 : (psn+1)%SAR_GROUP_LEN ? 0 : 1;
804  grpwtphdr[grppktnum][0] = (tpi << 7) | (WTP_PDU_SEGM_INVOKE << 3) | (gtr << 2) | (ttr << 1);
805  grpwtphdr[grppktnum][3] = psn;
806 
807  /* read payload from file */
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);
811 
812  grppktnum++;
813  grpsize++;
814  }
815 
816  int retry = 0;
817  while (retry++ < SAR_MAX_RETRIES)
818  {
819  /* send a group of WTP Segmented Invoke messages */
820  for (grppktnum = 0; grppktnum < grpsize; grppktnum++)
821  {
822  debug("fakewap", 0, "Sending WTP_SEGM_INVOKE, psn %u, payload len %d",
823  psn-grpsize+grppktnum+1, grpmsglen[grppktnum]);
824  ret = wap_msg_send( fd, grpwtphdr[grppktnum], sizeof(WTP_Segm_Invoke), tid, tid_new,
825  NULL, 0, grpmsgbuf[grppktnum], grpmsglen[grppktnum] );
826  if (ret == -1)
827  {
828  error(0, "fakewap: failure sending wtp invoke");
829  goto send_post_exit;
830  }
831  }
832 
833  if (ttr) {
834  /* receive WTP Result */
835  CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Result, tid );
836  ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Result),
837  tid, msgbuf, sizeof(msgbuf), timeout, MSG_PEEK );
838  } else {
839  /* receive segm invoke ack for the group */
840  CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Segm_Ack, tid );
841  reply_hdr[4] = psn;
842  ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Segm_Ack),
843  tid, msgbuf, sizeof(msgbuf), timeout, 0 );
844  }
845  if (ret < 0)
846  {
847  if (retry>=SAR_MAX_RETRIES) {
848  error(0, "fakewap: failure receiving WTP Segm Ack, psn %u, giving up", psn);
849  goto send_post_exit;
850  }
851  warning(0, "fakewap: failure receiving WTP Segm Ack, psn %u, retrying", psn);
852  continue;
853  }
854 
855  if (ttr) {
856  debug("fakewap", 0, "Received WTP_RESULT");
857  } else {
858  debug("fakewap", 0, "Received WTP_ACK, psn %d", psn);
859  }
860  break;
861  } /* while (retry) */
862  } /* while (!ttr) */
863  } /* if (transaction_mode==CONNECTION_ORIENTED) */
864 
865 send_post_exit:
866  octstr_destroy(postmsg);
867  close(infd);
868  return ret;
869 }
870 
871 /*
872 ** Function (or thread) sets up a dgram socket. Then it loops: WTL/WSP
873 ** Connect, Get a url and Disconnect until all requests are have been done.
874 */
875 static void client_session( void * arg)
876 {
877  int fd;
878  int ret;
879  int url_len = 0, url_off = 0;
880  double nowsec, lastsec, tmp, sleepTime;
881  long uSleepTime;
882  struct timeval now;
883  struct timezone tz;
884  char * url;
885  unsigned char sid[20];
886  int sid_len = 0;
887  unsigned char buf[64*1024];
888  unsigned char reply_hdr[32];
889  long timeout = WAP_MSG_RECEIVE_TIMEOUT; /* wap gw is broken if no input */
890  static unsigned short tid = 0;
891  unsigned short old_tid;
892  int tid_new = 0;
893  int connection_retries = 0;
894  int i_this;
895 
896  fd = udp_client_socket();
897  if (fd == -1)
898  panic(0, "fakewap: Couldn't create socket.");
899 
900  if (src_addr.sin_addr.s_addr!=INADDR_ANY || src_addr.sin_port!=0)
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);
903 
904  /*
905  ** Loop until all URLs have been requested
906  */
907  for (;;) {
908  /*
909  * Get start time of this request
910  */
911  gettimeofday(&now, &tz);
912  lastsec = (double) now.tv_sec + now.tv_usec / 1e6;
913 
914  /*
915  * Get next transaction number or exit if too many transactions
916  */
917  i_this = get_next_transaction();
918  if (max_send != MAX_SEND && i_this > max_send) break;
919 
921  /*
922  * Connect, save sid from reply and finally ack the reply
923  */
924  old_tid = tid;
925  tid = next_tid(old_tid);
926  tid_new = (tid < old_tid); /* Did we wrap? */
927 
928  WSP_Connect[3] = 2 + octstr_len(useragent); /* set header length */
929  memcpy( buf, WSP_Connect, sizeof(WSP_Connect));
930  memcpy( &buf[sizeof(WSP_Connect)], octstr_get_cstr(useragent), octstr_len(useragent) );
931  ret = wap_msg_send( fd, WTP_Invoke_Cl2, sizeof(WTP_Invoke_Cl2), tid, tid_new,
932  buf, sizeof(WSP_Connect)+octstr_len(useragent), NULL, 0 );
933  if (ret == -1) panic(0, "fakewap: Send WSP_Connect failed");
934 
936  ret = wap_msg_recv( fd, reply_hdr, sizeof(WSP_ConnectReply),
937  tid, buf, sizeof(buf), timeout, 0 );
938  if (ret == -1) panic(0, "fakewap: Receive WSP_ConnectReply failed");
939 
940  if (ret > 2)
941  {
942  sid_len = ReadVarIntLen(&buf[4]);
943  memcpy( sid, &buf[4], sid_len);
944  debug("fakewap", 0, "Received WSP_ConnectReply, SessID %d", ReadVarIntVal(&buf[4]));
945  }
946 
947  /*
948  ** Send abort and continue if we get an unexpected reply
949  */
950  if (ret == 0) {
951  if (connection_retries++ > 3) {
952  panic(0, "fakewap: Cannot connect WAP GW!");
953  }
954  wap_msg_send( fd, WTP_Abort, sizeof(WTP_Abort), tid, tid_new, NULL, 0, NULL, 0 );
955  continue;
956  }
957  else {
958  connection_retries = 0;
959  }
960  ret = wap_msg_send( fd, WTP_Ack, sizeof(WTP_Ack), tid, tid_new, NULL, 0, NULL, 0 );
961 
962  if (ret == -1) panic(0, "fakewap: Send WTP_Ack failed");
963  }
964 
965  /*
966  ** Send WSP Get or Post for a given URL
967  */
968  old_tid = tid;
969  tid = next_tid(old_tid);
970  tid_new = (tid < old_tid); /* Did we wrap? */
971  url = choose_message(urls, num_urls);
972  url_len = strlen(url);
973  url_off = StoreVarInt( buf, url_len );
974  memcpy( buf+url_off, url, url_len );
975  buf[url_len+url_off] = 0x80; /* Accept: *\* */
976  buf[url_len+url_off+1] = 0x80; /* Accept: *\* */
977 
978  /* send WSP Post if an input file is specified */
979  if (infile)
980  {
981  ret = send_post(fd, tid, tid_new, url);
982  }
983  else /* send WSP Get */
984  {
986  unsigned char wsphdr[32];
987  wsphdr[0] = tid;
988  memcpy(&wsphdr[1], WSP_Get, sizeof(WSP_Get));
989  ret = wap_msg_send( fd, NULL, 0, tid, tid_new,
990  wsphdr, sizeof(WSP_Get)+1, buf, url_len+url_off+2 );
991  } else {
992  ret = wap_msg_send( fd, WTP_Invoke_Cl2, sizeof(WTP_Invoke_Cl2), tid, tid_new,
993  WSP_Get, sizeof(WSP_Get), buf, url_len+url_off );
994  }
995  if (ret == -1) break;
996  }
997 
998  Octstr* wspreply = octstr_create("");
1000  /* Connectionless - receive WSP Reply
1001  */
1002  reply_hdr[0] = tid;
1003  ret = wap_msg_recv( fd, reply_hdr, 1,
1004  tid, buf, sizeof(buf), timeout, 0 );
1005  if (ret == -1) break;
1006 
1007  octstr_append_data(wspreply, (char*)&buf[1], ret-1);
1008  }
1009  else {
1010  /* Connection-Oriented - reassemble WSP Reply from WTP segments
1011  */
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];
1015  int data_offset;
1016  memset(segment_len, 0, sizeof(segment_len));
1017  while (!ttr)
1018  {
1019  CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Result, tid );
1020  ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Result),
1021  tid, buf, sizeof(buf), timeout, 0 );
1022  timeout = WAP_MSG_RECEIVE_TIMEOUT;
1023  if (ret == -1) break;
1024 
1025  gtr = (buf[0] & 0x04) ? 1 : 0;
1026  ttr = (buf[0] & 0x02) ? 1 : 0;
1027  if (GET_WTP_PDU_TYPE(buf) == WTP_PDU_RESULT)
1028  {
1029  psn = 0;
1030  data_offset = 3;
1031  debug("fakewap", 0, "Received WTP_RESULT pdu, gtr %d, ttr %d, payload len %d", gtr, ttr, ret - data_offset);
1032  }
1033  else /* segmented result */
1034  {
1035  psn = buf[3];
1036  data_offset = 4;
1037  debug("fakewap", 0, "Received WTP_SEGM_RESULT pdu, psn %d, gtr %d, ttr %d, payload len %d", psn, gtr, ttr, ret - data_offset);
1038  }
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]);
1043 
1044  if (gtr || ttr || (psn < gtr_psn))
1045  {
1046  if (gtr || ttr)
1047  gtr_psn = psn;
1048  if (ttr)
1049  ttr_psn = psn;
1050 
1051  /* check for lost segments and send NACK */
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;
1057  if (num_lost > 0)
1058  {
1059  /* send NACK since some segments got lost */
1060  memcpy(buf, WTP_Nack, sizeof(WTP_Nack));
1061  buf[3] = num_lost;
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]);
1064  ret = wap_msg_send( fd, buf, sizeof(WTP_Nack)+num_lost, tid, tid_new, NULL, 0, NULL, 0 );
1065  ttr = 0;
1066  }
1067  else if (psn > 0)
1068  {
1069  /* send WTP Ack for a group of segments */
1070  WTP_Segm_Ack[4] = gtr_psn;
1071  debug("fakewap", 0, "Sending WTP_ACK pdu, gtr_psn %d", gtr_psn);
1072  ret = wap_msg_send( fd, WTP_Segm_Ack, sizeof(WTP_Segm_Ack), tid, tid_new, NULL, 0, NULL, 0 );
1073  }
1074  else
1075  {
1076  /* send regular WTP Ack for first segment */
1077  debug("fakewap", 0, "Sending WTP_ACK pdu, psn 0");
1078  ret = wap_msg_send( fd, WTP_Ack, sizeof(WTP_Ack), tid, tid_new, NULL, 0, NULL, 0 );
1079  }
1080  if (ret == -1)
1081  break;
1082  if ((ttr_psn >= 0) && (num_lost==0)) {
1083  /* received all segments */
1084  ttr = 1;
1085  }
1086  }
1087  }
1088  if (!ttr) {
1089  panic(0, "fakewap: Failed to receive entire message!?!");
1090  break;
1091  }
1092 
1093  for (psn = 0; psn <= gtr_psn; psn++)
1094  octstr_append_data(wspreply, (char*)segment_data[psn], segment_len[psn]);
1095  }
1096 
1097  /* validate WSP Reply
1098  */
1099  WSP_PDU* wsppdu = wsp_pdu_unpack(wspreply);
1100  if (!wsppdu)
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));
1104  }
1105  else
1106  {
1107  struct Reply* wspreply = &wsppdu->u.Reply;
1108  int status;
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);
1113  else
1114  status = (wspreply->status >> 4) * 100 - 100 + (wspreply->status & 0x0f);
1115  if (status != 200) {
1116  warning(0, "fakewap: Warning - received reply with status %d", status);
1117  } else {
1118  info(0, "fakewap: Received WSP Reply with status code 200OK");
1119  }
1120 
1121  /* if output file arg was specified write the received wsp payload to file */
1122  if (outfile)
1123  {
1124  int outfd = creat(outfile, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
1125  if (outfd < 0) {
1126  panic(0, "fakewap: failed to create output file %s, errno %d", outfile, errno);
1127  }
1128 
1129  ret = write(outfd, octstr_get_cstr(wspreply->data), octstr_len(wspreply->data));
1130  if (ret < 0) {
1131  panic(0, "fakewap: failed to write to output file %s, errno %d", outfile, errno);
1132  }
1133 
1134  close(outfd);
1135  debug("fakewap", 0, "Wrote %d bytes of response payload to output file %s", ret, outfile);
1136  }
1137  }
1138 
1140  /*
1141  ** Finally disconnect with the sid returned by connect reply
1142  */
1143  {
1144  ret = wap_msg_send( fd, WTP_Invoke_Cl0, sizeof(WTP_Invoke_Cl0), tid, tid_new,
1145  WSP_Disconnect, sizeof(WSP_Disconnect), sid, sid_len );
1146 
1147  if (ret == -1) break;
1148  }
1149  }
1150 
1151  /*
1152  ** Get end time of the request
1153  */
1154  gettimeofday(&now, &tz);
1155  nowsec = (double) now.tv_sec + now.tv_usec / 1e6;
1156  tmp = nowsec - lastsec; /* Duration of request */
1157  sleepTime = interval-tmp; /* Amount of time left to sleep */
1158  uSleepTime = sleepTime * 1e6;
1159 
1160  mutex_lock( mutex );
1161  if (tmp < besttime) besttime = tmp;
1162  if (tmp > worsttime) worsttime = tmp;
1163  totaltime += tmp;
1164  mutex_unlock( mutex );
1165 
1166  if (brief == 1)
1167  {
1168  info(0, "fakewap: finished session # %d", i_this);
1169  }
1170 
1171  /*
1172  ** If we've done all the requests, then don't bother to sleep
1173  */
1174  if (i_this >= max_send) break;
1175 
1176  if (tmp < (double)interval) {
1177  usleep( uSleepTime );
1178  }
1179  }
1180  close(fd);
1181 
1182  /* The last end_time stays */
1183  mutex_lock( mutex );
1184  time(&end_time);
1185  mutex_unlock( mutex );
1186 }
1187 
1188 
1189 static void help(void) {
1190  info(0, "\n%s", usage);
1191 }
1192 
1193 
1194 
1195 /* The main program. */
1196 int main(int argc, char **argv)
1197 {
1198  int i, opt;
1199  double delta;
1200  int proto_version, tcl, tid_new;
1201 #ifdef SunOS
1202  struct sigaction alrm;
1203 
1204  alrm.sa_handler = SIG_IGN;
1205 
1206  sigaction(SIGALRM,&alrm,NULL);
1207 #endif
1208 
1209  gwlib_init();
1210 
1211  proto_version = 0;
1212  tcl = 2;
1213  tid_new = 0;
1214 
1215  hostname = octstr_create("localhost");
1216 
1217  /* restart args scanning */
1218  optind = 1;
1219 
1220  /* reset globals */
1221  interval = 1.0;
1222  port = 0;
1223  max_send = 1;
1224  tid_addition = 1;
1225  threads = 1;
1226  num_sent = 0;
1227  totaltime = 0;
1228  besttime = 1000000L;
1229  worsttime = 0;
1230  brief = 0;
1231  verbose = 0;
1232  test_separation = 0;
1233  infile = NULL;
1234  outfile = NULL;
1235  content_type = "text/plain";
1236  src_addr.sin_family = AF_INET;
1237  src_addr.sin_addr.s_addr = INADDR_ANY;
1238  src_addr.sin_port = 0;
1240  packet_loss = 0;
1241 
1242  /* create default user agent header prepend with a9, and end with 0 */
1243  const char firstchar[] = {0xa9, 0}; /* code value for user agent header */
1244  Octstr* temp = octstr_create("fakewap");
1245  useragent = octstr_create(firstchar);
1246  octstr_append_data(useragent, octstr_get_cstr(temp), octstr_len(temp) );
1247  octstr_append_data(useragent, "\0", 1 );
1248 
1249  while ((opt = getopt(argc, argv, "Fhc:g:p:m:i:t:V:t:nsd:A:C:D:I:M:P:w:l:")) != EOF)
1250  {
1251  switch (opt) {
1252  case 'g':
1253  octstr_destroy(hostname);
1254  hostname = octstr_create(optarg);
1255  break;
1256 
1257  case 'p':
1258  port = atoi(optarg);
1259  break;
1260 
1261  case 'm':
1262  max_send = atoi(optarg);
1263  break;
1264 
1265  case 'i':
1266  interval = atof(optarg);
1267  break;
1268 
1269  case 'c':
1270  threads = atoi(optarg);
1271  break;
1272 
1273  case 'V':
1274  proto_version = atoi(optarg);
1275  break;
1276 
1277  case 't':
1278  tcl = atoi(optarg);
1279  break;
1280 
1281  case 'n':
1282  tid_new = 1;
1283  break;
1284 
1285  case 's':
1286  test_separation = 1;
1287  break;
1288 
1289  case 'd':
1290  tid_addition = atoi(optarg);
1291  break;
1292 
1293  case 'D':
1294  brief = (atoi(optarg) >= 1);
1295  verbose = (atoi(optarg) >= 2);
1296  break;
1297 
1298  case 'h':
1299  help();
1300  exit(0);
1301  break;
1302 
1303  case 'F':
1304  nofailexit=1;
1305  break;
1306 
1307  case 'w':
1308  outfile = optarg;
1309  break;
1310 
1311  case 'A':
1312  octstr_destroy(useragent);
1313  octstr_destroy(temp);
1314  /* create user agent header prepend with a9, and end with 0 */
1315  useragent = octstr_create(firstchar);
1316  temp = octstr_create(optarg);
1317  octstr_append_data(useragent, octstr_get_cstr(temp), octstr_len(temp) );
1318  octstr_append_data(useragent, "\0", 1 );
1319  break;
1320 
1321  case 'C':
1322  if (!strcmp("mms", optarg))
1323  content_type = "application/vnd.wap.mms-message";
1324  else
1325  content_type = "text/plain";
1326  break;
1327 
1328  case 'I':
1329  {
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);
1335  if (ret==5)
1336  src_addr.sin_port = htons(srcport);
1337  break;
1338  }
1339 
1340  case 'M':
1341  transaction_mode = atoi(optarg);
1342  if ((transaction_mode!=0) && (transaction_mode!=1)) {
1343  error(0, "fakewap: invalid transaction mode %s", optarg);
1344  return -1;
1345  }
1346  break;
1347 
1348  case 'P':
1349  infile = optarg;
1350  break;
1351 
1352  case 'l':
1353  packet_loss = atoi(optarg);
1354  if ((packet_loss < 0) && (packet_loss >=99)) {
1355  error(0, "fakewap: invalid packet loss rate %s, expect 0-99", optarg);
1356  return -1;
1357  }
1358  break;
1359 
1360  case '?':
1361  default:
1362  error(0, "fakewap: Unknown option %c", opt);
1363  help();
1364  panic(0, "fakewap: Stopping.");
1365  }
1366  }
1367 
1368  time(&start_time);
1369 
1370  if (optind >= argc)
1371  panic(0, "%s", usage);
1372 
1373  if ((!brief) && (!verbose))
1374  {
1376  }
1377 
1378  if (port==0) {
1380  port = 9200;
1381  else
1382  port = 9201;
1383  }
1384 
1385  WTP_Invoke_Cl2[3] |= (proto_version&3)<<6;
1386  /* WTP_Invoke_Cl2[0] += (pdu_type&15)<<3; */
1387  WTP_Invoke_Cl2[3] |= tcl&3;
1388  WTP_Invoke_Cl2[3] |= (tid_new&1)<<5;
1389 
1390  gateway_addr = udp_create_address(hostname, port);
1391 
1392  urls = argv + optind;
1393  num_urls = argc - optind;
1394 
1395  srand((unsigned int) time(NULL));
1396 
1397  mutex = (Mutex*)mutex_create();
1398 
1399  info(0, "fakewap: starting");
1400 
1401  if (threads < 1) threads = 1;
1402 
1403  /*
1404  ** Start 'extra' client threads and finally execute the
1405  ** session of main thread
1406  */
1407  for (i = 1; i < threads; i++)
1409  client_session(NULL);
1410 
1411  /* Wait for the other sessions to complete */
1413 
1414  info(0, "fakewap: complete.");
1415  info(0, "fakewap: %d client threads made total %d transactions.",
1416  threads, num_sent);
1417  delta = difftime(end_time, start_time);
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",
1423 
1424  octstr_destroy(hostname);
1425  octstr_destroy(gateway_addr);
1426  mutex_destroy(mutex);
1427 
1428  gwlib_shutdown();
1429  return 0;
1430 }
static char * choose_message(char **urls, int num_urls)
Definition: fakewap.c:364
int max_send
Definition: fakewap.c:236
void error(int err, const char *fmt,...)
Definition: log.c:612
static void help(void)
Definition: fakewap.c:1189
void info(int err, const char *fmt,...)
Definition: log.c:636
static unsigned short next_tid(unsigned short old_tid)
Definition: fakewap.c:372
#define min(a, b)
Definition: fakewap.c:326
unsigned char WSP_ConnectReply[]
Definition: fakewap.c:271
#define WTP_PDU_INVOKE
Definition: fakewap.c:204
Definition: http.c:1998
unsigned char WSP_Post[]
Definition: fakewap.c:277
union wsp_pdu::@89 u
int test_separation
Definition: fakewap.c:246
static void set_tid_new(Octstr *hdr)
Definition: fakewap.c:316
void octstr_append_data(Octstr *ostr, const char *data, long len)
Definition: octstr.c:1495
double worsttime
Definition: fakewap.c:242
unsigned char WTP_Segm_Invoke[]
Definition: fakewap.c:291
int threads
Definition: fakewap.c:239
unsigned char WTP_Segm_Result[]
Definition: fakewap.c:288
static void print_data(const char *trace, unsigned char *msg, int msg_len)
Definition: fakewap.c:348
#define mutex_unlock(m)
Definition: thread.h:136
#define WTP_PDU_ABORT
Definition: fakewap.c:207
#define GET_WTP_PDU_TYPE(hdr)
Definition: fakewap.c:198
unsigned char WSP_Reply[]
Definition: fakewap.c:275
#define GET_TID(hdr)
Definition: fakewap.c:300
unsigned char WTP_Invoke_Cl2[]
Definition: fakewap.c:284
static int get_next_transaction(void)
Definition: fakewap.c:648
#define mutex_create()
Definition: thread.h:96
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)
Definition: fakewap.c:436
int brief
Definition: fakewap.c:243
#define TXN_MODE_CONNECTION_LESS
Definition: fakewap.c:218
char ** urls
Definition: fakewap.c:229
int optind
Definition: attgetopt.c:80
unsigned char WTP_Ack[]
Definition: fakewap.c:280
static void print_msg(const char *trace, unsigned char *msg, int msg_len)
Definition: fakewap.c:334
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)
Definition: fakewap.c:540
unsigned char WTP_Abort[]
Definition: fakewap.c:282
#define WTP_PDU_RESULT
Definition: fakewap.c:205
int packet_loss
Definition: fakewap.c:252
char * outfile
Definition: fakewap.c:248
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
int send_post(int fd, unsigned short tid, int tid_new, char *url)
Definition: fakewap.c:657
void gwthread_join_every(gwthread_func_t *func)
unsigned char WSP_Concat[]
Definition: fakewap.c:278
#define WTP_PDU_ACK
Definition: fakewap.c:206
static void set_tid(Octstr *hdr, int tid)
Definition: fakewap.c:306
unsigned short tid_addition
Definition: fakewap.c:237
int getopt(int argc, char **argv, char *opts)
Definition: attgetopt.c:84
#define SAR_SEGM_SIZE
Definition: fakewap.c:221
struct sockaddr_in src_addr
Definition: fakewap.c:250
#define WAP_MSG_RECEIVE_TIMEOUT
Definition: fakewap.c:224
#define TXN_MODE_CONNECTION_ORIENTED
Definition: fakewap.c:219
int verbose
Definition: fakewap.c:244
unsigned char WSP_Connect[]
Definition: fakewap.c:260
int udp_recvfrom_flags(int s, Octstr **datagram, Octstr **addr, int sockrcvflags)
Definition: socket.c:588
#define SAR_MAX_RETRIES
Definition: fakewap.c:223
int udp_client_socket(void)
Definition: socket.c:464
double besttime
Definition: fakewap.c:242
int num_sent
Definition: fakewap.c:240
time_t start_time
Definition: fakewap.c:241
void log_set_output_level(enum output_level level)
Definition: log.c:217
Mutex * mutex
Definition: fakewap.c:238
static int ReadVarIntVal(const unsigned char *buf)
Definition: fakewap.c:419
#define WSP_PDU_DISCONNECT
Definition: fakewap.c:214
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
unsigned char WTP_Nack[]
Definition: fakewap.c:290
#define WSP_PDU_POST
Definition: fakewap.c:216
int num_urls
Definition: fakewap.c:230
Octstr * useragent
Definition: fakewap.c:253
void warning(int err, const char *fmt,...)
Definition: log.c:624
#define SAR_GROUP_LEN
Definition: fakewap.c:222
time_t end_time
Definition: fakewap.c:241
Octstr * hostname
Definition: fakewap.c:232
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
#define WSP_PDU_GET
Definition: fakewap.c:215
void mutex_destroy(Mutex *mutex)
Definition: thread.c:97
const char * content_type
Definition: fakewap.c:249
unsigned char WTP_Invoke_Cl2MaxGrp[]
Definition: fakewap.c:285
double interval
Definition: fakewap.c:234
static char usage[]
Definition: fakewap.c:143
static void client_session(void *arg)
Definition: fakewap.c:875
unsigned char WTP_TidVe[]
Definition: fakewap.c:281
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
unsigned char WTP_Result[]
Definition: fakewap.c:287
Definition: octstr.c:118
int read_available(int fd, long wait_usec)
Definition: socket.c:406
unsigned char WSP_Get[]
Definition: fakewap.c:272
int nofailexit
Definition: fakewap.c:245
Definition: log.h:69
char * infile
Definition: fakewap.c:247
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
int type
Definition: wsp_pdu.h:87
char * optarg
Definition: attgetopt.c:82
static int StoreVarInt(unsigned char *buf, unsigned long varInt)
Definition: fakewap.c:381
#define panic
Definition: log.h:87
int transaction_mode
Definition: fakewap.c:251
#define WSP_PDU_CONNECT
Definition: fakewap.c:212
static int ReadVarIntLen(const unsigned char *buf)
Definition: fakewap.c:408
void gwlib_shutdown(void)
Definition: gwlib.c:94
Definition: thread.h:76
int main(int argc, char **argv)
Definition: fakewap.c:1196
int udp_sendto(int s, Octstr *datagram, Octstr *addr)
Definition: socket.c:567
void gwlib_init(void)
Definition: gwlib.c:78
#define MAX_SEND
Definition: fakewap.c:132
#define WTP_PDU_NACK
Definition: fakewap.c:210
#define CONSTRUCT_EXPECTED_REPLY_HDR(dest, template, tid)
Definition: fakewap.c:301
Octstr * gateway_addr
Definition: fakewap.c:233
static int get_wtp_pdu_type(Octstr *hdr)
Definition: fakewap.c:199
unsigned char WTP_Segm_Ack[]
Definition: fakewap.c:289
unsigned char WTP_Invoke_Cl0[]
Definition: fakewap.c:283
static Octstr * url
Definition: test_xmlrpc.c:84
void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len)
Definition: octstr.c:423
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
#define mutex_lock(m)
Definition: thread.h:130
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:413
int gw_rand(void)
Definition: protected.c:174
unsigned char WSP_Disconnect[]
Definition: fakewap.c:276
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
#define WTP_PDU_SEGM_INVOKE
Definition: fakewap.c:208
double totaltime
Definition: fakewap.c:242
WSP_PDU * wsp_pdu_unpack(Octstr *data)
Definition: wsp_pdu.c:178
Octstr * udp_create_address(Octstr *host_or_ip, int port)
Definition: socket.c:517
#define WTP_PDU_SEGM_RESULT
Definition: fakewap.c:209
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.