/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2005 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wapbox.c - main program for wapbox * * This module contains the main program for the WAP box of the WAP gateway. * See the architecture documentation for details. */ #include #include #include #include #include "gwlib/gwlib.h" #include "shared.h" #include "wml_compiler.h" #include "heartbeat.h" #include "wap/wap.h" #include "wap-appl.h" #include "wap-maps.h" #include "wap_push_ota.h" #include "wap_push_ppg.h" #include "gw/msg.h" #include "bb.h" #include "sms.h" #ifdef HAVE_WTLS_OPENSSL #include #include "wap/wtls.h" #include "gwlib/pki.h" #endif #include "radius/radius_acct.h" static void config_reload(int reload); static long logfilelevel=-1; enum { CONNECTIONLESS_PORT = 9200, CONNECTION_ORIENTED_PORT = 9201, WTLS_CONNECTIONLESS_PORT = 9202, WTLS_CONNECTION_ORIENTED_PORT = 9203 }; enum { DEFAULT_TIMER_FREQ = 1}; static Octstr *bearerbox_host; static long bearerbox_port = BB_DEFAULT_WAPBOX_PORT; static int bearerbox_ssl = 0; static Counter *sequence_counter = NULL; static long timer_freq = DEFAULT_TIMER_FREQ; static Octstr *config_filename; /* use strict XML parsing or relaxed */ static int wml_xml_strict = 1; /* smart error messaging related globals */ int wsp_smart_errors = 0; Octstr *device_home = NULL; /* Controlling segmentation of sms messages sent by wapbox (push related).*/ int concatenation = 1; long max_messages = 10; #ifdef HAVE_WTLS_OPENSSL RSA* private_key = NULL; X509* x509_cert = NULL; #endif static Cfg *init_wapbox(Cfg *cfg) { CfgGroup *grp; Octstr *s; Octstr *logfile; int lf, m; lf = m = 1; cfg_dump(cfg); /* * Extract info from the core group. */ grp = cfg_get_single_group(cfg, octstr_imm("core")); if (grp == NULL) panic(0, "No 'core' group in configuration."); if (cfg_get_integer(&bearerbox_port,grp,octstr_imm("wapbox-port")) == -1) panic(0, "No 'wapbox-port' in core group"); #ifdef HAVE_LIBSSL cfg_get_bool(&bearerbox_ssl, grp, octstr_imm("wapbox-port-ssl")); #endif /* HAVE_LIBSSL */ /* load parameters that could be later reloaded */ config_reload(0); conn_config_ssl(grp); /* * And the rest of the pull info comes from the wapbox group. */ grp = cfg_get_single_group(cfg, octstr_imm("wapbox")); if (grp == NULL) panic(0, "No 'wapbox' group in configuration."); bearerbox_host = cfg_get(grp, octstr_imm("bearerbox-host")); if (cfg_get_integer(&timer_freq, grp, octstr_imm("timer-freq")) == -1) timer_freq = DEFAULT_TIMER_FREQ; logfile = cfg_get(grp, octstr_imm("log-file")); if (logfile != NULL) { log_open(octstr_get_cstr(logfile), logfilelevel, GW_NON_EXCL); info(0, "Starting to log to file %s level %ld", octstr_get_cstr(logfile), logfilelevel); } octstr_destroy(logfile); if ((s = cfg_get(grp, octstr_imm("syslog-level"))) != NULL) { long level; if (octstr_compare(s, octstr_imm("none")) == 0) { log_set_syslog(NULL, 0); debug("wap", 0, "syslog parameter is none"); } else if (octstr_parse_long(&level, s, 0, 0) == -1) { log_set_syslog("wapbox", level); debug("wap", 0, "syslog parameter is %ld", level); } octstr_destroy(s); } else { log_set_syslog(NULL, 0); debug("wap", 0, "no syslog parameter"); } /* determine which timezone we use for access logging */ if ((s = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) { lf = (octstr_case_compare(s, octstr_imm("gmt")) == 0) ? 0 : 1; octstr_destroy(s); } /* should predefined markers be used, ie. prefixing timestamp */ cfg_get_bool(&m, grp, octstr_imm("access-log-clean")); /* open access-log file */ if ((s = cfg_get(grp, octstr_imm("access-log"))) != NULL) { info(0, "Logging accesses to '%s'.", octstr_get_cstr(s)); alog_open(octstr_get_cstr(s), lf, m ? 0 : 1); octstr_destroy(s); } /* configure the 'wtls' group */ #if (HAVE_WTLS_OPENSSL) /* Load up the necessary keys */ grp = cfg_get_single_group(cfg, octstr_imm("wtls")); if (grp != NULL) { if ((s = cfg_get(grp, octstr_imm("certificate-file"))) != NULL) { if (octstr_compare(s, octstr_imm("none")) == 0) { debug("bbox", 0, "certificate file not set"); } else { /* Load the certificate into the necessary parameter */ get_cert_from_file(s, &x509_cert); gw_assert(x509_cert != NULL); debug("bbox", 0, "certificate parameter is %s", s); } octstr_destroy(s); } else panic(0, "No 'certificate-file' in wtls group"); if ((s = cfg_get(grp, octstr_imm("privatekey-file"))) != NULL) { Octstr *password; password = cfg_get(grp, octstr_imm("privatekey-password")); if (octstr_compare(s, octstr_imm("none")) == 0) { debug("bbox", 0, "privatekey-file not set"); } else { /* Load the private key into the necessary parameter */ get_privkey_from_file(s, &private_key, password); gw_assert(private_key != NULL); debug("bbox", 0, "certificate parameter is %s", s); } if (password != NULL) octstr_destroy(password); octstr_destroy(s); } else panic(0, "No 'privatekey-file' in wtls group"); } #endif /* * Check if we have a 'radius-acct' proxy group and start the * corresponding thread for the proxy. */ grp = cfg_get_single_group(cfg, octstr_imm("radius-acct")); if (grp) { radius_acct_init(grp); } /* * We pass ppg configuration groups to the ppg module. */ grp = cfg_get_single_group(cfg, octstr_imm("ppg")); if (grp == NULL) { cfg_destroy(cfg); return NULL; } return cfg; } static void signal_handler(int signum) { /* * On some implementations (i.e. linuxthreads), signals are delivered * to all threads. We only want to handle each signal once for the * entire box, and we let the gwthread wrapper take care of choosing * one. */ if (!gwthread_shouldhandlesignal(signum)) return; switch (signum) { case SIGINT: case SIGTERM: if (program_status != shutting_down) { error(0, "SIGINT or SIGTERM received, let's die."); program_status = shutting_down; break; } break; case SIGHUP: warning(0, "SIGHUP received, catching and re-opening logs"); config_reload(1); log_reopen(); alog_reopen(); break; /* * It would be more proper to use SIGUSR1 for this, but on some * platforms that's reserved by the pthread support. */ case SIGQUIT: warning(0, "SIGQUIT received, reporting memory usage."); gw_check_leaks(); break; } } static void setup_signal_handlers(void) { struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGPIPE, &act, NULL); } /* * We create wdp_datagram for IP traffic and sms for SMS traffic. */ static Msg *pack_ip_datagram(WAPEvent *dgram) { Msg *msg; WAPAddrTuple *tuple; msg = msg_create(wdp_datagram); tuple = dgram->u.T_DUnitdata_Req.addr_tuple; msg->wdp_datagram.source_address = octstr_duplicate(tuple->local->address); msg->wdp_datagram.source_port = dgram->u.T_DUnitdata_Req.addr_tuple->local->port; msg->wdp_datagram.destination_address = octstr_duplicate(tuple->remote->address); msg->wdp_datagram.destination_port = dgram->u.T_DUnitdata_Req.addr_tuple->remote->port; msg->wdp_datagram.user_data = octstr_duplicate(dgram->u.T_DUnitdata_Req.user_data); return msg; } /* * Format for port UDH is defined in wdp, appendix A. It is %06%05%04 * %dest port high hex%dest port low%hex source port high hex%source port low * hex. (Unsecure) push client port itself is 2948. */ static Octstr *pack_udhdata(WAPAddrTuple *tuple) { int source_port, dest_port; Octstr *udh; source_port = tuple->local->port; dest_port = tuple->remote->port; udh = octstr_create(""); octstr_format_append(udh, "%c", 6); octstr_format_append(udh, "%c", 5); octstr_format_append(udh, "%c", 4); octstr_format_append(udh, "%c", (dest_port >> 8) & 0xff); octstr_format_append(udh, "%c", dest_port & 0xff); octstr_format_append(udh, "%c", (source_port >> 8) & 0xff); octstr_format_append(udh, "%c", source_port & 0xff); return udh; } /* * We send a normal 8-bit unconcatenated binary message with an udh. Caller * must do segmentation before calling this function. * * Note: we have hardcoded validity period here. We must eventually use push * control document to fill this field. */ static Msg *pack_sms_datagram(WAPEvent *dgram) { Msg *msg; WAPAddrTuple *tuple; msg = msg_create(sms); tuple = dgram->u.T_DUnitdata_Req.addr_tuple; msg->sms.sender = octstr_duplicate(tuple->local->address); msg->sms.receiver = octstr_duplicate(tuple->remote->address); msg->sms.udhdata = pack_udhdata(tuple); msg->sms.msgdata = octstr_duplicate(dgram->u.T_DUnitdata_Req.user_data); msg->sms.time = time(NULL); if (dgram->u.T_DUnitdata_Req.smsc_id != NULL) msg->sms.smsc_id = octstr_duplicate(dgram->u.T_DUnitdata_Req.smsc_id); else msg->sms.smsc_id = NULL; msg->sms.dlr_mask = dgram->u.T_DUnitdata_Req.dlr_mask; if (dgram->u.T_DUnitdata_Req.smsbox_id != NULL) msg->sms.boxc_id = octstr_duplicate(dgram->u.T_DUnitdata_Req.smsbox_id); else msg->sms.boxc_id = NULL; if (dgram->u.T_DUnitdata_Req.dlr_url != NULL) msg->sms.dlr_url = octstr_duplicate(dgram->u.T_DUnitdata_Req.dlr_url); else msg->sms.dlr_url = NULL; msg->sms.sms_type = mt_push; msg->sms.mwi = MWI_UNDEF; msg->sms.coding = DC_8BIT; msg->sms.mclass = MC_UNDEF; msg->sms.validity = 1440; msg->sms.deferred = -1; if (dgram->u.T_DUnitdata_Req.service_name != NULL) msg->sms.service = octstr_duplicate(dgram->u.T_DUnitdata_Req.service_name); return msg; } /* * Possible address types */ enum { ADDR_IPV4 = 0, ADDR_PLMN = 1, ADDR_USER = 2, ADDR_IPV6 = 3, ADDR_WINA = 4 }; /* * Send IP datagram as it is, segment SMS datagram if necessary. */ static void dispatch_datagram(WAPEvent *dgram) { Msg *msg, *part; List *sms_datagrams; static unsigned long msg_sequence = 0L; /* Used only by this function */ msg = part = NULL; sms_datagrams = NULL; if (dgram == NULL) { error(0, "WDP: dispatch_datagram received empty datagram, ignoring."); } else if (dgram->type != T_DUnitdata_Req) { warning(0, "WDP: dispatch_datagram received event of unexpected type."); wap_event_dump(dgram); } else if (dgram->u.T_DUnitdata_Req.address_type == ADDR_IPV4) { msg = pack_ip_datagram(dgram); write_to_bearerbox(msg); } else { msg_sequence = counter_increase(sequence_counter) & 0xff; msg = pack_sms_datagram(dgram); sms_datagrams = sms_split(msg, NULL, NULL, NULL, NULL, concatenation, msg_sequence, max_messages, MAX_SMS_OCTETS); debug("wap",0,"WDP (wapbox): delivering %ld segments to bearerbox", gwlist_len(sms_datagrams)); while ((part = gwlist_extract_first(sms_datagrams)) != NULL) { write_to_bearerbox(part); } gwlist_destroy(sms_datagrams, NULL); msg_destroy(msg); } wap_event_destroy(dgram); } /* * Reloading functions */ static void reload_int(int reload, Octstr *desc, long *o, long *n) { if (reload && *o != *n) { info(0, "Reloading int '%s' from %ld to %ld", octstr_get_cstr(desc), *o, *n); *o = *n; } } static void reload_bool(int reload, Octstr *desc, int *o, int *n) { if (reload && *o != *n) { info(0, "Reloading bool '%s' from %s to %s", octstr_get_cstr(desc), (*o ? "yes" : "no"), (*n ? "yes" : "no")); *o = *n; } } /* * Read all reloadable configuration directives */ static void config_reload(int reload) { Cfg *cfg; CfgGroup *grp; List *groups; long map_url_max; Octstr *s; long i; long new_value; int new_bool; Octstr *http_proxy_host; Octstr *http_interface_name; long http_proxy_port; List *http_proxy_exceptions; Octstr *http_proxy_username; Octstr *http_proxy_password; Octstr *http_proxy_exceptions_regex; int warn_map_url = 0; /* XXX TO-DO: if(reload) implement wapbox.suspend/mutex.lock */ if (reload) debug("config_reload", 0, "Reloading configuration"); /* * NOTE: we could lstat config file and only reload if it was modified, * but as we have a include directive, we don't know every file's * timestamp at this point */ cfg = cfg_create(config_filename); if (cfg_read(cfg) == -1) { warning(0, "Couldn't %sload configuration from `%s'.", (reload ? "re" : ""), octstr_get_cstr(config_filename)); return; } grp = cfg_get_single_group(cfg, octstr_imm("core")); http_proxy_host = cfg_get(grp, octstr_imm("http-proxy-host")); http_proxy_port = -1; cfg_get_integer(&http_proxy_port, grp, octstr_imm("http-proxy-port")); http_proxy_username = cfg_get(grp, octstr_imm("http-proxy-username")); http_proxy_password = cfg_get(grp, octstr_imm("http-proxy-password")); http_proxy_exceptions = cfg_get_list(grp, octstr_imm("http-proxy-exceptions")); http_proxy_exceptions_regex = cfg_get(grp, octstr_imm("http-proxy-exceptions-regex")); if (http_proxy_host != NULL && http_proxy_port > 0) { http_use_proxy(http_proxy_host, http_proxy_port, http_proxy_exceptions, http_proxy_username, http_proxy_password, http_proxy_exceptions_regex); } octstr_destroy(http_proxy_host); octstr_destroy(http_proxy_username); octstr_destroy(http_proxy_password); octstr_destroy(http_proxy_exceptions_regex); gwlist_destroy(http_proxy_exceptions, octstr_destroy_item); grp = cfg_get_single_group(cfg, octstr_imm("wapbox")); if (grp == NULL) { warning(0, "No 'wapbox' group in configuration."); return; } if (cfg_get_integer(&new_value, grp, octstr_imm("log-level")) != -1) { reload_int(reload, octstr_imm("log level"), &logfilelevel, &new_value); logfilelevel = new_value; log_set_log_level(new_value); } /* Configure interface name for http requests */ http_interface_name = cfg_get(grp, octstr_imm("http-interface-name")); if (http_interface_name != NULL) { http_set_interface(http_interface_name); octstr_destroy(http_interface_name); } /* * users may define 'smart-errors' to have WML decks returned with * error information instead of signaling using the HTTP reply codes */ cfg_get_bool(&new_bool, grp, octstr_imm("smart-errors")); reload_bool(reload, octstr_imm("smart error messaging"), &wsp_smart_errors, &new_bool); /* decide if our XML parser within WML compiler is strict or relaxed */ cfg_get_bool(&new_bool, grp, octstr_imm("wml-strict")); reload_bool(reload, octstr_imm("XML within WML has to be strict"), &wml_xml_strict, &new_bool); if (!wml_xml_strict) warning(0, "'wml-strict' config directive has been set to no, " "this may make you vulnerable against XML bogus input."); if (cfg_get_bool(&new_bool, grp, octstr_imm("concatenation")) == 1) reload_bool(reload, octstr_imm("concatenation"), &concatenation, &new_bool); else concatenation = 1; if (cfg_get_integer(&new_value, grp, octstr_imm("max-messages")) != -1) { max_messages = new_value; reload_int(reload, octstr_imm("max messages"), &max_messages, &new_value); } /* configure URL mappings */ map_url_max = -1; cfg_get_integer(&map_url_max, grp, octstr_imm("map-url-max")); if (map_url_max > 0) warn_map_url = 1; if (reload) { /* clear old map */ wap_map_destroy(); wap_map_user_destroy(); } if ((device_home = cfg_get(grp, octstr_imm("device-home"))) != NULL) { wap_map_url_config_device_home(octstr_get_cstr(device_home)); } if ((s = cfg_get(grp, octstr_imm("map-url"))) != NULL) { warn_map_url = 1; wap_map_url_config(octstr_get_cstr(s)); octstr_destroy(s); } debug("wap", 0, "map_url_max = %ld", map_url_max); for (i = 0; i <= map_url_max; i++) { Octstr *name; name = octstr_format("map-url-%d", i); if ((s = cfg_get(grp, name)) != NULL) wap_map_url_config(octstr_get_cstr(s)); octstr_destroy(name); } /* warn the user that he/she should use the new wap-url-map groups */ if (warn_map_url) warning(0, "'map-url' config directive and related are deprecated, " "please use wap-url-map group"); /* configure wap-url-map */ groups = cfg_get_multi_group(cfg, octstr_imm("wap-url-map")); while (groups && (grp = gwlist_extract_first(groups)) != NULL) { Octstr *name, *url, *map_url, *send_msisdn_query; Octstr *send_msisdn_header, *send_msisdn_format; int accept_cookies; name = cfg_get(grp, octstr_imm("name")); url = cfg_get(grp, octstr_imm("url")); map_url = cfg_get(grp, octstr_imm("map-url")); send_msisdn_query = cfg_get(grp, octstr_imm("send-msisdn-query")); send_msisdn_header = cfg_get(grp, octstr_imm("send-msisdn-header")); send_msisdn_format = cfg_get(grp, octstr_imm("send-msisdn-format")); accept_cookies = -1; cfg_get_bool(&accept_cookies, grp, octstr_imm("accept-cookies")); wap_map_add_url(name, url, map_url, send_msisdn_query, send_msisdn_header, send_msisdn_format, accept_cookies); info(0, "Added wap-url-map <%s> with url <%s>, map-url <%s>, " "send-msisdn-query <%s>, send-msisdn-header <%s>, " "send-msisdn-format <%s>, accept-cookies <%s>", octstr_get_cstr(name), octstr_get_cstr(url), octstr_get_cstr(map_url), octstr_get_cstr(send_msisdn_query), octstr_get_cstr(send_msisdn_header), octstr_get_cstr(send_msisdn_format), (accept_cookies ? "yes" : "no")); } gwlist_destroy(groups, NULL); /* configure wap-user-map */ groups = cfg_get_multi_group(cfg, octstr_imm("wap-user-map")); while (groups && (grp = gwlist_extract_first(groups)) != NULL) { Octstr *name, *user, *pass, *msisdn; name = cfg_get(grp, octstr_imm("name")); user = cfg_get(grp, octstr_imm("user")); pass = cfg_get(grp, octstr_imm("pass")); msisdn = cfg_get(grp, octstr_imm("msisdn")); wap_map_add_user(name, user, pass, msisdn); info(0,"Added wap-user-map <%s> with credentials <%s:%s> " "and MSISDN <%s>", octstr_get_cstr(name), octstr_get_cstr(user), octstr_get_cstr(pass), octstr_get_cstr(msisdn)); } gwlist_destroy(groups, NULL); cfg_destroy(cfg); /* XXX TO-DO: if(reload) implement wapbox.resume/mutex.unlock */ } int main(int argc, char **argv) { int cf_index; int restart = 0; Msg *msg; Cfg *cfg; double heartbeat_freq = DEFAULT_HEARTBEAT; gwlib_init(); cf_index = get_and_set_debugs(argc, argv, NULL); setup_signal_handlers(); if (argv[cf_index] == NULL) config_filename = octstr_create("kannel.conf"); else config_filename = octstr_create(argv[cf_index]); cfg = cfg_create(config_filename); if (cfg_read(cfg) == -1) panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(config_filename)); report_versions("wapbox"); cfg = init_wapbox(cfg); info(0, "------------------------------------------------------------"); info(0, GW_NAME " wapbox version %s starting up.", GW_VERSION); sequence_counter = counter_create(); wsp_session_init(&wtp_resp_dispatch_event, &wtp_initiator_dispatch_event, &wap_appl_dispatch, &wap_push_ppg_dispatch_event); wsp_unit_init(&dispatch_datagram, &wap_appl_dispatch); wsp_push_client_init(&wsp_push_client_dispatch_event, &wtp_resp_dispatch_event); if (cfg) wtp_initiator_init(&dispatch_datagram, &wsp_session_dispatch_event, timer_freq); wtp_resp_init(&dispatch_datagram, &wsp_session_dispatch_event, &wsp_push_client_dispatch_event, timer_freq); wap_appl_init(cfg); #if (HAVE_WTLS_OPENSSL) wtls_secmgr_init(); wtls_init(); #endif if (cfg) { wap_push_ota_init(&wsp_session_dispatch_event, &wsp_unit_dispatch_event); wap_push_ppg_init(&wap_push_ota_dispatch_event, &wap_appl_dispatch, cfg); } wml_init(wml_xml_strict); if (bearerbox_host == NULL) bearerbox_host = octstr_create(BB_DEFAULT_HOST); connect_to_bearerbox(bearerbox_host, bearerbox_port, bearerbox_ssl, NULL /* bearerbox_our_port */); if (cfg) wap_push_ota_bb_address_set(bearerbox_host); program_status = running; if (0 > heartbeat_start(write_to_bearerbox, heartbeat_freq, wap_appl_get_load)) { info(0, GW_NAME "Could not start heartbeat."); } while (program_status != shutting_down) { WAPEvent *dgram; int ret; /* block infinite for reading messages */ ret = read_from_bearerbox(&msg, INFINITE_TIME); if (ret == -1) break; else if (ret == 1) /* timeout */ continue; else if (msg == NULL) /* just to be sure, may not happens */ break; if (msg_type(msg) == admin) { if (msg->admin.command == cmd_shutdown) { info(0, "Bearerbox told us to die"); program_status = shutting_down; } else if (msg->admin.command == cmd_restart) { info(0, "Bearerbox told us to restart"); restart = 1; program_status = shutting_down; } /* * XXXX here should be suspend/resume, add RSN */ } else if (msg_type(msg) == wdp_datagram) { switch (msg->wdp_datagram.destination_port) { case CONNECTIONLESS_PORT: case CONNECTION_ORIENTED_PORT: dgram = wap_event_create(T_DUnitdata_Ind); dgram->u.T_DUnitdata_Ind.addr_tuple = wap_addr_tuple_create( msg->wdp_datagram.source_address, msg->wdp_datagram.source_port, msg->wdp_datagram.destination_address, msg->wdp_datagram.destination_port); dgram->u.T_DUnitdata_Ind.user_data = msg->wdp_datagram.user_data; msg->wdp_datagram.user_data = NULL; wap_dispatch_datagram(dgram); break; case WTLS_CONNECTIONLESS_PORT: case WTLS_CONNECTION_ORIENTED_PORT: #if (HAVE_WTLS_OPENSSL) dgram = wtls_unpack_wdp_datagram(msg); if (dgram != NULL) wtls_dispatch_event(dgram); #endif break; default: panic(0,"Bad packet received! This shouldn't happen!"); break; } } else { warning(0, "Received other message than wdp/admin, ignoring!"); } msg_destroy(msg); } info(0, GW_NAME " wapbox terminating."); program_status = shutting_down; heartbeat_stop(ALL_HEARTBEATS); counter_destroy(sequence_counter); if (cfg) wtp_initiator_shutdown(); wtp_resp_shutdown(); wsp_push_client_shutdown(); wsp_unit_shutdown(); wsp_session_shutdown(); wap_appl_shutdown(); radius_acct_shutdown(); if (cfg) { wap_push_ota_shutdown(); wap_push_ppg_shutdown(); } wml_shutdown(); close_connection_to_bearerbox(); wap_map_destroy(); wap_map_user_destroy(); octstr_destroy(device_home); octstr_destroy(bearerbox_host); octstr_destroy(config_filename); /* * Just sleep for a while to get bearerbox chance to restart. * Otherwise we will fail while trying to connect to bearerbox! */ if (restart) { gwthread_sleep(5.0); } gwlib_shutdown(); /* now really restart */ if (restart) execvp(argv[0], argv); return 0; }