modules_s/timer/timer.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2006 iptelorg GmbH
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * For a license to use the ser software under conditions
00014  * other than those described here, or to purchase support for this
00015  * software, please contact iptel.org by e-mail at the following addresses:
00016  *    info@iptel.org
00017  *
00018  * ser is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  */
00027 
00028 
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <ctype.h>
00033 #include "../../timer.h"
00034 #include "../../timer_ticks.h"
00035 #include "../../route.h"
00036 #include "../../sr_module.h"
00037 #include "../../mem/mem.h"
00038 #include "../../mem/shm_mem.h"
00039 #include "../../str.h"
00040 #include "../../error.h"
00041 #include "../../config.h"
00042 #include "../../trim.h"
00043 #include "../../select.h"
00044 #include "../../ut.h"
00045 #include "../../select_buf.h"
00046 
00047 #include "../../receive.h"
00048 #include "../../ip_addr.h"
00049 
00050 #include "../../receive.h"
00051 #include "../../globals.h"
00052 #include "../../route.h"
00053 #include "../../parser/msg_parser.h"
00054 #include "../../action.h"
00055 #include "../../script_cb.h"
00056 #include "../../dset.h"
00057 #include "../../usr_avp.h"
00058 
00059 
00060 MODULE_VERSION
00061 
00062 #define MODULE_NAME "timer"
00063 
00064 struct timer_action {
00065         char *timer_name;
00066         int route_no;
00067         int interval;
00068         int enable_on_start;
00069         int disable_itself;
00070         unsigned short flags; /* slow / fast */
00071         struct timer_ln *link;
00072 
00073         struct timer_action* next;
00074 };
00075 
00076 /* list of all operations */
00077 static struct timer_action* timer_actions = 0;
00078 static struct timer_action* pkg_timer_actions = 0;
00079 static struct receive_info rcv_info;
00080 static struct timer_action* timer_executed = 0;
00081 
00082 #define eat_spaces(_p) \
00083         while( *(_p)==' ' || *(_p)=='\t' ){\
00084         (_p)++;}
00085 
00086 #define eat_alphanum(_p) \
00087         while ( (*(_p) >= 'a' && *(_p) <= 'z') || (*(_p) >= 'A' && *(_p) <= 'Z') || (*(_p) >= '0' && *(_p) <= '9') || (*(_p) == '_') ) {\
00088                 (_p)++;\
00089         }
00090 
00091 static struct timer_action* find_action_by_name(struct timer_action* timer_actions, char *name, int len) {
00092         struct timer_action *a;
00093         if (len == -1) len = strlen(name);
00094         for (a=timer_actions; a; a = a->next) {         
00095                 if (a->timer_name && strlen(a->timer_name)==len && strncmp(name, a->timer_name, len) == 0)
00096                         return a;
00097         }
00098         return NULL;
00099 }
00100 
00101 static int sel_root(str* res, select_t* s, struct sip_msg* msg) {  /* dummy */
00102         return 0;
00103 }
00104 
00105 static int sel_timer(str* res, select_t* s, struct sip_msg* msg) {
00106         struct timer_action* a;
00107         if (!msg) { /* select fixup */
00108                 a = find_action_by_name(timer_actions /* called after mod_init */, s->params[2].v.s.s, s->params[2].v.s.len);
00109                 if (!a) {
00110                         ERR(MODULE_NAME": timer_enable_fixup: timer '%.*s' not declared\n", s->params[2].v.s.len, s->params[2].v.s.s);
00111                         return E_CFG;
00112                 }
00113                 s->params[2].v.p = a;
00114         }
00115         return 0;
00116 }
00117 
00118 static int sel_enabled(str* res, select_t* s, struct sip_msg* msg) {
00119         static char buf[2] = "01";
00120         if (!msg) return sel_timer(res, s, msg);
00121         res->len = 1;
00122         res->s = &buf[(((struct timer_action*) s->params[2].v.p)->link->flags & F_TIMER_ACTIVE) != 0];
00123         return 0;
00124 }
00125 
00126 static int sel_executed(str* res, select_t* s, struct sip_msg* msg) {
00127         if (!timer_executed) return 1;
00128         res->s = timer_executed->timer_name;
00129         res->len = strlen(res->s);
00130         return 0;
00131 }
00132 
00133 select_row_t sel_declaration[] = {
00134         { NULL, SEL_PARAM_STR, STR_STATIC_INIT(MODULE_NAME), sel_root, SEL_PARAM_EXPECTED},
00135         { sel_root, SEL_PARAM_STR, STR_STATIC_INIT("timer"), sel_timer, SEL_PARAM_EXPECTED|CONSUME_NEXT_STR|FIXUP_CALL},
00136         { sel_timer, SEL_PARAM_STR, STR_STATIC_INIT("enabled"), sel_enabled, 0},
00137         { sel_root, SEL_PARAM_STR, STR_STATIC_INIT("executed"), sel_executed, 0},
00138         
00139         { NULL, SEL_PARAM_STR, STR_NULL, NULL, 0}
00140 };
00141 
00142 static unsigned int timer_msg_no = 0;
00143 
00144 static ticks_t timer_handler(ticks_t ticks, struct timer_ln* tl, void* data) {
00145         /*?min length of first line of message is 16 char!?*/
00146         #define MSG "GET /timer HTTP/0.9\n\n"
00147         struct sip_msg* msg;
00148         struct timer_action *a;
00149         struct run_act_ctx ra_ctx;
00150 
00151         a = data;
00152         if (!a->disable_itself) {
00153 
00154                 DEBUG(MODULE_NAME": handler: called at %d ticks, timer: '%s', pid:%d\n", ticks, a->timer_name, getpid());
00155 
00156                 if (a->route_no >= main_rt.idx) {
00157                         BUG(MODULE_NAME": invalid routing table number #%d of %d\n", a->route_no, main_rt.idx);
00158                         goto err2;
00159                 }
00160                 if (!main_rt.rlist[a->route_no]) {
00161                         WARN(MODULE_NAME": route not declared (hash:%d)\n", a->route_no);
00162                         goto err2;
00163                 }
00164                 msg=pkg_malloc(sizeof(struct sip_msg));
00165                 if (msg==0) {
00166                         ERR(MODULE_NAME": handler: no mem for sip_msg\n");
00167                         goto err2;
00168                 }
00169                 timer_msg_no++;
00170                 memset(msg, 0, sizeof(struct sip_msg)); /* init everything to 0 */
00171 
00172                 msg->buf=MSG;
00173                 msg->len=sizeof(MSG)-1;
00174 
00175                 msg->rcv= rcv_info;
00176                 msg->id=timer_msg_no;
00177                 msg->set_global_address=default_global_address;
00178                 msg->set_global_port=default_global_port;
00179 
00180                 if (parse_msg(msg->buf, msg->len, msg)!=0){
00181                         ERR(MODULE_NAME": handler: parse_msg failed\n");
00182                         goto err;
00183                 }
00184                 /* ... clear branches from previous message */
00185                 clear_branches();
00186                 reset_static_buffer();
00187                 if (exec_pre_script_cb(msg, REQUEST_CB_TYPE)==0 )
00188                         goto end; /* drop the request */
00189                 /* exec the routing script */
00190                 timer_executed = a;
00191                 init_run_actions_ctx(&ra_ctx);
00192                 run_actions(&ra_ctx, main_rt.rlist[a->route_no], msg);
00193                 timer_executed = 0;
00194                 /* execute post request-script callbacks */
00195                 exec_post_script_cb(msg, REQUEST_CB_TYPE);
00196         end:
00197                 reset_avps();
00198                 DEBUG(MODULE_NAME": handler: cleaning up\n");
00199         err:
00200                 free_sip_msg(msg);
00201                 pkg_free(msg);
00202         err2:   ;
00203         }
00204         /* begin critical section */
00205         if (a->disable_itself) {
00206 
00207                 timer_allow_del();
00208                 timer_del(a->link);
00209                 timer_reinit(a->link);
00210                 a->disable_itself = 0;
00211                 /* end critical section */
00212                 return 0;   /* do no call more */
00213         }
00214         else
00215                 return (ticks_t)(-1); /* periodical */
00216 }
00217 
00218 static int timer_enable_fixup(void** param, int param_no) {
00219         struct timer_action* a;
00220         int /*res, */n;
00221         switch (param_no) {
00222                 case 1:
00223                         a = find_action_by_name(timer_actions /* called after mod_init*/, (char*) *param, -1);
00224                         if (!a) {
00225                                 ERR(MODULE_NAME": timer_enable_fixup: timer '%s' not declared\n", (char*) *param);
00226                                 return E_CFG;
00227                         }
00228                         *param = a;
00229                         break;
00230                 case 2:
00231                 /*      res = fixup_int_12(param, param_no);
00232                         if (res < 0) return res; */
00233                         n=atoi((char *)*param);
00234                         *param = (void*)(long)(/*(int) *param*/n != 0);
00235                         break;
00236                 default: ;
00237         }
00238         return 0;
00239 }
00240 
00241 static int timer_enable_func(struct sip_msg* m, char* timer_act, char* enable) {
00242         struct timer_action* a;
00243         int en;
00244         a = (void*) timer_act;
00245         en = (int)(long) enable;
00246         /* timer is not deleted immediately but is removed from handler by itself because timer_del may be slow blocking procedure
00247          * Disable and enable in sequence may be tricky
00248          */
00249         /* begin critical section */
00250         if ((a->link->flags & F_TIMER_ACTIVE) == 0) {
00251                 if (en) {
00252                         timer_reinit(a->link);
00253                         timer_add(a->link, MS_TO_TICKS(a->interval));
00254                         a->disable_itself = 0;
00255                 }
00256         }
00257         else {
00258                 if (en && a->disable_itself) {
00259                         a->disable_itself = 0;  /* it's not 100% reliable! */
00260                 }
00261                 else if (!en) {
00262                         a->disable_itself++;
00263                 }
00264         }
00265         /* end critical section */
00266         return 1;
00267 }
00268 
00269 static int get_next_part(char** s, str* part, char delim) {
00270         char *c, *c2;
00271         c = c2 = *s;
00272         eat_spaces(c);
00273         while (*c2!=delim && *c2!=0) c2++;
00274 
00275         if (*c2) {
00276                 *s = c2+1;
00277         }
00278         else {
00279                 *s = c2;
00280         }
00281         eat_spaces(*s);
00282         c2--;
00283         /* rtrim */
00284         while ( c2 >= c && ((*c2 == ' ')||(*c2 == '\t')) ) c2--;
00285         part->s = c;
00286         part->len = c2-c+1;
00287         return part->len;
00288 }
00289 
00290 /* timer_id=route_no,interval_ms[,"slow"|"fast"[,"enable"]] */
00291 static int declare_timer(modparam_t type, char* param) {
00292         int n;
00293         unsigned int route_no, interval, enabled, flags;
00294         struct timer_action *pa;
00295         char *p, *save_p, c, *timer_name;
00296         str s;
00297 
00298         timer_name = 0;
00299         save_p = p = param;
00300         eat_alphanum(p);
00301         if (*p != '=' || p == save_p) goto err;
00302         *p = '\0';
00303         timer_name = save_p;
00304         p++;
00305         if (find_action_by_name(pkg_timer_actions, timer_name, -1) != NULL) {
00306                 ERR(MODULE_NAME": declare_timer: timer '%s' already exists\n", timer_name);
00307                 return E_CFG;
00308         }
00309 
00310         save_p = p;
00311         if (!get_next_part(&p, &s, ',')) goto err;
00312 
00313         c = s.s[s.len];
00314         s.s[s.len] = '\0';
00315         n = route_get(&main_rt, s.s);
00316         s.s[s.len] = c;
00317         if (n == -1) goto err;
00318         route_no = n;
00319 
00320         save_p = p;
00321         if (!get_next_part(&p, &s, ',')) goto err;
00322         if (str2int(&s, &interval) < 0) goto err;
00323 
00324         save_p = p;
00325         flags = 0;
00326         if (get_next_part(&p, &s, ',')) {
00327                 if (s.len == 4 && strncasecmp(s.s, "FAST", 4)==0)
00328                         flags = F_TIMER_FAST;
00329                 else if (s.len == 4 && strncasecmp(s.s, "SLOW", 4)==0)
00330                         ;
00331                 else goto err;
00332         }
00333 
00334         save_p = p;
00335         enabled = 0;
00336         if (get_next_part(&p, &s, ',')) {
00337                 if (s.len == 6 && strncasecmp(s.s, "ENABLE", 6)==0)
00338                         enabled = 1;
00339                 else goto err;
00340         }
00341 
00342         
00343         pa = pkg_malloc(sizeof(*pa));   /* cannot use shmmem here! */
00344         if (!pa) {
00345                 ERR(MODULE_NAME": cannot allocate timer data\n");
00346                 return E_OUT_OF_MEM;
00347         }
00348         memset(pa, 0, sizeof(*pa));
00349         pa->timer_name = timer_name;
00350         pa->route_no = route_no;
00351         pa->interval = interval;
00352         pa->enable_on_start = enabled;
00353         pa->flags = flags;
00354         pa->next = pkg_timer_actions;
00355         pkg_timer_actions = pa;
00356 
00357         return 0;
00358 err:
00359         ERR(MODULE_NAME": declare_timer: timer_name: '%s', error near '%s'\n", timer_name, save_p);
00360         return E_CFG;
00361 }
00362 
00363 static int mod_init() {
00364         struct timer_action *a, **pa;
00365 
00366         DEBUG(MODULE_NAME": init: initializing, pid=%d\n", getpid());
00367 
00368         /* copy from pkg to shm memory */
00369         for (pa=&timer_actions; pkg_timer_actions; pa=&(*pa)->next) {
00370                 a = pkg_timer_actions;
00371                 *pa = shm_malloc(sizeof(**pa));
00372                 if (!*pa) {
00373                         ERR(MODULE_NAME": cannot allocate timer data\n");
00374                         return E_OUT_OF_MEM;
00375                 }
00376                 memcpy(*pa, a, sizeof(**pa));
00377                 (*pa)->next = 0;
00378                 pkg_timer_actions = a->next;
00379                 pkg_free(a);
00380         }
00381 
00382         for (a=timer_actions; a; a=a->next) {
00383                 a->link = timer_alloc();
00384                 if (!a->link) {
00385                         ERR(MODULE_NAME": init: cannot allocate timer\n");
00386                         return E_OUT_OF_MEM;
00387                 }
00388                 timer_init(a->link, timer_handler, a, a->flags);
00389                 if (!a->link) {
00390                         ERR(MODULE_NAME": init: cannot initialize timer\n");
00391                         return E_CFG;
00392                 }
00393         }
00394 
00395         memset(&rcv_info, 0, sizeof(rcv_info));
00396         register_select_table(sel_declaration);
00397         return 0;
00398 }
00399 
00400 static int child_init(int rank) {
00401         struct timer_action* a;
00402         /* may I start timer in mod_init ?? */
00403         if (rank!=PROC_TIMER) return 0;
00404         for (a=timer_actions; a; a=a->next) {
00405                 if (a->enable_on_start) {
00406                         timer_add(a->link, MS_TO_TICKS(a->interval));
00407                 }
00408         }
00409         return 0;
00410 }
00411 
00412 static void destroy_mod(void) {
00413         struct timer_action* a;
00414         DEBUG(MODULE_NAME": destroy: destroying, pid=%d\n", getpid());
00415         while (timer_actions) {
00416                 a = timer_actions;
00417                 if (a->link) {
00418                         timer_del(a->link);
00419                         timer_free(a->link);
00420                 }
00421                 timer_actions = a->next;
00422                 shm_free(a);
00423         }
00424 }
00425 
00426 /*
00427  * Exported functions
00428  */
00429 static cmd_export_t cmds[] = {
00430         {MODULE_NAME"_enable", timer_enable_func, 2, timer_enable_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
00431         {0, 0, 0, 0, 0}
00432 };
00433 
00434 /*
00435  * Exported parameters
00436  */
00437 static param_export_t params[] = {
00438         {"declare_timer", PARAM_STRING|PARAM_USE_FUNC, (void*) declare_timer},
00439         {0, 0, 0}
00440 };
00441 
00442 
00443 struct module_exports exports = {
00444         MODULE_NAME,
00445         cmds,        /* Exported commands */
00446         0,           /* RPC */
00447         params,      /* Exported parameters */
00448         mod_init,    /* module initialization function */
00449         0,           /* response function*/
00450         destroy_mod, /* destroy function */
00451         0,           /* oncancel function */
00452         child_init   /* per-child init function */
00453 };