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

fakesmsc.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  * fakesmsc.c - simulate an SMS center, using a trivial protocol
00059  *
00060  * The protocol:
00061  *
00062  *  Client sends each message on its own line (terminated with \r\n or \n).
00063  *  The line begins with 3 space-separated fields:
00064  *  sender's phone number, receiver's phone number,
00065  *  type of message. Type of message can be one of "text", "data", or
00066  *  "udh". If type == "text", the rest of the line is taken as the message.
00067  *  If type == "data", the next field is taken to be the text of the
00068  *  message in urlcoded form. Space is coded as '+'. If type == "udh",
00069  *  the following 2 fields are taken to be the UDH and normal portions
00070  *  in urlcoded form. Space is again coded as '+'.
00071  *  The server sends replies back in the same format.
00072  *
00073  * Lars Wirzenius, later edition by Kalle Marjola
00074  * Largely rewritten by Uoti Urpala
00075  */
00076 
00077 static char usage[] = "\n\
00078 Usage: fakesmsc [-H host] [-r port] [-i interval] [-m max] [-z <type>] <msg> ... \n\
00079 \n\
00080 * 'host' and 'port' define bearerbox connection (default localhost:10000),\n\
00081 * 'interval' is time in seconds (floats allowed) between generated messages,\n\
00082 * 'max' is the total number sent (-1, default, means unlimited),\n\
00083 * <type> bitmask of which elements to add randomized numbers for MO messages,\n\
00084 *        1: src no, 2: recv no, 4: last text element,\n\
00085 *        where the given static elements in <msg> are used as constant prefixes,\n\
00086 * <msg> is message to send, if several are given, they are sent randomly.\n\
00087 \n\
00088 msg format: \"sender receiver type(text/data/udh/route) [udhdata|route] msgdata\"\n\
00089 \n\
00090 Type \"text\" means plaintext msgdata, \"data\" urlcoded, \"udh\" urlcoded udh+msg\n\
00091 and \"route\" means smsbox-id routed plaintext msgdata\n\
00092 Examples: \n\
00093 \n\
00094 fakesmsc -m 1 \"123 345 udh %04udh%3f message+data+here\"\n\
00095 fakesmsc -m 1 \"123 345 route smsbox1 message+data+here\"\n\
00096 fakesmsc -i 0.01 -m 1000 \"123 345 text nop\" \"1 2 text another message here\"\n\
00097 fakesmsc -z 7 -m 1000 \"123<rand> 345<rand> text nop <rand>\"\n\
00098 \n\
00099 Server replies are shown in the same message format.\n";
00100 
00101 #include <errno.h>
00102 #include <math.h>
00103 #include <stdio.h>
00104 #include <stdlib.h>
00105 #include <string.h>
00106 #include <time.h>
00107 #include <unistd.h>
00108 #include <sys/time.h>
00109 #include <limits.h>
00110 #include <signal.h>
00111 
00112 #include <sys/param.h>
00113 
00114 #include "gwlib/gwlib.h"
00115 
00116 #define IN_BUFSIZE 256  /* Buffer size for stdin */
00117 #define IN_TIMEOUT 1    /* Timeout for stdin */
00118 
00119 
00120 static int port = 10000;
00121 static Octstr *host;
00122 static long max_send = LONG_MAX;
00123 static double interval = 1.0;
00124 static int sigint_received;
00125 static int rnd = 0;
00126 
00127 static void signal_handler(int signum) 
00128 {
00129     if (signum == SIGINT)
00130         sigint_received = 1;
00131     else
00132         panic(0, "Caught signal with no handler?!");
00133 }
00134 
00135 
00136 static void setup_signal_handlers(void) 
00137 {
00138     struct sigaction act;
00139 
00140     act.sa_handler = signal_handler;
00141     sigemptyset(&act.sa_mask);
00142     act.sa_flags = 0;
00143     sigaction(SIGINT, &act, NULL);
00144 }
00145 
00146 
00147 /* Choose a random message from a table of messages. */
00148 static Octstr *choose_message(Octstr **msgs, int num_msgs) 
00149 {
00150     /* the following doesn't give an even distribution, but who cares */
00151     return msgs[gw_rand() % num_msgs];
00152 }
00153 
00154 
00155 /* Get current time, as double. */
00156 static double get_current_time(void) 
00157 {
00158     struct timezone tz;
00159     struct timeval now;
00160 
00161     gettimeofday(&now, &tz);
00162     return (double) now.tv_sec + now.tv_usec / 1e6;
00163 }
00164 
00165 /* our arguments */
00166 static int check_args(int i, int argc, char **argv) 
00167 {
00168     if (strcmp(argv[i], "-r")==0 || strcmp(argv[i], "--port")==0)
00169         port = atoi(argv[i+1]);
00170     else if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "--host"))
00171         host = octstr_create(argv[i+1]);
00172     else if (strcmp(argv[i], "-m")==0 || strcmp(argv[i], "--messages")==0) {
00173         max_send = atoi(argv[i+1]);
00174         if (max_send < 0)
00175             max_send = LONG_MAX;
00176     }
00177     else if (strcmp(argv[i], "-i")==0 || strcmp(argv[i], "--interval")==0)
00178         interval = atof(argv[i+1]);
00179     else if (strcmp(argv[i], "-z")==0 || strcmp(argv[i], "--randomize")==0) {
00180         rnd = atoi(argv[i+1]);
00181         if (rnd < 0 || rnd > 7)
00182             rnd = 0;
00183     }
00184     else {
00185         panic(0, "%s", usage);
00186         return 0;
00187     }
00188 
00189     return 1;
00190 }
00191 
00192 /* randomization of message elements */
00193 static Octstr *randomize(Octstr *os)
00194 {
00195     Octstr *msg = octstr_create("");
00196     List *words = octstr_split_words(os);
00197     int i;
00198 
00199     /* randomize source and receiver number */
00200     octstr_format_append(msg, "%S", gwlist_get(words, 0));
00201     if (rnd & 0x1) 
00202         octstr_format_append(msg, "%d", gw_rand());
00203 
00204     octstr_format_append(msg, " %S", gwlist_get(words, 1));
00205     if (rnd & 0x2) 
00206         octstr_format_append(msg, "%d", gw_rand());
00207 
00208     for (i = 2; i < gwlist_len(words); i++) 
00209         octstr_format_append(msg, " %S", gwlist_get(words, i));
00210 
00211     if (rnd & 0x4)
00212         octstr_format_append(msg, " %d", gw_rand());
00213 
00214     octstr_append_char(msg, 10); /* End of line */
00215 
00216     gwlist_destroy(words, octstr_destroy_item);
00217 
00218     return msg;
00219 }
00220 
00221 /* The main program. */
00222 int main(int argc, char **argv) 
00223 {
00224     Connection *server;
00225     Octstr *line;
00226     Octstr **msgs;
00227     int i;
00228     int mptr, num_msgs;
00229     long num_received, num_sent;
00230     double first_received_at, last_received_at;
00231     double first_sent_at, last_sent_at;
00232     double start_time, end_time;
00233     double delta;
00234     int interactive, maxfd;
00235     char *cptr;
00236     char buffer[IN_BUFSIZE];
00237     fd_set rset;
00238     struct timeval alarm;
00239     FILE *fp;
00240 
00241     gwlib_init();
00242     setup_signal_handlers();
00243     host = octstr_create("localhost");
00244     start_time = get_current_time();
00245 
00246     mptr = get_and_set_debugs(argc, argv, check_args);
00247     num_msgs = argc - mptr;
00248         
00249     interactive = 0;
00250     msgs = NULL;
00251     fp = NULL;
00252     if (num_msgs <= 0) {
00253         interactive = 1;
00254         num_msgs = 0;
00255         info(0, "Entering interactive mode. Type your message on the command line");
00256         /* set up file pointer to stdin */
00257         fp = stdin;
00258         /* initialize set for select */
00259         FD_ZERO(&rset); 
00260     } else {
00261         msgs = gw_malloc(sizeof(Octstr *) * num_msgs);
00262         for (i = 0; i < num_msgs; i ++) {
00263             msgs[i] = octstr_create(argv[mptr + i]);
00264             octstr_append_char(msgs[i], 10); /* End of line */
00265         }
00266         info(0, "Host %s Port %d interval %.3f max-messages %ld",
00267              octstr_get_cstr(host), port, interval, max_send);
00268 
00269         srand((unsigned int) time(NULL));
00270     }
00271     info(0, "fakesmsc starting");
00272     server = conn_open_tcp(host, port, NULL);
00273     if (server == NULL)
00274        panic(0, "Failed to open connection");
00275 
00276     num_sent = 0;
00277     num_received = 0;
00278 
00279     first_received_at = 0;
00280     first_sent_at = 0;
00281     last_received_at = 0;
00282     last_sent_at = 0;
00283 
00284     /* infinitely loop */
00285     while (1) {
00286         /* Are we on interactive mode? */ 
00287         if (interactive == 1) {
00288             /* Check if we need to clean things up beforehand */
00289             if ( num_msgs > 0 ) {
00290                 for (i = 0; i < num_msgs; i ++)
00291                     octstr_destroy(msgs[i]);
00292                 gw_free(msgs);
00293                 num_msgs = 0;
00294             }
00295 
00296             /* we want either the file pointer or timer */
00297             FD_SET(fileno(fp), &rset);
00298             /* get the largest file descriptor */
00299             maxfd = fileno(fp) + 1;
00300         
00301             /* set timer to go off in 3 seconds */
00302             alarm.tv_sec = IN_TIMEOUT;
00303             alarm.tv_usec = 0;
00304         
00305             if (select(maxfd, &rset, NULL, NULL, &alarm) == -1)
00306                 goto over;
00307             /* something went off, let's see if it's stdin */
00308             if (FD_ISSET(fileno(fp), &rset)) { /* stdin is readable */
00309                 cptr = fgets(buffer, IN_BUFSIZE, stdin);
00310                 if( strlen( cptr ) < 2 )
00311                     goto rcv;
00312             } else { /* timer kicked in */
00313                 goto rcv;
00314             }
00315             num_msgs = 1;
00316             msgs = gw_malloc(sizeof(Octstr*));
00317             msgs[0] = octstr_create(cptr);
00318         }
00319         /* if we still have something to send as MO message */
00320         if (num_sent < max_send) {
00321             Octstr *os = choose_message(msgs, num_msgs);
00322             Octstr *msg = rnd > 0 ? randomize(os) : os;
00323  
00324             if (conn_write(server, msg) == -1)
00325                 panic(0, "write failed");
00326 
00327             ++num_sent;
00328             if (num_sent == max_send)
00329                 info(0, "fakesmsc: sent message %ld", num_sent);
00330             else
00331                 debug("send", 0, "fakesmsc: sent message %ld", num_sent);
00332       
00333             if (rnd > 0)
00334                 octstr_destroy(msg);
00335 
00336             last_sent_at = get_current_time();
00337             if (first_sent_at == 0)    
00338                 first_sent_at = last_sent_at;
00339         }
00340 rcv:
00341         do {
00342             delta = interval * num_sent - (get_current_time() - first_sent_at);
00343             if (delta < 0)
00344                 delta = 0;
00345             if (num_sent >= max_send)
00346                 delta = -1;
00347             conn_wait(server, delta);
00348             if (conn_error(server) || conn_eof(server) || sigint_received)
00349                 goto over;
00350 
00351             /* read as much as the smsc module provides us */
00352             while ((line = conn_read_line(server))) {
00353                 last_received_at = get_current_time();
00354                 if (first_received_at == 0)
00355                     first_received_at = last_received_at;
00356                 ++num_received;
00357                 if (num_received == max_send) {
00358                     info(0, "Got message %ld: <%s>", num_received,
00359                            octstr_get_cstr(line));
00360                 } else {
00361                     debug("receive", 0, "Got message %ld: <%s>", num_received,
00362                           octstr_get_cstr(line));
00363                 }
00364                 octstr_destroy(line);
00365             }
00366         } while (delta > 0 || num_sent >= max_send);
00367     }
00368 
00369 over:
00370     conn_destroy(server);
00371 
00372     /* destroy the MO messages */
00373     for (i = 0; i < num_msgs; i ++)
00374         octstr_destroy(msgs[i]);
00375     gw_free(msgs);
00376 
00377     end_time = get_current_time();
00378 
00379     info(0, "fakesmsc: %ld messages sent and %ld received", num_sent, num_received);
00380     info(0, "fakesmsc: total running time %.1f seconds", end_time - start_time);
00381     delta = last_sent_at - first_sent_at;
00382     if (delta == 0)
00383         delta = .01;
00384     if (num_sent > 1)
00385         info(0, "fakesmsc: from first to last sent message %.1f s, "
00386                 "%.1f msgs/s", delta, (num_sent - 1) / delta);
00387     delta = last_received_at - first_received_at;
00388     if (delta == 0)
00389         delta = .01;
00390     if (num_received > 1)
00391         info(0, "fakesmsc: from first to last received message %.1f s, "
00392                 "%.1f msgs/s", delta, (num_received - 1) / delta);
00393     info(0, "fakesmsc: terminating");
00394     
00395     return 0;
00396 }
00397 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.