1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 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 * bearerbox.c
59 *
60 * this is the core module of the bearerbox. It starts everything and
61 * listens to HTTP requests and traps signals.
62 * All started modules are responsible for the rest.
63 *
64 * Kalle Marjola <rpr@wapit.com> 2000 for project Kannel
65 */
66
67 #include <errno.h>
68 #include <stdlib.h>
69 #include <stdio.h>
70 #include <time.h>
71 #include <string.h>
72 #include <signal.h>
73 #include <unistd.h>
74
75 #include "gwlib/gwlib.h"
76 #include "msg.h"
77 #include "bearerbox.h"
78 #include "shared.h"
79 #include "dlr.h"
80 #include "load.h"
81
82 /* global variables; included to other modules as needed */
83
84 List *incoming_sms;
85 List *outgoing_sms;
86
87 List *incoming_wdp;
88 List *outgoing_wdp;
89
90 Counter *incoming_sms_counter;
91 Counter *outgoing_sms_counter;
92 Counter *incoming_dlr_counter;
93 Counter *outgoing_dlr_counter;
94 Counter *incoming_wdp_counter;
95 Counter *outgoing_wdp_counter;
96
97 /* incoming/outgoing sms queue control */
98 long max_incoming_sms_qlength;
99 long max_outgoing_sms_qlength;
100
101
102 Load *outgoing_sms_load;
103 Load *incoming_sms_load;
104 Load *incoming_dlr_load;
105 Load *outgoing_dlr_load;
106
107
108 /* this is not a list of items; instead it is used as
109 * indicator to note how many threads we have.
110 * ALL flow threads must exit before we may safely change
111 * bb_status from BB_SHUTDOWN to BB_DEAD
112 *
113 * XXX: prehaps we could also have items in this list, as
114 * descriptors of each thread?
115 */
116 List *flow_threads;
117
118 /* and still more abuse; we use this list to put us into
119 * 'suspend' state - if there are any producers (only core adds/removes them)
120 * receiver/sender systems just sit, blocked in gwlist_consume
121 */
122 List *suspended;
123
124 /* this one is like 'suspended', but only for receiving UDP/SMSC
125 * (suspended state puts producers for both lists)
126 */
127 List *isolated;
128
129 /* configuration filename */
130 Octstr *cfg_filename;
131
132 volatile sig_atomic_t bb_status;
133
134 /*
135 * Flags for main thread to check what is to do.
136 */
137 enum {
138 BB_LOGREOPEN = 1,
139 BB_CHECKLEAKS = 2
140 };
141 /* Here we will set above flags */
142 static volatile sig_atomic_t bb_todo = 0;
143
144 /* own global variables */
145
146 static Mutex *status_mutex;
147 static time_t start_time;
148 volatile sig_atomic_t restart = 0;
149
150
151 /* to avoid copied code */
152
set_shutdown_status(void)153 static void set_shutdown_status(void)
154 {
155 sig_atomic_t old = bb_status;
156 bb_status = BB_SHUTDOWN;
157
158 if (old == BB_SUSPENDED)
159 gwlist_remove_producer(suspended);
160 if (old == BB_SUSPENDED || old == BB_ISOLATED)
161 gwlist_remove_producer(isolated);
162 }
163
164
165 /*-------------------------------------------------------
166 * signals
167 */
168
signal_handler(int signum)169 static void signal_handler(int signum)
170 {
171 /* On some implementations (i.e. linuxthreads), signals are delivered
172 * to all threads. We only want to handle each signal once for the
173 * entire box, and we let the gwthread wrapper take care of choosing
174 * one.
175 */
176 if (!gwthread_shouldhandlesignal(signum))
177 return;
178
179 switch (signum) {
180 case SIGINT:
181 case SIGTERM:
182 if (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) {
183 bb_status = BB_SHUTDOWN;
184 }
185 else if (bb_status == BB_SHUTDOWN) {
186 bb_status = BB_DEAD;
187 }
188 else if (bb_status == BB_DEAD) {
189 panic(0, "Cannot die by its own will");
190 }
191 break;
192
193 case SIGHUP:
194 bb_todo |= BB_LOGREOPEN;
195 break;
196
197 /*
198 * It would be more proper to use SIGUSR1 for this, but on some
199 * platforms that's reserved by the pthread support.
200 */
201 case SIGQUIT:
202 bb_todo |= BB_CHECKLEAKS;
203 break;
204 }
205 }
206
setup_signal_handlers(void)207 static void setup_signal_handlers(void)
208 {
209 struct sigaction act;
210
211 act.sa_handler = signal_handler;
212 sigemptyset(&act.sa_mask);
213 act.sa_flags = 0;
214 sigaction(SIGINT, &act, NULL);
215 sigaction(SIGTERM, &act, NULL);
216 sigaction(SIGQUIT, &act, NULL);
217 sigaction(SIGHUP, &act, NULL);
218 sigaction(SIGPIPE, &act, NULL);
219 }
220
221
222 /*--------------------------------------------------------
223 * functions to start/init sub-parts of the bearerbox
224 *
225 * these functions are NOT thread safe but they have no need to be,
226 * as there is only one core bearerbox thread
227 */
228
start_smsc(Cfg * cfg)229 static int start_smsc(Cfg *cfg)
230 {
231 static int started = 0;
232
233 if (started)
234 return 0;
235
236 if (smsbox_start(cfg) == -1) {
237 error(0, "Unable to start smsbox module.");
238 return -1;
239 }
240
241 if (smsc2_start(cfg) == -1) {
242 error(0, "Unable to start smsc module.");
243 return -1;
244 }
245
246 started = 1;
247 return 0;
248 }
249
250
wdp_router(void * arg)251 static void wdp_router(void *arg)
252 {
253 Msg *msg;
254
255 gwlist_add_producer(flow_threads);
256
257 while (bb_status != BB_DEAD) {
258
259 if ((msg = gwlist_consume(outgoing_wdp)) == NULL)
260 break;
261
262 gw_assert(msg_type(msg) == wdp_datagram);
263
264 /*
265 if (msg->list == sms)
266 smsc_addwdp(msg);
267 else
268 */
269
270 udp_addwdp(msg);
271 }
272 udp_die();
273 /* smsc_endwdp(); */
274
275 gwlist_remove_producer(flow_threads);
276 }
277
278
start_wap(Cfg * cfg)279 static int start_wap(Cfg *cfg)
280 {
281 static int started = 0;
282
283 if (started)
284 return 0;
285
286 wapbox_start(cfg);
287
288 debug("bb", 0, "starting WDP router");
289 if (gwthread_create(wdp_router, NULL) == -1)
290 panic(0, "Failed to start a new thread for WDP routing");
291
292 started = 1;
293 return 0;
294 }
295
296
start_udp(Cfg * cfg)297 static int start_udp(Cfg *cfg)
298 {
299 static int started = 0;
300
301 if (started)
302 return 0;
303
304 udp_start(cfg);
305
306 start_wap(cfg);
307 started = 1;
308 return 0;
309 }
310
311
312 /*
313 * check that there is basic thingies in configuration
314 */
check_config(Cfg * cfg)315 static int check_config(Cfg *cfg)
316 {
317 CfgGroup *grp;
318 long smsp, wapp;
319
320 grp = cfg_get_single_group(cfg, octstr_imm("core"));
321 if (grp == NULL)
322 return -1;
323
324 if (cfg_get_integer(&smsp, grp, octstr_imm("smsbox-port")) == -1)
325 smsp = -1;
326 if (cfg_get_integer(&wapp, grp, octstr_imm("wapbox-port")) == -1)
327 wapp = -1;
328
329 #ifndef NO_SMS
330 grp = cfg_get_single_group(cfg, octstr_imm("smsbox"));
331 if (smsp != -1 && grp == NULL) {
332 error(0, "No 'smsbox' group in configuration, but smsbox-port set");
333 return -1;
334 }
335 #else
336 warning(0, "Kannel was compiled without SMS support");
337 #endif
338
339 #ifndef NO_WAP
340 grp = cfg_get_single_group(cfg, octstr_imm("wapbox"));
341 if (wapp != -1 && grp == NULL) {
342 error(0, "No 'wapbox' group in configuration, but wapbox-port set");
343 return -1;
344 }
345 #else
346 warning(0, "Kannel was compiled without WAP support");
347 #endif
348
349 return 0;
350 }
351
352
353 /*
354 * check our own variables
355 */
check_args(int i,int argc,char ** argv)356 static int check_args(int i, int argc, char **argv)
357 {
358 if (strcmp(argv[i], "-S")==0 || strcmp(argv[i], "--suspended")==0)
359 bb_status = BB_SUSPENDED;
360 else if (strcmp(argv[i], "-I")==0 || strcmp(argv[i], "--isolated")==0)
361 bb_status = BB_ISOLATED;
362 else
363 return -1;
364
365 return 0;
366 }
367
368
init_bearerbox(Cfg * cfg)369 static Cfg *init_bearerbox(Cfg *cfg)
370 {
371 CfgGroup *grp;
372 Octstr *log, *val;
373 long loglevel, store_dump_freq, value;
374 int lf, m;
375 #ifdef HAVE_LIBSSL
376 Octstr *ssl_server_cert_file;
377 Octstr *ssl_server_key_file;
378 int ssl_enabled = 0;
379 #endif /* HAVE_LIBSSL */
380 Octstr *http_proxy_host = NULL;
381 long http_proxy_port = -1;
382 int http_proxy_ssl = 0;
383 List *http_proxy_exceptions = NULL;
384 Octstr *http_proxy_username = NULL;
385 Octstr *http_proxy_password = NULL;
386 Octstr *http_proxy_exceptions_regex = NULL;
387
388 /* defaults: use localtime and markers for access-log */
389 lf = m = 1;
390
391 grp = cfg_get_single_group(cfg, octstr_imm("core"));
392
393 log = cfg_get(grp, octstr_imm("log-file"));
394 if (log != NULL) {
395 if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
396 loglevel = 0;
397 log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
398 octstr_destroy(log);
399 }
400 if ((val = cfg_get(grp, octstr_imm("syslog-level"))) != NULL) {
401 long level;
402 Octstr *facility;
403 if ((facility = cfg_get(grp, octstr_imm("syslog-facility"))) != NULL) {
404 log_set_syslog_facility(octstr_get_cstr(facility));
405 octstr_destroy(facility);
406 }
407 if (octstr_compare(val, octstr_imm("none")) == 0) {
408 log_set_syslog(NULL, 0);
409 } else if (octstr_parse_long(&level, val, 0, 10) > 0) {
410 log_set_syslog("bearerbox", level);
411 }
412 octstr_destroy(val);
413 } else {
414 log_set_syslog(NULL, 0);
415 }
416
417 if (check_config(cfg) == -1)
418 panic(0, "Cannot start with corrupted configuration");
419
420 /* determine which timezone we use for access logging */
421 if ((log = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) {
422 lf = (octstr_case_compare(log, octstr_imm("gmt")) == 0) ? 0 : 1;
423 octstr_destroy(log);
424 }
425
426 /* should predefined markers be used, ie. prefixing timestamp */
427 cfg_get_bool(&m, grp, octstr_imm("access-log-clean"));
428
429 /* custom access-log format */
430 if ((log = cfg_get(grp, octstr_imm("access-log-format"))) != NULL) {
431 bb_alog_init(log);
432 octstr_destroy(log);
433 }
434
435 /* open access-log file */
436 if ((log = cfg_get(grp, octstr_imm("access-log"))) != NULL) {
437 alog_open(octstr_get_cstr(log), lf, m ? 0 : 1);
438 octstr_destroy(log);
439 }
440
441 if (cfg_get_integer(&store_dump_freq, grp,
442 octstr_imm("store-dump-freq")) == -1)
443 store_dump_freq = -1;
444
445 log = cfg_get(grp, octstr_imm("store-file"));
446 /* initialize the store file */
447 if (log != NULL) {
448 warning(0, "'store-file' option deprecated, please use 'store-location' and 'store-type' instead.");
449 val = octstr_create("file");
450 } else {
451 log = cfg_get(grp, octstr_imm("store-location"));
452 val = cfg_get(grp, octstr_imm("store-type"));
453 }
454 if (store_init(val, log, store_dump_freq, msg_pack, msg_unpack_wrapper) == -1)
455 panic(0, "Could not start with store init failed.");
456 octstr_destroy(val);
457 octstr_destroy(log);
458
459 cfg_get_integer(&http_proxy_port, grp, octstr_imm("http-proxy-port"));
460 #ifdef HAVE_LIBSSL
461 cfg_get_bool(&http_proxy_ssl, grp, octstr_imm("http-proxy-ssl"));
462 #endif /* HAVE_LIBSSL */
463
464 http_proxy_host = cfg_get(grp,
465 octstr_imm("http-proxy-host"));
466 http_proxy_username = cfg_get(grp,
467 octstr_imm("http-proxy-username"));
468 http_proxy_password = cfg_get(grp,
469 octstr_imm("http-proxy-password"));
470 http_proxy_exceptions = cfg_get_list(grp,
471 octstr_imm("http-proxy-exceptions"));
472 http_proxy_exceptions_regex = cfg_get(grp,
473 octstr_imm("http-proxy-exceptions-regex"));
474
475 conn_config_ssl (grp);
476
477 /*
478 * Make sure we have "ssl-server-cert-file" and "ssl-server-key-file" specified
479 * in the core group since we need it to run SSL-enabled internal box
480 * connections configured via "smsbox-port-ssl = yes" and "wapbox-port-ssl = yes".
481 * Check only these, because for "admin-port-ssl" and "sendsms-port-ssl" for the
482 * SSL-enabled HTTP servers are probed within gw/bb_http.c:httpadmin_start()
483 */
484 #ifdef HAVE_LIBSSL
485 ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file"));
486 ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file"));
487 if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) {
488 /* we are fine, at least files are specified in the configuration */
489 } else {
490 cfg_get_bool(&ssl_enabled, grp, octstr_imm("smsbox-port-ssl"));
491 cfg_get_bool(&ssl_enabled, grp, octstr_imm("wapbox-port-ssl"));
492 if (ssl_enabled) {
493 panic(0, "You MUST specify cert and key files within core group for SSL-enabled inter-box connections!");
494 }
495 }
496 octstr_destroy(ssl_server_cert_file);
497 octstr_destroy(ssl_server_key_file);
498 #endif /* HAVE_LIBSSL */
499
500 /* if all seems to be OK by the first glimpse, real start-up */
501
502 outgoing_sms = gwlist_create();
503 incoming_sms = gwlist_create();
504 outgoing_wdp = gwlist_create();
505 incoming_wdp = gwlist_create();
506
507 outgoing_sms_counter = counter_create();
508 incoming_sms_counter = counter_create();
509 incoming_dlr_counter = counter_create();
510 outgoing_dlr_counter = counter_create();
511 outgoing_wdp_counter = counter_create();
512 incoming_wdp_counter = counter_create();
513
514 status_mutex = mutex_create();
515
516 outgoing_sms_load = load_create();
517 /* add 60,300,-1 entries */
518 load_add_interval(outgoing_sms_load, 60);
519 load_add_interval(outgoing_sms_load, 300);
520 load_add_interval(outgoing_sms_load, -1);
521 incoming_sms_load = load_create();
522 /* add 60,300,-1 entries */
523 load_add_interval(incoming_sms_load, 60);
524 load_add_interval(incoming_sms_load, 300);
525 load_add_interval(incoming_sms_load, -1);
526 incoming_dlr_load = load_create();
527 /* add 60,300,-1 entries to dlr */
528 load_add_interval(incoming_dlr_load, 60);
529 load_add_interval(incoming_dlr_load, 300);
530 load_add_interval(incoming_dlr_load, -1);
531 outgoing_dlr_load = load_create();
532 /* add 60,300,-1 entries to dlr */
533 load_add_interval(outgoing_dlr_load, 60);
534 load_add_interval(outgoing_dlr_load, 300);
535 load_add_interval(outgoing_dlr_load, -1);
536
537 setup_signal_handlers();
538
539 /* http-admin is REQUIRED */
540 httpadmin_start(cfg);
541
542 if (cfg_get_integer(&max_incoming_sms_qlength, grp,
543 octstr_imm("maximum-queue-length")) == -1)
544 max_incoming_sms_qlength = -1;
545 else {
546 warning(0, "Option 'maximum-queue-length' is deprecated! Please use"
547 " 'sms-incoming-queue-limit' instead!");
548 }
549
550 if (max_incoming_sms_qlength == -1 &&
551 cfg_get_integer(&max_incoming_sms_qlength, grp,
552 octstr_imm("sms-incoming-queue-limit")) == -1)
553 max_incoming_sms_qlength = -1;
554
555 if (cfg_get_integer(&max_outgoing_sms_qlength, grp,
556 octstr_imm("sms-outgoing-queue-limit")) == -1)
557 max_outgoing_sms_qlength = -1;
558
559 if (max_outgoing_sms_qlength < 0)
560 max_outgoing_sms_qlength = DEFAULT_OUTGOING_SMS_QLENGTH;
561
562 if (cfg_get_integer(&value, grp, octstr_imm("http-timeout")) == 0)
563 http_set_client_timeout(value);
564 #ifndef NO_SMS
565 {
566 List *list;
567
568 list = cfg_get_multi_group(cfg, octstr_imm("smsc"));
569 if (list != NULL) {
570 gwlist_destroy(list, NULL);
571 if (start_smsc(cfg) == -1) {
572 panic(0, "Unable to start SMSCs.");
573 return NULL;
574 }
575 }
576 }
577 #endif
578
579 #ifndef NO_WAP
580 grp = cfg_get_single_group(cfg, octstr_imm("core"));
581 val = cfg_get(grp, octstr_imm("wdp-interface-name"));
582 if (val != NULL && octstr_len(val) > 0)
583 start_udp(cfg);
584 octstr_destroy(val);
585
586 if (cfg_get_single_group(cfg, octstr_imm("wapbox")) != NULL)
587 start_wap(cfg);
588 #endif
589
590 if (http_proxy_host != NULL && http_proxy_port > 0) {
591 http_use_proxy(http_proxy_host, http_proxy_port, http_proxy_ssl,
592 http_proxy_exceptions, http_proxy_username,
593 http_proxy_password, http_proxy_exceptions_regex);
594 }
595
596 octstr_destroy(http_proxy_host);
597 octstr_destroy(http_proxy_username);
598 octstr_destroy(http_proxy_password);
599 octstr_destroy(http_proxy_exceptions_regex);
600 gwlist_destroy(http_proxy_exceptions, octstr_destroy_item);
601
602 return cfg;
603 }
604
605
empty_msg_lists(void)606 static void empty_msg_lists(void)
607 {
608 Msg *msg;
609
610 #ifndef NO_WAP
611 if (gwlist_len(incoming_wdp) > 0 || gwlist_len(outgoing_wdp) > 0)
612 warning(0, "Remaining WDP: %ld incoming, %ld outgoing",
613 gwlist_len(incoming_wdp), gwlist_len(outgoing_wdp));
614
615 info(0, "Total WDP messages: received %ld, sent %ld",
616 counter_value(incoming_wdp_counter),
617 counter_value(outgoing_wdp_counter));
618 #endif
619
620 while ((msg = gwlist_extract_first(incoming_wdp)) != NULL)
621 msg_destroy(msg);
622 while ((msg = gwlist_extract_first(outgoing_wdp)) != NULL)
623 msg_destroy(msg);
624
625 gwlist_destroy(incoming_wdp, NULL);
626 gwlist_destroy(outgoing_wdp, NULL);
627
628 counter_destroy(incoming_wdp_counter);
629 counter_destroy(outgoing_wdp_counter);
630
631 #ifndef NO_SMS
632 /* XXX we should record these so that they are not forever lost... */
633 if (gwlist_len(incoming_sms) > 0 || gwlist_len(outgoing_sms) > 0)
634 debug("bb", 0, "Remaining SMS: %ld incoming, %ld outgoing",
635 gwlist_len(incoming_sms), gwlist_len(outgoing_sms));
636
637 info(0, "Total SMS messages: received %ld, dlr %ld, sent %ld, dlr %ld",
638 counter_value(incoming_sms_counter),
639 counter_value(incoming_dlr_counter),
640 counter_value(outgoing_sms_counter),
641 counter_value(outgoing_dlr_counter));
642 #endif
643
644 gwlist_destroy(incoming_sms, msg_destroy_item);
645 gwlist_destroy(outgoing_sms, msg_destroy_item);
646
647 counter_destroy(incoming_sms_counter);
648 counter_destroy(incoming_dlr_counter);
649 counter_destroy(outgoing_sms_counter);
650 counter_destroy(outgoing_dlr_counter);
651
652 load_destroy(incoming_sms_load);
653 load_destroy(incoming_dlr_load);
654 load_destroy(outgoing_sms_load);
655 load_destroy(outgoing_dlr_load);
656 }
657
658
dispatch_into_queue(Msg * msg)659 static void dispatch_into_queue(Msg *msg)
660 {
661 char id[UUID_STR_LEN + 1];
662
663 gw_assert(msg != NULL),
664 gw_assert(msg_type(msg) == sms);
665
666 switch (msg->sms.sms_type) {
667 case mt_push:
668 case mt_reply:
669 case report_mt:
670 gwlist_append(outgoing_sms, msg);
671 break;
672 case mo:
673 case report_mo:
674 gwlist_append(incoming_sms, msg);
675 break;
676 default:
677 uuid_unparse(msg->sms.id, id);
678 error(0, "Not handled sms_type %ld within store for message ID %s",
679 msg->sms.sms_type, id);
680 msg_destroy(msg);
681 break;
682 }
683 }
684
685
main(int argc,char ** argv)686 int main(int argc, char **argv)
687 {
688 int cf_index;
689 Cfg *cfg;
690
691 bb_status = BB_RUNNING;
692
693 gwlib_init();
694 start_time = time(NULL);
695
696 suspended = gwlist_create();
697 isolated = gwlist_create();
698 gwlist_add_producer(suspended);
699 gwlist_add_producer(isolated);
700
701 cf_index = get_and_set_debugs(argc, argv, check_args);
702
703 if (argv[cf_index] == NULL)
704 cfg_filename = octstr_create("kannel.conf");
705 else
706 cfg_filename = octstr_create(argv[cf_index]);
707 cfg = cfg_create(cfg_filename);
708
709 if (cfg_read(cfg) == -1)
710 panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(cfg_filename));
711
712 dlr_init(cfg);
713
714 report_versions("bearerbox");
715
716 flow_threads = gwlist_create();
717
718 if (init_bearerbox(cfg) == NULL)
719 panic(0, "Initialization failed.");
720
721 info(0, "----------------------------------------");
722 info(0, GW_NAME " bearerbox II version %s starting", GW_VERSION);
723
724 gwthread_sleep(5.0); /* give time to threads to register themselves */
725
726 if (store_load(dispatch_into_queue) == -1)
727 panic(0, "Cannot start with store-file failing");
728
729 info(0, "MAIN: Start-up done, entering mainloop");
730 if (bb_status == BB_SUSPENDED) {
731 info(0, "Gateway is now SUSPENDED by startup arguments");
732 } else if (bb_status == BB_ISOLATED) {
733 info(0, "Gateway is now ISOLATED by startup arguments");
734 gwlist_remove_producer(suspended);
735 } else {
736 smsc2_resume(1);
737 gwlist_remove_producer(suspended);
738 gwlist_remove_producer(isolated);
739 }
740
741 while (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD &&
742 gwlist_producer_count(flow_threads) > 0) {
743 /* debug("bb", 0, "Main Thread: going to sleep."); */
744 /*
745 * Not infinite sleep here, because we should notice
746 * when all "flow threads" are dead and shutting bearerbox
747 * down.
748 * XXX if all "flow threads" call gwthread_wakeup(MAIN_THREAD_ID),
749 * we can enter infinite sleep then.
750 */
751 gwthread_sleep(10.0);
752 /* debug("bb", 0, "Main Thread: woken up."); */
753
754 if (bb_todo == 0) {
755 continue;
756 }
757
758 if (bb_todo & BB_LOGREOPEN) {
759 warning(0, "SIGHUP received, catching and re-opening logs");
760 log_reopen();
761 alog_reopen();
762 bb_todo = bb_todo & ~BB_LOGREOPEN;
763 }
764
765 if (bb_todo & BB_CHECKLEAKS) {
766 warning(0, "SIGQUIT received, reporting memory usage.");
767 gw_check_leaks();
768 bb_todo = bb_todo & ~BB_CHECKLEAKS;
769 }
770 }
771
772 if (bb_status == BB_SHUTDOWN || bb_status == BB_DEAD)
773 warning(0, "Killing signal or HTTP admin command received, shutting down...");
774
775 /* call shutdown */
776 bb_shutdown();
777
778 /* wait until flow threads exit */
779 while (gwlist_consume(flow_threads) != NULL)
780 ;
781
782 info(0, "All flow threads have died, killing core");
783 bb_status = BB_DEAD;
784 httpadmin_stop();
785
786 boxc_cleanup();
787 smsc2_cleanup();
788 store_shutdown();
789 empty_msg_lists();
790 gwlist_destroy(flow_threads, NULL);
791 gwlist_destroy(suspended, NULL);
792 gwlist_destroy(isolated, NULL);
793 mutex_destroy(status_mutex);
794
795 alog_close(); /* if we have any */
796 bb_alog_shutdown();
797 cfg_destroy(cfg);
798 octstr_destroy(cfg_filename);
799 dlr_shutdown();
800
801 /* now really restart */
802 if (restart)
803 restart_box(argv);
804
805 gwlib_shutdown();
806
807 return 0;
808 }
809
810
811 /*----------------------------------------------------------------
812 * public functions used via HTTP adminstration interface/module
813 */
814
bb_shutdown(void)815 int bb_shutdown(void)
816 {
817 static int called = 0;
818
819 mutex_lock(status_mutex);
820
821 if (called) {
822 mutex_unlock(status_mutex);
823 return -1;
824 }
825 debug("bb", 0, "Shutting down " GW_NAME "...");
826
827 called = 1;
828 set_shutdown_status();
829 mutex_unlock(status_mutex);
830
831 #ifndef NO_SMS
832 debug("bb", 0, "shutting down smsc");
833 smsc2_shutdown();
834 #endif
835 #ifndef NO_WAP
836 debug("bb", 0, "shutting down udp");
837 udp_shutdown();
838 #endif
839
840 return 0;
841 }
842
843
bb_isolate(void)844 int bb_isolate(void)
845 {
846 mutex_lock(status_mutex);
847 if (bb_status != BB_RUNNING && bb_status != BB_SUSPENDED) {
848 mutex_unlock(status_mutex);
849 return -1;
850 }
851 if (bb_status == BB_RUNNING) {
852 smsc2_suspend();
853 gwlist_add_producer(isolated);
854 } else
855 gwlist_remove_producer(suspended);
856
857 bb_status = BB_ISOLATED;
858 mutex_unlock(status_mutex);
859 return 0;
860 }
861
862
bb_suspend(void)863 int bb_suspend(void)
864 {
865 mutex_lock(status_mutex);
866 if (bb_status != BB_RUNNING && bb_status != BB_ISOLATED) {
867 mutex_unlock(status_mutex);
868 return -1;
869 }
870 if (bb_status != BB_ISOLATED) {
871 smsc2_suspend();
872 gwlist_add_producer(isolated);
873 }
874 bb_status = BB_SUSPENDED;
875 gwlist_add_producer(suspended);
876 mutex_unlock(status_mutex);
877 return 0;
878 }
879
880
bb_resume(void)881 int bb_resume(void)
882 {
883 mutex_lock(status_mutex);
884 if (bb_status != BB_SUSPENDED && bb_status != BB_ISOLATED) {
885 mutex_unlock(status_mutex);
886 return -1;
887 }
888 if (bb_status == BB_SUSPENDED)
889 gwlist_remove_producer(suspended);
890
891 smsc2_resume(0);
892 bb_status = BB_RUNNING;
893 gwlist_remove_producer(isolated);
894 mutex_unlock(status_mutex);
895 return 0;
896 }
897
898
bb_flush_dlr(void)899 int bb_flush_dlr(void)
900 {
901 /* beware that mutex locking is done in dlr_foobar() routines */
902 if (bb_status != BB_SUSPENDED) {
903 return -1;
904 }
905 dlr_flush();
906 return 0;
907 }
908
909
bb_stop_smsc(Octstr * id)910 int bb_stop_smsc(Octstr *id)
911 {
912 return smsc2_stop_smsc(id);
913 }
914
915
bb_restart_smsc(Octstr * id)916 int bb_restart_smsc(Octstr *id)
917 {
918 return smsc2_restart_smsc(id);
919 }
920
bb_add_smsc(Octstr * id)921 int bb_add_smsc(Octstr *id)
922 {
923 return smsc2_add_smsc(id);
924 }
925
bb_remove_smsc(Octstr * id)926 int bb_remove_smsc(Octstr *id)
927 {
928 return smsc2_remove_smsc(id);
929 }
930
bb_restart(void)931 int bb_restart(void)
932 {
933 restart = 1;
934 return bb_shutdown();
935 }
936
bb_reload_lists(void)937 int bb_reload_lists(void)
938 {
939 return smsc2_reload_lists();
940 }
941
bb_remove_message(Octstr * message_id)942 int bb_remove_message(Octstr *message_id)
943 {
944 Msg *msg;
945 int ret;
946
947 msg = msg_create(ack);
948 msg->ack.nack = ack_failed;
949 msg->ack.time = time(NULL);
950 uuid_parse(octstr_get_cstr(message_id), msg->ack.id);
951 ret = store_save(msg);
952 msg_destroy(msg);
953 if (ret != 0) {
954 error(0, "Could not delete message %s", octstr_get_cstr(message_id));
955 return -1;
956 }
957 return 0;
958 }
959
960
961 #define append_status(r, s, f, x) { s = f(x); octstr_append(r, s); \
962 octstr_destroy(s); }
963
bb_print_status(int status_type)964 Octstr *bb_print_status(int status_type)
965 {
966 char *s, *lb;
967 char *frmt, *footer;
968 Octstr *ret, *str, *version;
969 time_t t;
970
971 if ((lb = bb_status_linebreak(status_type)) == NULL)
972 return octstr_create("Un-supported format");
973
974 t = time(NULL) - start_time;
975
976 if (bb_status == BB_RUNNING)
977 s = "running";
978 else if (bb_status == BB_ISOLATED)
979 s = "isolated";
980 else if (bb_status == BB_SUSPENDED)
981 s = "suspended";
982 else if (bb_status == BB_FULL)
983 s = "filled";
984 else
985 s = "going down";
986
987 version = version_report_string("bearerbox");
988
989 if (status_type == BBSTATUS_HTML) {
990 frmt = "%s</p>\n\n"
991 " <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>\n\n"
992 " <p>WDP: received %ld (%ld queued), sent %ld "
993 "(%ld queued)</p>\n\n"
994 " <p>SMS: received %ld (%ld queued), sent %ld "
995 "(%ld queued), store size %ld<br>\n"
996 " SMS: inbound (%.2f,%.2f,%.2f) msg/sec, "
997 "outbound (%.2f,%.2f,%.2f) msg/sec</p>\n\n"
998 " <p>DLR: received %ld, sent %ld<br>\n"
999 " DLR: inbound (%.2f,%.2f,%.2f) msg/sec, outbound (%.2f,%.2f,%.2f) msg/sec<br>\n"
1000 " DLR: %ld queued, using %s storage</p>\n\n";
1001 footer = "<p>";
1002 } else if (status_type == BBSTATUS_WML) {
1003 frmt = "%s</p>\n\n"
1004 " <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>\n\n"
1005 " <p>WDP: received %ld (%ld queued)<br/>\n"
1006 " WDP: sent %ld (%ld queued)</p>\n\n"
1007 " <p>SMS: received %ld (%ld queued)<br/>\n"
1008 " SMS: sent %ld (%ld queued)<br/>\n"
1009 " SMS: store size %ld<br/>\n"
1010 " SMS: inbound (%.2f,%.2f,%.2f) msg/sec<br/>\n"
1011 " SMS: outbound (%.2f,%.2f,%.2f) msg/sec</p>\n"
1012 " <p>DLR: received %ld<br/>\n"
1013 " DLR: sent %ld<br/>\n"
1014 " DLR: inbound (%.2f,%.2f,%.2f) msg/sec<br/>\n"
1015 " DLR: outbound (%.2f,%.2f,%.2f) msg/sec<br/>\n"
1016 " DLR: %ld queued<br/>\n"
1017 " DLR: using %s storage</p>\n\n";
1018 footer = "<p>";
1019 } else if (status_type == BBSTATUS_XML) {
1020 frmt = "<version>%s</version>\n"
1021 "<status>%s, uptime %ldd %ldh %ldm %lds</status>\n"
1022 "\t<wdp>\n\t\t<received><total>%ld</total><queued>%ld</queued>"
1023 "</received>\n\t\t<sent><total>%ld</total><queued>%ld</queued>"
1024 "</sent>\n\t</wdp>\n"
1025 "\t<sms>\n\t\t<received><total>%ld</total><queued>%ld</queued>"
1026 "</received>\n\t\t<sent><total>%ld</total><queued>%ld</queued>"
1027 "</sent>\n\t\t<storesize>%ld</storesize>\n\t\t"
1028 "<inbound>%.2f,%.2f,%.2f</inbound>\n\t\t"
1029 "<outbound>%.2f,%.2f,%.2f</outbound>\n\t\t"
1030 "</sms>\n"
1031 "\t<dlr>\n\t\t<received><total>%ld</total></received>\n\t\t"
1032 "<sent><total>%ld</total></sent>\n\t\t"
1033 "<inbound>%.2f,%.2f,%.2f</inbound>\n\t\t"
1034 "<outbound>%.2f,%.2f,%.2f</outbound>\n\t\t"
1035 "<queued>%ld</queued>\n\t\t<storage>%s</storage>\n\t</dlr>\n";
1036 footer = "";
1037 } else {
1038 frmt = "%s\n\nStatus: %s, uptime %ldd %ldh %ldm %lds\n\n"
1039 "WDP: received %ld (%ld queued), sent %ld (%ld queued)\n\n"
1040 "SMS: received %ld (%ld queued), sent %ld (%ld queued), store size %ld\n"
1041 "SMS: inbound (%.2f,%.2f,%.2f) msg/sec, "
1042 "outbound (%.2f,%.2f,%.2f) msg/sec\n\n"
1043 "DLR: received %ld, sent %ld\n"
1044 "DLR: inbound (%.2f,%.2f,%.2f) msg/sec, outbound (%.2f,%.2f,%.2f) msg/sec\n"
1045 "DLR: %ld queued, using %s storage\n\n";
1046 footer = "";
1047 }
1048
1049 ret = octstr_format(frmt,
1050 octstr_get_cstr(version),
1051 s, t/3600/24, t/3600%24, t/60%60, t%60,
1052 counter_value(incoming_wdp_counter),
1053 gwlist_len(incoming_wdp) + boxc_incoming_wdp_queue(),
1054 counter_value(outgoing_wdp_counter), gwlist_len(outgoing_wdp) + udp_outgoing_queue(),
1055 counter_value(incoming_sms_counter), gwlist_len(incoming_sms),
1056 counter_value(outgoing_sms_counter), gwlist_len(outgoing_sms),
1057 store_messages(),
1058 load_get(incoming_sms_load,0), load_get(incoming_sms_load,1), load_get(incoming_sms_load,2),
1059 load_get(outgoing_sms_load,0), load_get(outgoing_sms_load,1), load_get(outgoing_sms_load,2),
1060 counter_value(incoming_dlr_counter), counter_value(outgoing_dlr_counter),
1061 load_get(incoming_dlr_load,0), load_get(incoming_dlr_load,1), load_get(incoming_dlr_load,2),
1062 load_get(outgoing_dlr_load,0), load_get(outgoing_dlr_load,1), load_get(outgoing_dlr_load,2),
1063 dlr_messages(), dlr_type());
1064
1065 octstr_destroy(version);
1066
1067 append_status(ret, str, boxc_status, status_type);
1068 append_status(ret, str, smsc2_status, status_type);
1069 octstr_append_cstr(ret, footer);
1070
1071 return ret;
1072 }
1073
1074
bb_status_linebreak(int status_type)1075 char *bb_status_linebreak(int status_type)
1076 {
1077 switch (status_type) {
1078 case BBSTATUS_HTML:
1079 return "<br>\n";
1080 case BBSTATUS_WML:
1081 return "<br/>\n";
1082 case BBSTATUS_TEXT:
1083 return "\n";
1084 case BBSTATUS_XML:
1085 return "\n";
1086 default:
1087 return NULL;
1088 }
1089 }
1090