sms.c

Go to the documentation of this file.
00001 /*
00002  * $Id: sms.c 4949 2008-09-18 12:02:39Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
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  * History:
00023  * --------
00024  *  2003-03-11  updated to the new module exports interface (andrei)
00025  *  2003-03-16  flags export parameter added (janakj)
00026  *  2003-03-19  all mallocs/frees replaced w/ pkg_malloc/pkg_free (andrei)
00027  *  2003-04-02  port_no_str does not contain a leading ':' anymore (andrei)
00028  *  2003-04-06  Only child 1 will execute child init (janakj)
00029  *  2003-10-24  updated to the new socket_info lists (andrei)
00030  */
00031 
00032 
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <stdlib.h>
00036 #include <unistd.h>
00037 #include <fcntl.h>
00038 
00039 #include "../../sr_module.h"
00040 #include "../../error.h"
00041 #include "../../dprint.h"
00042 #include "../../ut.h"
00043 #include "../../globals.h"
00044 #include "../../mem/mem.h"
00045 #include "../../mem/shm_mem.h"
00046 #include "../../socket_info.h"
00047 #include "../tm/tm_load.h"
00048 #include "sms_funcs.h"
00049 #include "sms_report.h"
00050 #include "libsms_modem.h"
00051 
00052 
00053 MODULE_VERSION
00054 
00055 
00056 static int sms_init(void);
00057 static int sms_exit(void);
00058 static int w_sms_send_msg(struct sip_msg*, char*, char* );
00059 static int w_sms_send_msg_to_net(struct sip_msg*, char*, char*);
00060 static int fixup_sms_send_msg_to_net(void** param, int param_no);
00061 static void sms_process(int);
00062 
00063 
00064 
00065 /* parameters */
00066 char *networks_config = 0;
00067 char *modems_config   = 0;
00068 char *links_config    = 0;
00069 char *default_net_str = 0;
00070 char *domain_str      = 0;
00071 
00072 /*global variables*/
00073 int    default_net    = 0;
00074 int    max_sms_parts  = MAX_SMS_PARTS;
00075 str    domain;
00076 int    *queued_msgs    = 0;
00077 int    use_contact     = 0;
00078 int    sms_report_type = NO_REPORT;
00079 struct tm_binds tmb;
00080 
00081 
00082 static proc_export_t sms_procs[] = {
00083    {"SMS receiver",  0,  0, sms_process, 0 },
00084    {0,0,0,0,0}
00085 };
00086 
00087 
00088 static cmd_export_t cmds[]={
00089    {"sms_send_msg_to_net", (cmd_function)w_sms_send_msg_to_net, 1, 
00090         fixup_sms_send_msg_to_net, 0, REQUEST_ROUTE},
00091    {"sms_send_msg",        (cmd_function)w_sms_send_msg,        0,  
00092         0, 0,                         REQUEST_ROUTE},
00093    {0,0,0,0,0,0}
00094 };
00095 
00096 
00097 static param_export_t params[]={
00098    {"networks",        STR_PARAM, &networks_config },
00099    {"modems",          STR_PARAM, &modems_config   },
00100    {"links",           STR_PARAM, &links_config    },
00101    {"default_net",     STR_PARAM, &default_net_str },
00102    {"max_sms_parts",   INT_PARAM, &max_sms_parts   },
00103    {"domain",          STR_PARAM, &domain_str      },
00104    {"use_contact",     INT_PARAM, &use_contact     },
00105    {"sms_report_type", INT_PARAM, &sms_report_type },
00106    {0,0,0}
00107 };
00108 
00109 
00110 struct module_exports exports= {
00111    "sms",
00112    DEFAULT_DLFLAGS, /* dlopen flags */
00113    cmds,
00114    params,
00115    0,          /* exported statistics */
00116    0,          /* exported MI functions */
00117    0,          /* exported pseudo-variables */
00118    sms_procs,  /* extra processes */
00119    sms_init,   /* module initialization function */
00120    0,
00121    (destroy_function) sms_exit,   /* module exit function */
00122    0           /* per-child init function */
00123 };
00124 
00125 
00126 
00127 
00128 static int fixup_sms_send_msg_to_net(void** param, int param_no)
00129 {
00130    long net_nr,i;
00131 
00132    if (param_no==1) {
00133       for(net_nr=-1,i=0;i<nr_of_networks&&net_nr==-1;i++)
00134          if (!strcasecmp(networks[i].name,*param))
00135             net_nr = i;
00136       if (net_nr==-1) {
00137          LM_ERR("etwork \"%s\" not found in net list!\n",(char*)*param);
00138          return E_UNSPEC;
00139       } else {
00140          pkg_free(*param);
00141          *param=(void*)net_nr;
00142          return 0;
00143       }
00144    }
00145    return 0;
00146 }
00147 
00148 
00149 
00150 
00151 
00152 #define eat_spaces(_p) \
00153    while( *(_p)==' ' || *(_p)=='\t' ){\
00154    (_p)++;}
00155 
00156 
00157 
00158 
00159 int set_modem_arg(struct modem *mdm, char *arg, char *arg_end)
00160 {
00161    int err, foo;
00162 
00163    if (*(arg+1)!='=') {
00164       LM_ERR("invalid parameter syntax near [=]\n");
00165       goto error;
00166    }
00167    switch (*arg)
00168    {
00169       case 'd':  /* device */
00170          memcpy(mdm->device,arg+2,arg_end-arg-2);
00171          mdm->device[arg_end-arg-2] = 0;
00172          break;
00173       case 'p':  /* pin */
00174          memcpy(mdm->pin,arg+2,arg_end-arg-2);
00175          mdm->pin[arg_end-arg-2] = 0;
00176          break;
00177       case 'm':  /* mode */
00178          if (!strncasecmp(arg+2,"OLD",3)
00179          && arg_end-arg-2==3) {
00180             mdm->mode = MODE_OLD;
00181          } else if (!strncasecmp(arg+2,"DIGICOM",7)
00182          && arg_end-arg-2==7) {
00183             mdm->mode = MODE_DIGICOM;
00184          } else if (!strncasecmp(arg+2,"ASCII",5)
00185          && arg_end-arg-2==5) {
00186             mdm->mode = MODE_ASCII;
00187          } else if (!strncasecmp(arg+2,"NEW",3)
00188          && arg_end-arg-2==3) {
00189             mdm->mode = MODE_NEW;
00190          } else {
00191             LM_ERR("invalid value \"%.*s\" for param [m]\n",
00192                (int)(arg_end-arg-2),arg+2);
00193             goto error;
00194          }
00195          break;
00196       case 'c':  /* sms center number */
00197          memcpy(mdm->smsc,arg+2,arg_end-arg-2);
00198          mdm->smsc[arg_end-arg-2] = 0;
00199          break;
00200       case 'r':  /* retry time */
00201          foo=str2s(arg+2,arg_end-arg-2,&err);
00202          if (err) {
00203             LM_ERR("failed to convert [r] arg to integer!\n");
00204             goto error;
00205          }
00206          mdm->retry = foo;
00207          break;
00208       case 'l':  /* looping interval */
00209          foo=str2s(arg+2,arg_end-arg-2,&err);
00210          if (err) {
00211             LM_ERR("failed to convert [l] arg to integer!\n");
00212             goto error;
00213          }
00214          mdm->looping_interval = foo;
00215          break;
00216       case 'b':  /* baudrate */
00217          foo=str2s(arg+2,arg_end-arg-2,&err);
00218          if (err) {
00219             LM_ERR("failed to convert [b] arg to integer!\n");
00220             goto error;
00221          }
00222          switch (foo) {
00223             case   300: foo=B300; break;
00224             case  1200: foo=B1200; break;
00225             case  2400: foo=B2400; break;
00226             case  9600: foo=B9600; break;
00227             case 19200: foo=B19200; break;
00228             case 38400: foo=B38400; break;
00229             case 57600: foo=B57600; break;
00230             default:
00231                LM_ERR("unsupported value %d for [b] arg!\n",foo);
00232                goto error;
00233          }
00234          mdm->baudrate = foo;
00235          break;
00236       default:
00237          LM_ERR("unknown param name [%c]\n",*arg);
00238          goto error;
00239    }
00240 
00241    return 1;
00242 error:
00243    return -1;
00244 }
00245 
00246 
00247 
00248 
00249 int set_network_arg(struct network *net, char *arg, char *arg_end)
00250 {
00251    int err,foo;
00252 
00253    if (*(arg+1)!='=') {
00254       LM_ERR("invalid parameter syntax near [=]\n");
00255       goto error;
00256    }
00257    switch (*arg)
00258    {
00259       case 'm':  /* maximum sms per one call */
00260          foo=str2s(arg+2,arg_end-arg-2,&err);
00261          if (err) {
00262             LM_ERR("cannot convert [m] arg to integer!\n");
00263             goto error;
00264          }
00265          net->max_sms_per_call = foo;
00266          break;
00267       default:
00268          LM_ERR("unknown param name [%c]\n",*arg);
00269          goto error;
00270    }
00271 
00272    return 1;
00273 error:
00274    return -1;
00275 }
00276 
00277 
00278 
00279 
00280 int parse_config_lines(void)
00281 {
00282    char *p,*start;
00283    int  i, k, step;
00284    int  mdm_nr, net_nr;
00285 
00286    nr_of_networks = 0;
00287    nr_of_modems = 0;
00288 
00289    step = 1;
00290    /* parsing modems configuration string */
00291    if ( (p = modems_config)==0) {
00292       LM_ERR("param \"modems\" not found\n");
00293       goto error;
00294    }
00295    while (*p)
00296    {
00297       eat_spaces(p);
00298       /*get modem's name*/
00299       start = p;
00300       while (*p!=' ' && *p!='\t' && *p!='[' && *p!=0)
00301          p++;
00302       if ( p==start || *p==0 )
00303          goto parse_error;
00304       memcpy(modems[nr_of_modems].name, start, p-start);
00305       modems[nr_of_modems].name[p-start] = 0;
00306       modems[nr_of_modems].smsc[0] = 0;
00307       modems[nr_of_modems].device[0] = 0;
00308       modems[nr_of_modems].pin[0] = 0;
00309       modems[nr_of_modems].mode = MODE_NEW;
00310       modems[nr_of_modems].retry = 4;
00311       modems[nr_of_modems].looping_interval = 20;
00312       modems[nr_of_modems].baudrate = B9600;
00313       memset(modems[nr_of_modems].net_list,0XFF,
00314          sizeof(modems[nr_of_modems].net_list) );
00315       /*get modem parameters*/
00316       eat_spaces(p);
00317       if (*p!='[')
00318          goto parse_error;
00319       p++;
00320       while (*p!=']')
00321       {
00322          eat_spaces(p);
00323          start = p;
00324          while(*p!=' ' && *p!='\t' && *p!=']' && *p!=';' && *p!=0)
00325             p++;
00326          if ( p==start || *p==0 )
00327             goto parse_error;
00328          if (set_modem_arg( &(modems[nr_of_modems]), start, p)==-1)
00329             goto error;
00330          eat_spaces(p);
00331          if (*p==';') {
00332             p++;
00333             eat_spaces(p);
00334          }
00335       }
00336       if (*p!=']')
00337          goto parse_error;
00338       p++;
00339       /* end of element */
00340       if (modems[nr_of_modems].device[0]==0) {
00341          LM_ERR("modem %s has no device associated\n",
00342                modems[nr_of_modems].name);
00343          goto error;
00344       }
00345       if (modems[nr_of_modems].smsc[0]==0) {
00346          LM_WARN("modem %s has no sms center associated -> using"
00347             " the default one from modem\n",modems[nr_of_modems].name);
00348       }
00349       nr_of_modems++;
00350       eat_spaces(p);
00351       if (*p==';') {
00352          p++;
00353          eat_spaces(p);
00354       }
00355    }
00356    if (nr_of_modems==0)
00357    {
00358       LM_ERR("failed to parse config modems - no modem found!\n");
00359       goto error;
00360    }
00361 
00362    step++;
00363    /* parsing networks configuration string */
00364    if ( (p = networks_config)==0) {
00365       LM_ERR("param \"networks\" not found\n");
00366       goto error;
00367    }
00368    while (*p)
00369    {
00370       eat_spaces(p);
00371       /*get network name*/
00372       start = p;
00373       while (*p!=' ' && *p!='\t' && *p!='[' && *p!=0)
00374          p++;
00375       if ( p==start || *p==0 )
00376          goto parse_error;
00377       memcpy(networks[nr_of_networks].name, start, p-start);
00378       networks[nr_of_networks].name[p-start] = 0;
00379       networks[nr_of_networks].max_sms_per_call = 10;
00380       /*get network parameters*/
00381       eat_spaces(p);
00382       if (*p!='[')
00383          goto parse_error;
00384       p++;
00385       while (*p!=']')
00386       {
00387          eat_spaces(p);
00388          start = p;
00389          while(*p!=' ' && *p!='\t' && *p!=']' && *p!=';' && *p!=0)
00390             p++;
00391          if ( p==start || *p==0 )
00392             goto parse_error;
00393          if (set_network_arg( &(networks[nr_of_networks]), start, p)==-1)
00394             goto error;
00395          eat_spaces(p);
00396          if (*p==';') {
00397             p++;
00398             eat_spaces(p);
00399          }
00400       }
00401       if (*p!=']')
00402          goto parse_error;
00403       p++;
00404       /* end of element */
00405       nr_of_networks++;
00406       eat_spaces(p);
00407       if (*p==';')
00408          p++;
00409       eat_spaces(p);
00410    }
00411    if (nr_of_networks==0)
00412    {
00413       LM_ERR("no network found!\n");
00414       goto error;
00415    }
00416 
00417    step++;
00418    /* parsing links configuration string */
00419    if ( (p = links_config)==0) {
00420       LM_ERR("param \"links\" not found\n");
00421       goto error;
00422    }
00423    while (*p)
00424    {
00425       eat_spaces(p);
00426       /*get modem's device*/
00427       start = p;
00428       while (*p!=' ' && *p!='\t' && *p!='[' && *p!=0)
00429          p++;
00430       if ( p==start || *p==0 )
00431          goto parse_error;
00432       /*looks for modem index*/
00433       for(mdm_nr=-1,i=0;i<nr_of_modems && mdm_nr==-1;i++)
00434          if (!strncasecmp(modems[i].name,start,p-start)&&
00435          modems[i].name[p-start]==0)
00436             mdm_nr = i;
00437       if (mdm_nr==-1) {
00438          LM_ERR("unknown modem %.*s \n,",(int)(p-start), start);
00439          goto error;
00440       }
00441       /*get associated networks list*/
00442       eat_spaces(p);
00443       if (*p!='[')
00444          goto parse_error;
00445       p++;
00446       k=0;
00447       while (*p!=']')
00448       {
00449          eat_spaces(p);
00450          start = p;
00451          while(*p!=' ' && *p!='\t' && *p!=']' && *p!=';' && *p!=0)
00452             p++;
00453          if ( p==start || *p==0 )
00454             goto parse_error;
00455          /* lookup for the network -> get its index */
00456          for(net_nr=-1,i=0;i<nr_of_networks&&net_nr==-1;i++)
00457             if (!strncasecmp(networks[i].name,start,p-start)
00458             && networks[i].name[p-start]==0)
00459                net_nr = i;
00460          if (net_nr==-1) {
00461             LM_ERR("associated net <%.*s> not found in net list\n",
00462                (int)(p-start), start);
00463             goto error;
00464          }
00465          LM_DBG("linking net \"%s\" to modem \"%s\" on pos %d.\n",
00466                networks[net_nr].name,modems[mdm_nr].name,k);
00467          modems[mdm_nr].net_list[k++]=net_nr;
00468          eat_spaces(p);
00469          if (*p==';') {
00470             p++;
00471             eat_spaces(p);
00472          }
00473       }
00474       if (*p!=']')
00475          goto parse_error;
00476       p++;
00477       /* end of element */
00478       eat_spaces(p);
00479       if (*p==';') {
00480          p++;
00481          eat_spaces(p);
00482       }
00483    }
00484 
00485    /* resolving default network name - if any*/
00486    if (default_net_str) {
00487       for(net_nr=-1,i=0;i<nr_of_networks&&net_nr==-1;i++)
00488          if (!strcasecmp(networks[i].name,default_net_str))
00489             net_nr = i;
00490       if (net_nr==-1) {
00491          LM_ERR("network \"%s\" not found in net list!\n",default_net_str);
00492          goto error;
00493       }
00494       default_net = net_nr;
00495    }
00496 
00497    return 0;
00498 parse_error:
00499    LM_ERR("SMS %s config: parse error before  chr %d [%.*s]\n",
00500       (step==1)?"modems":(step==2?"networks":"links"),
00501       (int)(p - ((step==1)?modems_config:
00502                (step==2?networks_config:links_config))),
00503       (*p==0)?4:1,(*p==0)?"NULL":p );
00504                
00505 error:
00506    return -1;
00507 }
00508 
00509 
00510 
00511 
00512 int global_init(void)
00513 {
00514    int   i, net_pipe[2], foo;
00515    char  *p;
00516    struct socket_info* si;
00517 
00518    /* load the TM API */
00519    if (load_tm_api(&tmb)!=0) {
00520       LM_ERR("failed to load TM API\n");
00521       goto error;
00522    }
00523 
00524    /*fix domain length*/
00525    if (domain_str) {
00526       domain.s = domain_str;
00527       domain.len = strlen(domain_str);
00528    } else {
00529       si=get_first_socket();
00530       if (si==0){
00531          LM_CRIT("null listen socket list\n");
00532          goto error;
00533       }
00534       /*do I have to add port?*/
00535       i = (si->port_no_str.len && si->port_no!=5060);
00536       domain.len = si->name.len + i*(si->port_no_str.len+1);
00537       domain.s = (char*)pkg_malloc(domain.len);
00538       if (!domain.s) {
00539          LM_ERR("no more pkg memory!\n");
00540          goto error;
00541       }
00542       p = domain.s;
00543       memcpy(p,si->name.s,si->name.len);
00544       p += si->name.len;
00545       if (i) {
00546          *p=':'; p++;
00547          memcpy(p,si->port_no_str.s, si->port_no_str.len);
00548          p += si->port_no_str.len;
00549       }
00550    }
00551 
00552    /* creates pipes for networks */
00553    for(i=0;i<nr_of_networks;i++)
00554    {
00555       /* create the pipe*/
00556       if (pipe(net_pipe)==-1) {
00557          LM_ERR("failed create pipe!\n");
00558          goto error;
00559       }
00560       networks[i].pipe_out = net_pipe[0];
00561       net_pipes_in[i] = net_pipe[1];
00562       /* sets reading from pipe to non blocking */
00563       if ((foo=fcntl(net_pipe[0],F_GETFL,0))<0) {
00564          LM_ERR("failed to get flag for pipe - fcntl\n");
00565          goto error;
00566       }
00567       foo |= O_NONBLOCK;
00568       if (fcntl(net_pipe[0],F_SETFL,foo)<0) {
00569          LM_ERR("failed to set flag for pipe"
00570             " - fcntl\n");
00571          goto error;
00572       }
00573    }
00574 
00575    /* if report will be used, init the report queue */
00576    if (sms_report_type!=NO_REPORT && !init_report_queue()) {
00577       LM_ERR("no more share memory!\n");
00578       goto error;
00579    }
00580 
00581    /* alloc in shm for queued_msgs */
00582    queued_msgs = (int*)shm_malloc(sizeof(int));
00583    if (!queued_msgs) {
00584       LM_ERR("no more share memory!\n");
00585       goto error;
00586    }
00587    *queued_msgs = 0;
00588 
00589    return 1;
00590 error:
00591    return -1;
00592 }
00593 
00594 
00595 
00596 void sms_process(int rank)
00597 {
00598    modem_process(&(modems[rank]));
00599    exit(-1);
00600 }
00601 
00602 
00603 
00604 static int sms_init(void)
00605 {
00606    if (parse_config_lines()==-1)
00607       return -1;
00608    if (global_init()==-1)
00609       return -1;
00610    /* update the number of required processes */
00611    sms_procs[0].no = nr_of_modems;
00612    return 0;
00613 }
00614 
00615 
00616 
00617 
00618 static int sms_exit(void)
00619 {
00620    if ((!domain_str) && (domain.s))
00621       pkg_free(domain.s);
00622 
00623    if (queued_msgs)
00624       shm_free(queued_msgs);
00625 
00626    if (sms_report_type!=NO_REPORT)
00627       destroy_report_queue();
00628 
00629    return 0;
00630 }
00631 
00632 
00633 
00634 
00635 static int w_sms_send_msg(struct sip_msg *msg, char *foo, char *bar)
00636 {
00637    return push_on_network(msg, default_net);
00638 }
00639 
00640 
00641 
00642 
00643 static int w_sms_send_msg_to_net(struct sip_msg *msg, char *net_nr, char *foo)
00644 {
00645    return push_on_network(msg,(unsigned int)(unsigned long)net_nr);
00646 }
00647 

Generated on Thu May 24 12:00:30 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6