Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
fakesmsc.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  * fakesmsc.c - simulate an SMS center, using a trivial protocol
59  *
60  * The protocol:
61  *
62  * Client sends each message on its own line (terminated with \r\n or \n).
63  * The line begins with 3 space-separated fields:
64  * sender's phone number, receiver's phone number,
65  * type of message. Type of message can be one of "text", "data", or
66  * "udh". If type == "text", the rest of the line is taken as the message.
67  * If type == "data", the next field is taken to be the text of the
68  * message in urlcoded form. Space is coded as '+'. If type == "udh",
69  * the following 2 fields are taken to be the UDH and normal portions
70  * in urlcoded form. Space is again coded as '+'.
71  * The server sends replies back in the same format.
72  *
73  * Lars Wirzenius, later edition by Kalle Marjola
74  * Largely rewritten by Uoti Urpala
75  */
76 
77 static char usage[] = "\n\
78 Usage: fakesmsc [-H host] [-r port] [-i interval] [-m max] [-z <type>] <msg> ... \n\
79 \n\
80 * 'host' and 'port' define bearerbox connection (default localhost:10000),\n\
81 * 'interval' is time in seconds (floats allowed) between generated messages,\n\
82 * 'max' is the total number sent (-1, default, means unlimited),\n\
83 * <type> bitmask of which elements to add randomized numbers for MO messages,\n\
84 * 1: src no, 2: recv no, 4: last text element,\n\
85 * where the given static elements in <msg> are used as constant prefixes,\n\
86 * <msg> is message to send, if several are given, they are sent randomly.\n\
87 \n\
88 msg format: \"sender receiver type(text|data|ucs2|udh-data|udh-text|route|dlr-mask) [udhdata|route|dlrmask] msgdata\"\n\
89 \n\
90 Type \"text\" means plaintext msgdata, \"data\" urlcoded, \"udh\" url-encoded udh+msg,\n\
91 \"ucs2\" unicode url-encoded msgdata and \"route\" means smsbox-id routed plaintext msgdata\n\
92 Examples: \n\
93 \n\
94 fakesmsc -m 1 \"123 345 udh %04udh%3f message+data+here\"\n\
95 fakesmsc -m 1 \"123 345 route smsbox1 message+data+here\"\n\
96 fakesmsc -i 0.01 -m 1000 \"123 345 text nop\" \"1 2 text another message here\"\n\
97 fakesmsc -z 7 -m 1000 \"123<rand> 345<rand> text nop <rand>\"\n\
98 \n\
99 Server replies are shown in the same message format.\n";
100 
101 #include <errno.h>
102 #include <math.h>
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <string.h>
106 #include <time.h>
107 #include <unistd.h>
108 #include <sys/time.h>
109 #include <limits.h>
110 #include <signal.h>
111 
112 #include <sys/param.h>
113 
114 #include "gwlib/gwlib.h"
115 
116 #define IN_BUFSIZE 256 /* Buffer size for stdin */
117 #define IN_TIMEOUT 1 /* Timeout for stdin */
118 
119 
120 static int port = 10000;
121 static Octstr *host;
122 static long max_send = LONG_MAX;
123 static double interval = 1.0;
124 static int sigint_received;
125 static int rnd = 0;
126 
127 static void signal_handler(int signum)
128 {
129  if (signum == SIGINT)
130  sigint_received = 1;
131  else
132  panic(0, "Caught signal with no handler?!");
133 }
134 
135 
136 static void setup_signal_handlers(void)
137 {
138  struct sigaction act;
139 
140  act.sa_handler = signal_handler;
141  sigemptyset(&act.sa_mask);
142  act.sa_flags = 0;
143  sigaction(SIGINT, &act, NULL);
144 }
145 
146 
147 /* Choose a random message from a table of messages. */
148 static Octstr *choose_message(Octstr **msgs, int num_msgs)
149 {
150  /* the following doesn't give an even distribution, but who cares */
151  return msgs[gw_rand() % num_msgs];
152 }
153 
154 
155 /* Get current time, as double. */
156 static double get_current_time(void)
157 {
158  struct timezone tz;
159  struct timeval now;
160 
161  gettimeofday(&now, &tz);
162  return (double) now.tv_sec + now.tv_usec / 1e6;
163 }
164 
165 /* our arguments */
166 static int check_args(int i, int argc, char **argv)
167 {
168  if (strcmp(argv[i], "-r")==0 || strcmp(argv[i], "--port")==0)
169  port = atoi(argv[i+1]);
170  else if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "--host"))
171  host = octstr_create(argv[i+1]);
172  else if (strcmp(argv[i], "-m")==0 || strcmp(argv[i], "--messages")==0) {
173  max_send = atoi(argv[i+1]);
174  if (max_send < 0)
175  max_send = LONG_MAX;
176  }
177  else if (strcmp(argv[i], "-i")==0 || strcmp(argv[i], "--interval")==0)
178  interval = atof(argv[i+1]);
179  else if (strcmp(argv[i], "-z")==0 || strcmp(argv[i], "--randomize")==0) {
180  rnd = atoi(argv[i+1]);
181  if (rnd < 0 || rnd > 7)
182  rnd = 0;
183  }
184  else {
185  panic(0, "%s", usage);
186  return 0;
187  }
188 
189  return 1;
190 }
191 
192 /* randomization of message elements */
193 static Octstr *randomize(Octstr *os)
194 {
195  Octstr *msg = octstr_create("");
196  List *words = octstr_split_words(os);
197  int i;
198 
199  /* randomize source and receiver number */
200  octstr_format_append(msg, "%S", gwlist_get(words, 0));
201  if (rnd & 0x1)
202  octstr_format_append(msg, "%d", gw_rand());
203 
204  octstr_format_append(msg, " %S", gwlist_get(words, 1));
205  if (rnd & 0x2)
206  octstr_format_append(msg, "%d", gw_rand());
207 
208  for (i = 2; i < gwlist_len(words); i++)
209  octstr_format_append(msg, " %S", gwlist_get(words, i));
210 
211  if (rnd & 0x4)
212  octstr_format_append(msg, " %d", gw_rand());
213 
214  octstr_append_char(msg, 10); /* End of line */
215 
217 
218  return msg;
219 }
220 
221 /* The main program. */
222 int main(int argc, char **argv)
223 {
225  Octstr *line;
226  Octstr **msgs;
227  int i;
228  int mptr, num_msgs;
229  long num_received, num_sent;
230  double first_received_at, last_received_at;
231  double first_sent_at, last_sent_at;
232  double start_time, end_time;
233  double delta;
234  int interactive, maxfd;
235  char *cptr;
236  char buffer[IN_BUFSIZE];
237  fd_set rset;
238  struct timeval alarm;
239  FILE *fp;
240 
241  gwlib_init();
243  host = octstr_create("localhost");
244  start_time = get_current_time();
245 
246  mptr = get_and_set_debugs(argc, argv, check_args);
247  num_msgs = argc - mptr;
248 
249  interactive = 0;
250  msgs = NULL;
251  fp = NULL;
252  if (num_msgs <= 0) {
253  interactive = 1;
254  num_msgs = 0;
255  info(0, "Entering interactive mode. Type your message on the command line");
256  /* set up file pointer to stdin */
257  fp = stdin;
258  /* initialize set for select */
259  FD_ZERO(&rset);
260  } else {
261  msgs = gw_malloc(sizeof(Octstr *) * num_msgs);
262  for (i = 0; i < num_msgs; i ++) {
263  msgs[i] = octstr_create(argv[mptr + i]);
264  octstr_append_char(msgs[i], 10); /* End of line */
265  }
266  info(0, "Host %s Port %d interval %.3f max-messages %ld",
268 
269  srand((unsigned int) time(NULL));
270  }
271  info(0, "fakesmsc starting");
272  server = conn_open_tcp(host, port, NULL);
273  if (server == NULL)
274  panic(0, "Failed to open connection");
275 
276  num_sent = 0;
277  num_received = 0;
278 
279  first_received_at = 0;
280  first_sent_at = 0;
281  last_received_at = 0;
282  last_sent_at = 0;
283 
284  /* infinitely loop */
285  while (1) {
286  /* Are we on interactive mode? */
287  if (interactive == 1) {
288  /* Check if we need to clean things up beforehand */
289  if ( num_msgs > 0 ) {
290  for (i = 0; i < num_msgs; i ++)
291  octstr_destroy(msgs[i]);
292  gw_free(msgs);
293  num_msgs = 0;
294  }
295 
296  /* we want either the file pointer or timer */
297  FD_SET(fileno(fp), &rset);
298  /* get the largest file descriptor */
299  maxfd = fileno(fp) + 1;
300 
301  /* set timer to go off in 3 seconds */
302  alarm.tv_sec = IN_TIMEOUT;
303  alarm.tv_usec = 0;
304 
305  if (select(maxfd, &rset, NULL, NULL, &alarm) == -1)
306  goto over;
307  /* something went off, let's see if it's stdin */
308  if (FD_ISSET(fileno(fp), &rset)) { /* stdin is readable */
309  cptr = fgets(buffer, IN_BUFSIZE, stdin);
310  if (!cptr)
311  goto over;
312  if( strlen( cptr ) < 2 )
313  goto rcv;
314  } else { /* timer kicked in */
315  goto rcv;
316  }
317  num_msgs = 1;
318  msgs = gw_malloc(sizeof(Octstr*));
319  msgs[0] = octstr_create(cptr);
320  }
321  /* if we still have something to send as MO message */
322  if (num_sent < max_send) {
323  Octstr *os = choose_message(msgs, num_msgs);
324  Octstr *msg = rnd > 0 ? randomize(os) : os;
325 
326  if (conn_write(server, msg) == -1)
327  panic(0, "write failed");
328 
329  ++num_sent;
330  if (num_sent == max_send)
331  info(0, "fakesmsc: sent message %ld", num_sent);
332  else
333  debug("send", 0, "fakesmsc: sent message %ld", num_sent);
334 
335  if (rnd > 0)
336  octstr_destroy(msg);
337 
338  last_sent_at = get_current_time();
339  if (first_sent_at == 0)
340  first_sent_at = last_sent_at;
341  }
342 rcv:
343  do {
344  delta = interval * num_sent - (get_current_time() - first_sent_at);
345  if (delta < 0)
346  delta = 0;
347  if (num_sent >= max_send)
348  delta = -1;
349  conn_wait(server, delta);
350  if (conn_error(server) || conn_eof(server) || sigint_received)
351  goto over;
352 
353  /* read as much as the smsc module provides us */
354  while ((line = conn_read_line(server))) {
355  last_received_at = get_current_time();
356  if (first_received_at == 0)
357  first_received_at = last_received_at;
358  ++num_received;
359  if (num_received == max_send) {
360  info(0, "Got message %ld: <%s>", num_received,
361  octstr_get_cstr(line));
362  } else {
363  debug("receive", 0, "Got message %ld: <%s>", num_received,
364  octstr_get_cstr(line));
365  }
366  octstr_destroy(line);
367  }
368  } while (delta > 0 || num_sent >= max_send);
369  }
370 
371 over:
372  conn_destroy(server);
373 
374  /* destroy the MO messages */
375  for (i = 0; i < num_msgs; i ++)
376  octstr_destroy(msgs[i]);
377  gw_free(msgs);
378 
379  end_time = get_current_time();
380 
381  info(0, "fakesmsc: %ld messages sent and %ld received", num_sent, num_received);
382  info(0, "fakesmsc: total running time %.1f seconds", end_time - start_time);
383  delta = last_sent_at - first_sent_at;
384  if (delta == 0)
385  delta = .01;
386  if (num_sent > 1)
387  info(0, "fakesmsc: from first to last sent message %.1f s, "
388  "%.1f msgs/s", delta, (num_sent - 1) / delta);
389  delta = last_received_at - first_received_at;
390  if (delta == 0)
391  delta = .01;
392  if (num_received > 1)
393  info(0, "fakesmsc: from first to last received message %.1f s, "
394  "%.1f msgs/s", delta, (num_received - 1) / delta);
395  info(0, "fakesmsc: terminating");
396 
397  return 0;
398 }
399 
Octstr * conn_read_line(Connection *conn)
Definition: conn.c:1126
void info(int err, const char *fmt,...)
Definition: log.c:636
#define IN_TIMEOUT
Definition: fakesmsc.c:117
Definition: http.c:1998
Connection * conn_open_tcp(Octstr *host, int port, Octstr *our_host)
Definition: conn.c:488
static Octstr * choose_message(Octstr **msgs, int num_msgs)
Definition: fakesmsc.c:148
static void setup_signal_handlers(void)
Definition: fakesmsc.c:136
static char usage[]
Definition: fakesmsc.c:77
long gwlist_len(List *list)
Definition: list.c:166
void * gwlist_get(List *list, long pos)
Definition: list.c:292
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1515
int main(int argc, char **argv)
Definition: fakesmsc.c:222
static Octstr * randomize(Octstr *os)
Definition: fakesmsc.c:193
static Octstr * host
Definition: fakesmsc.c:121
static double interval
Definition: fakesmsc.c:123
static void signal_handler(int signum)
Definition: fakesmsc.c:127
int conn_eof(Connection *conn)
Definition: conn.c:697
static long max_send
Definition: fakesmsc.c:122
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static time_t start_time
Definition: bearerbox.c:148
int conn_write(Connection *conn, Octstr *data)
Definition: conn.c:1043
int num_sent
Definition: fakewap.c:240
void conn_destroy(Connection *conn)
Definition: conn.c:619
List * octstr_split_words(const Octstr *ostr)
Definition: octstr.c:1600
time_t end_time
Definition: fakewap.c:241
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:334
static int check_args(int i, int argc, char **argv)
Definition: fakesmsc.c:166
Definition: octstr.c:118
int conn_wait(Connection *conn, double seconds)
Definition: conn.c:896
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
#define panic
Definition: log.h:87
#define IN_BUFSIZE
Definition: fakesmsc.c:116
void octstr_format_append(Octstr *os, const char *fmt,...)
Definition: octstr.c:2505
static void server(int lport, int pport)
static int rnd
Definition: fakesmsc.c:125
void gwlib_init(void)
Definition: gwlib.c:78
int conn_error(Connection *conn)
Definition: conn.c:708
static int sigint_received
Definition: fakesmsc.c:124
int get_and_set_debugs(int argc, char **argv, int(*find_own)(int index, int argc, char **argv))
Definition: utils.c:626
int gw_rand(void)
Definition: protected.c:174
Definition: list.c:102
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static double get_current_time(void)
Definition: fakesmsc.c:156
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.