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