mi_datagram.c

Go to the documentation of this file.
00001 /*
00002  * $Id: mi_datagram.c 1133 2007-04-02 17:31:13Z ancuta_onofrei $
00003  *
00004  * Copyright (C) 2007 Voice Sistem SRL
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00021  *
00022  *
00023  * History:
00024  * ---------
00025  *  2007-06-25  first version (ancuta)
00026  */
00027 
00028 /*!
00029  * \file
00030  * \brief MI_DATAGRAM :: Unix socket and network socket (UDP) API for the Kamailio manager interface
00031  * \ingroup mi
00032  */
00033 
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <sys/stat.h>
00037 #include <sys/types.h>
00038 #include <unistd.h>
00039 #include <errno.h>
00040 #include <signal.h>
00041 #include <sys/socket.h>
00042 #include <netinet/in.h>
00043 #include <arpa/inet.h>
00044 #include <stdarg.h>
00045 #include <time.h>
00046 #include <stdio.h>
00047 #include <fcntl.h>
00048 
00049 
00050 #include "../../sr_module.h"
00051 #include "../../resolve.h"
00052 #include "../../dprint.h"
00053 #include "../../ut.h"
00054 #include "../../mem/mem.h"
00055 #include "../../mem/shm_mem.h"
00056 #include "../../mi/mi.h"
00057 #include "../../ip_addr.h"
00058 #include "mi_datagram.h"
00059 #include "datagram_fnc.h"
00060 #include "mi_datagram_parser.h"
00061 #include "mi_datagram_writer.h"
00062 
00063 
00064 /* AF_LOCAL is not defined on solaris */
00065 
00066 #if !defined(AF_LOCAL)
00067 #define AF_LOCAL AF_UNIX
00068 #endif
00069 #if !defined(PF_LOCAL)
00070 #define PF_LOCAL PF_UNIX
00071 #endif
00072 
00073 
00074 #define MAX_CTIME_LEN     128
00075 #define MAX_NB_PORT    65535
00076 
00077 static int mi_mod_init(void);
00078 static int mi_child_init(int rank);
00079 static int mi_destroy(void);
00080 static int pre_datagram_process(void);
00081 static int post_datagram_process(void);
00082 static void datagram_process(int rank);
00083 
00084 /* local variables */
00085 static int mi_socket_domain =  AF_LOCAL;
00086 static sockaddr_dtgram mi_dtgram_addr;
00087 
00088 /* socket definition parameter */
00089 static char *mi_socket = 0;
00090 int mi_socket_timeout = 2000;
00091 static rx_tx_sockets sockets;
00092 
00093 /* unixsock specific parameters */
00094 static int  mi_unix_socket_uid = -1;
00095 static char *mi_unix_socket_uid_s = 0;
00096 static int  mi_unix_socket_gid = -1;
00097 static char *mi_unix_socket_gid_s = 0;
00098 static int mi_unix_socket_mode = S_IRUSR| S_IWUSR| S_IRGRP| S_IWGRP;
00099 
00100 /* mi specific parameters */
00101 static char *mi_reply_indent = DEFAULT_MI_REPLY_IDENT;
00102 
00103 
00104 
00105 MODULE_VERSION
00106 
00107 
00108 static proc_export_t mi_procs[] = {
00109    {"MI Datagram",  pre_datagram_process,  post_datagram_process,
00110          datagram_process, MI_CHILD_NO },
00111    {0,0,0,0,0}
00112 };
00113 
00114 
00115 static param_export_t mi_params[] = {
00116    {"children_count",      INT_PARAM,    &mi_procs[0].no           },
00117    {"socket_name",         STR_PARAM,    &mi_socket                },
00118    {"socket_timeout",      INT_PARAM,    &mi_socket_timeout        },
00119    {"unix_socket_mode",    INT_PARAM,    &mi_unix_socket_mode      },
00120    {"unix_socket_group",   STR_PARAM,    &mi_unix_socket_gid_s     },
00121    {"unix_socket_group",   INT_PARAM,    &mi_unix_socket_gid       },
00122    {"unix_socket_user",    STR_PARAM,    &mi_unix_socket_uid_s     },
00123    {"unix_socket_user",    INT_PARAM,    &mi_unix_socket_uid       },
00124    {"reply_indent",        STR_PARAM,    &mi_reply_indent          },
00125    {0,0,0}
00126 };
00127 
00128 
00129 struct module_exports exports = {
00130    "mi_datagram",                 /* module name */
00131    DEFAULT_DLFLAGS,               /* dlopen flags */
00132    0,                             /* exported functions */
00133    mi_params,                     /* exported parameters */
00134    0,                             /* exported statistics */
00135    0,                             /* exported MI functions */
00136    0,                             /* exported pseudo-variables */
00137    mi_procs,                      /* extra processes */
00138    mi_mod_init,                   /* module initialization function */
00139    0,                             /* response handling function */
00140    (destroy_function) mi_destroy, /* destroy function */
00141    mi_child_init                  /* per-child init function */
00142 };
00143 
00144 
00145 static int mi_mod_init(void)
00146 {
00147    unsigned int port_no;
00148    int n;
00149    struct stat filestat;
00150    struct hostent * host;
00151    char *p, *host_s;
00152    str port_str;
00153 
00154    /* checking the mi_socket module param */
00155    LM_DBG("testing socket existance...\n");
00156 
00157    if( mi_socket==NULL || *mi_socket == 0) {
00158       LM_ERR("no DATAGRAM_ socket configured\n");
00159       return -1;
00160    }
00161 
00162    LM_DBG("the socket's name/addres is %s\n", mi_socket);
00163 
00164    memset( &mi_dtgram_addr, 0, sizeof(mi_dtgram_addr) );
00165 
00166    if(strncmp(mi_socket, "udp:",4) == 0)
00167    {
00168       /*for an UDP socket*/
00169       LM_DBG("we have an udp socket\n");
00170       /*separate proto and host */
00171       p = mi_socket+4;
00172       if( (*(p)) == '\0') {
00173          LM_ERR("malformed ip address\n");
00174          return -1;
00175       }
00176       host_s=p;
00177       LM_DBG("the remaining address after separating the protocol is %s\n",p);
00178 
00179       if( (p = strrchr(p+1, ':')) == 0 ) {
00180          LM_ERR("no port specified\n");
00181          return -1;
00182       }
00183 
00184       /*the address contains a port number*/
00185       *p = '\0';
00186       p++;
00187       port_str.s = p;
00188       port_str.len = strlen(p);
00189       LM_DBG("the port string is %s\n", p);
00190       if(str2int(&port_str, &port_no) != 0 ) {
00191          LM_ERR("there is not a valid number port\n");
00192          return -1;
00193       }
00194       *p = '\0';
00195       if (port_no<1024  || port_no>MAX_NB_PORT)
00196       {
00197          LM_ERR("invalid port number; must be in [1024,%d]\n",MAX_NB_PORT);
00198          return -1;
00199       }
00200       
00201       if(! (host = resolvehost(host_s, 0)) ) {
00202          LM_ERR("failed to resolve %s\n", host_s);
00203          return -1;
00204       }
00205       LM_DBG("the ip is %s\n",host_s);
00206       if(hostent2su( &(mi_dtgram_addr.udp_addr), host, 0, port_no ) !=0){
00207          LM_ERR("failed to resolve %s\n", mi_socket);
00208          return -1;
00209       }
00210       mi_socket_domain = host->h_addrtype;
00211       return 0;
00212    } 
00213    /* in case of a Unix socket*/
00214    LM_DBG("we have an UNIX socket\n");
00215       
00216    n=stat(mi_socket, &filestat);
00217    if( n==0) {
00218       LM_INFO("the socket %s already exists, trying to delete it...\n", mi_socket);
00219       if (unlink(mi_socket)<0) {
00220          LM_ERR("cannot delete old socket: %s\n", strerror(errno));
00221          return -1;
00222       }
00223    } else if (n<0 && errno!=ENOENT) {
00224       LM_ERR("socket stat failed:%s\n", strerror(errno));
00225       return -1;
00226    }
00227 
00228    /* check mi_unix_socket_mode */
00229    if(!mi_unix_socket_mode) {
00230       LM_WARN("cannot specify mi_unix_socket_mode = 0, forcing it to rw-------\n");
00231       mi_unix_socket_mode = S_IRUSR| S_IWUSR;
00232    }
00233    
00234    if (mi_unix_socket_uid_s) {
00235       if (user2uid(&mi_unix_socket_uid, &mi_unix_socket_gid, mi_unix_socket_uid_s)<0) {
00236          LM_ERR("bad user name %s\n", mi_unix_socket_uid_s);
00237          return -1;
00238       }
00239    }
00240    
00241    if (mi_unix_socket_gid_s) {
00242       if (group2gid(&mi_unix_socket_gid, mi_unix_socket_gid_s)<0) {
00243          LM_ERR("bad group name %s\n", mi_unix_socket_gid_s);
00244          return -1;
00245       }
00246    }
00247 
00248    /*create the unix socket address*/
00249    mi_dtgram_addr.unix_addr.sun_family = AF_LOCAL;
00250    memcpy( mi_dtgram_addr.unix_addr.sun_path, mi_socket, strlen(mi_socket));
00251 
00252    return 0;
00253 }
00254 
00255 
00256 static int mi_child_init(int rank)
00257 {
00258    if (rank==PROC_TIMER || rank>0 ) {
00259       if(mi_datagram_writer_init( DATAGRAM_SOCK_BUF_SIZE , mi_reply_indent )!= 0) {
00260          LM_CRIT("failed to initiate mi_datagram_writer\n");
00261          return -1;
00262       }
00263    }
00264    return 0;
00265 }
00266 
00267 
00268 static int pre_datagram_process(void)
00269 {
00270    int res;
00271 
00272    /*create the sockets*/
00273    res = mi_init_datagram_server(&mi_dtgram_addr, mi_socket_domain, &sockets,
00274                mi_unix_socket_mode, mi_unix_socket_uid, mi_unix_socket_gid);
00275 
00276    if ( res ) {
00277       LM_CRIT("function mi_init_datagram_server returned with error!!!\n");
00278       return -1;
00279    }
00280 
00281    return 0;
00282 }
00283 
00284 
00285 static void datagram_process(int rank)
00286 {
00287    LM_INFO("a new child %d/%d\n", rank, getpid());
00288 
00289    /*child's initial settings*/
00290    if ( init_mi_child()!=0) {
00291       LM_CRIT("failed to init the mi process\n");
00292       exit(-1);
00293    }
00294    if (mi_init_datagram_buffer()!=0) {
00295       LM_ERR("failed to allocate datagram buffer\n");
00296       exit(-1);
00297    }
00298 
00299    if (mi_datagram_writer_init( DATAGRAM_SOCK_BUF_SIZE , mi_reply_indent )!= 0) {
00300       LM_CRIT("failed to initiate mi_datagram_writer\n");
00301       exit(-1);
00302    }
00303 
00304    mi_datagram_server(sockets.rx_sock, sockets.tx_sock);
00305 
00306    exit(-1);
00307 }
00308 
00309 
00310 static int post_datagram_process(void)
00311 {
00312    /* close the sockets */
00313    close(sockets.rx_sock);
00314    close(sockets.tx_sock);
00315    return 0;
00316 }
00317 
00318 
00319 static int mi_destroy(void)
00320 {
00321    int n;
00322    struct stat filestat;
00323 
00324    /* destroying the socket descriptors */
00325    if(mi_socket_domain == AF_UNIX) {
00326       n=stat(mi_socket, &filestat);
00327       if (n==0) {
00328          if (unlink(mi_socket)<0){
00329             LM_ERR("cannot delete the socket (%s): %s\n", 
00330                   mi_socket, strerror(errno));
00331             goto error;
00332          }
00333       } else if (n<0 && errno!=ENOENT) {
00334          LM_ERR("socket stat failed: %s\n", strerror(errno));
00335          goto error;
00336       }
00337    }
00338 
00339    return 0;
00340 error:
00341    return -1;
00342 
00343 }

Generated on Wed May 23 20:00:27 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6