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

bb_udp.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  * bb_udpc.c : bearerbox UDP sender/receiver module
00059  *
00060  * handles start/restart/shutdown/suspend/die operations of the UDP
00061  * WDP interface
00062  *
00063  * Kalle Marjola <rpr@wapit.com> 2000 for project Kannel
00064  */
00065 
00066 #include <errno.h>
00067 #include <stdlib.h>
00068 #include <stdio.h>
00069 #include <time.h>
00070 #include <string.h>
00071 #include <sys/time.h>
00072 #include <sys/types.h>
00073 #include <unistd.h>
00074 #include <signal.h>
00075 #include <fcntl.h>
00076 #include <assert.h>
00077 
00078 #include "gwlib/gwlib.h"
00079 #include "msg.h"
00080 #include "bearerbox.h"
00081 
00082 /* passed from bearerbox core */
00083 
00084 extern volatile sig_atomic_t bb_status;
00085 extern List *incoming_wdp;
00086 
00087 extern Counter *incoming_wdp_counter;
00088 extern Counter *outgoing_wdp_counter;
00089 
00090 extern List *flow_threads;
00091 extern List *suspended;
00092 extern List *isolated;
00093 
00094 /* our own thingies */
00095 
00096 static volatile sig_atomic_t udp_running;
00097 static List *udpc_list;
00098 
00099 
00100 typedef struct _udpc {
00101     int fd;
00102     Octstr *addr;
00103     List *outgoing_list;
00104     long receiver;
00105 } Udpc;
00106 
00107 
00108 /*
00109  * IP numbers which are allowed or denied us of the bearerbox via UDP.
00110  */
00111 static Octstr *allow_ip;
00112 static Octstr *deny_ip;
00113 
00114 
00115 /* forward declarations */
00116 
00117 static void udpc_destroy(Udpc *udpc);
00118 
00119 /*-------------------------------------------------
00120  *  receiver thingies
00121  */
00122 
00123 static void udp_receiver(void *arg)
00124 {
00125     Octstr *datagram, *cliaddr;
00126     int ret;
00127     Msg *msg;
00128     Udpc *conn = arg;
00129     Octstr *ip;
00130 
00131     gwlist_add_producer(incoming_wdp);
00132     gwlist_add_producer(flow_threads);
00133     gwthread_wakeup(MAIN_THREAD_ID);
00134     
00135     /* remove messages from socket until it is closed */
00136     while (bb_status != BB_DEAD && bb_status != BB_SHUTDOWN) {
00137 
00138     gwlist_consume(isolated);   /* block here if suspended/isolated */
00139 
00140     if (read_available(conn->fd, 100000) < 1)
00141         continue;
00142 
00143     ret = udp_recvfrom(conn->fd, &datagram, &cliaddr);
00144     if (ret == -1) {
00145         if (errno == EAGAIN)
00146         /* No datagram available, don't block. */
00147         continue;
00148 
00149         error(errno, "Failed to receive an UDP");
00150         /*
00151          * just continue, or is there ANY error that would result
00152          * in situation where it would be better to break; or even
00153          * die off?     - Kalle 28.2
00154          */
00155         continue;
00156     }
00157 
00158     /* discard the message if the client is not allowed */
00159         ip = udp_get_ip(cliaddr);
00160     if (!is_allowed_ip(allow_ip, deny_ip, ip)) {
00161             warning(0, "UDP: Discarding packet from %s, IP is denied.",
00162                octstr_get_cstr(ip));
00163             octstr_destroy(datagram);
00164     } else {
00165         debug("bb.udp", 0, "datagram received");
00166         msg = msg_create(wdp_datagram);
00167     
00168         msg->wdp_datagram.source_address = udp_get_ip(cliaddr);
00169         msg->wdp_datagram.source_port    = udp_get_port(cliaddr);
00170         msg->wdp_datagram.destination_address = udp_get_ip(conn->addr);
00171         msg->wdp_datagram.destination_port    = udp_get_port(conn->addr);
00172         msg->wdp_datagram.user_data = datagram;
00173     
00174         gwlist_produce(incoming_wdp, msg);
00175         counter_increase(incoming_wdp_counter);
00176     }
00177 
00178     octstr_destroy(cliaddr);
00179     octstr_destroy(ip);
00180     }    
00181     gwlist_remove_producer(incoming_wdp);
00182     gwlist_remove_producer(flow_threads);
00183 }
00184 
00185 
00186 /*---------------------------------------------
00187  * sender thingies
00188  */
00189 
00190 static int send_udp(int fd, Msg *msg)
00191 {
00192     Octstr *cliaddr;
00193     int ret;
00194 
00195     cliaddr = udp_create_address(msg->wdp_datagram.destination_address,
00196                  msg->wdp_datagram.destination_port);
00197     ret = udp_sendto(fd, msg->wdp_datagram.user_data, cliaddr);
00198     if (ret == -1)
00199     error(0, "WDP/UDP: could not send UDP datagram");
00200     octstr_destroy(cliaddr);
00201     return ret;
00202 }
00203 
00204 
00205 static void udp_sender(void *arg)
00206 {
00207     Msg *msg;
00208     Udpc *conn = arg;
00209 
00210     gwlist_add_producer(flow_threads);
00211     while(bb_status != BB_DEAD) {
00212 
00213     gwlist_consume(suspended);  /* block here if suspended */
00214 
00215     if ((msg = gwlist_consume(conn->outgoing_list)) == NULL)
00216         break;
00217 
00218     debug("bb.udp", 0, "udp: sending message");
00219     
00220         if (send_udp(conn->fd, msg) == -1)
00221         /* ok, we failed... tough
00222          * XXX log the message or something like that... but this
00223          * is not as fatal as it is with SMS-messages...
00224          */ {
00225         msg_destroy(msg);
00226         continue;
00227     }
00228     counter_increase(outgoing_wdp_counter);
00229     msg_destroy(msg);
00230     }
00231     gwthread_join(conn->receiver);
00232 
00233     udpc_destroy(conn);
00234     gwlist_remove_producer(flow_threads);
00235 }
00236 
00237 /*---------------------------------------------------------------
00238  * accept/create thingies
00239  */
00240 
00241 
00242 static Udpc *udpc_create(int port, char *interface_name)
00243 {
00244     Udpc *udpc;
00245     Octstr *os;
00246     int fl;
00247     
00248     udpc = gw_malloc(sizeof(Udpc));
00249     udpc->fd = udp_bind(port, interface_name);
00250 
00251     os = octstr_create(interface_name);
00252     udpc->addr = udp_create_address(os, port);
00253     octstr_destroy(os);
00254     if (udpc->addr == NULL) {
00255     error(0, "updc_create: could not resolve interface <%s>",
00256           interface_name);
00257     close(udpc->fd);
00258     gw_free(udpc);
00259     return NULL;
00260     }
00261 
00262     fl = fcntl(udpc->fd, F_GETFL);
00263     fcntl(udpc->fd, F_SETFL, fl | O_NONBLOCK);
00264 
00265     os = udp_get_ip(udpc->addr);
00266     debug("bb.udp", 0, "udpc_create: Bound to UDP <%s:%d>",
00267       octstr_get_cstr(os), udp_get_port(udpc->addr));
00268 
00269     octstr_destroy(os);
00270     
00271     udpc->outgoing_list = gwlist_create();
00272 
00273     return udpc;
00274 }    
00275 
00276 
00277 static void udpc_destroy(Udpc *udpc)
00278 {
00279     if (udpc == NULL)
00280     return;
00281 
00282     if (udpc->fd >= 0)
00283     close(udpc->fd);
00284     octstr_destroy(udpc->addr);
00285     gw_assert(gwlist_len(udpc->outgoing_list) == 0);
00286     gwlist_destroy(udpc->outgoing_list, NULL);
00287 
00288     gw_free(udpc);
00289 }    
00290 
00291 
00292 static int add_service(int port, char *interface_name)
00293 {
00294     Udpc *udpc;
00295     
00296     if ((udpc = udpc_create(port, interface_name)) == NULL)
00297     goto error;
00298     gwlist_add_producer(udpc->outgoing_list);
00299 
00300     udpc->receiver = gwthread_create(udp_receiver, udpc);
00301     if (udpc->receiver == -1)
00302     goto error;
00303 
00304     if (gwthread_create(udp_sender, udpc) == -1)
00305     goto error;
00306 
00307     gwlist_append(udpc_list, udpc);
00308     return 0;
00309     
00310 error:    
00311     error(0, "Failed to start UDP receiver/sender thread");
00312     udpc_destroy(udpc);
00313     return -1;
00314 }
00315 
00316 
00317 
00318 /*-------------------------------------------------------------
00319  * public functions
00320  *
00321  */
00322 
00323 int udp_start(Cfg *cfg)
00324 {
00325     CfgGroup *grp;
00326     Octstr *iface;
00327     List *ifs;
00328     int allow_wtls;
00329     
00330     if (udp_running) return -1;
00331     
00332     debug("bb.udp", 0, "starting UDP sender/receiver module");
00333 
00334     grp = cfg_get_single_group(cfg, octstr_imm("core"));
00335     iface = cfg_get(grp, octstr_imm("wdp-interface-name"));
00336     if (iface == NULL) {
00337         error(0, "Missing wdp-interface-name variable, cannot start UDP");
00338         return -1;
00339     }
00340 
00341     allow_ip = cfg_get(grp, octstr_imm("udp-allow-ip"));
00342     deny_ip = cfg_get(grp, octstr_imm("udp-deny-ip"));
00343 
00344     /*  we'll activate WTLS as soon as we have a 'wtls' config group */
00345     grp = cfg_get_single_group(cfg, octstr_imm("wtls"));
00346     allow_wtls = grp != NULL ? 1 : 0;
00347 
00348     udpc_list = gwlist_create();    /* have a list of running systems */
00349 
00350     ifs = octstr_split(iface, octstr_imm(";"));
00351     octstr_destroy(iface);
00352     while (gwlist_len(ifs) > 0) {
00353         iface = gwlist_extract_first(ifs);
00354     info(0, "Adding interface %s", octstr_get_cstr(iface));
00355         add_service(9200, octstr_get_cstr(iface));   /* wsp     */
00356         add_service(9201, octstr_get_cstr(iface));   /* wsp/wtp */
00357     
00358 #ifdef HAVE_WTLS_OPENSSL
00359         if (allow_wtls) {
00360              add_service(9202, octstr_get_cstr(iface));   /* wsp/wtls   */
00361              add_service(9203, octstr_get_cstr(iface));   /* wsp/wtp/wtls */
00362         }
00363 #else
00364         if (allow_wtls)
00365              error(0, "These is a 'wtls' group in configuration, but no WTLS support compiled in!");
00366 #endif
00367     /* add_service(9204, octstr_get_cstr(interface_name));  * vcard */
00368     /* add_service(9205, octstr_get_cstr(interface_name));  * vcal  */
00369     /* add_service(9206, octstr_get_cstr(interface_name));  * vcard/wtls */
00370     /* add_service(9207, octstr_get_cstr(interface_name));  * vcal/wtls */
00371         octstr_destroy(iface);
00372     }
00373     gwlist_destroy(ifs, NULL);
00374     
00375     gwlist_add_producer(incoming_wdp);
00376     udp_running = 1;
00377     return 0;
00378 }
00379 
00380 
00381 /*
00382  * this function receives an WDP message and adds it to
00383  * corresponding outgoing_list.
00384  */
00385 int udp_addwdp(Msg *msg)
00386 {
00387     int i;
00388     Udpc *udpc, *def_udpc;
00389     Octstr *ip;
00390     
00391     def_udpc = NULL;
00392     if (!udp_running) return -1;
00393     assert(msg != NULL);
00394     assert(msg_type(msg) == wdp_datagram);
00395     
00396     gwlist_lock(udpc_list);
00397     /* select in which list to add this */
00398     for (i=0; i < gwlist_len(udpc_list); i++) {
00399         udpc = gwlist_get(udpc_list, i);
00400 
00401         if (msg->wdp_datagram.source_port == udp_get_port(udpc->addr)) {
00402                     def_udpc = udpc;
00403                     ip = udp_get_ip(udpc->addr);
00404             if (octstr_compare(msg->wdp_datagram.source_address, ip) == 0) {
00405                         octstr_destroy(ip);
00406                 gwlist_produce(udpc->outgoing_list, msg);
00407                 gwlist_unlock(udpc_list);
00408                 return 0;
00409             }
00410                     octstr_destroy(ip);
00411         }
00412     }
00413 
00414     if (NULL != def_udpc) {
00415     gwlist_produce(def_udpc->outgoing_list, msg);
00416     gwlist_unlock(udpc_list);
00417     return 0;
00418     }
00419 
00420     gwlist_unlock(udpc_list);
00421     return -1;
00422 }
00423 
00424 int udp_shutdown(void)
00425 {
00426     if (!udp_running) return -1;
00427 
00428     debug("bb.thread", 0, "udp_shutdown: Starting avalanche");
00429     gwlist_remove_producer(incoming_wdp);
00430     return 0;
00431 }
00432 
00433 
00434 int udp_die(void)
00435 {
00436     Udpc *udpc;
00437 
00438     if (!udp_running) return -1;
00439     
00440     /*
00441      * remove producers from all outgoing lists.
00442      */
00443     debug("bb.udp", 0, "udp_die: removing producers from udp-lists");
00444 
00445     while((udpc = gwlist_consume(udpc_list)) != NULL) {
00446     gwlist_remove_producer(udpc->outgoing_list);
00447     }
00448     gwlist_destroy(udpc_list, NULL);
00449     udp_running = 0;
00450     
00451     octstr_destroy(allow_ip);
00452     octstr_destroy(deny_ip);
00453     allow_ip = NULL;
00454     deny_ip = NULL;
00455     
00456     return 0;
00457 }
00458 
00459 
00460 int udp_outgoing_queue(void)
00461 {
00462     int i, q = 0;
00463     Udpc *udpc;
00464 
00465     if (!udp_running || udpc_list == NULL)
00466     return 0;
00467 
00468     gwlist_lock(udpc_list);
00469     for (i=0; i < gwlist_len(udpc_list); i++) {
00470     udpc = gwlist_get(udpc_list, i);
00471     q += gwlist_len(udpc->outgoing_list);
00472     }
00473     gwlist_unlock(udpc_list);
00474     return q;
00475 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.