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 
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 "../../lib/kmi/mi.h"
00057 #include "../../ip_addr.h"
00058 #include "../../pt.h"
00059 #include "../../globals.h"
00060 #include "../../cfg/cfg_struct.h"
00061 #include "mi_datagram.h"
00062 #include "datagram_fnc.h"
00063 #include "mi_datagram_parser.h"
00064 #include "mi_datagram_writer.h"
00065 
00066 
00067 /* AF_LOCAL is not defined on solaris */
00068 
00069 #if !defined(AF_LOCAL)
00070 #define AF_LOCAL AF_UNIX
00071 #endif
00072 #if !defined(PF_LOCAL)
00073 #define PF_LOCAL PF_UNIX
00074 #endif
00075 
00076 
00077 #define MAX_CTIME_LEN     128
00078 #define MAX_NB_PORT       65535
00079 
00080 static int mi_mod_init(void);
00081 static int mi_child_init(int rank);
00082 static int mi_destroy(void);
00083 static int pre_datagram_process(void);
00084 static int post_datagram_process(void);
00085 static void datagram_process(int rank);
00086 
00087 /* local variables */
00088 static int mi_socket_domain =  AF_LOCAL;
00089 static sockaddr_dtgram mi_dtgram_addr;
00090 
00091 /* socket definition parameter */
00092 static char *mi_socket = 0;
00093 int mi_socket_timeout = 2000;
00094 static rx_tx_sockets sockets;
00095 
00096 /* unixsock specific parameters */
00097 static int  mi_unix_socket_uid = -1;
00098 static char *mi_unix_socket_uid_s = 0;
00099 static int  mi_unix_socket_gid = -1;
00100 static char *mi_unix_socket_gid_s = 0;
00101 static int mi_unix_socket_mode = S_IRUSR| S_IWUSR| S_IRGRP| S_IWGRP;
00102 
00103 /* mi specific parameters */
00104 static char *mi_reply_indent = DEFAULT_MI_REPLY_IDENT;
00105 
00106 
00107 
00108 MODULE_VERSION
00109 
00110 
00111 static proc_export_t mi_procs[] = {
00112         {"MI Datagram",  pre_datagram_process,  post_datagram_process,
00113                         datagram_process, MI_CHILD_NO },
00114         {0,0,0,0,0}
00115 };
00116 
00117 
00118 static param_export_t mi_params[] = {
00119         {"children_count",      INT_PARAM,    &mi_procs[0].no           },
00120         {"socket_name",         STR_PARAM,    &mi_socket                },
00121         {"socket_timeout",      INT_PARAM,    &mi_socket_timeout        },
00122         {"unix_socket_mode",    INT_PARAM,    &mi_unix_socket_mode      },
00123         {"unix_socket_group",   STR_PARAM,    &mi_unix_socket_gid_s     },
00124         {"unix_socket_group",   INT_PARAM,    &mi_unix_socket_gid       },
00125         {"unix_socket_user",    STR_PARAM,    &mi_unix_socket_uid_s     },
00126         {"unix_socket_user",    INT_PARAM,    &mi_unix_socket_uid       },
00127         {"reply_indent",        STR_PARAM,    &mi_reply_indent          },
00128         {0,0,0}
00129 };
00130 
00131 
00132 struct module_exports exports = {
00133         "mi_datagram",                 /* module name */
00134         DEFAULT_DLFLAGS,               /* dlopen flags */
00135         0,                             /* exported functions */
00136         mi_params,                     /* exported parameters */
00137         0,                             /* exported statistics */
00138         0,                             /* exported MI functions */
00139         0,                             /* exported pseudo-variables */
00140         mi_procs,                      /* extra processes */
00141         mi_mod_init,                   /* module initialization function */
00142         0,                             /* response handling function */
00143         (destroy_function) mi_destroy, /* destroy function */
00144         mi_child_init                  /* per-child init function */
00145 };
00146 
00147 
00148 static int mi_mod_init(void)
00149 {
00150         unsigned int port_no;
00151         int n;
00152         struct stat filestat;
00153         struct hostent * host;
00154         char *p, *host_s;
00155         str port_str;
00156 
00157         /* checking the mi_socket module param */
00158         LM_DBG("testing socket existance...\n");
00159 
00160         if( mi_socket==NULL || *mi_socket == 0) {
00161                 LM_ERR("no DATAGRAM_ socket configured\n");
00162                 return -1;
00163         }
00164 
00165         LM_DBG("the socket's name/addres is %s\n", mi_socket);
00166 
00167         memset( &mi_dtgram_addr, 0, sizeof(mi_dtgram_addr) );
00168 
00169         if(strncmp(mi_socket, "udp:",4) == 0)
00170         {
00171                 /*for an UDP socket*/
00172                 LM_DBG("we have an udp socket\n");
00173                 /*separate proto and host */
00174                 p = mi_socket+4;
00175                 if( (*(p)) == '\0') {
00176                         LM_ERR("malformed ip address\n");
00177                         return -1;
00178                 }
00179                 host_s=p;
00180                 LM_DBG("the remaining address after separating the protocol is %s\n",p);
00181 
00182                 if( (p = strrchr(p+1, ':')) == 0 ) {
00183                         LM_ERR("no port specified\n");
00184                         return -1;
00185                 }
00186 
00187                 /*the address contains a port number*/
00188                 *p = '\0';
00189                 p++;
00190                 port_str.s = p;
00191                 port_str.len = strlen(p);
00192                 LM_DBG("the port string is %s\n", p);
00193                 if(str2int(&port_str, &port_no) != 0 ) {
00194                         LM_ERR("there is not a valid number port\n");
00195                         return -1;
00196                 }
00197                 *p = '\0';
00198                 if (port_no<1024  || port_no>MAX_NB_PORT)
00199                 {
00200                         LM_ERR("invalid port number; must be in [1024,%d]\n",MAX_NB_PORT);
00201                         return -1;
00202                 }
00203                 
00204                 if(! (host = resolvehost(host_s)) ) {
00205                         LM_ERR("failed to resolve %s\n", host_s);
00206                         return -1;
00207                 }
00208                 LM_DBG("the ip is %s\n",host_s);
00209                 if(hostent2su( &(mi_dtgram_addr.udp_addr), host, 0, port_no ) !=0){
00210                         LM_ERR("failed to resolve %s\n", mi_socket);
00211                         return -1;
00212                 }
00213                 mi_socket_domain = host->h_addrtype;
00214                 goto done;
00215         } 
00216         /* in case of a Unix socket*/
00217         LM_DBG("we have an UNIX socket\n");
00218                 
00219         n=stat(mi_socket, &filestat);
00220         if( n==0) {
00221                 LM_INFO("the socket %s already exists, trying to delete it...\n", mi_socket);
00222                 if(config_check==0) {
00223                         if (unlink(mi_socket)<0) {
00224                                 LM_ERR("cannot delete old socket: %s\n", strerror(errno));
00225                                 return -1;
00226                         }
00227                 }
00228         } else if (n<0 && errno!=ENOENT) {
00229                 LM_ERR("socket stat failed:%s\n", strerror(errno));
00230                 return -1;
00231         }
00232 
00233         /* check mi_unix_socket_mode */
00234         if(!mi_unix_socket_mode) {
00235                 LM_WARN("cannot specify mi_unix_socket_mode = 0, forcing it to rw-------\n");
00236                 mi_unix_socket_mode = S_IRUSR| S_IWUSR;
00237         }
00238         
00239         if (mi_unix_socket_uid_s) {
00240                 if (user2uid(&mi_unix_socket_uid, &mi_unix_socket_gid, mi_unix_socket_uid_s)<0) {
00241                         LM_ERR("bad user name %s\n", mi_unix_socket_uid_s);
00242                         return -1;
00243                 }
00244         }
00245         
00246         if (mi_unix_socket_gid_s) {
00247                 if (group2gid(&mi_unix_socket_gid, mi_unix_socket_gid_s)<0) {
00248                         LM_ERR("bad group name %s\n", mi_unix_socket_gid_s);
00249                         return -1;
00250                 }
00251         }
00252 
00253         /*create the unix socket address*/
00254         mi_dtgram_addr.unix_addr.sun_family = AF_LOCAL;
00255         memcpy( mi_dtgram_addr.unix_addr.sun_path, mi_socket, strlen(mi_socket));
00256 
00257 done:
00258         /* add space for extra processes */
00259         register_procs(mi_procs[0].no);
00260         /* add child to update local config framework structures */
00261         cfg_register_child(mi_procs[0].no);
00262 
00263         return 0;
00264 }
00265 
00266 
00267 static int mi_child_init(int rank)
00268 {
00269         int i;
00270         int pid;
00271 
00272         if (rank==PROC_TIMER || rank>0 ) {
00273                 if(mi_datagram_writer_init( DATAGRAM_SOCK_BUF_SIZE , mi_reply_indent )!= 0) {
00274                         LM_CRIT("failed to initiate mi_datagram_writer\n");
00275                         return -1;
00276                 }
00277         }
00278         if (rank==PROC_MAIN) {
00279                 if(pre_datagram_process()!=0)
00280                 {
00281                         LM_ERR("pre-fork function failed\n");
00282                         return -1;
00283                 }
00284                 for(i=0; i<mi_procs[0].no; i++)
00285                 {
00286                         pid=fork_process(PROC_NOCHLDINIT, "MI DATAGRAM", 1);
00287                         if (pid<0)
00288                                 return -1; /* error */
00289                         if(pid==0) {
00290                                 /* child */
00291 
00292                                 /* initialize the config framework */
00293                                 if (cfg_child_init())
00294                                         return -1;
00295 
00296                                 datagram_process(i);
00297                                 return 0;
00298                         }
00299                 }
00300                 if(post_datagram_process()!=0)
00301                 {
00302                         LM_ERR("post-fork function failed\n");
00303                         return -1;
00304                 }
00305         }
00306         return 0;
00307 }
00308 
00309 
00310 static int pre_datagram_process(void)
00311 {
00312         int res;
00313 
00314         /*create the sockets*/
00315         res = mi_init_datagram_server(&mi_dtgram_addr, mi_socket_domain, &sockets,
00316                                         mi_unix_socket_mode, mi_unix_socket_uid, mi_unix_socket_gid);
00317 
00318         if ( res ) {
00319                 LM_CRIT("function mi_init_datagram_server returned with error!!!\n");
00320                 return -1;
00321         }
00322 
00323         return 0;
00324 }
00325 
00326 
00327 static void datagram_process(int rank)
00328 {
00329         LM_INFO("a new child %d/%d\n", rank, getpid());
00330 
00331         /*child's initial settings*/
00332         if ( init_mi_child(PROC_NOCHLDINIT, 1)!=0) {
00333                 LM_CRIT("failed to init the mi process\n");
00334                 exit(-1);
00335         }
00336         if (mi_init_datagram_buffer()!=0) {
00337                 LM_ERR("failed to allocate datagram buffer\n");
00338                 exit(-1);
00339         }
00340 
00341         if (mi_datagram_writer_init( DATAGRAM_SOCK_BUF_SIZE , mi_reply_indent )!= 0) {
00342                 LM_CRIT("failed to initiate mi_datagram_writer\n");
00343                 exit(-1);
00344         }
00345 
00346         mi_datagram_server(sockets.rx_sock, sockets.tx_sock);
00347 
00348         exit(-1);
00349 }
00350 
00351 
00352 static int post_datagram_process(void)
00353 {
00354         /* close the sockets */
00355         close(sockets.rx_sock);
00356         close(sockets.tx_sock);
00357         return 0;
00358 }
00359 
00360 
00361 static int mi_destroy(void)
00362 {
00363         int n;
00364         struct stat filestat;
00365 
00366         /* destroying the socket descriptors */
00367         if(mi_socket_domain == AF_UNIX) {
00368                 n=stat(mi_socket, &filestat);
00369                 if (n==0) {
00370                         if(config_check==0) {
00371                                 if (unlink(mi_socket)<0){
00372                                         LM_ERR("cannot delete the socket (%s): %s\n", 
00373                                                 mi_socket, strerror(errno));
00374                                         goto error;
00375                                 }
00376                         }
00377                 } else if (n<0 && errno!=ENOENT) {
00378                         LM_ERR("socket stat failed: %s\n", strerror(errno));
00379                         goto error;
00380                 }
00381         }
00382 
00383         return 0;
00384 error:
00385         return -1;
00386 
00387 }