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

wapbox.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * wapbox.c - main program for wapbox
00059  *
00060  * This module contains the main program for the WAP box of the WAP gateway.
00061  * See the architecture documentation for details.
00062  */
00063 
00064 #include <stdlib.h>
00065 #include <time.h>
00066 #include <unistd.h>
00067 #include <signal.h>
00068 
00069 #include "gwlib/gwlib.h"
00070 #include "shared.h"
00071 #include "wml_compiler.h"
00072 #include "heartbeat.h"
00073 #include "wap/wap.h"
00074 #include "wap-appl.h"
00075 #include "wap-maps.h"
00076 #include "wap_push_ota.h"
00077 #include "wap_push_ppg.h"
00078 #include "gw/msg.h"
00079 #include "bb.h"
00080 #include "sms.h"
00081 #ifdef HAVE_WTLS_OPENSSL
00082 #include <openssl/x509.h>
00083 #include "wap/wtls.h"
00084 #include "gwlib/pki.h"
00085 #endif
00086 #include "radius/radius_acct.h"
00087 
00088 static void config_reload(int reload);
00089 static long logfilelevel=-1;
00090 
00091 enum {
00092     CONNECTIONLESS_PORT = 9200,
00093     CONNECTION_ORIENTED_PORT = 9201,
00094     WTLS_CONNECTIONLESS_PORT = 9202,
00095     WTLS_CONNECTION_ORIENTED_PORT = 9203
00096 };
00097 
00098 enum { DEFAULT_TIMER_FREQ = 1};
00099 
00100 static Octstr *bearerbox_host;
00101 static long bearerbox_port = BB_DEFAULT_WAPBOX_PORT;
00102 static int bearerbox_ssl = 0;
00103 static Counter *sequence_counter = NULL;
00104 static long timer_freq = DEFAULT_TIMER_FREQ;
00105 static Octstr *config_filename;
00106 
00107 /* use strict XML parsing or relaxed */
00108 static int wml_xml_strict = 1;
00109 
00110 /* smart error messaging related globals */
00111 int wsp_smart_errors = 0;
00112 Octstr *device_home = NULL;
00113 
00114 /* Controlling segmentation of sms messages sent by wapbox (push related).*/
00115 int concatenation = 1;
00116 long max_messages = 10;
00117 
00118 #ifdef HAVE_WTLS_OPENSSL
00119 RSA* private_key = NULL;
00120 X509* x509_cert = NULL;
00121 #endif
00122 
00123 static Cfg *init_wapbox(Cfg *cfg)
00124 {
00125     CfgGroup *grp;
00126     Octstr *s;
00127     Octstr *logfile;
00128     int lf, m;
00129 
00130     lf = m = 1;
00131 
00132     cfg_dump(cfg);
00133     
00134     /*
00135      * Extract info from the core group.
00136      */
00137     grp = cfg_get_single_group(cfg, octstr_imm("core"));
00138     if (grp == NULL)
00139         panic(0, "No 'core' group in configuration.");
00140     
00141     if (cfg_get_integer(&bearerbox_port,grp,octstr_imm("wapbox-port")) == -1)
00142         panic(0, "No 'wapbox-port' in core group");
00143 #ifdef HAVE_LIBSSL
00144     cfg_get_bool(&bearerbox_ssl, grp, octstr_imm("wapbox-port-ssl"));
00145 #endif /* HAVE_LIBSSL */
00146     
00147     /* load parameters that could be later reloaded */
00148     config_reload(0);
00149     
00150     conn_config_ssl(grp);
00151 
00152     /*
00153      * And the rest of the pull info comes from the wapbox group.
00154      */
00155     grp = cfg_get_single_group(cfg, octstr_imm("wapbox"));
00156     if (grp == NULL)
00157         panic(0, "No 'wapbox' group in configuration.");
00158     
00159     bearerbox_host = cfg_get(grp, octstr_imm("bearerbox-host"));
00160     if (cfg_get_integer(&timer_freq, grp, octstr_imm("timer-freq")) == -1)
00161         timer_freq = DEFAULT_TIMER_FREQ;
00162 
00163     logfile = cfg_get(grp, octstr_imm("log-file"));
00164     if (logfile != NULL) {
00165         log_open(octstr_get_cstr(logfile), logfilelevel, GW_NON_EXCL);
00166         info(0, "Starting to log to file %s level %ld", 
00167              octstr_get_cstr(logfile), logfilelevel);
00168     }
00169     octstr_destroy(logfile);
00170 
00171     if ((s = cfg_get(grp, octstr_imm("syslog-level"))) != NULL) {
00172         long level;
00173     
00174         if (octstr_compare(s, octstr_imm("none")) == 0) {
00175             log_set_syslog(NULL, 0);
00176             debug("wap", 0, "syslog parameter is none");
00177         } else if (octstr_parse_long(&level, s, 0, 0) == -1) {
00178             log_set_syslog("wapbox", level);
00179             debug("wap", 0, "syslog parameter is %ld", level);
00180         }
00181         octstr_destroy(s);
00182     } else {
00183         log_set_syslog(NULL, 0);
00184         debug("wap", 0, "no syslog parameter");
00185     }
00186 
00187     /* determine which timezone we use for access logging */
00188     if ((s = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) {
00189         lf = (octstr_case_compare(s, octstr_imm("gmt")) == 0) ? 0 : 1;
00190         octstr_destroy(s);
00191     }
00192 
00193     /* should predefined markers be used, ie. prefixing timestamp */
00194     cfg_get_bool(&m, grp, octstr_imm("access-log-clean"));
00195 
00196     /* open access-log file */
00197     if ((s = cfg_get(grp, octstr_imm("access-log"))) != NULL) {
00198         info(0, "Logging accesses to '%s'.", octstr_get_cstr(s));
00199         alog_open(octstr_get_cstr(s), lf, m ? 0 : 1);
00200         octstr_destroy(s);
00201     }
00202 
00203     /* configure the 'wtls' group */
00204 #if (HAVE_WTLS_OPENSSL)
00205     /* Load up the necessary keys */
00206     grp = cfg_get_single_group(cfg, octstr_imm("wtls"));
00207   
00208     if (grp != NULL) {
00209         if ((s = cfg_get(grp, octstr_imm("certificate-file"))) != NULL) {
00210             if (octstr_compare(s, octstr_imm("none")) == 0) {
00211                 debug("bbox", 0, "certificate file not set");
00212             } else {
00213                 /* Load the certificate into the necessary parameter */
00214                 get_cert_from_file(s, &x509_cert);
00215                 gw_assert(x509_cert != NULL);
00216                 debug("bbox", 0, "certificate parameter is %s", s);
00217             }
00218             octstr_destroy(s);
00219         } else
00220             panic(0, "No 'certificate-file' in wtls group");
00221 
00222         if ((s = cfg_get(grp, octstr_imm("privatekey-file"))) != NULL) {
00223             Octstr *password;
00224             password = cfg_get(grp, octstr_imm("privatekey-password"));
00225             if (octstr_compare(s, octstr_imm("none")) == 0) {
00226                 debug("bbox", 0, "privatekey-file not set");
00227             } else {
00228                 /* Load the private key into the necessary parameter */
00229                 get_privkey_from_file(s, &private_key, password);
00230                 gw_assert(private_key != NULL);
00231                 debug("bbox", 0, "certificate parameter is %s", s);
00232             }
00233             if (password != NULL)
00234                 octstr_destroy(password);
00235             octstr_destroy(s);
00236         } else
00237             panic(0, "No 'privatekey-file' in wtls group");
00238     }
00239 #endif
00240 
00241     /*
00242      * Check if we have a 'radius-acct' proxy group and start the
00243      * corresponding thread for the proxy.
00244      */
00245     grp = cfg_get_single_group(cfg, octstr_imm("radius-acct"));
00246     if (grp) {
00247         radius_acct_init(grp);
00248     }
00249 
00250     /*
00251      * We pass ppg configuration groups to the ppg module.
00252      */   
00253     grp = cfg_get_single_group(cfg, octstr_imm("ppg"));
00254     if (grp == NULL) { 
00255         cfg_destroy(cfg);
00256         return NULL;
00257     }
00258 
00259     return cfg;
00260 }
00261 
00262 
00263 static void signal_handler(int signum) 
00264 {
00265     /* 
00266      * On some implementations (i.e. linuxthreads), signals are delivered
00267      * to all threads.  We only want to handle each signal once for the
00268      * entire box, and we let the gwthread wrapper take care of choosing
00269      * one. */
00270     if (!gwthread_shouldhandlesignal(signum))
00271         return;
00272     
00273     switch (signum) {
00274         case SIGINT:
00275         case SIGTERM:
00276             if (program_status != shutting_down) {
00277                 error(0, "SIGINT or SIGTERM received, let's die.");
00278                 program_status = shutting_down;
00279                 break;
00280             }
00281             break;
00282     
00283         case SIGHUP:
00284             warning(0, "SIGHUP received, catching and re-opening logs");
00285             config_reload(1);
00286             log_reopen();
00287             alog_reopen();
00288             break;
00289     
00290         /* 
00291          * It would be more proper to use SIGUSR1 for this, but on some
00292          * platforms that's reserved by the pthread support. 
00293          */
00294         case SIGQUIT:
00295             warning(0, "SIGQUIT received, reporting memory usage.");
00296             gw_check_leaks();
00297             break;
00298         }
00299 }
00300 
00301 
00302 static void setup_signal_handlers(void) 
00303 {
00304     struct sigaction act;
00305     
00306     act.sa_handler = signal_handler;
00307     sigemptyset(&act.sa_mask);
00308     act.sa_flags = 0;
00309     sigaction(SIGINT, &act, NULL);
00310     sigaction(SIGQUIT, &act, NULL);
00311     sigaction(SIGHUP, &act, NULL);
00312     sigaction(SIGPIPE, &act, NULL);
00313 }
00314 
00315 /*
00316  * We create wdp_datagram for IP traffic and sms for SMS traffic. 
00317  */
00318 static Msg *pack_ip_datagram(WAPEvent *dgram)
00319 {
00320     Msg *msg;
00321     WAPAddrTuple *tuple;
00322 
00323     msg = msg_create(wdp_datagram);
00324     tuple = dgram->u.T_DUnitdata_Req.addr_tuple;
00325     msg->wdp_datagram.source_address =
00326         octstr_duplicate(tuple->local->address);
00327     msg->wdp_datagram.source_port =
00328         dgram->u.T_DUnitdata_Req.addr_tuple->local->port;
00329     msg->wdp_datagram.destination_address =
00330         octstr_duplicate(tuple->remote->address);
00331     msg->wdp_datagram.destination_port =
00332         dgram->u.T_DUnitdata_Req.addr_tuple->remote->port;
00333     msg->wdp_datagram.user_data =
00334         octstr_duplicate(dgram->u.T_DUnitdata_Req.user_data);
00335 
00336    return msg;
00337 }
00338 
00339 /*
00340  * Format for port UDH is defined in wdp, appendix A. It is %06%05%04
00341  * %dest port high hex%dest port low%hex source port high hex%source port low
00342  * hex. (Unsecure) push client port itself is 2948.
00343  */
00344 static Octstr *pack_udhdata(WAPAddrTuple *tuple)
00345 {
00346     int source_port,
00347         dest_port;
00348     Octstr *udh;
00349     
00350     source_port = tuple->local->port;
00351     dest_port = tuple->remote->port;  
00352     
00353     udh = octstr_create("");
00354     octstr_format_append(udh, "%c", 6);
00355     octstr_format_append(udh, "%c", 5);
00356     octstr_format_append(udh, "%c", 4);
00357     octstr_format_append(udh, "%c", (dest_port >> 8) & 0xff);
00358     octstr_format_append(udh, "%c", dest_port & 0xff);
00359     octstr_format_append(udh, "%c", (source_port >> 8) & 0xff);
00360     octstr_format_append(udh, "%c", source_port & 0xff);
00361 
00362     return udh;
00363 }
00364 
00365 /*
00366  * We send a normal 8-bit unconcatenated binary  message with an udh. Caller 
00367  * must do segmentation before calling this function.
00368  *
00369  * Note: we have hardcoded validity period here. We must eventually use push
00370  * control document to fill this field. 
00371  */
00372 static Msg *pack_sms_datagram(WAPEvent *dgram)
00373 {
00374     Msg *msg;
00375     WAPAddrTuple *tuple;
00376 
00377     msg = msg_create(sms);
00378     tuple = dgram->u.T_DUnitdata_Req.addr_tuple;
00379     msg->sms.sender = octstr_duplicate(tuple->local->address);
00380     msg->sms.receiver = octstr_duplicate(tuple->remote->address);
00381     msg->sms.udhdata = pack_udhdata(tuple);
00382     msg->sms.msgdata = octstr_duplicate(dgram->u.T_DUnitdata_Req.user_data);
00383     msg->sms.time = time(NULL);
00384     if (dgram->u.T_DUnitdata_Req.smsc_id != NULL)
00385         msg->sms.smsc_id = octstr_duplicate(dgram->u.T_DUnitdata_Req.smsc_id);
00386     else
00387         msg->sms.smsc_id = NULL;
00388     msg->sms.dlr_mask = dgram->u.T_DUnitdata_Req.dlr_mask;
00389     if (dgram->u.T_DUnitdata_Req.smsbox_id != NULL)
00390         msg->sms.boxc_id = octstr_duplicate(dgram->u.T_DUnitdata_Req.smsbox_id);
00391     else
00392         msg->sms.boxc_id = NULL;
00393     if (dgram->u.T_DUnitdata_Req.dlr_url != NULL)
00394         msg->sms.dlr_url = octstr_duplicate(dgram->u.T_DUnitdata_Req.dlr_url);
00395     else
00396         msg->sms.dlr_url = NULL;
00397     msg->sms.sms_type = mt_push;
00398     msg->sms.mwi = MWI_UNDEF;
00399     msg->sms.coding = DC_8BIT;
00400     msg->sms.mclass = MC_UNDEF;
00401     msg->sms.validity = 1440;
00402     msg->sms.deferred = -1;
00403     if (dgram->u.T_DUnitdata_Req.service_name != NULL)
00404         msg->sms.service = octstr_duplicate(dgram->u.T_DUnitdata_Req.service_name);
00405     
00406     return msg;   
00407 }
00408 
00409 /*
00410  * Possible address types
00411  */
00412 
00413 enum {
00414     ADDR_IPV4 = 0,
00415     ADDR_PLMN = 1,
00416     ADDR_USER = 2,
00417     ADDR_IPV6 = 3,
00418     ADDR_WINA = 4
00419 };
00420 
00421 /*
00422  * Send IP datagram as it is, segment SMS datagram if necessary.
00423  */
00424 static void dispatch_datagram(WAPEvent *dgram)
00425 {
00426     Msg *msg, *part;
00427     List *sms_datagrams;
00428     static unsigned long msg_sequence = 0L;   /* Used only by this function */
00429 
00430     msg = part = NULL;
00431     sms_datagrams = NULL;
00432 
00433     if (dgram == NULL) {
00434         error(0, "WDP: dispatch_datagram received empty datagram, ignoring.");
00435     } 
00436     else if (dgram->type != T_DUnitdata_Req) {
00437         warning(0, "WDP: dispatch_datagram received event of unexpected type.");
00438         wap_event_dump(dgram);
00439     } 
00440     else if (dgram->u.T_DUnitdata_Req.address_type == ADDR_IPV4) {
00441        msg = pack_ip_datagram(dgram);
00442        write_to_bearerbox(msg);
00443     } else {
00444         msg_sequence = counter_increase(sequence_counter) & 0xff;
00445         msg = pack_sms_datagram(dgram);
00446         sms_datagrams = sms_split(msg, NULL, NULL, NULL, NULL, concatenation, 
00447                                   msg_sequence, max_messages, MAX_SMS_OCTETS);
00448         debug("wap",0,"WDP (wapbox): delivering %ld segments to bearerbox",
00449               gwlist_len(sms_datagrams));
00450         while ((part = gwlist_extract_first(sms_datagrams)) != NULL) {
00451            write_to_bearerbox(part);
00452         }
00453 
00454         gwlist_destroy(sms_datagrams, NULL);
00455         msg_destroy(msg);
00456     }
00457 
00458     wap_event_destroy(dgram);
00459 }
00460 
00461 
00462 /*
00463  * Reloading functions
00464  */
00465 
00466 static void reload_int(int reload, Octstr *desc, long *o, long *n)
00467 {
00468     if (reload && *o != *n) {
00469         info(0, "Reloading int '%s' from %ld to %ld", 
00470              octstr_get_cstr(desc), *o, *n);
00471         *o = *n;
00472     }
00473 }
00474 
00475 static void reload_bool(int reload, Octstr *desc, int *o, int *n)
00476 {
00477     if (reload && *o != *n) {
00478         info(0, "Reloading bool '%s' from %s to %s", 
00479              octstr_get_cstr(desc), 
00480              (*o ? "yes" : "no"), (*n ? "yes" : "no"));
00481         *o = *n;
00482     }
00483 }
00484 
00485 
00486 /*
00487  * Read all reloadable configuration directives
00488  */
00489 static void config_reload(int reload) {
00490     Cfg *cfg;
00491     CfgGroup *grp;
00492     List *groups;
00493     long map_url_max;
00494     Octstr *s;
00495     long i;
00496     long new_value;
00497     int new_bool;
00498     Octstr *http_proxy_host;
00499     Octstr *http_interface_name;
00500     long http_proxy_port;
00501     int http_proxy_ssl = 0;
00502     List *http_proxy_exceptions;
00503     Octstr *http_proxy_username;
00504     Octstr *http_proxy_password;
00505     Octstr *http_proxy_exceptions_regex;
00506     int warn_map_url = 0;
00507 
00508     /* XXX TO-DO: if(reload) implement wapbox.suspend/mutex.lock */
00509     
00510     if (reload)
00511         debug("config_reload", 0, "Reloading configuration");
00512 
00513     /* 
00514      * NOTE: we could lstat config file and only reload if it was modified, 
00515      * but as we have a include directive, we don't know every file's
00516      * timestamp at this point
00517      */
00518 
00519     cfg = cfg_create(config_filename);
00520 
00521     if (cfg_read(cfg) == -1) {
00522         warning(0, "Couldn't %sload configuration from `%s'.", 
00523                    (reload ? "re" : ""), octstr_get_cstr(config_filename));
00524         return;
00525     }
00526 
00527     grp = cfg_get_single_group(cfg, octstr_imm("core"));
00528 
00529     http_proxy_host = cfg_get(grp, octstr_imm("http-proxy-host"));
00530     http_proxy_port =  -1;
00531     cfg_get_integer(&http_proxy_port, grp, octstr_imm("http-proxy-port"));
00532 #ifdef HAVE_LIBSSL
00533     cfg_get_bool(&http_proxy_ssl, grp, octstr_imm("http-proxy-ssl"));
00534 #endif /* HAVE_LIBSSL */
00535     http_proxy_username = cfg_get(grp, octstr_imm("http-proxy-username"));
00536     http_proxy_password = cfg_get(grp, octstr_imm("http-proxy-password"));
00537     http_proxy_exceptions = cfg_get_list(grp, octstr_imm("http-proxy-exceptions"));
00538     http_proxy_exceptions_regex = cfg_get(grp, octstr_imm("http-proxy-exceptions-regex"));
00539     if (http_proxy_host != NULL && http_proxy_port > 0) {
00540         http_use_proxy(http_proxy_host, http_proxy_port, http_proxy_ssl,
00541                        http_proxy_exceptions, http_proxy_username, 
00542                        http_proxy_password, http_proxy_exceptions_regex);
00543     }
00544     octstr_destroy(http_proxy_host);
00545     octstr_destroy(http_proxy_username);
00546     octstr_destroy(http_proxy_password);
00547     octstr_destroy(http_proxy_exceptions_regex);
00548     gwlist_destroy(http_proxy_exceptions, octstr_destroy_item);
00549 
00550     grp = cfg_get_single_group(cfg, octstr_imm("wapbox"));
00551     if (grp == NULL) {
00552         warning(0, "No 'wapbox' group in configuration.");
00553         return;
00554     }
00555     
00556     if (cfg_get_integer(&new_value, grp, octstr_imm("log-level")) != -1) {
00557         reload_int(reload, octstr_imm("log level"), &logfilelevel, &new_value);
00558         logfilelevel = new_value;
00559         log_set_log_level(new_value);
00560     }
00561 
00562     /* Configure interface name for http requests */
00563     http_interface_name = cfg_get(grp, octstr_imm("http-interface-name"));
00564     if (http_interface_name != NULL) {
00565         http_set_interface(http_interface_name);
00566         octstr_destroy(http_interface_name);
00567     }
00568 
00569     /* 
00570      * users may define 'smart-errors' to have WML decks returned with
00571      * error information instead of signaling using the HTTP reply codes
00572      */
00573     cfg_get_bool(&new_bool, grp, octstr_imm("smart-errors"));
00574     reload_bool(reload, octstr_imm("smart error messaging"), &wsp_smart_errors, &new_bool);
00575 
00576     /* decide if our XML parser within WML compiler is strict or relaxed */
00577     cfg_get_bool(&new_bool, grp, octstr_imm("wml-strict"));
00578     reload_bool(reload, octstr_imm("XML within WML has to be strict"), 
00579                 &wml_xml_strict, &new_bool);
00580     if (!wml_xml_strict)
00581         warning(0, "'wml-strict' config directive has been set to no, "
00582                    "this may make you vulnerable against XML bogus input.");
00583 
00584     if (cfg_get_bool(&new_bool, grp, octstr_imm("concatenation")) == 1)
00585         reload_bool(reload, octstr_imm("concatenation"), &concatenation, &new_bool);
00586     else
00587         concatenation = 1;
00588 
00589     if (cfg_get_integer(&new_value, grp, octstr_imm("max-messages")) != -1) {
00590         max_messages = new_value;
00591         reload_int(reload, octstr_imm("max messages"), &max_messages, &new_value);
00592     }
00593 
00594     /* configure URL mappings */
00595     map_url_max = -1;
00596     cfg_get_integer(&map_url_max, grp, octstr_imm("map-url-max"));
00597     if (map_url_max > 0)
00598         warn_map_url = 1;
00599 
00600     if (reload) { /* clear old map */
00601         wap_map_destroy();
00602         wap_map_user_destroy();
00603     }
00604     
00605     if ((device_home = cfg_get(grp, octstr_imm("device-home"))) != NULL) {
00606         wap_map_url_config_device_home(octstr_get_cstr(device_home));
00607     }
00608     if ((s = cfg_get(grp, octstr_imm("map-url"))) != NULL) {
00609         warn_map_url = 1;
00610         wap_map_url_config(octstr_get_cstr(s));
00611         octstr_destroy(s);
00612     }
00613     debug("wap", 0, "map_url_max = %ld", map_url_max);
00614 
00615     for (i = 0; i <= map_url_max; i++) {
00616         Octstr *name;
00617         name = octstr_format("map-url-%d", i);
00618         if ((s = cfg_get(grp, name)) != NULL)
00619             wap_map_url_config(octstr_get_cstr(s));
00620         octstr_destroy(name);
00621     }
00622 
00623     /* warn the user that he/she should use the new wap-url-map groups */
00624     if (warn_map_url)
00625         warning(0, "'map-url' config directive and related are deprecated, "
00626                    "please use wap-url-map group");
00627 
00628     /* configure wap-url-map */
00629     groups = cfg_get_multi_group(cfg, octstr_imm("wap-url-map"));
00630     while (groups && (grp = gwlist_extract_first(groups)) != NULL) {
00631         Octstr *name, *url, *map_url, *send_msisdn_query;
00632         Octstr *send_msisdn_header, *send_msisdn_format;
00633         int accept_cookies;
00634 
00635         name = cfg_get(grp, octstr_imm("name"));
00636         url = cfg_get(grp, octstr_imm("url"));
00637         map_url = cfg_get(grp, octstr_imm("map-url"));
00638         send_msisdn_query = cfg_get(grp, octstr_imm("send-msisdn-query"));
00639         send_msisdn_header = cfg_get(grp, octstr_imm("send-msisdn-header"));
00640         send_msisdn_format = cfg_get(grp, octstr_imm("send-msisdn-format"));
00641         accept_cookies = -1;
00642         cfg_get_bool(&accept_cookies, grp, octstr_imm("accept-cookies"));
00643 
00644         wap_map_add_url(name, url, map_url, send_msisdn_query, send_msisdn_header,
00645                         send_msisdn_format, accept_cookies);
00646 
00647         info(0, "Added wap-url-map <%s> with url <%s>, map-url <%s>, "
00648                 "send-msisdn-query <%s>, send-msisdn-header <%s>, "
00649                 "send-msisdn-format <%s>, accept-cookies <%s>", 
00650              octstr_get_cstr(name), octstr_get_cstr(url), 
00651              octstr_get_cstr(map_url), octstr_get_cstr(send_msisdn_query), 
00652              octstr_get_cstr(send_msisdn_header), 
00653              octstr_get_cstr(send_msisdn_format), (accept_cookies ? "yes" : "no"));
00654     }
00655     gwlist_destroy(groups, NULL);
00656 
00657     /* configure wap-user-map */
00658     groups = cfg_get_multi_group(cfg, octstr_imm("wap-user-map"));
00659     while (groups && (grp = gwlist_extract_first(groups)) != NULL) {
00660         Octstr *name, *user, *pass, *msisdn;
00661 
00662         name = cfg_get(grp, octstr_imm("name"));
00663         user = cfg_get(grp, octstr_imm("user"));
00664         pass = cfg_get(grp, octstr_imm("pass"));
00665         msisdn = cfg_get(grp, octstr_imm("msisdn"));
00666            
00667         wap_map_add_user(name, user, pass, msisdn);
00668 
00669         info(0,"Added wap-user-map <%s> with credentials <%s:%s> "
00670                "and MSISDN <%s>", octstr_get_cstr(name),
00671              octstr_get_cstr(user), octstr_get_cstr(pass),
00672              octstr_get_cstr(msisdn));
00673     }
00674     gwlist_destroy(groups, NULL);
00675 
00676     cfg_destroy(cfg);
00677     /* XXX TO-DO: if(reload) implement wapbox.resume/mutex.unlock */
00678 }
00679 
00680 int main(int argc, char **argv) 
00681 {
00682     int cf_index;
00683     int restart = 0;
00684     Msg *msg;
00685     Cfg *cfg;
00686     double heartbeat_freq =  DEFAULT_HEARTBEAT;
00687     
00688     gwlib_init();
00689     cf_index = get_and_set_debugs(argc, argv, NULL);
00690     
00691     setup_signal_handlers();
00692     
00693     if (argv[cf_index] == NULL)
00694         config_filename = octstr_create("kannel.conf");
00695     else
00696         config_filename = octstr_create(argv[cf_index]);
00697     cfg = cfg_create(config_filename);
00698 
00699     if (cfg_read(cfg) == -1)
00700         panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(config_filename));
00701 
00702     report_versions("wapbox");
00703 
00704     cfg = init_wapbox(cfg);
00705 
00706     info(0, "------------------------------------------------------------");
00707     info(0, GW_NAME " wapbox version %s starting up.", GW_VERSION);
00708     
00709     sequence_counter = counter_create();
00710     wsp_session_init(&wtp_resp_dispatch_event,
00711                      &wtp_initiator_dispatch_event,
00712                      &wap_appl_dispatch,
00713                      &wap_push_ppg_dispatch_event);
00714     wsp_unit_init(&dispatch_datagram, &wap_appl_dispatch);
00715     wsp_push_client_init(&wsp_push_client_dispatch_event, 
00716                          &wtp_resp_dispatch_event);
00717     
00718     if (cfg)
00719         wtp_initiator_init(&dispatch_datagram, &wsp_session_dispatch_event,
00720                            timer_freq);
00721 
00722     wtp_resp_init(&dispatch_datagram, &wsp_session_dispatch_event,
00723                   &wsp_push_client_dispatch_event, timer_freq);
00724     wap_appl_init(cfg);
00725 
00726 #if (HAVE_WTLS_OPENSSL)
00727     wtls_secmgr_init();
00728     wtls_init();
00729 #endif
00730     
00731     if (cfg) {
00732         wap_push_ota_init(&wsp_session_dispatch_event, 
00733                           &wsp_unit_dispatch_event);
00734         wap_push_ppg_init(&wap_push_ota_dispatch_event, &wap_appl_dispatch, 
00735                           cfg);
00736     }
00737         
00738     wml_init(wml_xml_strict);
00739     
00740     if (bearerbox_host == NULL)
00741         bearerbox_host = octstr_create(BB_DEFAULT_HOST);
00742     connect_to_bearerbox(bearerbox_host, bearerbox_port, bearerbox_ssl, NULL
00743             /* bearerbox_our_port */);
00744 
00745     if (cfg)
00746         wap_push_ota_bb_address_set(bearerbox_host);
00747         
00748     program_status = running;
00749     if (0 > heartbeat_start(write_to_bearerbox, heartbeat_freq, 
00750                                        wap_appl_get_load)) {
00751         info(0, GW_NAME "Could not start heartbeat.");
00752     }
00753 
00754     while (program_status != shutting_down) {
00755     WAPEvent *dgram;
00756         int ret;
00757 
00758         /* block infinite for reading messages */
00759         ret = read_from_bearerbox(&msg, INFINITE_TIME);
00760         if (ret == -1)
00761             break;
00762         else if (ret == 1) /* timeout */
00763             continue;
00764         else if (msg == NULL) /* just to be sure, may not happens */
00765             break;
00766     if (msg_type(msg) == admin) {
00767         if (msg->admin.command == cmd_shutdown) {
00768         info(0, "Bearerbox told us to die");
00769         program_status = shutting_down;
00770         } else if (msg->admin.command == cmd_restart) {
00771         info(0, "Bearerbox told us to restart");
00772         restart = 1;
00773         program_status = shutting_down;
00774         }
00775         /*
00776          * XXXX here should be suspend/resume, add RSN
00777          */
00778     } else if (msg_type(msg) == wdp_datagram) {
00779         switch (msg->wdp_datagram.destination_port) {
00780         case CONNECTIONLESS_PORT:
00781         case CONNECTION_ORIENTED_PORT:
00782             dgram = wap_event_create(T_DUnitdata_Ind);
00783             dgram->u.T_DUnitdata_Ind.addr_tuple = wap_addr_tuple_create(
00784                 msg->wdp_datagram.source_address,
00785                 msg->wdp_datagram.source_port,
00786                 msg->wdp_datagram.destination_address,
00787                 msg->wdp_datagram.destination_port);
00788             dgram->u.T_DUnitdata_Ind.user_data = msg->wdp_datagram.user_data;
00789             msg->wdp_datagram.user_data = NULL;
00790 
00791             wap_dispatch_datagram(dgram); 
00792             break;
00793         case WTLS_CONNECTIONLESS_PORT:
00794         case WTLS_CONNECTION_ORIENTED_PORT:
00795 #if (HAVE_WTLS_OPENSSL)
00796             dgram = wtls_unpack_wdp_datagram(msg);
00797             if (dgram != NULL)
00798                 wtls_dispatch_event(dgram);
00799 #endif
00800             break;
00801         default:
00802                 panic(0,"Bad packet received! This shouldn't happen!");
00803                 break;
00804         } 
00805     } else {
00806         warning(0, "Received other message than wdp/admin, ignoring!");
00807     }
00808     msg_destroy(msg);
00809     }
00810 
00811     info(0, GW_NAME " wapbox terminating.");
00812     
00813     program_status = shutting_down;
00814     heartbeat_stop(ALL_HEARTBEATS);
00815     counter_destroy(sequence_counter);
00816 
00817     if (cfg)
00818         wtp_initiator_shutdown();
00819 
00820     wtp_resp_shutdown();
00821     wsp_push_client_shutdown();
00822     wsp_unit_shutdown();
00823     wsp_session_shutdown();
00824     wap_appl_shutdown();
00825     radius_acct_shutdown();
00826 
00827     if (cfg) {
00828         wap_push_ota_shutdown();
00829         wap_push_ppg_shutdown();
00830     }
00831 
00832     wml_shutdown();
00833     close_connection_to_bearerbox();
00834     wap_map_destroy();
00835     wap_map_user_destroy();
00836     octstr_destroy(device_home);
00837     octstr_destroy(bearerbox_host);
00838     octstr_destroy(config_filename);
00839 
00840     /*
00841      * Just sleep for a while to get bearerbox chance to restart.
00842      * Otherwise we will fail while trying to connect to bearerbox!
00843      */
00844     if (restart) {
00845         gwthread_sleep(5.0);
00846     }
00847 
00848     gwlib_shutdown();
00849 
00850     /* now really restart */
00851     if (restart)
00852         execvp(argv[0], argv);
00853 
00854     return 0;
00855 }
00856 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.