1d34001a20c89f1f36a4cd879b5d482a514153d7
[sip-router] / modules_s / timer / timer.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2006 iptelorg GmbH
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser 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  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27
28
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include "../../timer.h"
34 #include "../../timer_ticks.h"
35 #include "../../route.h"
36 #include "../../sr_module.h"
37 #include "../../mem/mem.h"
38 #include "../../mem/shm_mem.h"
39 #include "../../str.h"
40 #include "../../error.h"
41 #include "../../config.h"
42 #include "../../trim.h"
43 #include "../../select.h"
44 #include "../../ut.h"
45 #include "../../select_buf.h"
46
47 #include "../../receive.h"
48 #include "../../ip_addr.h"
49
50 #include "../../receive.h"
51 #include "../../globals.h"
52 #include "../../route.h"
53 #include "../../parser/msg_parser.h"
54 #include "../../action.h"
55 #include "../../script_cb.h"
56 #include "../../dset.h"
57 #include "../../usr_avp.h"
58
59
60 MODULE_VERSION
61
62 #define MODULE_NAME "timer"
63
64 struct timer_action {
65         char *timer_name;
66         int route_no;
67         int interval;
68         int enable_on_start;
69         int disable_itself;
70         unsigned short flags; /* slow / fast */
71         struct timer_ln *link;
72
73         struct timer_action* next;
74 };
75
76 /* list of all operations */
77 static struct timer_action* timer_actions = 0;
78 static struct timer_action* pkg_timer_actions = 0;
79 static struct receive_info rcv_info;
80 static struct timer_action* timer_executed = 0;
81
82 #define eat_spaces(_p) \
83         while( *(_p)==' ' || *(_p)=='\t' ){\
84         (_p)++;}
85
86 #define eat_alphanum(_p) \
87         while ( (*(_p) >= 'a' && *(_p) <= 'z') || (*(_p) >= 'A' && *(_p) <= 'Z') || (*(_p) >= '0' && *(_p) <= '9') || (*(_p) == '_') ) {\
88                 (_p)++;\
89         }
90
91 static struct timer_action* find_action_by_name(struct timer_action* timer_actions, char *name, int len) {
92         struct timer_action *a;
93         if (len == -1) len = strlen(name);
94         for (a=timer_actions; a; a = a->next) {         
95                 if (a->timer_name && strlen(a->timer_name)==len && strncmp(name, a->timer_name, len) == 0)
96                         return a;
97         }
98         return NULL;
99 }
100
101 static int sel_root(str* res, select_t* s, struct sip_msg* msg) {  /* dummy */
102         return 0;
103 }
104
105 static int sel_timer(str* res, select_t* s, struct sip_msg* msg) {
106         struct timer_action* a;
107         if (!msg) { /* select fixup */
108                 a = find_action_by_name(timer_actions /* called after mod_init */, s->params[2].v.s.s, s->params[2].v.s.len);
109                 if (!a) {
110                         ERR(MODULE_NAME": timer_enable_fixup: timer '%.*s' not declared\n", s->params[2].v.s.len, s->params[2].v.s.s);
111                         return E_CFG;
112                 }
113                 s->params[2].v.p = a;
114         }
115         return 0;
116 }
117
118 static int sel_enabled(str* res, select_t* s, struct sip_msg* msg) {
119         static char buf[2] = "01";
120         if (!msg) return sel_timer(res, s, msg);
121         res->len = 1;
122         res->s = &buf[(((struct timer_action*) s->params[2].v.p)->link->flags & F_TIMER_ACTIVE) != 0];
123         return 0;
124 }
125
126 static int sel_executed(str* res, select_t* s, struct sip_msg* msg) {
127         if (!timer_executed) return 1;
128         res->s = timer_executed->timer_name;
129         res->len = strlen(res->s);
130         return 0;
131 }
132
133 select_row_t sel_declaration[] = {
134         { NULL, SEL_PARAM_STR, STR_STATIC_INIT(MODULE_NAME), sel_root, SEL_PARAM_EXPECTED},
135         { sel_root, SEL_PARAM_STR, STR_STATIC_INIT("timer"), sel_timer, SEL_PARAM_EXPECTED|CONSUME_NEXT_STR|FIXUP_CALL},
136         { sel_timer, SEL_PARAM_STR, STR_STATIC_INIT("enabled"), sel_enabled, 0},
137         { sel_root, SEL_PARAM_STR, STR_STATIC_INIT("executed"), sel_executed, 0},
138         
139         { NULL, SEL_PARAM_STR, STR_NULL, NULL, 0}
140 };
141
142 static unsigned int timer_msg_no = 0;
143
144 static ticks_t timer_handler(ticks_t ticks, struct timer_ln* tl, void* data) {
145         /*?min length of first line of message is 16 char!?*/
146         #define MSG "GET /timer HTTP/0.9\n\n"
147         struct sip_msg* msg;
148         struct timer_action *a;
149         struct run_act_ctx ra_ctx;
150
151         a = data;
152         if (!a->disable_itself) {
153
154                 DEBUG(MODULE_NAME": handler: called at %d ticks, timer: '%s', pid:%d\n", ticks, a->timer_name, getpid());
155
156                 if (a->route_no >= main_rt.idx) {
157                         BUG(MODULE_NAME": invalid routing table number #%d of %d\n", a->route_no, main_rt.idx);
158                         goto err2;
159                 }
160                 if (!main_rt.rlist[a->route_no]) {
161                         WARN(MODULE_NAME": route not declared (hash:%d)\n", a->route_no);
162                         goto err2;
163                 }
164                 msg=pkg_malloc(sizeof(struct sip_msg));
165                 if (msg==0) {
166                         ERR(MODULE_NAME": handler: no mem for sip_msg\n");
167                         goto err2;
168                 }
169                 timer_msg_no++;
170                 memset(msg, 0, sizeof(struct sip_msg)); /* init everything to 0 */
171
172                 msg->buf=MSG;
173                 msg->len=sizeof(MSG)-1;
174
175                 msg->rcv= rcv_info;
176                 msg->id=timer_msg_no;
177                 msg->set_global_address=default_global_address;
178                 msg->set_global_port=default_global_port;
179
180                 if (parse_msg(msg->buf, msg->len, msg)!=0){
181                         ERR(MODULE_NAME": handler: parse_msg failed\n");
182                         goto err;
183                 }
184                 /* ... clear branches from previous message */
185                 clear_branches();
186                 reset_static_buffer();
187                 if (exec_pre_script_cb(msg, REQUEST_CB_TYPE)==0 )
188                         goto end; /* drop the request */
189                 /* exec the routing script */
190                 timer_executed = a;
191                 init_run_actions_ctx(&ra_ctx);
192                 run_actions(&ra_ctx, main_rt.rlist[a->route_no], msg);
193                 timer_executed = 0;
194                 /* execute post request-script callbacks */
195                 exec_post_script_cb(msg, REQUEST_CB_TYPE);
196         end:
197                 reset_avps();
198                 DEBUG(MODULE_NAME": handler: cleaning up\n");
199         err:
200                 free_sip_msg(msg);
201                 pkg_free(msg);
202         err2:   ;
203         }
204         /* begin critical section */
205         if (a->disable_itself) {
206
207                 timer_allow_del(a->link);
208                 timer_del(a->link);
209                 timer_reinit(a->link);
210                 a->disable_itself = 0;
211                 /* end critical section */
212                 return 0;   /* do no call more */
213         }
214         else
215                 return (ticks_t)(-1); /* periodical */
216 }
217
218 static int timer_enable_fixup(void** param, int param_no) {
219         struct timer_action* a;
220         int /*res, */n;
221         switch (param_no) {
222                 case 1:
223                         a = find_action_by_name(timer_actions /* called after mod_init*/, (char*) *param, -1);
224                         if (!a) {
225                                 ERR(MODULE_NAME": timer_enable_fixup: timer '%s' not declared\n", (char*) *param);
226                                 return E_CFG;
227                         }
228                         *param = a;
229                         break;
230                 case 2:
231                 /*      res = fixup_int_12(param, param_no);
232                         if (res < 0) return res; */
233                         n=atoi((char *)*param);
234                         *param = (void*)(long)(/*(int) *param*/n != 0);
235                         break;
236                 default: ;
237         }
238         return 0;
239 }
240
241 static int timer_enable_func(struct sip_msg* m, char* timer_act, char* enable) {
242         struct timer_action* a;
243         int en;
244         a = (void*) timer_act;
245         en = (int)(long) enable;
246         /* timer is not deleted immediately but is removed from handler by itself because timer_del may be slow blocking procedure
247          * Disable and enable in sequence may be tricky
248          */
249         /* begin critical section */
250         if ((a->link->flags & F_TIMER_ACTIVE) == 0) {
251                 if (en) {
252                         timer_reinit(a->link);
253                         timer_add(a->link, MS_TO_TICKS(a->interval));
254                         a->disable_itself = 0;
255                 }
256         }
257         else {
258                 if (en && a->disable_itself) {
259                         a->disable_itself = 0;  /* it's not 100% reliable! */
260                 }
261                 else if (!en) {
262                         a->disable_itself++;
263                 }
264         }
265         /* end critical section */
266         return 1;
267 }
268
269 static int get_next_part(char** s, str* part, char delim) {
270         char *c, *c2;
271         c = c2 = *s;
272         eat_spaces(c);
273         while (*c2!=delim && *c2!=0) c2++;
274
275         if (*c2) {
276                 *s = c2+1;
277         }
278         else {
279                 *s = c2;
280         }
281         eat_spaces(*s);
282         c2--;
283         /* rtrim */
284         while ( c2 >= c && ((*c2 == ' ')||(*c2 == '\t')) ) c2--;
285         part->s = c;
286         part->len = c2-c+1;
287         return part->len;
288 }
289
290 /* timer_id=route_no,interval_ms[,"slow"|"fast"[,"enable"]] */
291 static int declare_timer(modparam_t type, char* param) {
292         int n;
293         unsigned int route_no, interval, enabled, flags;
294         struct timer_action *pa;
295         char *p, *save_p, c, *timer_name;
296         str s;
297
298         timer_name = 0;
299         save_p = p = param;
300         eat_alphanum(p);
301         if (*p != '=' || p == save_p) goto err;
302         *p = '\0';
303         timer_name = save_p;
304         p++;
305         if (find_action_by_name(pkg_timer_actions, timer_name, -1) != NULL) {
306                 ERR(MODULE_NAME": declare_timer: timer '%s' already exists\n", timer_name);
307                 return E_CFG;
308         }
309
310         save_p = p;
311         if (!get_next_part(&p, &s, ',')) goto err;
312
313         c = s.s[s.len];
314         s.s[s.len] = '\0';
315         n = route_get(&main_rt, s.s);
316         s.s[s.len] = c;
317         if (n == -1) goto err;
318         route_no = n;
319
320         save_p = p;
321         if (!get_next_part(&p, &s, ',')) goto err;
322         if (str2int(&s, &interval) < 0) goto err;
323
324         save_p = p;
325         flags = 0;
326         if (get_next_part(&p, &s, ',')) {
327                 if (s.len == 4 && strncasecmp(s.s, "FAST", 4)==0)
328                         flags = F_TIMER_FAST;
329                 else if (s.len == 4 && strncasecmp(s.s, "SLOW", 4)==0)
330                         ;
331                 else goto err;
332         }
333
334         save_p = p;
335         enabled = 0;
336         if (get_next_part(&p, &s, ',')) {
337                 if (s.len == 6 && strncasecmp(s.s, "ENABLE", 6)==0)
338                         enabled = 1;
339                 else goto err;
340         }
341
342         
343         pa = pkg_malloc(sizeof(*pa));   /* cannot use shmmem here! */
344         if (!pa) {
345                 ERR(MODULE_NAME": cannot allocate timer data\n");
346                 return E_OUT_OF_MEM;
347         }
348         memset(pa, 0, sizeof(*pa));
349         pa->timer_name = timer_name;
350         pa->route_no = route_no;
351         pa->interval = interval;
352         pa->enable_on_start = enabled;
353         pa->flags = flags;
354         pa->next = pkg_timer_actions;
355         pkg_timer_actions = pa;
356
357         return 0;
358 err:
359         ERR(MODULE_NAME": declare_timer: timer_name: '%s', error near '%s'\n", timer_name, save_p);
360         return E_CFG;
361 }
362
363 static int mod_init() {
364         struct timer_action *a, **pa;
365
366         DEBUG(MODULE_NAME": init: initializing, pid=%d\n", getpid());
367
368         /* copy from pkg to shm memory */
369         for (pa=&timer_actions; pkg_timer_actions; pa=&(*pa)->next) {
370                 a = pkg_timer_actions;
371                 *pa = shm_malloc(sizeof(**pa));
372                 if (!*pa) {
373                         ERR(MODULE_NAME": cannot allocate timer data\n");
374                         return E_OUT_OF_MEM;
375                 }
376                 memcpy(*pa, a, sizeof(**pa));
377                 (*pa)->next = 0;
378                 pkg_timer_actions = a->next;
379                 pkg_free(a);
380         }
381
382         for (a=timer_actions; a; a=a->next) {
383                 a->link = timer_alloc();
384                 if (!a->link) {
385                         ERR(MODULE_NAME": init: cannot allocate timer\n");
386                         return E_OUT_OF_MEM;
387                 }
388                 timer_init(a->link, timer_handler, a, a->flags);
389                 if (!a->link) {
390                         ERR(MODULE_NAME": init: cannot initialize timer\n");
391                         return E_CFG;
392                 }
393         }
394
395         memset(&rcv_info, 0, sizeof(rcv_info));
396         register_select_table(sel_declaration);
397         return 0;
398 }
399
400 static int child_init(int rank) {
401         struct timer_action* a;
402         /* may I start timer in mod_init ?? */
403         if (rank!=PROC_TIMER) return 0;
404         for (a=timer_actions; a; a=a->next) {
405                 if (a->enable_on_start) {
406                         timer_add(a->link, MS_TO_TICKS(a->interval));
407                 }
408         }
409         return 0;
410 }
411
412 static void destroy_mod(void) {
413         struct timer_action* a;
414         DEBUG(MODULE_NAME": destroy: destroying, pid=%d\n", getpid());
415         while (timer_actions) {
416                 a = timer_actions;
417                 if (a->link) {
418                         timer_del(a->link);
419                         timer_free(a->link);
420                 }
421                 timer_actions = a->next;
422                 shm_free(a);
423         }
424 }
425
426 /*
427  * Exported functions
428  */
429 static cmd_export_t cmds[] = {
430         {MODULE_NAME"_enable", timer_enable_func, 2, timer_enable_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
431         {0, 0, 0, 0, 0}
432 };
433
434 /*
435  * Exported parameters
436  */
437 static param_export_t params[] = {
438         {"declare_timer", PARAM_STRING|PARAM_USE_FUNC, (void*) declare_timer},
439         {0, 0, 0}
440 };
441
442
443 struct module_exports exports = {
444         MODULE_NAME,
445         cmds,        /* Exported commands */
446         0,           /* RPC */
447         params,      /* Exported parameters */
448         mod_init,    /* module initialization function */
449         0,           /* response function*/
450         destroy_mod, /* destroy function */
451         0,           /* oncancel function */
452         child_init   /* per-child init function */
453 };