wapbox.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:16k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * wapbox.c - main program for wapbox
  3.  *
  4.  * This module contains the main program for the WAP box of the WAP gateway.
  5.  * See the architecture documentation for details.
  6.  */
  7. #include <stdlib.h>
  8. #include <time.h>
  9. #include <unistd.h>
  10. #include <signal.h>
  11. #include "gwlib/gwlib.h"
  12. #include "shared.h"
  13. #include "wml_compiler.h"
  14. #include "heartbeat.h"
  15. #include "wap/wap.h"
  16. #include "wap-appl.h"
  17. #include "wap_push_ota.h"
  18. #include "wap_push_ppg.h"
  19. #include "gw/msg.h"
  20. #include "bb.h"
  21. #include "sms.h"
  22. #ifdef HAVE_WTLS_OPENSSL
  23. #include <openssl/x509.h>
  24. #include "wap/wtls.h"
  25. #include "gwlib/pki.h"
  26. #endif
  27. enum {
  28.     CONNECTIONLESS_PORT = 9200,
  29.     CONNECTION_ORIENTED_PORT = 9201,
  30.     WTLS_CONNECTIONLESS_PORT = 9202,
  31.     WTLS_CONNECTION_ORIENTED_PORT = 9203
  32. };
  33. enum { MAX_SMS_OCTETS = 140 };
  34. static Octstr *bearerbox_host;
  35. static long bearerbox_port = BB_DEFAULT_WAPBOX_PORT;
  36. static int bearerbox_ssl = 0;
  37. static Counter *sequence_counter = NULL;
  38. int wtp_forced_sar = 0;
  39. int wsp_smart_errors = 0;
  40. #ifdef HAVE_WTLS_OPENSSL
  41. RSA* private_key = NULL;
  42. X509* x509_cert = NULL;
  43. #endif
  44. static Cfg *init_wapbox(Cfg *cfg)
  45. {
  46.     CfgGroup *grp;
  47.     Octstr *s;
  48.     long i;
  49.     Octstr *logfile;
  50.     long logfilelevel;
  51.     Octstr *http_proxy_host;
  52.     long http_proxy_port;
  53.     List *http_proxy_exceptions;
  54.     Octstr *http_proxy_username;
  55.     Octstr *http_proxy_password;
  56.     long map_url_max;
  57.     cfg_dump(cfg);
  58.     
  59.     /*
  60.      * Extract info from the core group.
  61.      */
  62.     grp = cfg_get_single_group(cfg, octstr_imm("core"));
  63.     if (grp == NULL)
  64.      panic(0, "No 'core' group in configuration.");
  65.     
  66.     if (cfg_get_integer(&bearerbox_port,grp,octstr_imm("wapbox-port")) == -1)
  67.         panic(0, "No 'wapbox-port' in core group");
  68. #ifdef HAVE_LIBSSL
  69.     cfg_get_bool(&bearerbox_ssl, grp, octstr_imm("wapbox-port-ssl"));
  70. #endif /* HAVE_LIBSSL */
  71.     
  72.     http_proxy_host = cfg_get(grp, octstr_imm("http-proxy-host"));
  73.     http_proxy_port =  -1;
  74.     cfg_get_integer(&http_proxy_port, grp, octstr_imm("http-proxy-port"));
  75.     http_proxy_username = cfg_get(grp, octstr_imm("http-proxy-username"));
  76.     http_proxy_password = cfg_get(grp, octstr_imm("http-proxy-password"));
  77.     http_proxy_exceptions = cfg_get_list(grp, octstr_imm("http-proxy-exceptions"));
  78.     if (http_proxy_host != NULL && http_proxy_port > 0) {
  79.         http_use_proxy(http_proxy_host, http_proxy_port, 
  80.                        http_proxy_exceptions, http_proxy_username, 
  81.                        http_proxy_password);
  82.     }
  83.     conn_config_ssl (grp);
  84.     octstr_destroy(http_proxy_host);
  85.     octstr_destroy(http_proxy_username);
  86.     octstr_destroy(http_proxy_password);
  87.     list_destroy(http_proxy_exceptions, octstr_destroy_item);
  88.       
  89.     /*
  90.      * And the rest of the pull info comes from the wapbox group.
  91.      */
  92.     grp = cfg_get_single_group(cfg, octstr_imm("wapbox"));
  93.     if (grp == NULL)
  94.         panic(0, "No 'wapbox' group in configuration.");
  95.     
  96.     bearerbox_host = cfg_get(grp, octstr_imm("bearerbox-host"));
  97.     
  98.     logfile = cfg_get(grp, octstr_imm("log-file"));
  99.     if (cfg_get_integer(&logfilelevel, grp, octstr_imm("log-level")) == -1)
  100.      logfilelevel = 0;
  101.     if (logfile != NULL) {
  102.         log_open(octstr_get_cstr(logfile), logfilelevel);
  103.         info(0, "Starting to log to file %s level %ld", 
  104.              octstr_get_cstr(logfile), logfilelevel);
  105.     }
  106.     octstr_destroy(logfile);
  107.     if ((s = cfg_get(grp, octstr_imm("syslog-level"))) != NULL) {
  108.         long level;
  109.         if (octstr_compare(s, octstr_imm("none")) == 0) {
  110.             log_set_syslog(NULL, 0);
  111.             debug("wap", 0, "syslog parameter is none");
  112.         } else if (octstr_parse_long(&level, s, 0, 0) == -1) {
  113.             log_set_syslog("wapbox", level);
  114.             debug("wap", 0, "syslog parameter is %ld", level);
  115.         }
  116.         octstr_destroy(s);
  117.     } else {
  118.         log_set_syslog(NULL, 0);
  119.         debug("wap", 0, "no syslog parameter");
  120.     }
  121.     s = cfg_get(grp, octstr_imm("access-log"));
  122.     if (s != NULL) {
  123.         info(0, "Logging accesses to '%s'.", octstr_get_cstr(s));
  124.         alog_open(octstr_get_cstr(s), 1);
  125.             /* XXX should be able to use gmtime, too */
  126.         octstr_destroy(s);
  127.     } else {
  128.         debug("wap", 0, "Could not open access-log");
  129.     }
  130.     /* configure URL mappings */
  131.     map_url_max = -1;
  132.     cfg_get_integer(&map_url_max, grp, octstr_imm("map-url-max"));
  133.     if ((s = cfg_get(grp, octstr_imm("device-home"))) != NULL) {
  134.         wsp_http_map_url_config_device_home(octstr_get_cstr(s));
  135.         octstr_destroy(s);
  136.     }
  137.     if ((s = cfg_get(grp, octstr_imm("map-url"))) != NULL) {
  138.         wsp_http_map_url_config(octstr_get_cstr(s));
  139.         octstr_destroy(s);
  140.     }
  141.     debug("wap", 0, "map_url_max = %ld", map_url_max);
  142.     for (i = 0; i <= map_url_max; i++) {
  143.         Octstr *name;
  144.         name = octstr_format("map-url-%d", i);
  145.         if ((s = cfg_get(grp, name)) != NULL)
  146.             wsp_http_map_url_config(octstr_get_cstr(s));
  147.         octstr_destroy(name);
  148.     }
  149.     wsp_http_map_url_config_info(); /* debugging aid */
  150.     /* check if we are using a kludge to allow WTP-SAR only clients */
  151.     cfg_get_bool(&wtp_forced_sar, grp, octstr_imm("force-sar"));
  152.     /* 
  153.      * users may define 'smart-errors' to have WML decks returned with
  154.      * error information instread of signaling using the HTTP reply codes
  155.      */
  156.     cfg_get_bool(&wsp_smart_errors, grp, octstr_imm("smart-errors"));
  157.     /* configure the 'wtls' group */
  158. #if (HAVE_WTLS_OPENSSL)
  159.     /* Load up the necessary keys */
  160.     grp = cfg_get_single_group(cfg, octstr_imm("wtls"));
  161.   
  162.     if (grp != NULL) {
  163.         if ((s = cfg_get(grp, octstr_imm("certificate-file"))) != NULL) {
  164.             if (octstr_compare(s, octstr_imm("none")) == 0) {
  165.                 debug("bbox", 0, "certificate file not set");
  166.             } else {
  167.                 /* Load the certificate into the necessary parameter */
  168.                 get_cert_from_file(s, &x509_cert);
  169.                 gw_assert(x509_cert != NULL);
  170.                 debug("bbox", 0, "certificate parameter is %s", s);
  171.             }
  172.             octstr_destroy(s);
  173.         } else
  174.             panic(0, "No 'certificate-file' in wtls group");
  175.         if ((s = cfg_get(grp, octstr_imm("privatekey-file"))) != NULL) {
  176.             Octstr *password;
  177.             password = cfg_get(grp, octstr_imm("privatekey-password"));
  178.             if (octstr_compare(s, octstr_imm("none")) == 0) {
  179.                 debug("bbox", 0, "privatekey-file not set");
  180.             } else {
  181.                 /* Load the private key into the necessary parameter */
  182.                 get_privkey_from_file(s, &private_key, password);
  183.                 gw_assert(private_key != NULL);
  184.                 debug("bbox", 0, "certificate parameter is %s", s);
  185.             }
  186.             if (password != NULL)
  187.                 octstr_destroy(password);
  188.             octstr_destroy(s);
  189.         } else
  190.             panic(0, "No 'privatekey-file' in wtls group");
  191.     }
  192. #endif
  193.     /*
  194.      * We pass ppg configuration groups to the ppg module.
  195.      */   
  196.     grp = cfg_get_single_group(cfg, octstr_imm("ppg"));
  197.     if (grp == NULL) { 
  198.         cfg_destroy(cfg);
  199.         return NULL;
  200.     }
  201.     return cfg;
  202. }
  203. static void signal_handler(int signum) 
  204. {
  205.     /* 
  206.      * On some implementations (i.e. linuxthreads), signals are delivered
  207.      * to all threads.  We only want to handle each signal once for the
  208.      * entire box, and we let the gwthread wrapper take care of choosing
  209.      * one. */
  210.     if (!gwthread_shouldhandlesignal(signum))
  211.         return;
  212.     
  213.     switch (signum) {
  214.         case SIGINT:
  215.             if (program_status != shutting_down) {
  216.                 error(0, "SIGINT received, let's die.");
  217.                 program_status = shutting_down;
  218.                 break;
  219.             }
  220.             break;
  221.     
  222.         case SIGHUP:
  223.             warning(0, "SIGHUP received, catching and re-opening logs");
  224.             log_reopen();
  225.             break;
  226.     
  227.         /* 
  228.          * It would be more proper to use SIGUSR1 for this, but on some
  229.          * platforms that's reserved by the pthread support. 
  230.          */
  231.         case SIGQUIT:
  232.             warning(0, "SIGQUIT received, reporting memory usage.");
  233.             gw_check_leaks();
  234.             break;
  235.         }
  236. }
  237. static void setup_signal_handlers(void) 
  238. {
  239.     struct sigaction act;
  240.     
  241.     act.sa_handler = signal_handler;
  242.     sigemptyset(&act.sa_mask);
  243.     act.sa_flags = 0;
  244.     sigaction(SIGINT, &act, NULL);
  245.     sigaction(SIGQUIT, &act, NULL);
  246.     sigaction(SIGHUP, &act, NULL);
  247.     sigaction(SIGPIPE, &act, NULL);
  248. }
  249. /*
  250.  * We create wdp_datagram for IP traffic and sms for SMS traffic. 
  251.  */
  252. static Msg *pack_ip_datagram(WAPEvent *dgram)
  253. {
  254.     Msg *msg;
  255.     WAPAddrTuple *tuple;
  256.     msg = msg_create(wdp_datagram);
  257.     tuple = dgram->u.T_DUnitdata_Req.addr_tuple;
  258.     msg->wdp_datagram.source_address =
  259.         octstr_duplicate(tuple->local->address);
  260.     msg->wdp_datagram.source_port =
  261.         dgram->u.T_DUnitdata_Req.addr_tuple->local->port;
  262.     msg->wdp_datagram.destination_address =
  263.         octstr_duplicate(tuple->remote->address);
  264.     msg->wdp_datagram.destination_port =
  265.         dgram->u.T_DUnitdata_Req.addr_tuple->remote->port;
  266.     msg->wdp_datagram.user_data =
  267.         octstr_duplicate(dgram->u.T_DUnitdata_Req.user_data);
  268.    return msg;
  269. }
  270. /*
  271.  * Format for port UDH is defined in wdp, appendix A. It is %06%05%04
  272.  * %dest port high hex%dest port low%hex source port high hex%source port low
  273.  * hex. (Unsecure) push client port itself is 2948.
  274.  */
  275. static Octstr *pack_udhdata(WAPAddrTuple *tuple)
  276. {
  277.     int source_port,
  278.         dest_port;
  279.     Octstr *udh;
  280.     
  281.     source_port = tuple->local->port;
  282.     dest_port = tuple->remote->port;  
  283.     
  284.     udh = octstr_create("");
  285.     octstr_format_append(udh, "%c", 6);
  286.     octstr_format_append(udh, "%c", 5);
  287.     octstr_format_append(udh, "%c", 4);
  288.     octstr_format_append(udh, "%c", (dest_port >> 8) & 0xff);
  289.     octstr_format_append(udh, "%c", dest_port & 0xff);
  290.     octstr_format_append(udh, "%c", (source_port >> 8) & 0xff);
  291.     octstr_format_append(udh, "%c", source_port & 0xff);
  292.     return udh;
  293. }
  294. /*
  295.  * We send a normal 8-bit unconcatenated unicode message with an udh. Caller 
  296.  * must do segmentation before calling this function.
  297.  */
  298. static Msg *pack_sms_datagram(WAPEvent *dgram)
  299. {
  300.     Msg *msg;
  301.     WAPAddrTuple *tuple;
  302.     msg = msg_create(sms);
  303.     tuple = dgram->u.T_DUnitdata_Req.addr_tuple;
  304.     msg->sms.sender = octstr_duplicate(tuple->local->address);
  305.     msg->sms.receiver = octstr_duplicate(tuple->remote->address);
  306.     msg->sms.udhdata = pack_udhdata(tuple);
  307.     msg->sms.msgdata = octstr_duplicate(dgram->u.T_DUnitdata_Req.user_data);
  308.     msg->sms.time = time(NULL);
  309.     msg->sms.smsc_id = NULL;
  310.     msg->sms.sms_type = mt_push;
  311.     msg->sms.mwi = MWI_UNDEF;
  312.     msg->sms.coding = DC_8BIT;
  313.     msg->sms.mclass = MC_UNDEF;
  314.     msg->sms.validity = 0;
  315.     msg->sms.deferred = 0;
  316.     
  317.     return msg;   
  318. }
  319. /*
  320.  * Possible address types
  321.  */
  322. enum {
  323.     ADDR_IPV4 = 0,
  324.     ADDR_PLMN = 1,
  325.     ADDR_USER = 2,
  326.     ADDR_IPV6 = 3,
  327.     ADDR_WINA = 4
  328. };
  329. /*
  330.  * Send IP datagram as it is, segment SMS datagram if necessary.
  331.  */
  332. static void dispatch_datagram(WAPEvent *dgram)
  333. {
  334.     Msg *msg,
  335.         *part;
  336.     List *sms_datagrams;
  337.     long max_msgs,
  338.          msg_len;
  339.     static unsigned long msg_sequence = 0L;   /* Used only by this function */
  340.     msg = part = NULL;
  341.     gw_assert(dgram);
  342.     sms_datagrams = NULL;
  343.     if (dgram->type != T_DUnitdata_Req) {
  344.         warning(0, "dispatch_datagram received event of unexpected type.");
  345.         wap_event_dump(dgram);
  346.     } else {
  347.         if (dgram->u.T_DUnitdata_Req.address_type == ADDR_IPV4) {
  348.     msg = pack_ip_datagram(dgram);
  349.             write_to_bearerbox(msg);
  350.         } else {
  351.     msg = pack_sms_datagram(dgram);
  352.             msg_sequence = counter_increase(sequence_counter) & 0xff;
  353.             msg_len = octstr_len(msg->sms.msgdata);
  354.             max_msgs = (msg_len / MAX_SMS_OCTETS) + 1; 
  355.             sms_datagrams = sms_split(msg, NULL, NULL, NULL, NULL, 1, 
  356.                                       msg_sequence, max_msgs, MAX_SMS_OCTETS);
  357.             while ((part = list_extract_first(sms_datagrams)) != NULL)
  358.             write_to_bearerbox(part);
  359.             list_destroy(sms_datagrams, NULL);
  360.             msg_destroy(msg);
  361.         }
  362.     }
  363.     wap_event_destroy(dgram);
  364. }
  365. int main(int argc, char **argv) 
  366. {
  367.     int cf_index;
  368.     Msg *msg;
  369.     Octstr *filename;
  370.     Cfg *cfg;
  371.     double heartbeat_freq =  DEFAULT_HEARTBEAT;
  372.     
  373.     gwlib_init();
  374.     cf_index = get_and_set_debugs(argc, argv, NULL);
  375.     
  376.     setup_signal_handlers();
  377.     
  378.     if (argv[cf_index] == NULL)
  379.         filename = octstr_create("kannel.conf");
  380.     else
  381.         filename = octstr_create(argv[cf_index]);
  382.     cfg = cfg_create(filename);
  383.     if (cfg_read(cfg) == -1)
  384.         panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(filename));
  385.     octstr_destroy(filename);
  386.     
  387.     report_versions("wapbox");
  388.     cfg = init_wapbox(cfg);
  389.     info(0, "------------------------------------------------------------");
  390.     info(0, GW_NAME " wapbox version %s starting up.", VERSION);
  391.     
  392.     sequence_counter = counter_create();
  393.     wsp_session_init(&wtp_resp_dispatch_event,
  394.                      &wtp_initiator_dispatch_event,
  395.                      &wap_appl_dispatch,
  396.                      &wap_push_ppg_dispatch_event);
  397.     wsp_unit_init(&dispatch_datagram, &wap_appl_dispatch);
  398.     wsp_push_client_init(&wsp_push_client_dispatch_event, 
  399.                          &wtp_resp_dispatch_event);
  400.     
  401.     if (cfg)
  402.         wtp_initiator_init(&dispatch_datagram, &wsp_session_dispatch_event);
  403.     wtp_resp_init(&dispatch_datagram, &wsp_session_dispatch_event,
  404.                   &wsp_push_client_dispatch_event);
  405.     wap_appl_init(cfg);
  406. #if (HAVE_WTLS_OPENSSL)
  407.     wtls_secmgr_init();
  408.     wtls_init();
  409. #endif
  410.     
  411.     if (cfg) {
  412.         wap_push_ota_init(&wsp_session_dispatch_event, 
  413.                           &wsp_unit_dispatch_event);
  414.         wap_push_ppg_init(&wap_push_ota_dispatch_event, &wap_appl_dispatch, 
  415.                           cfg);
  416.     }
  417.     wml_init();
  418.     
  419.     if (bearerbox_host == NULL)
  420.      bearerbox_host = octstr_create(BB_DEFAULT_HOST);
  421.     connect_to_bearerbox(bearerbox_host, bearerbox_port, bearerbox_ssl, NULL
  422.     /* bearerbox_our_port */);
  423.     if (cfg)
  424.         wap_push_ota_bb_address_set(bearerbox_host);
  425.     
  426.     program_status = running;
  427.     if (0 > heartbeat_start(write_to_bearerbox, heartbeat_freq, 
  428.                            wap_appl_get_load)) {
  429.         info(0, GW_NAME "Could not start heartbeat.");
  430.     }
  431.     while (program_status != shutting_down) {
  432. WAPEvent *dgram;
  433. msg = read_from_bearerbox();
  434. if (msg == NULL)
  435.     break;
  436. if (msg_type(msg) == admin) {
  437.     if (msg->admin.command == cmd_shutdown) {
  438. info(0, "Bearerbox told us to die");
  439. program_status = shutting_down;
  440.     }
  441.     /*
  442.      * XXXX here should be suspend/resume, add RSN
  443.      */
  444. } else if (msg_type(msg) == wdp_datagram) {
  445.         switch (msg->wdp_datagram.destination_port) {
  446.         case CONNECTIONLESS_PORT:
  447.         case CONNECTION_ORIENTED_PORT:
  448.      dgram = wap_event_create(T_DUnitdata_Ind);
  449.      dgram->u.T_DUnitdata_Ind.addr_tuple = wap_addr_tuple_create(
  450. msg->wdp_datagram.source_address,
  451. msg->wdp_datagram.source_port,
  452. msg->wdp_datagram.destination_address,
  453. msg->wdp_datagram.destination_port);
  454.      dgram->u.T_DUnitdata_Ind.user_data = msg->wdp_datagram.user_data;
  455.      msg->wdp_datagram.user_data = NULL;
  456.            wap_dispatch_datagram(dgram); 
  457. break;
  458.         case WTLS_CONNECTIONLESS_PORT:
  459.         case WTLS_CONNECTION_ORIENTED_PORT:
  460. #if (HAVE_WTLS_OPENSSL)
  461.             dgram = wtls_unpack_wdp_datagram(msg);
  462.             if (dgram != NULL)
  463.                 wtls_dispatch_event(dgram);
  464. #endif
  465. break;
  466.         default:
  467.                 panic(0,"Bad packet received! This shouldn't happen!");
  468.                 break;
  469.         } 
  470. } else {
  471.     warning(0, "Received other message than wdp/admin, ignoring!");
  472. }
  473. msg_destroy(msg);
  474.     }
  475.     info(0, GW_NAME " wapbox terminating.");
  476.     
  477.     program_status = shutting_down;
  478.     heartbeat_stop(ALL_HEARTBEATS);
  479.     counter_destroy(sequence_counter);
  480.     if (cfg)
  481.         wtp_initiator_shutdown();
  482.     wtp_resp_shutdown();
  483.     wsp_push_client_shutdown();
  484.     wsp_unit_shutdown();
  485.     wsp_session_shutdown();
  486.     wap_appl_shutdown();
  487.     if (cfg) {
  488.         wap_push_ota_shutdown();
  489.         wap_push_ppg_shutdown();
  490.     }
  491.     wml_shutdown();
  492.     close_connection_to_bearerbox();
  493.     wsp_http_map_destroy();
  494.     octstr_destroy(bearerbox_host);
  495.     gwlib_shutdown();
  496.     return 0;
  497. }