sms.c

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