drouting: handle errors in fixup function
[sip-router] / src / modules / drouting / prefix_tree.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2005-2009 Voice Sistem SRL
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  *
22  * History:
23  * ---------
24  *  2005-02-20  first version (cristian)
25  *  2005-02-27  ported to 0.9.0 (bogdan)
26  */
27
28
29 #include <stdlib.h>
30 #include <stdio.h>
31
32 #include "../../core/str.h"
33 #include "../../core/mem/shm_mem.h"
34
35 #include "prefix_tree.h"
36 #include "routing.h"
37 #include "dr_time.h"
38
39 extern int inode;
40 extern int unode;
41
42
43
44 static inline int 
45 check_time(
46                 tmrec_t *time_rec
47                 )
48 {
49         ac_tm_t att;
50
51         /* shortcut: if there is no dstart, timerec is valid */
52         if (time_rec->dtstart==0)
53                 return 1;
54
55         memset( &att, 0, sizeof(att));
56
57         /* set current time */
58         if ( ac_tm_set_time( &att, time(0) ) )
59                 return 0;
60
61         /* does the recv_time match the specified interval?  */
62         if (check_tmrec( time_rec, &att, 0)!=0)
63                 return 0;
64
65         return 1;
66 }
67
68
69 static inline rt_info_t*
70 internal_check_rt(
71                 ptree_node_t *ptn,
72                 unsigned int rgid
73                 )
74 {
75         int i;
76         int rg_pos=0;
77         rg_entry_t* rg=NULL;
78         rt_info_wrp_t* rtlw=NULL;
79
80         if((NULL==ptn) || (NULL==ptn->rg))
81                 return NULL;
82
83         rg_pos = ptn->rg_pos;
84         rg=ptn->rg;
85         for(i=0;(i<rg_pos) && (rg[i].rgid!=rgid);i++);
86         if(i<rg_pos) {
87                 LM_DBG("found rgid %d (rule list %p)\n", 
88                                 rgid, rg[i].rtlw);
89                 rtlw=rg[i].rtlw;
90                 while(rtlw!=NULL) {
91                         if(check_time(rtlw->rtl->time_rec))
92                                 return rtlw->rtl;
93                         rtlw=rtlw->next;
94                 }
95         }
96
97         return NULL;
98 }
99
100
101 rt_info_t* 
102 check_rt(
103         ptree_node_t *ptn,
104         unsigned int rgid
105         )
106 {
107         return internal_check_rt( ptn, rgid);
108 }
109
110
111 rt_info_t*
112 get_prefix(
113         ptree_t *ptree,
114         str* prefix,
115         unsigned int rgid
116         )
117 {
118         rt_info_t *rt = NULL;
119         char *tmp=NULL;
120         int idx=0;
121
122         if(NULL == ptree)
123                 goto err_exit;
124         if(NULL == prefix)
125                 goto err_exit;
126         tmp = prefix->s;
127         /* go the tree down to the last digit in the 
128          * prefix string or down to a leaf */
129         while(tmp< (prefix->s+prefix->len)) {
130                 idx = get_node_index(*tmp);
131                 if (idx == -1){
132                         /* unknown character in the prefix string */
133                         goto err_exit;
134                 }
135                 if( tmp == (prefix->s+prefix->len-1) ) {
136                         /* last digit in the prefix string */
137                         break;
138                 }
139                 if( NULL == ptree->ptnode[idx].next) {
140                         /* this is a leaf */
141                         break;
142                 }
143                 ptree = ptree->ptnode[idx].next;
144                 tmp++;
145         }
146         /* go in the tree up to the root trying to match the prefix */
147         while(ptree !=NULL ) {
148                 /* is it a real node or an intermediate one */
149                 idx = get_node_index(*tmp);
150                 if(idx!=-1 && NULL != ptree->ptnode[idx].rg) {
151                         /* real node; check the constraints on the routing info*/
152                         if( NULL != (rt = internal_check_rt( &(ptree->ptnode[idx]), rgid)))
153                                 break;
154                 }
155                 tmp--;
156                 ptree = ptree->bp;
157         }
158         return rt;
159
160 err_exit:
161         return NULL;
162 }
163
164
165 pgw_t*
166 get_pgw(
167                 pgw_t* pgw_l,
168                 long id
169                 )
170 {
171         if(NULL==pgw_l)
172                 goto err_exit;
173         while(NULL != pgw_l) {
174                 if(id == pgw_l->id) {
175                         return pgw_l;
176                 }
177                 pgw_l = pgw_l->next;
178         }
179 err_exit:
180         return NULL;
181 }
182
183
184 int 
185 add_prefix(
186         ptree_t *ptree,
187         str* prefix,
188         rt_info_t *r,
189         unsigned int rg
190         ) 
191 {
192         char* tmp=NULL;
193         int res = 0;
194         if(NULL==ptree)
195                 goto err_exit;
196         tmp = prefix->s;
197         while(tmp < (prefix->s+prefix->len)) {
198                 if(NULL == tmp)
199                         goto err_exit;
200                 int insert_index = get_node_index(*tmp);
201                 if (insert_index == -1){
202                         /* unknown character in the prefix string */
203                         goto err_exit;
204                 }
205                 if( tmp == (prefix->s+prefix->len-1) ) {
206                         /* last symbol in the prefix string */
207                         
208                         LM_DBG("adding info %p, %d at: "
209                                 "%p (%d)\n", r, rg, &(ptree->ptnode[insert_index]), insert_index);
210                         res = add_rt_info(&(ptree->ptnode[insert_index]), r,rg);
211                         if(res < 0 )
212                                 goto err_exit;
213                         unode++;
214                         res = 1;
215                         goto ok_exit;
216                 }
217                 /* process the current symbol in the prefix */
218                 if(NULL == ptree->ptnode[insert_index].next) {
219                         /* allocate new node */
220                         INIT_PTREE_NODE(ptree, ptree->ptnode[insert_index].next);
221                         inode+=PTREE_CHILDREN;
222 #if 0
223                         printf("new tree node: %p (bp: %p)\n", 
224                                         ptree->ptnode[insert_index].next,
225                                         ptree->ptnode[insert_index].next->bp
226                                         );
227 #endif
228                 }
229                 ptree = ptree->ptnode[insert_index].next;
230                 tmp++; 
231         }
232
233 ok_exit:
234         return 0;
235
236 err_exit:
237         return -1;
238 }
239
240 int 
241 del_tree(
242                 ptree_t* t
243                 )
244 {
245         int i,j;
246         if(NULL == t)
247                 goto exit;
248         /* delete all the children */
249         for(i=0; i< PTREE_CHILDREN; i++) {
250                 /* shm_free the rg array of rt_info */
251                 if(NULL!=t->ptnode[i].rg) {
252                         for(j=0;j<t->ptnode[i].rg_pos;j++) {
253                                 /* if non intermediate delete the routing info */
254                                 if(t->ptnode[i].rg[j].rtlw !=NULL)
255                                         del_rt_list(t->ptnode[i].rg[j].rtlw);
256                         }
257                         shm_free(t->ptnode[i].rg);
258                 }
259                 /* if non leaf delete all the children */
260                 if(t->ptnode[i].next != NULL)
261                         del_tree(t->ptnode[i].next);
262         }
263         shm_free(t);
264 exit:
265         return 0;
266 }
267
268 void
269 del_rt_list(
270                 rt_info_wrp_t *rwl
271                 )
272 {
273         rt_info_wrp_t* t=rwl;
274         while(rwl!=NULL) {
275                 t=rwl;
276                 rwl=rwl->next;
277                 if ( (--t->rtl->ref_cnt)==0)
278                         free_rt_info(t->rtl);
279                 shm_free(t);
280         }
281 }
282
283 void
284 free_rt_info(
285                 rt_info_t *rl
286                 )
287 {
288         if(NULL == rl)
289                 return;
290         if(NULL!=rl->pgwl)
291                 shm_free(rl->pgwl);
292         if(NULL!=rl->time_rec)
293                 tmrec_free(rl->time_rec);
294         shm_free(rl);
295         return;
296 }
297
298 void
299 print_rt(
300                 rt_info_t*rt
301                 )
302 {
303         int i=0;
304         if(NULL==rt)
305                 return;
306         printf("priority:%d list of gw:\n", rt->priority);
307         for(i=0;i<rt->pgwa_len;i++)
308                 if(NULL!=rt->pgwl[i].pgw) 
309                         printf("  id:%ld pri:%.*s ip:%.*s \n",
310                                 rt->pgwl[i].pgw->id, 
311                                 rt->pgwl[i].pgw->pri.len, rt->pgwl[i].pgw->pri.s,
312                                 rt->pgwl[i].pgw->ip.len, rt->pgwl[i].pgw->ip.s);
313 }
314
315
316 int
317 get_node_index(
318                 char ch
319                 )
320 {
321         switch (ch)
322         {
323                 case '0':
324                 case '1':
325                 case '2':
326                 case '3':
327                 case '4':
328                 case '5':
329                 case '6':
330                 case '7':
331                 case '8':
332                 case '9':
333                         return ch - '0';
334                 case '*':
335                         return 10;
336                 case '#':
337                         return 11;
338                 case '+':
339                         return 12;
340         }
341         return -1;
342 }