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

drive_smpp.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  * drive_smpp.c - SMPP server for testing purposes
00059  *
00060  * Lars Wirzenius
00061  */
00062 
00063 
00064 #include <errno.h>
00065 #include <signal.h>
00066 #include <sys/types.h>
00067 #include <sys/socket.h>
00068 
00069 #include "gwlib/gwlib.h"
00070 #include "gw/smsc/smpp_pdu.h"
00071 #include "gw/msg.h"
00072 
00073 
00074 static int quitting = 0;
00075 static Octstr *smsc_system_id;
00076 static Octstr *smsc_source_addr;
00077 static Counter *message_id_counter;
00078 static Octstr *bearerbox_host;
00079 static int port_for_smsbox;
00080 static Counter *num_to_esme;
00081 static long max_to_esme;
00082 static Counter *num_from_bearerbox;
00083 static Counter *num_to_bearerbox;
00084 static Counter *num_from_esme;
00085 static time_t start_time = (time_t) -1;
00086 static time_t first_to_esme = (time_t) -1;
00087 static time_t last_to_esme = (time_t) -1;
00088 static time_t last_from_esme = (time_t) -1;
00089 static time_t first_from_bb = (time_t) -1;
00090 static time_t last_to_bb = (time_t) -1;
00091 static long enquire_interval = 1; /* Measured in messages, not time. */
00092 
00093 
00094 static void quit(void)
00095 {
00096     quitting = 1;
00097     gwthread_wakeup_all();
00098 }
00099 
00100 
00101 typedef struct {
00102     Connection *conn;
00103     int transmitter;
00104     int receiver;
00105 } ESME;
00106 
00107 
00108 static ESME *esme_create(Connection *conn)
00109 {
00110     ESME *esme;
00111     
00112     esme = gw_malloc(sizeof(*esme));
00113     esme->conn = conn;
00114     esme->transmitter = 0;
00115     esme->receiver = 0;
00116     return esme;
00117 }
00118 
00119 
00120 static void esme_destroy(ESME *esme)
00121 {
00122     if (esme != NULL) {
00123     conn_destroy(esme->conn);
00124     gw_free(esme);
00125     }
00126 }
00127 
00128 
00129 static SMPP_PDU *handle_bind_transmitter(ESME *esme, SMPP_PDU *pdu)
00130 {
00131     SMPP_PDU *resp;
00132     
00133     esme->transmitter = 1;
00134     resp = smpp_pdu_create(bind_transmitter_resp,
00135                             pdu->u.bind_transmitter.sequence_number);
00136 #if 0 /* XXX system_id is not implemented in the PDU at the moment */
00137     resp->u.bind_transmitter_resp.system_id = 
00138         octstr_duplicate(smsc_system_id);
00139 #endif
00140     return resp;
00141 }
00142 
00143 
00144 static SMPP_PDU *handle_bind_receiver(ESME *esme, SMPP_PDU *pdu)
00145 {
00146     SMPP_PDU *resp;
00147     
00148     esme->receiver = 1;
00149     resp = smpp_pdu_create(bind_receiver_resp,
00150                             pdu->u.bind_receiver.sequence_number);
00151 #if 0 /* XXX system_id is not implemented in the PDU at the moment */
00152     resp->u.bind_receiver_resp.system_id = octstr_duplicate(smsc_system_id);
00153 #endif
00154     return resp;
00155 }
00156 
00157 
00158 static SMPP_PDU *handle_submit_sm(ESME *esme, SMPP_PDU *pdu)
00159 {
00160     SMPP_PDU *resp;
00161     unsigned long id;
00162     
00163     debug("test.smpp", 0, "submit_sm: short_message = <%s>",
00164           octstr_get_cstr(pdu->u.submit_sm.short_message));
00165     id = counter_increase(num_from_esme) + 1;
00166     if (id == max_to_esme)
00167         info(0, "ESME has submitted all messages to SMSC.");
00168     time(&last_from_esme);
00169 
00170     resp = smpp_pdu_create(submit_sm_resp, pdu->u.submit_sm.sequence_number);
00171 #if 0 /* XXX message_id is not implemented in the PDU at the moment */
00172     resp->u.submit_sm_resp.message_id = 
00173         octstr_format("%ld", counter_increase(message_id_counter));
00174 #endif
00175     return resp;
00176 }
00177 
00178 
00179 static SMPP_PDU *handle_deliver_sm_resp(ESME *esme, SMPP_PDU *pdu)
00180 {
00181     return NULL;
00182 }
00183 
00184 
00185 static SMPP_PDU *handle_unbind(ESME *esme, SMPP_PDU *pdu)
00186 {
00187     SMPP_PDU *resp;
00188     
00189     resp = smpp_pdu_create(unbind_resp, pdu->u.unbind.sequence_number);
00190     return resp;
00191 }
00192 
00193 
00194 static SMPP_PDU *handle_enquire_link(ESME *esme, SMPP_PDU *pdu)
00195 {
00196     return smpp_pdu_create(enquire_link_resp, 
00197                            pdu->u.enquire_link.sequence_number);
00198 }
00199 
00200 
00201 static SMPP_PDU *handle_enquire_link_resp(ESME *esme, SMPP_PDU *pdu)
00202 {
00203     return NULL;
00204 }
00205 
00206 
00207 static struct {
00208     unsigned long type;
00209     SMPP_PDU *(*handler)(ESME *, SMPP_PDU *);
00210 } handlers[] = {
00211     #define HANDLER(name) { name, handle_ ## name },
00212     HANDLER(bind_transmitter)
00213     HANDLER(bind_receiver)
00214     HANDLER(submit_sm)
00215     HANDLER(deliver_sm_resp)
00216     HANDLER(unbind)
00217     HANDLER(enquire_link)
00218     HANDLER(enquire_link_resp)
00219     #undef HANDLER
00220 };
00221 static int num_handlers = sizeof(handlers) / sizeof(handlers[0]);
00222 
00223 
00224 static void handle_pdu(ESME *esme, SMPP_PDU *pdu)
00225 {
00226     SMPP_PDU *resp;
00227     Octstr *os;
00228     int i;
00229 
00230     debug("test.smpp", 0, "Handling SMPP PDU of type %s", pdu->type_name);
00231     for (i = 0; i < num_handlers; ++i) {
00232         if (handlers[i].type == pdu->type) {
00233         resp = handlers[i].handler(esme, pdu);
00234         if (resp != NULL) {
00235             os = smpp_pdu_pack(resp);
00236         conn_write(esme->conn, os);
00237         octstr_destroy(os);
00238         smpp_pdu_destroy(resp);
00239         }
00240         return;
00241     }
00242     }
00243 
00244     error(0, "Unhandled SMPP PDU.");
00245     smpp_pdu_dump(pdu);
00246 }
00247 
00248 
00249 static void send_smpp_thread(void *arg)
00250 {
00251     ESME *esme;
00252     Octstr *os;
00253     SMPP_PDU *pdu;
00254     unsigned long id;
00255 
00256     esme = arg;
00257     
00258     id = 0;
00259     while (!quitting && counter_value(num_to_esme) < max_to_esme) {
00260     id = counter_increase(num_to_esme) + 1;
00261         while (!quitting && counter_value(num_from_esme) + 500 < id)
00262         gwthread_sleep(1.0);
00263     if (quitting)
00264         break;
00265     pdu = smpp_pdu_create(deliver_sm,
00266                    counter_increase(message_id_counter));
00267     pdu->u.deliver_sm.source_addr = octstr_create("456");
00268     pdu->u.deliver_sm.destination_addr = octstr_create("123");
00269     pdu->u.deliver_sm.short_message = octstr_format("%ld", id);
00270     os = smpp_pdu_pack(pdu);
00271     conn_write(esme->conn, os);
00272     octstr_destroy(os);
00273     smpp_pdu_destroy(pdu);
00274     if (first_to_esme == (time_t) -1)
00275         time(&first_to_esme);
00276     debug("test.smpp", 0, 
00277           "Delivered SMS %ld of %ld to bearerbox via SMPP.",
00278           id, max_to_esme);
00279 
00280         if ((id % enquire_interval) == 0) {
00281         pdu = smpp_pdu_create(enquire_link, 
00282                               counter_increase(message_id_counter));
00283         os = smpp_pdu_pack(pdu);
00284         conn_write(esme->conn, os);
00285         octstr_destroy(os);
00286         smpp_pdu_destroy(pdu);
00287         debug("test.smpp", 0, "Sent enquire_link to bearerbox.");
00288     }
00289     }
00290     time(&last_to_esme);
00291     if (id == max_to_esme)
00292     info(0, "All messages sent to ESME.");
00293     debug("test.smpp", 0, "%s terminates.", __func__);
00294 }
00295 
00296 
00297 static void receive_smpp_thread(void *arg)
00298 {
00299     ESME *esme;
00300     Octstr *os;
00301     long len;
00302     long sender_id;
00303     SMPP_PDU *pdu;
00304 
00305     esme = arg;
00306     
00307     sender_id = -1;
00308     len = 0;
00309     while (!quitting && conn_wait(esme->conn, -1.0) != -1) {
00310         for (;;) {
00311         if (len == 0) {
00312         len = smpp_pdu_read_len(esme->conn);
00313         if (len == -1) {
00314             error(0, "Client sent garbage, closing connection.");
00315             goto error;
00316         } else if (len == 0) {
00317             if (conn_eof(esme->conn) || conn_error(esme->conn))
00318                 goto error;
00319             break;
00320         }
00321         }
00322     
00323             gw_assert(len > 0);
00324         os = smpp_pdu_read_data(esme->conn, len);
00325         if (os != NULL) {
00326                 len = 0;
00327         pdu = smpp_pdu_unpack(os);
00328         if (pdu == NULL) {
00329             error(0, "PDU unpacking failed!");
00330             octstr_dump(os, 0);
00331         } else {
00332             handle_pdu(esme, pdu);
00333             smpp_pdu_destroy(pdu);
00334         }
00335         octstr_destroy(os);
00336         } else if (conn_eof(esme->conn) || conn_error(esme->conn))
00337             goto error;
00338         else
00339         break;
00340     }
00341 
00342         if (!quitting && esme->receiver && sender_id == -1)
00343         sender_id = gwthread_create(send_smpp_thread, esme);
00344     }
00345 
00346 error:
00347     if (sender_id != -1) {
00348     quit();
00349     gwthread_join(sender_id);
00350     }
00351     esme_destroy(esme);
00352     quit();
00353     debug("test.smpp", 0, "%s terminates.", __func__);
00354 }
00355 
00356 
00357 static void smsbox_thread(void *arg)
00358 {
00359     Connection *conn;
00360     Msg *msg;
00361     Octstr *os;
00362     Octstr *reply_msg;
00363     unsigned long count;
00364     
00365     msg = msg_create(sms);
00366     msg->sms.sender = octstr_create("123");
00367     msg->sms.receiver = octstr_create("456");
00368     msg->sms.msgdata = octstr_create("hello world");
00369     reply_msg = msg_pack(msg);
00370     msg_destroy(msg);
00371 
00372     gwthread_sleep(1.0);
00373     conn = conn_open_tcp(bearerbox_host, port_for_smsbox, NULL);
00374     if (conn == NULL) {
00375     gwthread_sleep(2.0);
00376     conn = conn_open_tcp(bearerbox_host, port_for_smsbox, NULL);
00377         if (conn == NULL)
00378         panic(0, "Couldn't connect to bearerbox as smsbox");
00379     }
00380 
00381     while (!quitting && conn_wait(conn, -1.0) != -1) {
00382         for (;;) {
00383         os = conn_read_withlen(conn);
00384         if (os == NULL) {
00385         if (conn_eof(conn) || conn_error(conn))
00386             goto error;
00387         break;
00388         }
00389         
00390         msg = msg_unpack(os);
00391         if (msg == NULL || msg->type == wdp_datagram)
00392         error(0, "Bearerbox sent garbage to smsbox");
00393 
00394         if (msg->type == sms) {
00395         if (first_from_bb == (time_t) -1)
00396             time(&first_from_bb);
00397         count = counter_increase(num_from_bearerbox) + 1;
00398         debug("test.smpp", 0, 
00399               "Bearerbox sent sms #%ld <%s> to smsbox, sending reply.",
00400               count, octstr_get_cstr(msg->sms.msgdata));
00401         if (count == max_to_esme)
00402             info(0, "Bearerbox has sent all messages to smsbox.");
00403         conn_write_withlen(conn, reply_msg);
00404         counter_increase(num_to_bearerbox);
00405         }
00406         msg_destroy(msg);
00407         octstr_destroy(os);
00408         time(&last_to_bb);
00409     }
00410     }
00411     
00412 error:
00413     conn_destroy(conn);
00414     octstr_destroy(reply_msg);
00415     debug("test.smpp", 0, "%s terminates.", __func__);
00416 }
00417 
00418 
00419 static void accept_thread(void *arg)
00420 {
00421     int fd;
00422     int new_fd;
00423     int port;
00424     socklen_t addrlen;
00425     struct sockaddr addr;
00426     long smsbox_thread_id;
00427     
00428     port = *(int *) arg;
00429     fd = make_server_socket(port, NULL);
00430     if (fd == -1)
00431         panic(0, "Couldn't create SMPP listen port.");
00432     
00433     smsbox_thread_id = -1;
00434     for (;;) {
00435     if (gwthread_pollfd(fd, POLLIN, -1.0) != POLLIN)
00436         break;
00437     addrlen = sizeof(addr);
00438     new_fd = accept(fd, &addr, &addrlen);
00439         if (start_time == (time_t) -1)
00440         time(&start_time);
00441     gwthread_create(receive_smpp_thread, 
00442             esme_create(conn_wrap_fd(new_fd, 0)));
00443     if (smsbox_thread_id == -1)
00444         smsbox_thread_id = gwthread_create(smsbox_thread, NULL);
00445     }
00446     
00447     debug("test.smpp", 0, "%s terminates.", __func__);
00448 }
00449 
00450 
00451 static void handler(int signal)
00452 {
00453     panic(0, "Caught signal %d.", signal);
00454 }
00455 
00456 
00457 static void help(void)
00458 {
00459     info(0, "drive_smpp [-h] [-v level] [-p port]");
00460 }
00461 
00462 
00463 int main(int argc, char **argv)
00464 {
00465     struct sigaction act;
00466     int http_port;
00467     int port;
00468     int opt;
00469     double run_time;
00470     char *log_file;
00471 
00472     gwlib_init();
00473 
00474     act.sa_handler = handler;
00475     sigemptyset(&act.sa_mask);
00476     act.sa_flags = 0;
00477     sigaction(SIGTERM, &act, NULL);
00478     sigaction(SIGINT, &act, NULL);
00479 
00480     port = 2345;
00481     http_port = 8080;
00482     smsc_system_id = octstr_create("kannel_smpp");
00483     smsc_source_addr = octstr_create("123456");
00484     message_id_counter = counter_create();
00485     bearerbox_host = octstr_create("127.0.0.1");
00486     port_for_smsbox = 13001;
00487     max_to_esme = 1;
00488     num_to_esme = counter_create();
00489     num_from_esme = counter_create();
00490     num_to_bearerbox = counter_create();
00491     num_from_bearerbox = counter_create();
00492     log_file = NULL;
00493 
00494     while ((opt = getopt(argc, argv, "hv:p:P:m:l:")) != EOF) {
00495     switch (opt) {
00496     case 'v':
00497         log_set_output_level(atoi(optarg));
00498         break;
00499 
00500     case 'h':
00501         help();
00502         exit(0);
00503 
00504     case 'm':
00505         max_to_esme = atoi(optarg);
00506         break;
00507 
00508     case 'p':
00509         port = atoi(optarg);
00510         break;
00511 
00512     case 'P':
00513         http_port = atoi(optarg);
00514         break;
00515 
00516         case 'l':
00517         log_file = optarg;
00518         break;
00519 
00520     case '?':
00521     default:
00522         error(0, "Invalid option %c", opt);
00523         help();
00524         panic(0, "Stopping.");
00525     }
00526     }
00527 
00528     if (log_file != NULL)
00529         log_open(log_file, GW_DEBUG, GW_NON_EXCL);
00530 
00531     info(0, "Starting drive_smpp test.");
00532     gwthread_create(accept_thread, &port);
00533     gwthread_join_all();
00534     debug("test.smpp", 0, "Program exiting normally.");
00535 
00536     run_time = difftime(last_from_esme, first_to_esme);
00537 
00538     info(0, "Number of messages sent to ESME: %ld",
00539          counter_value(num_to_esme));
00540     info(0, "Number of messages sent to smsbox: %ld",
00541          counter_value(num_from_bearerbox));
00542     info(0, "Number of messages sent to bearerbox: %ld",
00543          counter_value(num_to_bearerbox));
00544     info(0, "Number of messages sent to SMSC: %ld",
00545          counter_value(num_from_esme));
00546     info(0, "Time: %.0f secs", run_time);
00547     info(0, "Time until all sent to ESME: %.0f secs", 
00548          difftime(last_to_esme, start_time));
00549     info(0, "Time from first from bb to last to bb: %.0f secs", 
00550          difftime(last_to_bb, first_from_bb));
00551     info(0, "Time until all sent to SMSC: %.0f secs", 
00552          difftime(last_from_esme, start_time));
00553     info(0, "SMPP messages SMSC to ESME: %.1f msgs/sec",
00554          counter_value(num_to_esme) / run_time);
00555     info(0, "SMPP messages ESME to SMSC: %.1f msgs/sec",
00556          counter_value(num_from_esme) / run_time);
00557 
00558     octstr_destroy(smsc_system_id);
00559     octstr_destroy(smsc_source_addr);
00560     octstr_destroy(bearerbox_host);
00561     counter_destroy(num_to_esme);
00562     counter_destroy(num_from_esme);
00563     counter_destroy(num_to_bearerbox);
00564     counter_destroy(num_from_bearerbox);
00565     counter_destroy(message_id_counter);
00566 
00567     gwlib_shutdown();
00568     return 0;
00569 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.