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

bearerbox.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  * bearerbox.c
00059  * 
00060  * this is the core module of the bearerbox. It starts everything and
00061  * listens to HTTP requests and traps signals.
00062  * All started modules are responsible for the rest.
00063  *
00064  * Kalle Marjola <rpr@wapit.com> 2000 for project Kannel
00065  */
00066 
00067 #include <errno.h>
00068 #include <stdlib.h>
00069 #include <stdio.h>
00070 #include <time.h>
00071 #include <string.h>
00072 #include <signal.h>
00073 #include <unistd.h>
00074 
00075 #include "gwlib/gwlib.h"
00076 #include "msg.h"
00077 #include "bearerbox.h"
00078 #include "shared.h"
00079 #include "dlr.h"
00080 
00081 /* global variables; included to other modules as needed */
00082 
00083 List *incoming_sms;
00084 List *outgoing_sms;
00085 
00086 List *incoming_wdp;
00087 List *outgoing_wdp;
00088 
00089 Counter *incoming_sms_counter;
00090 Counter *outgoing_sms_counter;
00091 Counter *incoming_wdp_counter;
00092 Counter *outgoing_wdp_counter;
00093 
00094 /* incoming/outgoing sms queue control */
00095 long max_incoming_sms_qlength;
00096 long max_outgoing_sms_qlength;
00097 
00098 
00099 /* this is not a list of items; instead it is used as
00100  * indicator to note how many threads we have.
00101  * ALL flow threads must exit before we may safely change
00102  * bb_status from BB_SHUTDOWN to BB_DEAD
00103  *
00104  * XXX: prehaps we could also have items in this list, as
00105  *     descriptors of each thread?
00106  */
00107 List *flow_threads;
00108 
00109 /* and still more abuse; we use this list to put us into
00110  * 'suspend' state - if there are any producers (only core adds/removes them)
00111  * receiver/sender systems just sit, blocked in gwlist_consume
00112  */
00113 List *suspended;
00114 
00115 /* this one is like 'suspended', but only for receiving UDP/SMSC
00116  * (suspended state puts producers for both lists)
00117  */
00118 List *isolated;
00119 
00120 volatile sig_atomic_t bb_status;
00121 
00122 /* 
00123  * Flags for main thread to check what is to do.
00124  */
00125 enum {
00126     BB_LOGREOPEN = 1,
00127     BB_CHECKLEAKS = 2
00128 };
00129 /* Here we will set above flags */
00130 static volatile sig_atomic_t bb_todo = 0;
00131 
00132 /* own global variables */
00133 
00134 static Mutex *status_mutex;
00135 static time_t start_time;
00136 volatile sig_atomic_t restart = 0;
00137 
00138 
00139 /* to avoid copied code */
00140 
00141 static void set_shutdown_status(void)
00142 {
00143     sig_atomic_t old = bb_status;
00144     bb_status = BB_SHUTDOWN;
00145     
00146     if (old == BB_SUSPENDED)
00147         gwlist_remove_producer(suspended);
00148     if (old == BB_SUSPENDED || old == BB_ISOLATED)
00149         gwlist_remove_producer(isolated);
00150 }
00151 
00152 
00153 /*-------------------------------------------------------
00154  * signals
00155  */
00156 
00157 static void signal_handler(int signum)
00158 {
00159     /* On some implementations (i.e. linuxthreads), signals are delivered
00160      * to all threads.  We only want to handle each signal once for the
00161      * entire box, and we let the gwthread wrapper take care of choosing
00162      * one.
00163      */
00164     if (!gwthread_shouldhandlesignal(signum))
00165     return;
00166 
00167     switch (signum) {
00168         case SIGINT:
00169         case SIGTERM:
00170             if (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) {
00171                 bb_status = BB_SHUTDOWN;
00172             }
00173             else if (bb_status == BB_SHUTDOWN) {
00174                 bb_status = BB_DEAD;
00175             }
00176             else if (bb_status == BB_DEAD) {
00177                 panic(0, "Cannot die by its own will");
00178             }
00179             break;
00180 
00181         case SIGHUP:
00182             bb_todo |= BB_LOGREOPEN;
00183             break;
00184 
00185         /*
00186          * It would be more proper to use SIGUSR1 for this, but on some
00187          * platforms that's reserved by the pthread support.
00188          */
00189         case SIGQUIT:
00190            bb_todo |= BB_CHECKLEAKS;
00191            break;
00192     }
00193 }
00194 
00195 static void setup_signal_handlers(void)
00196 {
00197     struct sigaction act;
00198 
00199     act.sa_handler = signal_handler;
00200     sigemptyset(&act.sa_mask);
00201     act.sa_flags = 0;
00202     sigaction(SIGINT, &act, NULL);
00203     sigaction(SIGTERM, &act, NULL);
00204     sigaction(SIGQUIT, &act, NULL);
00205     sigaction(SIGHUP, &act, NULL);
00206     sigaction(SIGPIPE, &act, NULL);
00207 }
00208 
00209 
00210 /*--------------------------------------------------------
00211  * functions to start/init sub-parts of the bearerbox
00212  *
00213  * these functions are NOT thread safe but they have no need to be,
00214  * as there is only one core bearerbox thread
00215  */
00216 
00217 static int start_smsc(Cfg *cfg)
00218 {
00219     static int started = 0;
00220 
00221     if (started) 
00222         return 0;
00223 
00224     smsbox_start(cfg);
00225 
00226     smsc2_start(cfg);
00227 
00228     started = 1;
00229     return 0;
00230 }
00231 
00232 
00233 static void wdp_router(void *arg)
00234 {
00235     Msg *msg;
00236 
00237     gwlist_add_producer(flow_threads);
00238     
00239     while (bb_status != BB_DEAD) {
00240 
00241         if ((msg = gwlist_consume(outgoing_wdp)) == NULL)
00242             break;
00243 
00244         gw_assert(msg_type(msg) == wdp_datagram);
00245     
00246         /*
00247         if (msg->list == sms)
00248             smsc_addwdp(msg);
00249         else
00250         */
00251 
00252         udp_addwdp(msg);
00253     }
00254     udp_die();
00255     /* smsc_endwdp(); */
00256 
00257     gwlist_remove_producer(flow_threads);
00258 }
00259 
00260 
00261 static int start_wap(Cfg *cfg)
00262 {
00263     static int started = 0;
00264 
00265     if (started) 
00266         return 0;
00267     
00268     wapbox_start(cfg);
00269 
00270     debug("bb", 0, "starting WDP router");
00271     if (gwthread_create(wdp_router, NULL) == -1)
00272         panic(0, "Failed to start a new thread for WDP routing");
00273 
00274     started = 1;
00275     return 0;
00276 }
00277 
00278 
00279 static int start_udp(Cfg *cfg)
00280 {
00281     static int started = 0;
00282 
00283     if (started) 
00284         return 0;
00285 
00286     udp_start(cfg);
00287 
00288     start_wap(cfg);
00289     started = 1;
00290     return 0;
00291 }
00292 
00293 
00294 /*
00295  * check that there is basic thingies in configuration
00296  */
00297 static int check_config(Cfg *cfg)
00298 {
00299     CfgGroup *grp;
00300     long smsp, wapp;
00301 
00302     grp = cfg_get_single_group(cfg, octstr_imm("core"));
00303     if (grp == NULL)
00304         return -1;
00305 
00306     if (cfg_get_integer(&smsp, grp, octstr_imm("smsbox-port")) == -1)
00307         smsp = -1;
00308     if (cfg_get_integer(&wapp, grp, octstr_imm("wapbox-port")) == -1)
00309         wapp = -1;
00310     
00311 #ifndef NO_SMS    
00312     grp = cfg_get_single_group(cfg, octstr_imm("smsbox"));
00313     if (smsp != -1 && grp == NULL) {
00314         error(0, "No 'smsbox' group in configuration, but smsbox-port set");
00315         return -1;
00316     }
00317 #else
00318     warning(0, "Kannel was compiled without SMS support");
00319 #endif
00320     
00321 #ifndef NO_WAP  
00322     grp = cfg_get_single_group(cfg, octstr_imm("wapbox"));
00323     if (wapp != -1 && grp == NULL) {
00324         error(0, "No 'wapbox' group in configuration, but wapbox-port set");
00325         return -1;
00326     }
00327 #else
00328     warning(0, "Kannel was compiled without WAP support");
00329 #endif
00330     
00331     return 0;
00332 }
00333 
00334 
00335 /*
00336  * check our own variables
00337  */
00338 static int check_args(int i, int argc, char **argv) 
00339 {
00340     if (strcmp(argv[i], "-S")==0 || strcmp(argv[i], "--suspended")==0)
00341         bb_status = BB_SUSPENDED;
00342     else if (strcmp(argv[i], "-I")==0 || strcmp(argv[i], "--isolated")==0)
00343         bb_status = BB_ISOLATED;
00344     else
00345         return -1;
00346 
00347     return 0;
00348 }
00349 
00350 
00351 static Cfg *init_bearerbox(Cfg *cfg)
00352 {
00353     CfgGroup *grp;
00354     Octstr *log, *val;
00355     long loglevel, store_dump_freq;
00356     int lf, m;
00357 #ifdef HAVE_LIBSSL
00358     Octstr *ssl_server_cert_file;
00359     Octstr *ssl_server_key_file;
00360     int ssl_enabled = 0;
00361 #endif /* HAVE_LIBSSL */
00362 
00363     /* defaults: use localtime and markers for access-log */
00364     lf = m = 1;
00365     
00366     grp = cfg_get_single_group(cfg, octstr_imm("core"));
00367 
00368     log = cfg_get(grp, octstr_imm("log-file"));
00369     if (log != NULL) {
00370         if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
00371             loglevel = 0;
00372         log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
00373         octstr_destroy(log);
00374     }
00375 
00376     if (check_config(cfg) == -1)
00377         panic(0, "Cannot start with corrupted configuration");
00378 
00379     /* determine which timezone we use for access logging */
00380     if ((log = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) {
00381         lf = (octstr_case_compare(log, octstr_imm("gmt")) == 0) ? 0 : 1;
00382         octstr_destroy(log);
00383     }
00384 
00385     /* should predefined markers be used, ie. prefixing timestamp */
00386     cfg_get_bool(&m, grp, octstr_imm("access-log-clean"));
00387 
00388     /* custom access-log format  */
00389     if ((log = cfg_get(grp, octstr_imm("access-log-format"))) != NULL) {
00390         bb_alog_init(log);
00391         octstr_destroy(log);
00392     }
00393 
00394     /* open access-log file */
00395     if ((log = cfg_get(grp, octstr_imm("access-log"))) != NULL) {
00396         alog_open(octstr_get_cstr(log), lf, m ? 0 : 1);
00397         octstr_destroy(log);
00398     }
00399 
00400     if (cfg_get_integer(&store_dump_freq, grp,
00401                            octstr_imm("store-dump-freq")) == -1)
00402         store_dump_freq = -1;
00403 
00404     log = cfg_get(grp, octstr_imm("store-file"));
00405     /* initialize the store file */
00406     if (log != NULL) {
00407         warning(0, "'store-file' option deprecated, please use 'store-location' and 'store-type' instead.");
00408         val = octstr_create("file");
00409     } else {
00410         log = cfg_get(grp, octstr_imm("store-location"));
00411         val = cfg_get(grp, octstr_imm("store-type"));
00412     }
00413     if (store_init(val, log, store_dump_freq, msg_pack, msg_unpack_wrapper) == -1)
00414         panic(0, "Could not start with store init failed.");
00415     octstr_destroy(val);
00416     octstr_destroy(log);
00417 
00418     conn_config_ssl (grp);
00419 
00420     /*
00421      * Make sure we have "ssl-server-cert-file" and "ssl-server-key-file" specified
00422      * in the core group since we need it to run SSL-enabled internal box 
00423      * connections configured via "smsbox-port-ssl = yes" and "wapbox-port-ssl = yes".
00424      * Check only these, because for "admin-port-ssl" and "sendsms-port-ssl" for the 
00425      * SSL-enabled HTTP servers are probed within gw/bb_http.c:httpadmin_start()
00426      */
00427 #ifdef HAVE_LIBSSL
00428     ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file"));
00429     ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file"));
00430     if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) {
00431        /* we are fine, at least files are specified in the configuration */
00432     } else {
00433         cfg_get_bool(&ssl_enabled, grp, octstr_imm("smsbox-port-ssl"));
00434         cfg_get_bool(&ssl_enabled, grp, octstr_imm("wapbox-port-ssl"));
00435         if (ssl_enabled) {
00436            panic(0, "You MUST specify cert and key files within core group for SSL-enabled inter-box connections!");
00437         }
00438     }
00439     octstr_destroy(ssl_server_cert_file);
00440     octstr_destroy(ssl_server_key_file);
00441 #endif /* HAVE_LIBSSL */
00442 
00443     /* if all seems to be OK by the first glimpse, real start-up */
00444 
00445     outgoing_sms = gwlist_create();
00446     incoming_sms = gwlist_create();
00447     outgoing_wdp = gwlist_create();
00448     incoming_wdp = gwlist_create();
00449 
00450     outgoing_sms_counter = counter_create();
00451     incoming_sms_counter = counter_create();
00452     outgoing_wdp_counter = counter_create();
00453     incoming_wdp_counter = counter_create();
00454 
00455     status_mutex = mutex_create();
00456 
00457     setup_signal_handlers();
00458     
00459     /* http-admin is REQUIRED */
00460     httpadmin_start(cfg);
00461 
00462     if (cfg_get_integer(&max_incoming_sms_qlength, grp,
00463                            octstr_imm("maximum-queue-length")) == -1)
00464         max_incoming_sms_qlength = -1;
00465     else {
00466         warning(0, "Option 'maximum-queue-length' is deprecated! Please use"
00467                           " 'sms-incoming-queue-limit' instead!");
00468     }
00469 
00470     if (max_incoming_sms_qlength == -1 &&
00471         cfg_get_integer(&max_incoming_sms_qlength, grp,
00472                                   octstr_imm("sms-incoming-queue-limit")) == -1)
00473         max_incoming_sms_qlength = -1;
00474         
00475     if (cfg_get_integer(&max_outgoing_sms_qlength, grp,
00476                                   octstr_imm("sms-outgoing-queue-limit")) == -1)
00477         max_outgoing_sms_qlength = -1;
00478 
00479 #ifndef NO_SMS    
00480     {
00481         List *list;
00482     
00483         list = cfg_get_multi_group(cfg, octstr_imm("smsc"));
00484         if (list != NULL) {
00485             start_smsc(cfg);
00486             gwlist_destroy(list, NULL);
00487         }
00488     }
00489 #endif
00490     
00491 #ifndef NO_WAP
00492     grp = cfg_get_single_group(cfg, octstr_imm("core"));
00493     val = cfg_get(grp, octstr_imm("wdp-interface-name"));
00494     if (val != NULL && octstr_len(val) > 0)
00495         start_udp(cfg);
00496     octstr_destroy(val);
00497 
00498     if (cfg_get_single_group(cfg, octstr_imm("wapbox")) != NULL)
00499         start_wap(cfg);
00500 #endif
00501     
00502     return cfg;
00503 }
00504 
00505 
00506 static void empty_msg_lists(void)
00507 {
00508     Msg *msg;
00509 
00510 #ifndef NO_WAP
00511     if (gwlist_len(incoming_wdp) > 0 || gwlist_len(outgoing_wdp) > 0)
00512         warning(0, "Remaining WDP: %ld incoming, %ld outgoing",
00513                 gwlist_len(incoming_wdp), gwlist_len(outgoing_wdp));
00514 
00515     info(0, "Total WDP messages: received %ld, sent %ld",
00516          counter_value(incoming_wdp_counter),
00517          counter_value(outgoing_wdp_counter));
00518 #endif
00519     
00520     while ((msg = gwlist_extract_first(incoming_wdp)) != NULL)
00521         msg_destroy(msg);
00522     while ((msg = gwlist_extract_first(outgoing_wdp)) != NULL)
00523         msg_destroy(msg);
00524 
00525     gwlist_destroy(incoming_wdp, NULL);
00526     gwlist_destroy(outgoing_wdp, NULL);
00527 
00528     counter_destroy(incoming_wdp_counter);
00529     counter_destroy(outgoing_wdp_counter);
00530     
00531 #ifndef NO_SMS
00532     /* XXX we should record these so that they are not forever lost... */
00533     if (gwlist_len(incoming_sms) > 0 || gwlist_len(outgoing_sms) > 0)
00534         debug("bb", 0, "Remaining SMS: %ld incoming, %ld outgoing",
00535               gwlist_len(incoming_sms), gwlist_len(outgoing_sms));
00536 
00537     info(0, "Total SMS messages: received %ld, sent %ld",
00538          counter_value(incoming_sms_counter),
00539          counter_value(outgoing_sms_counter));
00540 #endif
00541 
00542     gwlist_destroy(incoming_sms, msg_destroy_item);
00543     gwlist_destroy(outgoing_sms, msg_destroy_item);
00544     
00545     counter_destroy(incoming_sms_counter);
00546     counter_destroy(outgoing_sms_counter);
00547 }
00548 
00549 
00550 static void dispatch_into_queue(Msg *msg)
00551 {
00552     gw_assert(msg != NULL),
00553     gw_assert(msg_type(msg) == sms);
00554 
00555     switch (msg->sms.sms_type) {
00556         case mt_push:
00557         case mt_reply:
00558         case report_mt:
00559             gwlist_append(outgoing_sms, msg);
00560             break;
00561         case mo:
00562         case report_mo:
00563             gwlist_append(incoming_sms, msg);
00564             break;
00565         default:
00566             panic(0, "Not handled sms_type within store!");
00567     }
00568 }
00569 
00570 
00571 int main(int argc, char **argv)
00572 {
00573     int cf_index;
00574     Cfg *cfg;
00575     Octstr *filename;
00576 
00577     bb_status = BB_RUNNING;
00578     
00579     gwlib_init();
00580     start_time = time(NULL);
00581 
00582     suspended = gwlist_create();
00583     isolated = gwlist_create();
00584     gwlist_add_producer(suspended);
00585     gwlist_add_producer(isolated);
00586 
00587     cf_index = get_and_set_debugs(argc, argv, check_args);
00588 
00589     if (argv[cf_index] == NULL)
00590         filename = octstr_create("kannel.conf");
00591     else
00592         filename = octstr_create(argv[cf_index]);
00593     cfg = cfg_create(filename); 
00594     
00595     if (cfg_read(cfg) == -1)
00596         panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(filename));
00597     
00598     octstr_destroy(filename);
00599 
00600     dlr_init(cfg);
00601     
00602     report_versions("bearerbox");
00603 
00604     flow_threads = gwlist_create();
00605     
00606     init_bearerbox(cfg);
00607 
00608     info(0, "----------------------------------------");
00609     info(0, GW_NAME " bearerbox II version %s starting", GW_VERSION);
00610 
00611     gwthread_sleep(5.0); /* give time to threads to register themselves */
00612 
00613     if (store_load(dispatch_into_queue) == -1)
00614         panic(0, "Cannot start with store-file failing");
00615     
00616     info(0, "MAIN: Start-up done, entering mainloop");
00617     if (bb_status == BB_SUSPENDED) {
00618         info(0, "Gateway is now SUSPENDED by startup arguments");
00619     } else if (bb_status == BB_ISOLATED) {
00620         info(0, "Gateway is now ISOLATED by startup arguments");
00621         gwlist_remove_producer(suspended);
00622     } else {
00623         smsc2_resume();
00624         gwlist_remove_producer(suspended);  
00625         gwlist_remove_producer(isolated);
00626     }
00627 
00628     while (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD && 
00629            gwlist_producer_count(flow_threads) > 0) {
00630         /* debug("bb", 0, "Main Thread: going to sleep."); */
00631         /*
00632          * Not infinite sleep here, because we should notice
00633          * when all "flow threads" are dead and shutting bearerbox
00634          * down.
00635          * XXX if all "flow threads" call gwthread_wakeup(MAIN_THREAD_ID),
00636          * we can enter infinite sleep then.
00637          */
00638         gwthread_sleep(10.0);
00639         /* debug("bb", 0, "Main Thread: woken up."); */
00640 
00641         if (bb_todo == 0) {
00642             continue;
00643         }
00644 
00645         if (bb_todo & BB_LOGREOPEN) {
00646             warning(0, "SIGHUP received, catching and re-opening logs");
00647             log_reopen();
00648             alog_reopen();
00649             bb_todo = bb_todo & ~BB_LOGREOPEN;
00650         }
00651 
00652         if (bb_todo & BB_CHECKLEAKS) {
00653             warning(0, "SIGQUIT received, reporting memory usage.");
00654             gw_check_leaks();
00655             bb_todo = bb_todo & ~BB_CHECKLEAKS;
00656         }
00657     }
00658 
00659     if (bb_status == BB_SHUTDOWN || bb_status == BB_DEAD)
00660         warning(0, "Killing signal or HTTP admin command received, shutting down...");
00661 
00662     /* call shutdown */
00663     bb_shutdown();
00664 
00665     /* wait until flow threads exit */
00666     while (gwlist_consume(flow_threads) != NULL)
00667         ;
00668 
00669     info(0, "All flow threads have died, killing core");
00670     bb_status = BB_DEAD;
00671     httpadmin_stop();
00672 
00673     boxc_cleanup();
00674     smsc2_cleanup();
00675     store_shutdown();
00676     empty_msg_lists();
00677     gwlist_destroy(flow_threads, NULL);
00678     gwlist_destroy(suspended, NULL);
00679     gwlist_destroy(isolated, NULL);
00680     mutex_destroy(status_mutex);
00681 
00682     alog_close();       /* if we have any */
00683     bb_alog_shutdown();
00684     cfg_destroy(cfg);
00685     dlr_shutdown();
00686     gwlib_shutdown();
00687 
00688     if (restart == 1)
00689         execvp(argv[0],argv);
00690 
00691     return 0;
00692 }
00693 
00694 
00695 /*----------------------------------------------------------------
00696  * public functions used via HTTP adminstration interface/module
00697  */
00698 
00699 int bb_shutdown(void)
00700 {
00701     static int called = 0;
00702     
00703     mutex_lock(status_mutex);
00704     
00705     if (called) {
00706         mutex_unlock(status_mutex);
00707         return -1;
00708     }
00709     debug("bb", 0, "Shutting down " GW_NAME "...");
00710 
00711     called = 1;
00712     set_shutdown_status();
00713     mutex_unlock(status_mutex);
00714 
00715 #ifndef NO_SMS
00716     debug("bb", 0, "shutting down smsc");
00717     smsc2_shutdown();
00718 #endif
00719 #ifndef NO_WAP
00720     debug("bb", 0, "shutting down udp");
00721     udp_shutdown();
00722 #endif
00723     
00724     return 0;
00725 }
00726 
00727 
00728 int bb_isolate(void)
00729 {
00730     mutex_lock(status_mutex);
00731     if (bb_status != BB_RUNNING && bb_status != BB_SUSPENDED) {
00732         mutex_unlock(status_mutex);
00733         return -1;
00734     }
00735     if (bb_status == BB_RUNNING) {
00736         smsc2_suspend();
00737         gwlist_add_producer(isolated);
00738     } else
00739     gwlist_remove_producer(suspended);
00740 
00741     bb_status = BB_ISOLATED;
00742     mutex_unlock(status_mutex);
00743     return 0;
00744 }
00745 
00746 
00747 int bb_suspend(void)
00748 {
00749     mutex_lock(status_mutex);
00750     if (bb_status != BB_RUNNING && bb_status != BB_ISOLATED) {
00751         mutex_unlock(status_mutex);
00752         return -1;
00753     }
00754     if (bb_status != BB_ISOLATED) {
00755         smsc2_suspend();
00756         gwlist_add_producer(isolated);
00757     }
00758     bb_status = BB_SUSPENDED;
00759     gwlist_add_producer(suspended);
00760     mutex_unlock(status_mutex);
00761     return 0;
00762 }
00763 
00764 
00765 int bb_resume(void)
00766 {
00767     mutex_lock(status_mutex);
00768     if (bb_status != BB_SUSPENDED && bb_status != BB_ISOLATED) {
00769         mutex_unlock(status_mutex);
00770         return -1;
00771     }
00772     if (bb_status == BB_SUSPENDED)
00773         gwlist_remove_producer(suspended);
00774 
00775     smsc2_resume();
00776     bb_status = BB_RUNNING;
00777     gwlist_remove_producer(isolated);
00778     mutex_unlock(status_mutex);
00779     return 0;
00780 }
00781 
00782 
00783 int bb_flush_dlr(void)
00784 {
00785     /* beware that mutex locking is done in dlr_foobar() routines */
00786     if (bb_status != BB_SUSPENDED) {
00787         return -1;
00788     }
00789     dlr_flush();
00790     return 0;
00791 }
00792 
00793 
00794 int bb_stop_smsc(Octstr *id)
00795 {
00796     return smsc2_stop_smsc(id);
00797 }
00798 
00799 
00800 int bb_restart_smsc(Octstr *id)
00801 {
00802     return smsc2_restart_smsc(id);
00803 }
00804 
00805 int bb_restart(void)
00806 {
00807     restart = 1;
00808     return bb_shutdown();
00809 }
00810 
00811 
00812 #define append_status(r, s, f, x) { s = f(x); octstr_append(r, s); \
00813                                     octstr_destroy(s); }
00814 
00815 Octstr *bb_print_status(int status_type)
00816 {
00817     char *s, *lb;
00818     char *frmt, *footer;
00819     char buf[1024];
00820     Octstr *ret, *str, *version;
00821     time_t t;
00822 
00823     if ((lb = bb_status_linebreak(status_type)) == NULL)
00824         return octstr_create("Un-supported format");
00825 
00826     t = time(NULL) - start_time;
00827     
00828     if (bb_status == BB_RUNNING)
00829         s = "running";
00830     else if (bb_status == BB_ISOLATED)
00831         s = "isolated";
00832     else if (bb_status == BB_SUSPENDED)
00833         s = "suspended";
00834     else if (bb_status == BB_FULL)
00835         s = "filled";
00836     else
00837         s = "going down";
00838 
00839     version = version_report_string("bearerbox");
00840 
00841     if (status_type == BBSTATUS_HTML) {
00842         frmt = "%s</p>\n\n"
00843                " <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>\n\n"
00844                " <p>WDP: received %ld (%ld queued), sent %ld "
00845                "(%ld queued)</p>\n\n"
00846                " <p>SMS: received %ld (%ld queued), sent %ld "
00847                "(%ld queued), store size %ld</p>\n"
00848                " <p>SMS: inbound %.2f msg/sec, outbound %.2f msg/sec</p>\n\n"
00849                " <p>DLR: %ld queued, using %s storage</p>\n\n";
00850         footer = "<p>";
00851     } else if (status_type == BBSTATUS_WML) {
00852         frmt = "%s</p>\n\n"
00853                "   <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>\n\n"
00854                "   <p>WDP: received %ld (%ld queued)<br/>\n"
00855                "      WDP: sent %ld (%ld queued)</p>\n\n"
00856                "   <p>SMS: received %ld (%ld queued)<br/>\n"
00857                "      SMS: sent %ld (%ld queued)<br/>\n"
00858                "      SMS: store size %ld<br/>\n"
00859                "      SMS: inbound %.2f msg/sec<br/>\n"
00860                "      SMS: outbound %.2f msg/sec</p>\n\n"
00861                "   <p>DLR: %ld queued<br/>\n"
00862                "      DLR: using %s storage</p>\n\n";
00863         footer = "<p>";
00864     } else if (status_type == BBSTATUS_XML) {
00865         frmt = "<version>%s</version>\n"
00866                "<status>%s, uptime %ldd %ldh %ldm %lds</status>\n"
00867                "\t<wdp>\n\t\t<received><total>%ld</total><queued>%ld</queued>"
00868                "</received>\n\t\t<sent><total>%ld</total><queued>%ld</queued>"
00869                "</sent>\n\t</wdp>\n"
00870                "\t<sms>\n\t\t<received><total>%ld</total><queued>%ld</queued>"
00871                "</received>\n\t\t<sent><total>%ld</total><queued>%ld</queued>"
00872                "</sent>\n\t\t<storesize>%ld</storesize>\n\t\t"
00873                "<inbound>%.2f</inbound>\n\t\t<outbound>%.2f</outbound>\n\t</sms>\n"
00874                "\t<dlr>\n\t\t<queued>%ld</queued>\n\t\t<storage>%s</storage>\n\t</dlr>\n";
00875         footer = "";
00876     } else {
00877         frmt = "%s\n\nStatus: %s, uptime %ldd %ldh %ldm %lds\n\n"
00878                "WDP: received %ld (%ld queued), sent %ld (%ld queued)\n\n"
00879                "SMS: received %ld (%ld queued), sent %ld (%ld queued), store size %ld\n"
00880                "SMS: inbound %.2f msg/sec, outbound %.2f msg/sec\n\n"
00881                "DLR: %ld queued, using %s storage\n\n";
00882         footer = "";
00883     }
00884     
00885     sprintf(buf, frmt,
00886         octstr_get_cstr(version),
00887         s, t/3600/24, t/3600%24, t/60%60, t%60,
00888         counter_value(incoming_wdp_counter),
00889         gwlist_len(incoming_wdp) + boxc_incoming_wdp_queue(),
00890         counter_value(outgoing_wdp_counter), gwlist_len(outgoing_wdp) + udp_outgoing_queue(),
00891         counter_value(incoming_sms_counter), gwlist_len(incoming_sms),
00892         counter_value(outgoing_sms_counter), gwlist_len(outgoing_sms),
00893         store_messages(),
00894         (float) counter_value(incoming_sms_counter)/t,
00895         (float) counter_value(outgoing_sms_counter)/t,
00896         dlr_messages(), dlr_type());
00897 
00898     octstr_destroy(version);
00899     ret = octstr_create(buf);
00900     
00901     append_status(ret, str, boxc_status, status_type);
00902     append_status(ret, str, smsc2_status, status_type);
00903     octstr_append_cstr(ret, footer);
00904     
00905     return ret;
00906 }
00907 
00908 
00909 char *bb_status_linebreak(int status_type)
00910 {
00911     switch (status_type) {
00912         case BBSTATUS_HTML:
00913             return "<br>\n";
00914         case BBSTATUS_WML:
00915             return "<br/>\n";
00916         case BBSTATUS_TEXT:
00917             return "\n";
00918         case BBSTATUS_XML:
00919             return "\n";
00920         default:
00921             return NULL;
00922     }
00923 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.