4d96c806d2a59bc6f740989e47e231a38696abd4
[sip-router] / modules_k / sms / sms.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License 
19  * along with this program; if not, write to the Free Software 
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * History:
23  * --------
24  *  2003-03-11  updated to the new module exports interface (andrei)
25  *  2003-03-16  flags export parameter added (janakj)
26  *  2003-03-19  all mallocs/frees replaced w/ pkg_malloc/pkg_free (andrei)
27  *  2003-04-02  port_no_str does not contain a leading ':' anymore (andrei)
28  *  2003-04-06  Only child 1 will execute child init (janakj)
29  *  2003-10-24  updated to the new socket_info lists (andrei)
30  */
31
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38
39 #include "../../sr_module.h"
40 #include "../../error.h"
41 #include "../../dprint.h"
42 #include "../../ut.h"
43 #include "../../globals.h"
44 #include "../../mem/mem.h"
45 #include "../../mem/shm_mem.h"
46 #include "../../socket_info.h"
47 #include "../../modules/tm/tm_load.h"
48 #include "sms_funcs.h"
49 #include "sms_report.h"
50 #include "libsms_modem.h"
51
52
53 MODULE_VERSION
54
55
56 static int sms_init(void);
57 static int sms_exit(void);
58 static int w_sms_send_msg(struct sip_msg*, char*, char* );
59 static int w_sms_send_msg_to_net(struct sip_msg*, char*, char*);
60 static int fixup_sms_send_msg_to_net(void** param, int param_no);
61 static void sms_process(int);
62
63
64
65 /* parameters */
66 char *networks_config = 0;
67 char *modems_config   = 0;
68 char *links_config    = 0;
69 char *default_net_str = 0;
70 char *domain_str      = 0;
71
72 /*global variables*/
73 int    default_net    = 0;
74 int    max_sms_parts  = MAX_SMS_PARTS;
75 str    domain;
76 int    *queued_msgs    = 0;
77 int    use_contact     = 0;
78 int    sms_report_type = NO_REPORT;
79 struct tm_binds tmb;
80
81
82 static proc_export_t sms_procs[] = {
83         {"SMS receiver",  0,  0, sms_process, 0 },
84         {0,0,0,0,0}
85 };
86
87
88 static cmd_export_t cmds[]={
89         {"sms_send_msg_to_net", (cmd_function)w_sms_send_msg_to_net, 1, 
90              fixup_sms_send_msg_to_net, 0, REQUEST_ROUTE},
91         {"sms_send_msg",        (cmd_function)w_sms_send_msg,        0,  
92              0, 0,                         REQUEST_ROUTE},
93         {0,0,0,0,0,0}
94 };
95
96
97 static param_export_t params[]={
98         {"networks",        STR_PARAM, &networks_config },
99         {"modems",          STR_PARAM, &modems_config   },
100         {"links",           STR_PARAM, &links_config    },
101         {"default_net",     STR_PARAM, &default_net_str },
102         {"max_sms_parts",   INT_PARAM, &max_sms_parts   },
103         {"domain",          STR_PARAM, &domain_str      },
104         {"use_contact",     INT_PARAM, &use_contact     },
105         {"sms_report_type", INT_PARAM, &sms_report_type },
106         {0,0,0}
107 };
108
109
110 struct module_exports exports= {
111         "sms",
112         DEFAULT_DLFLAGS, /* dlopen flags */
113         cmds,
114         params,
115         0,          /* exported statistics */
116         0,          /* exported MI functions */
117         0,          /* exported pseudo-variables */
118         sms_procs,  /* extra processes */
119         sms_init,   /* module initialization function */
120         0,
121         (destroy_function) sms_exit,   /* module exit function */
122         0           /* per-child init function */
123 };
124
125
126
127
128 static int fixup_sms_send_msg_to_net(void** param, int param_no)
129 {
130         long net_nr,i;
131
132         if (param_no==1) {
133                 for(net_nr=-1,i=0;i<nr_of_networks&&net_nr==-1;i++)
134                         if (!strcasecmp(networks[i].name,*param))
135                                 net_nr = i;
136                 if (net_nr==-1) {
137                         LM_ERR("etwork \"%s\" not found in net list!\n",(char*)*param);
138                         return E_UNSPEC;
139                 } else {
140                         pkg_free(*param);
141                         *param=(void*)net_nr;
142                         return 0;
143                 }
144         }
145         return 0;
146 }
147
148
149
150
151
152 #define eat_spaces(_p) \
153         while( *(_p)==' ' || *(_p)=='\t' ){\
154         (_p)++;}
155
156
157
158
159 int set_modem_arg(struct modem *mdm, char *arg, char *arg_end)
160 {
161         int err, foo;
162
163         if (*(arg+1)!='=') {
164                 LM_ERR("invalid parameter syntax near [=]\n");
165                 goto error;
166         }
167         switch (*arg)
168         {
169                 case 'd':  /* device */
170                         memcpy(mdm->device,arg+2,arg_end-arg-2);
171                         mdm->device[arg_end-arg-2] = 0;
172                         break;
173                 case 'p':  /* pin */
174                         memcpy(mdm->pin,arg+2,arg_end-arg-2);
175                         mdm->pin[arg_end-arg-2] = 0;
176                         break;
177                 case 'm':  /* mode */
178                         if (!strncasecmp(arg+2,"OLD",3)
179                         && arg_end-arg-2==3) {
180                                 mdm->mode = MODE_OLD;
181                         } else if (!strncasecmp(arg+2,"DIGICOM",7)
182                         && arg_end-arg-2==7) {
183                                 mdm->mode = MODE_DIGICOM;
184                         } else if (!strncasecmp(arg+2,"ASCII",5)
185                         && arg_end-arg-2==5) {
186                                 mdm->mode = MODE_ASCII;
187                         } else if (!strncasecmp(arg+2,"NEW",3)
188                         && arg_end-arg-2==3) {
189                                 mdm->mode = MODE_NEW;
190                         } else {
191                                 LM_ERR("invalid value \"%.*s\" for param [m]\n",
192                                         (int)(arg_end-arg-2),arg+2);
193                                 goto error;
194                         }
195                         break;
196                 case 'c':  /* sms center number */
197                         memcpy(mdm->smsc,arg+2,arg_end-arg-2);
198                         mdm->smsc[arg_end-arg-2] = 0;
199                         break;
200                 case 'r':  /* retry time */
201                         foo=str2s(arg+2,arg_end-arg-2,&err);
202                         if (err) {
203                                 LM_ERR("failed to convert [r] arg to integer!\n");
204                                 goto error;
205                         }
206                         mdm->retry = foo;
207                         break;
208                 case 'l':  /* looping interval */
209                         foo=str2s(arg+2,arg_end-arg-2,&err);
210                         if (err) {
211                                 LM_ERR("failed to convert [l] arg to integer!\n");
212                                 goto error;
213                         }
214                         mdm->looping_interval = foo;
215                         break;
216                 case 'b':  /* baudrate */
217                         foo=str2s(arg+2,arg_end-arg-2,&err);
218                         if (err) {
219                                 LM_ERR("failed to convert [b] arg to integer!\n");
220                                 goto error;
221                         }
222                         switch (foo) {
223                                 case   300: foo=B300; break;
224                                 case  1200: foo=B1200; break;
225                                 case  2400: foo=B2400; break;
226                                 case  9600: foo=B9600; break;
227                                 case 19200: foo=B19200; break;
228                                 case 38400: foo=B38400; break;
229                                 case 57600: foo=B57600; break;
230                                 default:
231                                         LM_ERR("unsupported value %d for [b] arg!\n",foo);
232                                         goto error;
233                         }
234                         mdm->baudrate = foo;
235                         break;
236                 default:
237                         LM_ERR("unknown param name [%c]\n",*arg);
238                         goto error;
239         }
240
241         return 1;
242 error:
243         return -1;
244 }
245
246
247
248
249 int set_network_arg(struct network *net, char *arg, char *arg_end)
250 {
251         int err,foo;
252
253         if (*(arg+1)!='=') {
254                 LM_ERR("invalid parameter syntax near [=]\n");
255                 goto error;
256         }
257         switch (*arg)
258         {
259                 case 'm':  /* maximum sms per one call */
260                         foo=str2s(arg+2,arg_end-arg-2,&err);
261                         if (err) {
262                                 LM_ERR("cannot convert [m] arg to integer!\n");
263                                 goto error;
264                         }
265                         net->max_sms_per_call = foo;
266                         break;
267                 default:
268                         LM_ERR("unknown param name [%c]\n",*arg);
269                         goto error;
270         }
271
272         return 1;
273 error:
274         return -1;
275 }
276
277
278
279
280 int parse_config_lines(void)
281 {
282         char *p,*start;
283         int  i, k, step;
284         int  mdm_nr, net_nr;
285
286         nr_of_networks = 0;
287         nr_of_modems = 0;
288
289         step = 1;
290         /* parsing modems configuration string */
291         if ( (p = modems_config)==0) {
292                 LM_ERR("param \"modems\" not found\n");
293                 goto error;
294         }
295         while (*p)
296         {
297                 eat_spaces(p);
298                 /*get modem's name*/
299                 start = p;
300                 while (*p!=' ' && *p!='\t' && *p!='[' && *p!=0)
301                         p++;
302                 if ( p==start || *p==0 )
303                         goto parse_error;
304                 memcpy(modems[nr_of_modems].name, start, p-start);
305                 modems[nr_of_modems].name[p-start] = 0;
306                 modems[nr_of_modems].smsc[0] = 0;
307                 modems[nr_of_modems].device[0] = 0;
308                 modems[nr_of_modems].pin[0] = 0;
309                 modems[nr_of_modems].mode = MODE_NEW;
310                 modems[nr_of_modems].retry = 4;
311                 modems[nr_of_modems].looping_interval = 20;
312                 modems[nr_of_modems].baudrate = B9600;
313                 memset(modems[nr_of_modems].net_list,0XFF,
314                         sizeof(modems[nr_of_modems].net_list) );
315                 /*get modem parameters*/
316                 eat_spaces(p);
317                 if (*p!='[')
318                         goto parse_error;
319                 p++;
320                 while (*p!=']')
321                 {
322                         eat_spaces(p);
323                         start = p;
324                         while(*p!=' ' && *p!='\t' && *p!=']' && *p!=';' && *p!=0)
325                                 p++;
326                         if ( p==start || *p==0 )
327                                 goto parse_error;
328                         if (set_modem_arg( &(modems[nr_of_modems]), start, p)==-1)
329                                 goto error;
330                         eat_spaces(p);
331                         if (*p==';') {
332                                 p++;
333                                 eat_spaces(p);
334                         }
335                 }
336                 if (*p!=']')
337                         goto parse_error;
338                 p++;
339                 /* end of element */
340                 if (modems[nr_of_modems].device[0]==0) {
341                         LM_ERR("modem %s has no device associated\n",
342                                         modems[nr_of_modems].name);
343                         goto error;
344                 }
345                 if (modems[nr_of_modems].smsc[0]==0) {
346                         LM_WARN("modem %s has no sms center associated -> using"
347                                 " the default one from modem\n",modems[nr_of_modems].name);
348                 }
349                 nr_of_modems++;
350                 eat_spaces(p);
351                 if (*p==';') {
352                         p++;
353                         eat_spaces(p);
354                 }
355         }
356         if (nr_of_modems==0)
357         {
358                 LM_ERR("failed to parse config modems - no modem found!\n");
359                 goto error;
360         }
361
362         step++;
363         /* parsing networks configuration string */
364         if ( (p = networks_config)==0) {
365                 LM_ERR("param \"networks\" not found\n");
366                 goto error;
367         }
368         while (*p)
369         {
370                 eat_spaces(p);
371                 /*get network name*/
372                 start = p;
373                 while (*p!=' ' && *p!='\t' && *p!='[' && *p!=0)
374                         p++;
375                 if ( p==start || *p==0 )
376                         goto parse_error;
377                 memcpy(networks[nr_of_networks].name, start, p-start);
378                 networks[nr_of_networks].name[p-start] = 0;
379                 networks[nr_of_networks].max_sms_per_call = 10;
380                 /*get network parameters*/
381                 eat_spaces(p);
382                 if (*p!='[')
383                         goto parse_error;
384                 p++;
385                 while (*p!=']')
386                 {
387                         eat_spaces(p);
388                         start = p;
389                         while(*p!=' ' && *p!='\t' && *p!=']' && *p!=';' && *p!=0)
390                                 p++;
391                         if ( p==start || *p==0 )
392                                 goto parse_error;
393                         if (set_network_arg( &(networks[nr_of_networks]), start, p)==-1)
394                                 goto error;
395                         eat_spaces(p);
396                         if (*p==';') {
397                                 p++;
398                                 eat_spaces(p);
399                         }
400                 }
401                 if (*p!=']')
402                         goto parse_error;
403                 p++;
404                 /* end of element */
405                 nr_of_networks++;
406                 eat_spaces(p);
407                 if (*p==';')
408                         p++;
409                 eat_spaces(p);
410         }
411         if (nr_of_networks==0)
412         {
413                 LM_ERR("no network found!\n");
414                 goto error;
415         }
416
417         step++;
418         /* parsing links configuration string */
419         if ( (p = links_config)==0) {
420                 LM_ERR("param \"links\" not found\n");
421                 goto error;
422         }
423         while (*p)
424         {
425                 eat_spaces(p);
426                 /*get modem's device*/
427                 start = p;
428                 while (*p!=' ' && *p!='\t' && *p!='[' && *p!=0)
429                         p++;
430                 if ( p==start || *p==0 )
431                         goto parse_error;
432                 /*looks for modem index*/
433                 for(mdm_nr=-1,i=0;i<nr_of_modems && mdm_nr==-1;i++)
434                         if (!strncasecmp(modems[i].name,start,p-start)&&
435                         modems[i].name[p-start]==0)
436                                 mdm_nr = i;
437                 if (mdm_nr==-1) {
438                         LM_ERR("unknown modem %.*s \n,",(int)(p-start), start);
439                         goto error;
440                 }
441                 /*get associated networks list*/
442                 eat_spaces(p);
443                 if (*p!='[')
444                         goto parse_error;
445                 p++;
446                 k=0;
447                 while (*p!=']')
448                 {
449                         eat_spaces(p);
450                         start = p;
451                         while(*p!=' ' && *p!='\t' && *p!=']' && *p!=';' && *p!=0)
452                                 p++;
453                         if ( p==start || *p==0 )
454                                 goto parse_error;
455                         /* lookup for the network -> get its index */
456                         for(net_nr=-1,i=0;i<nr_of_networks&&net_nr==-1;i++)
457                                 if (!strncasecmp(networks[i].name,start,p-start)
458                                 && networks[i].name[p-start]==0)
459                                         net_nr = i;
460                         if (net_nr==-1) {
461                                 LM_ERR("associated net <%.*s> not found in net list\n",
462                                         (int)(p-start), start);
463                                 goto error;
464                         }
465                         LM_DBG("linking net \"%s\" to modem \"%s\" on pos %d.\n",
466                                         networks[net_nr].name,modems[mdm_nr].name,k);
467                         modems[mdm_nr].net_list[k++]=net_nr;
468                         eat_spaces(p);
469                         if (*p==';') {
470                                 p++;
471                                 eat_spaces(p);
472                         }
473                 }
474                 if (*p!=']')
475                         goto parse_error;
476                 p++;
477                 /* end of element */
478                 eat_spaces(p);
479                 if (*p==';') {
480                         p++;
481                         eat_spaces(p);
482                 }
483         }
484
485         /* resolving default network name - if any*/
486         if (default_net_str) {
487                 for(net_nr=-1,i=0;i<nr_of_networks&&net_nr==-1;i++)
488                         if (!strcasecmp(networks[i].name,default_net_str))
489                                 net_nr = i;
490                 if (net_nr==-1) {
491                         LM_ERR("network \"%s\" not found in net list!\n",default_net_str);
492                         goto error;
493                 }
494                 default_net = net_nr;
495         }
496
497         return 0;
498 parse_error:
499         LM_ERR("SMS %s config: parse error before  chr %d [%.*s]\n",
500                 (step==1)?"modems":(step==2?"networks":"links"),
501                 (int)(p - ((step==1)?modems_config:
502                                    (step==2?networks_config:links_config))),
503                 (*p==0)?4:1,(*p==0)?"NULL":p );
504                                         
505 error:
506         return -1;
507 }
508
509
510
511
512 int global_init(void)
513 {
514         int   i, net_pipe[2], foo;
515         char  *p;
516         struct socket_info* si;
517
518         /* load the TM API */
519         if (load_tm_api(&tmb)!=0) {
520                 LM_ERR("failed to load TM API\n");
521                 goto error;
522         }
523
524         /*fix domain length*/
525         if (domain_str) {
526                 domain.s = domain_str;
527                 domain.len = strlen(domain_str);
528         } else {
529                 si=get_first_socket();
530                 if (si==0){
531                         LM_CRIT("null listen socket list\n");
532                         goto error;
533                 }
534                 /*do I have to add port?*/
535                 i = (si->port_no_str.len && si->port_no!=5060);
536                 domain.len = si->name.len + i*(si->port_no_str.len+1);
537                 domain.s = (char*)pkg_malloc(domain.len);
538                 if (!domain.s) {
539                         LM_ERR("no more pkg memory!\n");
540                         goto error;
541                 }
542                 p = domain.s;
543                 memcpy(p,si->name.s,si->name.len);
544                 p += si->name.len;
545                 if (i) {
546                         *p=':'; p++;
547                         memcpy(p,si->port_no_str.s, si->port_no_str.len);
548                         p += si->port_no_str.len;
549                 }
550         }
551
552         /* creates pipes for networks */
553         for(i=0;i<nr_of_networks;i++)
554         {
555                 /* create the pipe*/
556                 if (pipe(net_pipe)==-1) {
557                         LM_ERR("failed create pipe!\n");
558                         goto error;
559                 }
560                 networks[i].pipe_out = net_pipe[0];
561                 net_pipes_in[i] = net_pipe[1];
562                 /* sets reading from pipe to non blocking */
563                 if ((foo=fcntl(net_pipe[0],F_GETFL,0))<0) {
564                         LM_ERR("failed to get flag for pipe - fcntl\n");
565                         goto error;
566                 }
567                 foo |= O_NONBLOCK;
568                 if (fcntl(net_pipe[0],F_SETFL,foo)<0) {
569                         LM_ERR("failed to set flag for pipe"
570                                 " - fcntl\n");
571                         goto error;
572                 }
573         }
574
575         /* if report will be used, init the report queue */
576         if (sms_report_type!=NO_REPORT && !init_report_queue()) {
577                 LM_ERR("no more share memory!\n");
578                 goto error;
579         }
580
581         /* alloc in shm for queued_msgs */
582         queued_msgs = (int*)shm_malloc(sizeof(int));
583         if (!queued_msgs) {
584                 LM_ERR("no more share memory!\n");
585                 goto error;
586         }
587         *queued_msgs = 0;
588
589         return 1;
590 error:
591         return -1;
592 }
593
594
595
596 void sms_process(int rank)
597 {
598         modem_process(&(modems[rank]));
599         exit(-1);
600 }
601
602
603
604 static int sms_init(void)
605 {
606         if (parse_config_lines()==-1)
607                 return -1;
608         if (global_init()==-1)
609                 return -1;
610         /* update the number of required processes */
611         sms_procs[0].no = nr_of_modems;
612         return 0;
613 }
614
615
616
617
618 static int sms_exit(void)
619 {
620         if ((!domain_str) && (domain.s))
621                 pkg_free(domain.s);
622
623         if (queued_msgs)
624                 shm_free(queued_msgs);
625
626         if (sms_report_type!=NO_REPORT)
627                 destroy_report_queue();
628
629         return 0;
630 }
631
632
633
634
635 static int w_sms_send_msg(struct sip_msg *msg, char *foo, char *bar)
636 {
637         return push_on_network(msg, default_net);
638 }
639
640
641
642
643 static int w_sms_send_msg_to_net(struct sip_msg *msg, char *net_nr, char *foo)
644 {
645         return push_on_network(msg,(unsigned int)(unsigned long)net_nr);
646 }
647