tmrec: use localtime_r() for a safer multi-thread usage
[sip-router] / src / modules / tmrec / tmrec_mod.c
1 /*
2  * Copyright (C) 2012 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22 /*! \file
23  * \brief The TMREC module
24  * \ingroup tmrec
25  */
26
27 /*! \defgroup tmrec TMREC
28  * This module provides time recurrence matching functions.
29  */
30
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "../../core/sr_module.h"
37 #include "../../core/dprint.h"
38 #include "../../core/ut.h"
39 #include "../../core/pvar.h"
40 #include "../../core/mod_fix.h"
41 #include "../../core/kemi.h"
42 #include "../../core/utils/tmrec.h"
43 #include "period.h"
44
45
46 MODULE_VERSION
47
48 static int  mod_init(void);
49 static int  child_init(int);
50 static void mod_destroy(void);
51
52 static int w_tmrec_match(struct sip_msg* msg, char* rec, char* t);
53 static int fixup_tmrec_match(void** param, int param_no);
54 static int w_is_leap_year(struct sip_msg* msg, char* t, char* p2);
55 static int fixup_is_leap_year(void** param, int param_no);
56 static int fixup_time_period_match(void** param, int param_no);
57 static int w_time_period_match(struct sip_msg* msg, char* period, char* t);
58
59 int tmrec_wday = 0;
60 char tmrec_separator = '|';
61 char *tmrec_separator_param = NULL;
62
63 static cmd_export_t cmds[]={
64         {"tmrec_match", (cmd_function)w_tmrec_match, 1, fixup_tmrec_match,
65                 0, ANY_ROUTE},
66         {"tmrec_match", (cmd_function)w_tmrec_match, 2, fixup_tmrec_match,
67                 0, ANY_ROUTE},
68         {"is_leap_year", (cmd_function)w_is_leap_year, 0, fixup_is_leap_year,
69                 0, ANY_ROUTE},
70         {"is_leap_year", (cmd_function)w_is_leap_year, 1, fixup_is_leap_year,
71                 0, ANY_ROUTE},
72         {"time_period_match", (cmd_function)w_time_period_match, 1, fixup_time_period_match,
73                 0, ANY_ROUTE},
74         {"time_period_match", (cmd_function)w_time_period_match, 2, fixup_time_period_match,
75                 0, ANY_ROUTE},
76         {0, 0, 0, 0, 0, 0}
77 };
78
79 static param_export_t params[]={
80         {"wday",                INT_PARAM,   &tmrec_wday},
81         {"separator",   PARAM_STRING,   &tmrec_separator_param},
82         {0, 0, 0}
83 };
84
85 struct module_exports exports = {
86         "tmrec",
87         DEFAULT_DLFLAGS, /* dlopen flags */
88         cmds,            /* exported functions */
89         params,          /* exported parameters */
90         0,               /* exported rpc functions */
91         0,               /* exported pseudo-variables */
92         0,               /* response function */
93         mod_init,        /* module init function */
94         child_init,      /* per child init function */
95         mod_destroy      /* destroy function */
96 };
97
98
99
100 /**
101  * init module function
102  */
103 static int mod_init(void)
104 {
105         if(tmrec_separator_param!=NULL)
106                 tmrec_separator = tmrec_separator_param[0];
107         return 0;
108 }
109
110 /**
111  * @brief Initialize async module children
112  */
113 static int child_init(int rank)
114 {
115         if (rank!=PROC_MAIN)
116                 return 0;
117
118         return 0;
119 }
120 /**
121  * destroy module function
122  */
123 static void mod_destroy(void)
124 {
125         return;
126 }
127
128 static int w_is_leap_year(struct sip_msg* msg, char* t, char* str2)
129 {
130         time_t tv;
131         struct tm tb;
132         int y;
133
134         if(msg==NULL)
135                 return -1;
136
137         if(t!=NULL)
138         {
139                 if(fixup_get_ivalue(msg, (gparam_t*)t, &y)!=0)
140                 {
141                         LM_ERR("invalid time parameter value\n");
142                         return -1;
143                 }
144         } else {
145                 tv = time(NULL);
146                 localtime_r(&tv, &tb);
147                 y = 1900 + tb.tm_year;
148         }
149
150         if(tr_is_leap_year(y))
151                 return 1;
152         return -1;
153 }
154
155 static int ki_is_leap_year_now(sip_msg_t* msg)
156 {
157         time_t tv;
158         struct tm tb;
159         int y;
160
161         tv = time(NULL);
162         localtime_r(&tv, &tb);
163         y = 1900 + tb.tm_year;
164
165         if(tr_is_leap_year(y))
166                 return 1;
167         return -1;
168 }
169
170 static int ki_is_leap_year(sip_msg_t* msg, int y)
171 {
172         if(tr_is_leap_year(y))
173                 return 1;
174         return -1;
175 }
176
177 static int fixup_is_leap_year(void** param, int param_no)
178 {
179         if(param_no==1)
180                 return fixup_igp_null(param, param_no);
181
182         return 0;
183 }
184
185 static int ki_tmrec_match_timestamp(sip_msg_t* msg, str *rv, int ti)
186 {
187         time_t tv;
188         ac_tm_t act;
189         tmrec_t tmr;
190
191         if(msg==NULL)
192                 return -1;
193
194         if(ti!=0) {
195                 tv = (time_t)ti;
196         } else {
197                 tv = time(NULL);
198         }
199         memset(&act, 0, sizeof(act));
200         memset(&tmr, 0, sizeof(tmr));
201
202         /* parse time recurrence definition */
203         if(tr_parse_recurrence_string(&tmr, rv->s, tmrec_separator)<0)
204                 return -1;
205
206         /* if there is no dstart, timerec is valid */
207         if (tmr.dtstart==0)
208                 goto done;
209
210         /* set current time */
211         if (ac_tm_set_time(&act, tv)<0)
212                 goto error;
213
214         /* match the specified recurence */
215         if (tr_check_recurrence(&tmr, &act, 0)!=0)
216                 goto error;
217
218 done:
219         tmrec_destroy(&tmr);
220         ac_tm_destroy(&act);
221         return 1;
222
223 error:
224         tmrec_destroy(&tmr);
225         ac_tm_destroy(&act);
226         return -1;
227 }
228
229 static int ki_tmrec_match(sip_msg_t* msg, str *rv)
230 {
231         return ki_tmrec_match_timestamp(msg, rv, 0);
232 }
233
234 static int w_tmrec_match(struct sip_msg* msg, char* rec, char* t)
235 {
236         str rv;
237         int ti = 0;
238
239         if(fixup_get_svalue(msg, (gparam_t*)rec, &rv)!=0)
240         {
241                 LM_ERR("invalid time recurrence parameter value\n");
242                 return -1;
243         }
244
245         if(t!=NULL)
246         {
247                 if(fixup_get_ivalue(msg, (gparam_t*)t, &ti)!=0)
248                 {
249                         LM_ERR("invalid time stamp parameter value\n");
250                         return -1;
251                 }
252         }
253
254         return ki_tmrec_match_timestamp(msg, &rv, ti);
255 }
256
257 static int fixup_tmrec_match(void** param, int param_no)
258 {
259         if(param_no==1)
260         {
261                 if(fixup_spve_null(param, 1)<0)
262                         return -1;
263                 return 0;
264         } else if(param_no==2) {
265                 if(fixup_igp_null(param, 1)<0)
266                         return -1;
267         }
268         return 0;
269 }
270
271 static int fixup_time_period_match(void** param, int param_no)
272 {
273         if(param_no==1)
274         {
275                 if(fixup_spve_null(param, 1)<0)
276                         return -1;
277                 return 0;
278         } else if(param_no==2) {
279                 if(fixup_igp_null(param, 1)<0)
280                         return -1;
281         }
282         return 0;
283 }
284
285 static int w_time_period_match(struct sip_msg* msg, char* period, char* t)
286 {
287         str rv;
288         time_t tv;
289         int ti;
290
291         if(msg==NULL)
292                 return -2;
293
294         if(fixup_get_svalue(msg, (gparam_t*)period, &rv)!=0)
295         {
296                 LM_ERR("invalid period parameter value\n");
297                 return -3;
298         }
299
300         if(t!=NULL)
301         {
302                 if(fixup_get_ivalue(msg, (gparam_t*)t, &ti)!=0)
303                 {
304                         LM_ERR("invalid time stamp parameter value\n");
305                         return -4;
306                 }
307                 tv = (time_t)ti;
308         } else {
309                 tv = time(NULL);
310         }
311
312         if (in_period(tv, rv.s))
313                 return 1;
314         return -1;
315 }
316
317 static int ki_time_period_match_timestamp(sip_msg_t* msg, str* period, int ti)
318 {
319         time_t tv;
320
321         if(ti!=0) {
322                 tv = (time_t)ti;
323         } else {
324                 tv = time(NULL);
325         }
326         if (in_period(tv, period->s))
327                 return 1;
328         return -1;
329 }
330
331 static int ki_time_period_match(sip_msg_t* msg, str* period)
332 {
333         return ki_time_period_match_timestamp(msg, period, 0);
334 }
335
336 /**
337  *
338  */
339 /* clang-format off */
340 static sr_kemi_t sr_kemi_tmrec_exports[] = {
341         { str_init("tmrec"), str_init("is_leap_year_now"),
342                 SR_KEMIP_INT, ki_is_leap_year_now,
343                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
344                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
345         },
346         { str_init("tmrec"), str_init("is_leap_year"),
347                 SR_KEMIP_INT, ki_is_leap_year,
348                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
349                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
350         },
351         { str_init("tmrec"), str_init("match"),
352                 SR_KEMIP_INT, ki_tmrec_match,
353                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
354                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
355         },
356         { str_init("tmrec"), str_init("match_timestamp"),
357                 SR_KEMIP_INT, ki_tmrec_match_timestamp,
358                 { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
359                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
360         },
361         { str_init("tmrec"), str_init("time_period_match"),
362                 SR_KEMIP_INT, ki_time_period_match,
363                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
364                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
365         },
366         { str_init("tmrec"), str_init("time_period_match_timestamp"),
367                 SR_KEMIP_INT, ki_time_period_match_timestamp,
368                 { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
369                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
370         },
371
372         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
373 };
374 /* clang-format on */
375
376 int mod_register(char *path, int *dlflags, void *p1, void *p2)
377 {
378         sr_kemi_modules_add(sr_kemi_tmrec_exports);
379         return 0;
380 }