Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
bearerbox.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * 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 
86 
89 
96 
97 /* incoming/outgoing sms queue control */
100 
101 
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  */
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  */
123 
124 /* this one is like 'suspended', but only for receiving UDP/SMSC
125  * (suspended state puts producers for both lists)
126  */
128 
129 /* configuration 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 {
141 };
142 /* Here we will set above flags */
143 static volatile sig_atomic_t bb_todo = 0;
144 
145 /* own global variables */
146 
148 static time_t start_time;
149 volatile sig_atomic_t restart = 0;
150 
151 
152 /* to avoid copied code */
153 
154 static void set_shutdown_status(void)
155 {
156  sig_atomic_t old = bb_status;
158 
159  if (old == BB_SUSPENDED)
160  gwlist_remove_producer(suspended);
161  if (old == BB_SUSPENDED || old == BB_ISOLATED)
162  gwlist_remove_producer(isolated);
163 }
164 
165 
166 /*-------------------------------------------------------
167  * signals
168  */
169 
170 static void signal_handler(int signum)
171 {
172  /* On some implementations (i.e. linuxthreads), signals are delivered
173  * to all threads. We only want to handle each signal once for the
174  * entire box, and we let the gwthread wrapper take care of choosing
175  * one.
176  */
177  if (!gwthread_shouldhandlesignal(signum))
178  return;
179 
180  switch (signum) {
181  case SIGINT:
182  case SIGTERM:
183  if (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) {
185  }
186  else if (bb_status == BB_SHUTDOWN) {
187  bb_status = BB_DEAD;
188  }
189  else if (bb_status == BB_DEAD) {
190  panic(0, "Cannot die by its own will");
191  }
192  break;
193 
194  case SIGHUP:
196  break;
197 
198  case SIGUSR2:
200  break;
201 
202  /*
203  * It would be more proper to use SIGUSR1 for this, but on some
204  * platforms that's reserved by the pthread support.
205  */
206  case SIGQUIT:
208  break;
209  }
210 }
211 
212 static void setup_signal_handlers(void)
213 {
214  struct sigaction act;
215 
216  act.sa_handler = signal_handler;
217  sigemptyset(&act.sa_mask);
218  act.sa_flags = 0;
219  sigaction(SIGINT, &act, NULL);
220  sigaction(SIGTERM, &act, NULL);
221  sigaction(SIGQUIT, &act, NULL);
222  sigaction(SIGHUP, &act, NULL);
223  sigaction(SIGPIPE, &act, NULL);
224  sigaction(SIGUSR2, &act, NULL);
225 }
226 
227 
228 /*--------------------------------------------------------
229  * functions to start/init sub-parts of the bearerbox
230  *
231  * these functions are NOT thread safe but they have no need to be,
232  * as there is only one core bearerbox thread
233  */
234 
235 static int start_smsc(Cfg *cfg)
236 {
237  static int started = 0;
238 
239  if (started)
240  return 0;
241 
242  if (smsbox_start(cfg) == -1) {
243  error(0, "Unable to start smsbox module.");
244  return -1;
245  }
246 
247  if (smsc2_start(cfg) == -1) {
248  error(0, "Unable to start smsc module.");
249  return -1;
250  }
251 
252  started = 1;
253  return 0;
254 }
255 
256 
257 static void wdp_router(void *arg)
258 {
259  Msg *msg;
260 
261  gwlist_add_producer(flow_threads);
262 
263  while (bb_status != BB_DEAD) {
264 
265  if ((msg = gwlist_consume(outgoing_wdp)) == NULL)
266  break;
267 
268  gw_assert(msg_type(msg) == wdp_datagram);
269 
270  /*
271  if (msg->list == sms)
272  smsc_addwdp(msg);
273  else
274  */
275 
276  udp_addwdp(msg);
277  }
278  udp_die();
279  /* smsc_endwdp(); */
280 
281  gwlist_remove_producer(flow_threads);
282 }
283 
284 
285 static int start_wap(Cfg *cfg)
286 {
287  static int started = 0;
288 
289  if (started)
290  return 0;
291 
292  wapbox_start(cfg);
293 
294  debug("bb", 0, "starting WDP router");
295  if (gwthread_create(wdp_router, NULL) == -1)
296  panic(0, "Failed to start a new thread for WDP routing");
297 
298  started = 1;
299  return 0;
300 }
301 
302 
303 static int start_udp(Cfg *cfg)
304 {
305  static int started = 0;
306 
307  if (started)
308  return 0;
309 
310  udp_start(cfg);
311 
312  start_wap(cfg);
313  started = 1;
314  return 0;
315 }
316 
317 
318 /*
319  * check that there is basic thingies in configuration
320  */
321 static int check_config(Cfg *cfg)
322 {
323  CfgGroup *grp;
324  long smsp, wapp;
325 
326  grp = cfg_get_single_group(cfg, octstr_imm("core"));
327  if (grp == NULL)
328  return -1;
329 
330  if (cfg_get_integer(&smsp, grp, octstr_imm("smsbox-port")) == -1)
331  smsp = -1;
332  if (cfg_get_integer(&wapp, grp, octstr_imm("wapbox-port")) == -1)
333  wapp = -1;
334 
335 #ifndef NO_SMS
336  grp = cfg_get_single_group(cfg, octstr_imm("smsbox"));
337  if (smsp != -1 && grp == NULL) {
338  error(0, "No 'smsbox' group in configuration, but smsbox-port set");
339  return -1;
340  }
341 #else
342  warning(0, "Kannel was compiled without SMS support");
343 #endif
344 
345 #ifndef NO_WAP
346  grp = cfg_get_single_group(cfg, octstr_imm("wapbox"));
347  if (wapp != -1 && grp == NULL) {
348  error(0, "No 'wapbox' group in configuration, but wapbox-port set");
349  return -1;
350  }
351 #else
352  warning(0, "Kannel was compiled without WAP support");
353 #endif
354 
355  return 0;
356 }
357 
358 
359 /*
360  * check our own variables
361  */
362 static int check_args(int i, int argc, char **argv)
363 {
364  if (strcmp(argv[i], "-S")==0 || strcmp(argv[i], "--suspended")==0)
366  else if (strcmp(argv[i], "-I")==0 || strcmp(argv[i], "--isolated")==0)
368  else
369  return -1;
370 
371  return 0;
372 }
373 
374 
376 {
377  CfgGroup *grp;
378  Octstr *log, *val;
379  long loglevel, store_dump_freq, value;
380  int lf, m;
381 #ifdef HAVE_LIBSSL
382  Octstr *ssl_server_cert_file;
383  Octstr *ssl_server_key_file;
384  int ssl_enabled = 0;
385 #endif /* HAVE_LIBSSL */
386  Octstr *http_proxy_host = NULL;
387  long http_proxy_port = -1;
388  int http_proxy_ssl = 0;
389  List *http_proxy_exceptions = NULL;
390  Octstr *http_proxy_username = NULL;
391  Octstr *http_proxy_password = NULL;
392  Octstr *http_proxy_exceptions_regex = NULL;
393 
394  /* defaults: use localtime and markers for access-log */
395  lf = m = 1;
396 
397  grp = cfg_get_single_group(cfg, octstr_imm("core"));
398 
399  log = cfg_get(grp, octstr_imm("log-file"));
400  if (log != NULL) {
401  if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
402  loglevel = 0;
403  log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
404  octstr_destroy(log);
405  }
406  if ((val = cfg_get(grp, octstr_imm("syslog-level"))) != NULL) {
407  long level;
408  Octstr *facility;
409  if ((facility = cfg_get(grp, octstr_imm("syslog-facility"))) != NULL) {
411  octstr_destroy(facility);
412  }
413  if (octstr_compare(val, octstr_imm("none")) == 0) {
414  log_set_syslog(NULL, 0);
415  } else if (octstr_parse_long(&level, val, 0, 10) > 0) {
416  log_set_syslog("bearerbox", level);
417  }
418  octstr_destroy(val);
419  } else {
420  log_set_syslog(NULL, 0);
421  }
422 
423  if (check_config(cfg) == -1)
424  panic(0, "Cannot start with corrupted configuration");
425 
426  /* determine which timezone we use for access logging */
427  if ((log = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) {
428  lf = (octstr_case_compare(log, octstr_imm("gmt")) == 0) ? 0 : 1;
429  octstr_destroy(log);
430  }
431 
432  /* should predefined markers be used, ie. prefixing timestamp */
433  cfg_get_bool(&m, grp, octstr_imm("access-log-clean"));
434 
435  /* custom access-log format */
436  if ((log = cfg_get(grp, octstr_imm("access-log-format"))) != NULL) {
437  bb_alog_init(log);
438  octstr_destroy(log);
439  }
440 
441  /* open access-log file */
442  if ((log = cfg_get(grp, octstr_imm("access-log"))) != NULL) {
443  alog_open(octstr_get_cstr(log), lf, m ? 0 : 1);
444  octstr_destroy(log);
445  }
446 
447  if (cfg_get_integer(&store_dump_freq, grp,
448  octstr_imm("store-dump-freq")) == -1)
449  store_dump_freq = -1;
450 
451  log = cfg_get(grp, octstr_imm("store-file"));
452  /* initialize the store file */
453  if (log != NULL) {
454  warning(0, "'store-file' option deprecated, please use 'store-location' and 'store-type' instead.");
455  val = octstr_create("file");
456  } else {
457  log = cfg_get(grp, octstr_imm("store-location"));
458  val = cfg_get(grp, octstr_imm("store-type"));
459  }
460  if (store_init(cfg, val, log, store_dump_freq, msg_pack, msg_unpack_wrapper) == -1)
461  panic(0, "Could not start with store init failed.");
462  octstr_destroy(val);
463  octstr_destroy(log);
464 
465  cfg_get_integer(&http_proxy_port, grp, octstr_imm("http-proxy-port"));
466 #ifdef HAVE_LIBSSL
467  cfg_get_bool(&http_proxy_ssl, grp, octstr_imm("http-proxy-ssl"));
468 #endif /* HAVE_LIBSSL */
469 
470  http_proxy_host = cfg_get(grp,
471  octstr_imm("http-proxy-host"));
472  http_proxy_username = cfg_get(grp,
473  octstr_imm("http-proxy-username"));
474  http_proxy_password = cfg_get(grp,
475  octstr_imm("http-proxy-password"));
476  http_proxy_exceptions = cfg_get_list(grp,
477  octstr_imm("http-proxy-exceptions"));
478  http_proxy_exceptions_regex = cfg_get(grp,
479  octstr_imm("http-proxy-exceptions-regex"));
480 
481  conn_config_ssl (grp);
482 
483  /*
484  * Make sure we have "ssl-server-cert-file" and "ssl-server-key-file" specified
485  * in the core group since we need it to run SSL-enabled internal box
486  * connections configured via "smsbox-port-ssl = yes" and "wapbox-port-ssl = yes".
487  * Check only these, because for "admin-port-ssl" and "sendsms-port-ssl" for the
488  * SSL-enabled HTTP servers are probed within gw/bb_http.c:httpadmin_start()
489  */
490 #ifdef HAVE_LIBSSL
491  ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file"));
492  ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file"));
493  if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) {
494  /* we are fine, at least files are specified in the configuration */
495  } else {
496  cfg_get_bool(&ssl_enabled, grp, octstr_imm("smsbox-port-ssl"));
497  cfg_get_bool(&ssl_enabled, grp, octstr_imm("wapbox-port-ssl"));
498  if (ssl_enabled) {
499  panic(0, "You MUST specify cert and key files within core group for SSL-enabled inter-box connections!");
500  }
501  }
502  octstr_destroy(ssl_server_cert_file);
503  octstr_destroy(ssl_server_key_file);
504 #endif /* HAVE_LIBSSL */
505 
506  /* if all seems to be OK by the first glimpse, real start-up */
507 
508  outgoing_sms = gwlist_create();
509  incoming_sms = gwlist_create();
510  outgoing_wdp = gwlist_create();
511  incoming_wdp = gwlist_create();
512 
513  outgoing_sms_counter = counter_create();
514  incoming_sms_counter = counter_create();
515  incoming_dlr_counter = counter_create();
516  outgoing_dlr_counter = counter_create();
517  outgoing_wdp_counter = counter_create();
518  incoming_wdp_counter = counter_create();
519 
520  status_mutex = mutex_create();
521 
522  outgoing_sms_load = load_create();
523  /* add 60,300,-1 entries */
524  load_add_interval(outgoing_sms_load, 60);
525  load_add_interval(outgoing_sms_load, 300);
526  load_add_interval(outgoing_sms_load, -1);
527  incoming_sms_load = load_create();
528  /* add 60,300,-1 entries */
529  load_add_interval(incoming_sms_load, 60);
530  load_add_interval(incoming_sms_load, 300);
531  load_add_interval(incoming_sms_load, -1);
532  incoming_dlr_load = load_create();
533  /* add 60,300,-1 entries to dlr */
534  load_add_interval(incoming_dlr_load, 60);
535  load_add_interval(incoming_dlr_load, 300);
536  load_add_interval(incoming_dlr_load, -1);
537  outgoing_dlr_load = load_create();
538  /* add 60,300,-1 entries to dlr */
539  load_add_interval(outgoing_dlr_load, 60);
540  load_add_interval(outgoing_dlr_load, 300);
541  load_add_interval(outgoing_dlr_load, -1);
542 
544 
545  /* http-admin is REQUIRED */
546  httpadmin_start(cfg);
547 
549  octstr_imm("maximum-queue-length")) == -1)
551  else {
552  warning(0, "Option 'maximum-queue-length' is deprecated! Please use"
553  " 'sms-incoming-queue-limit' instead!");
554  }
555 
556  if (max_incoming_sms_qlength == -1 &&
558  octstr_imm("sms-incoming-queue-limit")) == -1)
560 
562  octstr_imm("sms-outgoing-queue-limit")) == -1)
564 
565  if (max_outgoing_sms_qlength < 0)
567 
568  if (cfg_get_integer(&value, grp, octstr_imm("http-timeout")) == 0)
570 #ifndef NO_SMS
571  {
572  List *list;
573 
574  list = cfg_get_multi_group(cfg, octstr_imm("smsc"));
575  if (list != NULL) {
576  gwlist_destroy(list, NULL);
577  if (start_smsc(cfg) == -1) {
578  panic(0, "Unable to start SMSCs.");
579  return NULL;
580  }
581  }
582  }
583 #endif
584 
585 #ifndef NO_WAP
586  grp = cfg_get_single_group(cfg, octstr_imm("core"));
587  val = cfg_get(grp, octstr_imm("wdp-interface-name"));
588  if (val != NULL && octstr_len(val) > 0)
589  start_udp(cfg);
590  octstr_destroy(val);
591 
592  if (cfg_get_single_group(cfg, octstr_imm("wapbox")) != NULL)
593  start_wap(cfg);
594 #endif
595 
596  if (http_proxy_host != NULL && http_proxy_port > 0) {
597  http_use_proxy(http_proxy_host, http_proxy_port, http_proxy_ssl,
598  http_proxy_exceptions, http_proxy_username,
599  http_proxy_password, http_proxy_exceptions_regex);
600  }
601 
602  octstr_destroy(http_proxy_host);
603  octstr_destroy(http_proxy_username);
604  octstr_destroy(http_proxy_password);
605  octstr_destroy(http_proxy_exceptions_regex);
606  gwlist_destroy(http_proxy_exceptions, octstr_destroy_item);
607 
608  return cfg;
609 }
610 
611 
612 static void empty_msg_lists(void)
613 {
614  Msg *msg;
615 
616 #ifndef NO_WAP
617  if (gwlist_len(incoming_wdp) > 0 || gwlist_len(outgoing_wdp) > 0)
618  warning(0, "Remaining WDP: %ld incoming, %ld outgoing",
619  gwlist_len(incoming_wdp), gwlist_len(outgoing_wdp));
620 
621  info(0, "Total WDP messages: received %ld, sent %ld",
622  counter_value(incoming_wdp_counter),
623  counter_value(outgoing_wdp_counter));
624 #endif
625 
626  while ((msg = gwlist_extract_first(incoming_wdp)) != NULL)
627  msg_destroy(msg);
628  while ((msg = gwlist_extract_first(outgoing_wdp)) != NULL)
629  msg_destroy(msg);
630 
631  gwlist_destroy(incoming_wdp, NULL);
632  gwlist_destroy(outgoing_wdp, NULL);
633 
634  counter_destroy(incoming_wdp_counter);
635  counter_destroy(outgoing_wdp_counter);
636 
637 #ifndef NO_SMS
638  /* XXX we should record these so that they are not forever lost... */
639  if (gwlist_len(incoming_sms) > 0 || gwlist_len(outgoing_sms) > 0)
640  debug("bb", 0, "Remaining SMS: %ld incoming, %ld outgoing",
641  gwlist_len(incoming_sms), gwlist_len(outgoing_sms));
642 
643  info(0, "Total SMS messages: received %ld, dlr %ld, sent %ld, dlr %ld",
644  counter_value(incoming_sms_counter),
645  counter_value(incoming_dlr_counter),
646  counter_value(outgoing_sms_counter),
647  counter_value(outgoing_dlr_counter));
648 #endif
649 
650  gwlist_destroy(incoming_sms, msg_destroy_item);
651  gwlist_destroy(outgoing_sms, msg_destroy_item);
652 
653  counter_destroy(incoming_sms_counter);
654  counter_destroy(incoming_dlr_counter);
655  counter_destroy(outgoing_sms_counter);
656  counter_destroy(outgoing_dlr_counter);
657 
658  load_destroy(incoming_sms_load);
659  load_destroy(incoming_dlr_load);
660  load_destroy(outgoing_sms_load);
661  load_destroy(outgoing_dlr_load);
662 }
663 
664 
666 {
667  char id[UUID_STR_LEN + 1];
668 
669  gw_assert(msg != NULL),
670  gw_assert(msg_type(msg) == sms);
671 
672  switch (msg->sms.sms_type) {
673  case mt_push:
674  case mt_reply:
675  case report_mt:
676  gwlist_append(outgoing_sms, msg);
677  break;
678  case mo:
679  case report_mo:
680  gwlist_append(incoming_sms, msg);
681  break;
682  default:
683  uuid_unparse(msg->sms.id, id);
684  error(0, "Not handled sms_type %ld within store for message ID %s",
685  msg->sms.sms_type, id);
686  msg_destroy(msg);
687  break;
688  }
689 }
690 
691 
692 int main(int argc, char **argv)
693 {
694  int cf_index;
695  Cfg *cfg;
696 
698 
699  gwlib_init();
700  start_time = time(NULL);
701 
702  suspended = gwlist_create();
703  isolated = gwlist_create();
704  gwlist_add_producer(suspended);
705  gwlist_add_producer(isolated);
706 
707  cf_index = get_and_set_debugs(argc, argv, check_args);
708 
709  if (argv[cf_index] == NULL)
710  cfg_filename = octstr_create("kannel.conf");
711  else
712  cfg_filename = octstr_create(argv[cf_index]);
713  cfg = cfg_create(cfg_filename);
714 
715  if (cfg_read(cfg) == -1)
716  panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(cfg_filename));
717 
718  dlr_init(cfg);
719 
720  report_versions("bearerbox");
721 
722  flow_threads = gwlist_create();
723 
724  if (init_bearerbox(cfg) == NULL)
725  panic(0, "Initialization failed.");
726 
727  info(0, "----------------------------------------");
728  info(0, GW_NAME " bearerbox II version %s starting", GW_VERSION);
729 
730  gwthread_sleep(5.0); /* give time to threads to register themselves */
731 
732  if (store_load(dispatch_into_queue) == -1)
733  panic(0, "Cannot start with store-file failing");
734 
735  info(0, "MAIN: Start-up done, entering mainloop");
736  if (bb_status == BB_SUSPENDED) {
737  info(0, "Gateway is now SUSPENDED by startup arguments");
738  } else if (bb_status == BB_ISOLATED) {
739  info(0, "Gateway is now ISOLATED by startup arguments");
740  gwlist_remove_producer(suspended);
741  } else {
742  smsc2_resume(1);
743  gwlist_remove_producer(suspended);
744  gwlist_remove_producer(isolated);
745  }
746 
747  while (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD &&
748  gwlist_producer_count(flow_threads) > 0) {
749  /* debug("bb", 0, "Main Thread: going to sleep."); */
750  /*
751  * Not infinite sleep here, because we should notice
752  * when all "flow threads" are dead and shutting bearerbox
753  * down.
754  * XXX if all "flow threads" call gwthread_wakeup(MAIN_THREAD_ID),
755  * we can enter infinite sleep then.
756  */
757  gwthread_sleep(10.0);
758  /* debug("bb", 0, "Main Thread: woken up."); */
759 
760  if (bb_todo == 0) {
761  continue;
762  }
763 
765  warning(0, "SIGHUP received, re-opening logs and gracefully restarting.");
766  log_reopen();
767  alog_reopen();
769  bb_todo = bb_todo & ~BB_GRACEFUL_RESTART;
770  }
771 
772  if (bb_todo & BB_LOGREOPEN) {
773  warning(0, "SIGUSR2 received, re-opening logs.");
774  log_reopen();
775  alog_reopen();
776  bb_todo = bb_todo & ~BB_LOGREOPEN;
777  }
778 
779  if (bb_todo & BB_CHECKLEAKS) {
780  warning(0, "SIGQUIT received, reporting memory usage.");
781  gw_check_leaks();
782  bb_todo = bb_todo & ~BB_CHECKLEAKS;
783  }
784  }
785 
786  if (bb_status == BB_SHUTDOWN || bb_status == BB_DEAD)
787  warning(0, "Killing signal or HTTP admin command received, shutting down...");
788 
789  /* call shutdown */
790  bb_shutdown();
791 
792  /* wake up any sleeping threads */
794 
795  /* wait until flow threads exit */
796  while (gwlist_consume(flow_threads) != NULL)
797  ;
798 
799  info(0, "All flow threads have died, killing core");
800  bb_status = BB_DEAD;
801  httpadmin_stop();
802 
803  boxc_cleanup();
804  smsc2_cleanup();
805  store_shutdown();
806  empty_msg_lists();
807  gwlist_destroy(flow_threads, NULL);
808  gwlist_destroy(suspended, NULL);
809  gwlist_destroy(isolated, NULL);
810  mutex_destroy(status_mutex);
811 
812  alog_close(); /* if we have any */
814  cfg_destroy(cfg);
815  octstr_destroy(cfg_filename);
816  dlr_shutdown();
817 
818  /* now really restart */
819  if (restart)
820  restart_box(argv);
821 
822  gwlib_shutdown();
823 
824  return 0;
825 }
826 
827 
828 /*----------------------------------------------------------------
829  * public functions used via HTTP adminstration interface/module
830  */
831 
832 int bb_shutdown(void)
833 {
834  static int called = 0;
835 
836  mutex_lock(status_mutex);
837 
838  if (called) {
839  mutex_unlock(status_mutex);
840  return -1;
841  }
842  debug("bb", 0, "Shutting down " GW_NAME "...");
843 
844  called = 1;
846  mutex_unlock(status_mutex);
847 
848 #ifndef NO_SMS
849  debug("bb", 0, "shutting down smsc");
850  smsc2_shutdown();
851 #endif
852 #ifndef NO_WAP
853  debug("bb", 0, "shutting down udp");
854  udp_shutdown();
855 #endif
856 
857  return 0;
858 }
859 
860 
861 int bb_isolate(void)
862 {
863  mutex_lock(status_mutex);
865  mutex_unlock(status_mutex);
866  return -1;
867  }
868  if (bb_status == BB_RUNNING) {
869  smsc2_suspend();
870  gwlist_add_producer(isolated);
871  } else
872  gwlist_remove_producer(suspended);
873 
875  mutex_unlock(status_mutex);
876  return 0;
877 }
878 
879 
880 int bb_suspend(void)
881 {
882  mutex_lock(status_mutex);
883  if (bb_status != BB_RUNNING && bb_status != BB_ISOLATED) {
884  mutex_unlock(status_mutex);
885  return -1;
886  }
887  if (bb_status != BB_ISOLATED) {
888  smsc2_suspend();
889  gwlist_add_producer(isolated);
890  }
892  gwlist_add_producer(suspended);
893  mutex_unlock(status_mutex);
894  return 0;
895 }
896 
897 
898 int bb_resume(void)
899 {
900  mutex_lock(status_mutex);
902  mutex_unlock(status_mutex);
903  return -1;
904  }
905  if (bb_status == BB_SUSPENDED)
906  gwlist_remove_producer(suspended);
907 
908  smsc2_resume(0);
910  gwlist_remove_producer(isolated);
911  mutex_unlock(status_mutex);
912  return 0;
913 }
914 
915 
916 int bb_flush_dlr(void)
917 {
918  /* beware that mutex locking is done in dlr_foobar() routines */
919  if (bb_status != BB_SUSPENDED) {
920  return -1;
921  }
922  dlr_flush();
923  return 0;
924 }
925 
926 
928 {
929  return smsc2_stop_smsc(id);
930 }
931 
932 
934 {
935  return smsc2_restart_smsc(id);
936 }
937 
939 {
940  return smsc2_add_smsc(id);
941 }
942 
944 {
945  return smsc2_remove_smsc(id);
946 }
947 
948 int bb_restart(void)
949 {
950  restart = 1;
951  return bb_shutdown();
952 }
953 
955 {
956  return smsc2_graceful_restart();
957 }
958 
960 {
961  return smsc2_reload_lists();
962 }
963 
964 int bb_remove_message(Octstr *message_id)
965 {
966  Msg *msg;
967  int ret;
968 
969  msg = msg_create(ack);
970  msg->ack.nack = ack_failed;
971  msg->ack.time = time(NULL);
972  uuid_parse(octstr_get_cstr(message_id), msg->ack.id);
973  ret = store_save(msg);
974  msg_destroy(msg);
975  if (ret != 0) {
976  error(0, "Could not delete message %s", octstr_get_cstr(message_id));
977  return -1;
978  }
979  return 0;
980 }
981 
982 
983 #define append_status(r, s, f, x) { s = f(x); octstr_append(r, s); \
984  octstr_destroy(s); }
985 
986 Octstr *bb_print_status(int status_type)
987 {
988  char *s, *lb;
989  char *frmt, *footer;
990  Octstr *ret, *str, *version;
991  time_t t;
992 
993  if ((lb = bb_status_linebreak(status_type)) == NULL)
994  return octstr_create("Un-supported format");
995 
996  t = time(NULL) - start_time;
997 
998  if (bb_status == BB_RUNNING)
999  s = "running";
1000  else if (bb_status == BB_ISOLATED)
1001  s = "isolated";
1002  else if (bb_status == BB_SUSPENDED)
1003  s = "suspended";
1004  else if (bb_status == BB_FULL)
1005  s = "filled";
1006  else
1007  s = "going down";
1008 
1009  version = version_report_string("bearerbox");
1010 
1011  if (status_type == BBSTATUS_HTML) {
1012  frmt = "%s</p>\n\n"
1013  " <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>\n\n"
1014  " <p>WDP: received %ld (%ld queued), sent %ld "
1015  "(%ld queued)</p>\n\n"
1016  " <p>SMS: received %ld (%ld queued), sent %ld "
1017  "(%ld queued), store size %ld<br>\n"
1018  " SMS: inbound (%.2f,%.2f,%.2f) msg/sec, "
1019  "outbound (%.2f,%.2f,%.2f) msg/sec</p>\n\n"
1020  " <p>DLR: received %ld, sent %ld<br>\n"
1021  " DLR: inbound (%.2f,%.2f,%.2f) msg/sec, outbound (%.2f,%.2f,%.2f) msg/sec<br>\n"
1022  " DLR: %ld queued, using %s storage</p>\n\n";
1023  footer = "<p>";
1024  } else if (status_type == BBSTATUS_WML) {
1025  frmt = "%s</p>\n\n"
1026  " <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>\n\n"
1027  " <p>WDP: received %ld (%ld queued)<br/>\n"
1028  " WDP: sent %ld (%ld queued)</p>\n\n"
1029  " <p>SMS: received %ld (%ld queued)<br/>\n"
1030  " SMS: sent %ld (%ld queued)<br/>\n"
1031  " SMS: store size %ld<br/>\n"
1032  " SMS: inbound (%.2f,%.2f,%.2f) msg/sec<br/>\n"
1033  " SMS: outbound (%.2f,%.2f,%.2f) msg/sec</p>\n"
1034  " <p>DLR: received %ld<br/>\n"
1035  " DLR: sent %ld<br/>\n"
1036  " DLR: inbound (%.2f,%.2f,%.2f) msg/sec<br/>\n"
1037  " DLR: outbound (%.2f,%.2f,%.2f) msg/sec<br/>\n"
1038  " DLR: %ld queued<br/>\n"
1039  " DLR: using %s storage</p>\n\n";
1040  footer = "<p>";
1041  } else if (status_type == BBSTATUS_XML) {
1042  frmt = "<version>%s</version>\n"
1043  "<status>%s, uptime %ldd %ldh %ldm %lds</status>\n"
1044  "\t<wdp>\n\t\t<received><total>%ld</total><queued>%ld</queued>"
1045  "</received>\n\t\t<sent><total>%ld</total><queued>%ld</queued>"
1046  "</sent>\n\t</wdp>\n"
1047  "\t<sms>\n\t\t<received><total>%ld</total><queued>%ld</queued>"
1048  "</received>\n\t\t<sent><total>%ld</total><queued>%ld</queued>"
1049  "</sent>\n\t\t<storesize>%ld</storesize>\n\t\t"
1050  "<inbound>%.2f,%.2f,%.2f</inbound>\n\t\t"
1051  "<outbound>%.2f,%.2f,%.2f</outbound>\n\t\t"
1052  "</sms>\n"
1053  "\t<dlr>\n\t\t<received><total>%ld</total></received>\n\t\t"
1054  "<sent><total>%ld</total></sent>\n\t\t"
1055  "<inbound>%.2f,%.2f,%.2f</inbound>\n\t\t"
1056  "<outbound>%.2f,%.2f,%.2f</outbound>\n\t\t"
1057  "<queued>%ld</queued>\n\t\t<storage>%s</storage>\n\t</dlr>\n";
1058  footer = "";
1059  } else {
1060  frmt = "%s\n\nStatus: %s, uptime %ldd %ldh %ldm %lds\n\n"
1061  "WDP: received %ld (%ld queued), sent %ld (%ld queued)\n\n"
1062  "SMS: received %ld (%ld queued), sent %ld (%ld queued), store size %ld\n"
1063  "SMS: inbound (%.2f,%.2f,%.2f) msg/sec, "
1064  "outbound (%.2f,%.2f,%.2f) msg/sec\n\n"
1065  "DLR: received %ld, sent %ld\n"
1066  "DLR: inbound (%.2f,%.2f,%.2f) msg/sec, outbound (%.2f,%.2f,%.2f) msg/sec\n"
1067  "DLR: %ld queued, using %s storage\n\n";
1068  footer = "";
1069  }
1070 
1071  ret = octstr_format(frmt,
1072  octstr_get_cstr(version),
1073  s, t/3600/24, t/3600%24, t/60%60, t%60,
1074  counter_value(incoming_wdp_counter),
1075  gwlist_len(incoming_wdp) + boxc_incoming_wdp_queue(),
1076  counter_value(outgoing_wdp_counter), gwlist_len(outgoing_wdp) + udp_outgoing_queue(),
1077  counter_value(incoming_sms_counter), gwlist_len(incoming_sms),
1078  counter_value(outgoing_sms_counter), gwlist_len(outgoing_sms),
1079  store_messages(),
1080  load_get(incoming_sms_load,0), load_get(incoming_sms_load,1), load_get(incoming_sms_load,2),
1081  load_get(outgoing_sms_load,0), load_get(outgoing_sms_load,1), load_get(outgoing_sms_load,2),
1082  counter_value(incoming_dlr_counter), counter_value(outgoing_dlr_counter),
1083  load_get(incoming_dlr_load,0), load_get(incoming_dlr_load,1), load_get(incoming_dlr_load,2),
1084  load_get(outgoing_dlr_load,0), load_get(outgoing_dlr_load,1), load_get(outgoing_dlr_load,2),
1085  dlr_messages(), dlr_type());
1086 
1087  octstr_destroy(version);
1088 
1089  append_status(ret, str, boxc_status, status_type);
1090  append_status(ret, str, smsc2_status, status_type);
1091  octstr_append_cstr(ret, footer);
1092 
1093  return ret;
1094 }
1095 
1096 
1097 char *bb_status_linebreak(int status_type)
1098 {
1099  switch (status_type) {
1100  case BBSTATUS_HTML:
1101  return "<br>\n";
1102  case BBSTATUS_WML:
1103  return "<br/>\n";
1104  case BBSTATUS_TEXT:
1105  return "\n";
1106  case BBSTATUS_XML:
1107  return "\n";
1108  default:
1109  return NULL;
1110  }
1111 }
volatile sig_atomic_t bb_status
Definition: bearerbox.c:132
Counter * incoming_dlr_counter
Definition: bearerbox.c:92
static void wdp_router(void *arg)
Definition: bearerbox.c:257
void error(int err, const char *fmt,...)
Definition: log.c:612
int httpadmin_start(Cfg *cfg)
Definition: bb_http.c:542
void info(int err, const char *fmt,...)
Definition: log.c:636
int boxc_incoming_wdp_queue(void)
Definition: bb_boxc.c:1472
static int start_wap(Cfg *cfg)
Definition: bearerbox.c:285
int smsc2_add_smsc(Octstr *id)
Definition: bb_smscconn.c:1112
static void dispatch_into_queue(Msg *msg)
Definition: bearerbox.c:665
Counter * incoming_wdp_counter
Definition: bearerbox.c:94
List * suspended
Definition: bearerbox.c:122
List * outgoing_sms
Definition: bearerbox.c:85
void smsc2_cleanup(void)
Definition: bb_smscconn.c:1306
static void set_shutdown_status(void)
Definition: bearerbox.c:154
Load * outgoing_sms_load
Definition: bearerbox.c:102
Definition: msg.h:106
void counter_destroy(Counter *counter)
Definition: counter.c:110
#define mutex_unlock(m)
Definition: thread.h:136
void gwlist_append(List *list, void *item)
Definition: list.c:179
int smsc2_restart_smsc(Octstr *id)
Definition: bb_smscconn.c:998
Load * incoming_sms_load
Definition: bearerbox.c:103
char * bb_status_linebreak(int status_type)
Definition: bearerbox.c:1097
static int check_config(Cfg *cfg)
Definition: bearerbox.c:321
int udp_addwdp(Msg *msg)
Definition: bb_udp.c:385
Definition: msg.h:109
List * cfg_get_list(CfgGroup *grp, Octstr *varname)
Definition: cfg.c:787
void log_reopen(void)
Definition: log.c:261
static void empty_msg_lists(void)
Definition: bearerbox.c:612
static int check_args(int i, int argc, char **argv)
Definition: bearerbox.c:362
long gwlist_len(List *list)
Definition: list.c:166
int restart_box(char **argv)
Definition: shared.c:279
int smsc2_reload_lists(void)
Definition: bb_smscconn.c:1166
#define mutex_create()
Definition: thread.h:96
long(* store_messages)(void)
Definition: bb_store.c:71
List * incoming_wdp
Definition: bearerbox.c:87
Msg * msg_unpack_wrapper(Octstr *os)
Definition: msg.c:256
int load_add_interval(Load *load, int interval)
Definition: load.c:111
msg_type
Definition: msg.h:73
#define cfg_get(grp, varname)
Definition: cfg.h:86
static Mutex * status_mutex
Definition: bearerbox.c:147
void uuid_unparse(const uuid_t uu, char *out)
Definition: gw_uuid.c:561
static volatile sig_atomic_t bb_todo
Definition: bearerbox.c:143
#define msg_create(type)
Definition: msg.h:136
int gwthread_shouldhandlesignal(int signal)
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1509
Definition: msg.h:110
double load_get(Load *load, int pos)
Definition: load.c:191
int bb_add_smsc(Octstr *id)
Definition: bearerbox.c:938
int udp_outgoing_queue(void)
Definition: bb_udp.c:460
int bb_restart_smsc(Octstr *id)
Definition: bearerbox.c:933
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
void bb_alog_init(const Octstr *format)
Definition: bb_alog.c:359
static time_t start_time
Definition: bearerbox.c:148
Cfg * cfg_create(Octstr *filename)
Definition: cfg.c:318
int cfg_read(Cfg *cfg)
Definition: cfg.c:452
int smsc2_remove_smsc(Octstr *id)
Definition: bb_smscconn.c:1083
List * isolated
Definition: bearerbox.c:127
Definition: msg.h:108
int uuid_parse(const char *in, uuid_t uu)
Definition: gw_uuid.c:475
void msg_destroy_item(void *msg)
Definition: msg.c:147
void bb_alog_shutdown(void)
Definition: bb_alog.c:367
int bb_remove_smsc(Octstr *id)
Definition: bearerbox.c:943
long max_outgoing_sms_qlength
Definition: bearerbox.c:99
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
int udp_die(void)
Definition: bb_udp.c:434
#define DEFAULT_OUTGOING_SMS_QLENGTH
Definition: bearerbox.h:69
int bb_flush_dlr(void)
Definition: bearerbox.c:916
Definition: msg.h:79
Definition: cfg.c:164
Counter * counter_create(void)
Definition: counter.c:94
void cfg_destroy(Cfg *cfg)
Definition: cfg.c:331
int smsc2_stop_smsc(Octstr *id)
Definition: bb_smscconn.c:968
void * gwlist_extract_first(List *list)
Definition: list.c:305
Load * incoming_dlr_load
Definition: bearerbox.c:104
void conn_config_ssl(CfgGroup *grp)
Definition: conn.c:1472
void gwlist_remove_producer(List *list)
Definition: list.c:401
void httpadmin_stop(void)
Definition: bb_http.c:603
static void signal_handler(int signum)
Definition: bearerbox.c:170
long max_incoming_sms_qlength
Definition: bearerbox.c:98
List * incoming_sms
Definition: bearerbox.c:84
const char * dlr_type(void)
Definition: dlr.c:319
int store_init(Cfg *cfg, const Octstr *type, const Octstr *fname, long dump_freq, void *pack_func, void *unpack_func)
Definition: bb_store.c:82
int bb_suspend(void)
Definition: bearerbox.c:880
int bb_reload_lists(void)
Definition: bearerbox.c:959
List * cfg_get_multi_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:642
Counter * outgoing_sms_counter
Definition: bearerbox.c:91
int smsbox_start(Cfg *cfg)
Definition: bb_boxc.c:1227
int bb_stop_smsc(Octstr *id)
Definition: bearerbox.c:927
void msg_destroy(Msg *msg)
Definition: msg.c:132
static int start_smsc(Cfg *cfg)
Definition: bearerbox.c:235
int octstr_case_compare(const Octstr *os1, const Octstr *os2)
Definition: octstr.c:901
Load * outgoing_dlr_load
Definition: bearerbox.c:105
int main(int argc, char **argv)
Definition: bearerbox.c:692
void warning(int err, const char *fmt,...)
Definition: log.c:624
int udp_start(Cfg *cfg)
Definition: bb_udp.c:323
void log_set_syslog_facility(char *facility)
Definition: log.c:242
void alog_open(char *fname, int use_localtm, int use_markers)
Definition: accesslog.c:129
int bb_graceful_restart(void)
Definition: bearerbox.c:954
int udp_shutdown(void)
Definition: bb_udp.c:424
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
volatile sig_atomic_t restart
Definition: bearerbox.c:149
Counter * incoming_sms_counter
Definition: bearerbox.c:90
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:334
unsigned long counter_value(Counter *counter)
Definition: counter.c:145
gw_assert(wtls_machine->packet_to_send!=NULL)
#define load_create()
Definition: load.h:78
void gwthread_sleep(double seconds)
void log_set_syslog(const char *ident, int syslog_level)
Definition: log.c:248
void mutex_destroy(Mutex *mutex)
Definition: thread.c:97
void smsc2_suspend(void)
Definition: bb_smscconn.c:1251
Counter * outgoing_dlr_counter
Definition: bearerbox.c:93
#define UUID_STR_LEN
Definition: gw_uuid.h:19
void boxc_cleanup(void)
Definition: bb_boxc.c:1489
void alog_reopen(void)
Definition: accesslog.c:85
void(* store_shutdown)(void)
Definition: bb_store.c:76
void report_versions(const char *boxname)
Definition: utils.c:539
int log_open(char *filename, int level, enum excl_state excl)
Definition: log.c:339
static Cfg * cfg
Definition: smsbox.c:115
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
int smsc2_shutdown(void)
Definition: bb_smscconn.c:1268
#define append_status(r, s, f, x)
Definition: bearerbox.c:983
void dlr_init(Cfg *cfg)
Definition: dlr.c:233
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:756
Definition: octstr.c:118
int bb_shutdown(void)
Definition: bearerbox.c:832
void * gwlist_consume(List *list)
Definition: list.c:427
int bb_resume(void)
Definition: bearerbox.c:898
Octstr * cfg_filename
Definition: bearerbox.c:130
int smsc2_graceful_restart(void)
Definition: bb_smscconn.c:1522
void http_use_proxy(Octstr *hostname, int port, int ssl, List *exceptions, Octstr *username, Octstr *password, Octstr *exceptions_regex)
Definition: http.c:268
void dlr_flush(void)
Definition: dlr.c:491
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:739
static void setup_signal_handlers(void)
Definition: bearerbox.c:212
int wapbox_start(Cfg *cfg)
Definition: bb_boxc.c:1305
#define panic
Definition: log.h:87
Definition: cfg.c:73
int(* store_load)(void(*receive_msg)(Msg *))
Definition: bb_store.c:74
void load_destroy(Load *load)
Definition: load.c:145
Definition: load.c:76
List * flow_threads
Definition: bearerbox.c:116
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
void alog_close(void)
Definition: accesslog.c:111
void gwlib_shutdown(void)
Definition: gwlib.c:94
Octstr * msg_pack(Msg *msg)
Definition: msg.c:181
#define gwlist_create()
Definition: list.h:136
List * outgoing_wdp
Definition: bearerbox.c:88
int bb_remove_message(Octstr *message_id)
Definition: bearerbox.c:964
Octstr * boxc_status(int status_type)
Definition: bb_boxc.c:1348
Counter * outgoing_wdp_counter
Definition: bearerbox.c:95
int(* store_save)(Msg *msg)
Definition: bb_store.c:72
Definition: thread.h:76
Octstr * version_report_string(const char *boxname)
Definition: utils.c:549
void gwlib_init(void)
Definition: gwlib.c:78
Definition: msg.h:107
void smsc2_resume(int is_init)
Definition: bb_smscconn.c:1226
Octstr * smsc2_status(int status_type)
Definition: bb_smscconn.c:1354
CfgGroup * cfg_get_single_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:636
void gwlist_add_producer(List *list)
Definition: list.c:383
long dlr_messages(void)
Definition: dlr.c:308
int smsc2_start(Cfg *cfg)
Definition: bb_smscconn.c:806
int bb_isolate(void)
Definition: bearerbox.c:861
void http_set_client_timeout(long timeout)
Definition: http.c:1736
int bb_restart(void)
Definition: bearerbox.c:948
#define mutex_lock(m)
Definition: thread.h:130
int get_and_set_debugs(int argc, char **argv, int(*find_own)(int index, int argc, char **argv))
Definition: utils.c:626
void gwthread_wakeup_all(void)
Definition: list.c:102
static Octstr * lf
Definition: smsc_smasi.c:222
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
void dlr_shutdown()
Definition: dlr.c:299
static int start_udp(Cfg *cfg)
Definition: bearerbox.c:303
static Cfg * init_bearerbox(Cfg *cfg)
Definition: bearerbox.c:375
Octstr * bb_print_status(int status_type)
Definition: bearerbox.c:986
int gwlist_producer_count(List *list)
Definition: list.c:391
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.