all: updated FSF address in GPL text
[sip-router] / modules / carrierroute / cr_domain.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2007-2008 1&1 Internet AG
5  *
6  * This file is part of SIP-router, a free SIP server.
7  *
8  * SIP-router 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  * SIP-router 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
23 /**
24  * \file cr_domain.c
25  * \brief Contains the functions to manage routing domains.
26  * \ingroup carrierroute
27  * - Module; \ref carrierroute
28  */
29
30 #include <stdlib.h>
31 #include "../../mem/shm_mem.h"
32 #include "../../ut.h"
33 #include "cr_domain.h"
34 #include "cr_rule.h"
35 #include "carrierroute.h"
36
37
38 /**
39  * Destroys route_flags list in shared memory by freing all its memory.
40  *
41  * @param data the start of the route_flags list to be destroyed
42  */
43 static void destroy_route_flags_list(void *data) {
44         struct route_flags *rf, *rf_tmp;
45
46         rf=(struct route_flags *)(data);
47         while (rf!=NULL) {
48                 rf_tmp = rf->next;
49                 destroy_route_flags(rf);
50                 rf = rf_tmp;
51         }
52 }
53
54
55 /**
56  * Destroys failure_route_rule list in shared memory by freing all its memory.
57  *
58  * @param data the start of the failure_route_rule list to be destroyed
59  */
60 static void destroy_failure_route_rule_list(void *data) {
61         struct failure_route_rule *rs, *rs_tmp;
62         
63         rs = (struct failure_route_rule *)(data);
64         while (rs != NULL) {
65                 rs_tmp = rs->next;
66                 destroy_failure_route_rule(rs);
67                 rs = rs_tmp;
68         }
69 }
70
71
72 /**
73  * Create a new domain in shared memory and set it up.
74  *
75  * @param domain_id the id of the domain
76  * @param domain_name the name of the domain
77  *
78  * @return a pointer to the newly allocated domain data or NULL on
79  * error, in which case it LOGs an error message.
80  */
81 struct domain_data_t * create_domain_data(int domain_id, str * domain_name) {
82         struct domain_data_t * tmp;
83         if ((tmp = shm_malloc(sizeof(struct domain_data_t))) == NULL) {
84                 SHM_MEM_ERROR;
85                 return NULL;
86         }
87         memset(tmp, 0, sizeof(struct domain_data_t));
88         tmp->id = domain_id;
89         tmp->name = domain_name;
90         if ((tmp->tree = dtrie_init(cr_match_mode)) == NULL) {
91                 shm_free(tmp);
92                 return NULL;
93         }
94         if ((tmp->failure_tree = dtrie_init(cr_match_mode)) == NULL) {
95                 dtrie_destroy(&tmp->tree, NULL, cr_match_mode);
96                 shm_free(tmp);
97                 return NULL;
98         }
99         return tmp;
100 }
101
102
103 /**
104  * Destroys the given domain and frees the used memory.
105  *
106  * @param domain_data the structure to be destroyed.
107  */
108 void destroy_domain_data(struct domain_data_t *domain_data) {
109         if (domain_data) {
110                 dtrie_destroy(&domain_data->tree, destroy_route_flags_list, cr_match_mode);
111                 dtrie_destroy(&domain_data->failure_tree, destroy_failure_route_rule_list,
112                                 cr_match_mode);
113                 shm_free(domain_data);
114         }
115 }
116
117
118 /**
119  * Adds the given route information to the prefix tree identified by
120  * node. scan_prefix identifies the number for which the information
121  * is. The rewrite_* parameters define what to do in case of a match.
122  * prob gives the probability with which this rule applies if there are
123  * more than one for a given prefix.
124  *
125  * @param node the root of the routing tree
126  * @param scan_prefix the prefix for which to add the rule (must not contain non-digits)
127  * @param flags user defined flags
128  * @param mask mask for user defined flags
129  * @param full_prefix the whole scan prefix
130  * @param max_targets the number of targets
131  * @param prob the weight of the rule
132  * @param rewrite_hostpart the rewrite_host of the rule
133  * @param strip the number of digits to be stripped off userpart before prepending prefix
134  * @param rewrite_local_prefix the rewrite prefix
135  * @param rewrite_local_suffix the rewrite suffix
136  * @param status the status of the rule
137  * @param hash_index the hash index of the rule
138  * @param backup indicates if the route is backed up by another. only 
139                  useful if status==0, if set, it is the hash value
140                  of another rule
141   * @param backed_up an -1-termintated array of hash indices of the route 
142                     for which this route is backup
143  * @param comment a comment for the route rule
144  *
145  * @return 0 on success, -1 on failure
146  *
147  * @see add_route()
148  */
149 int add_route_to_tree(struct dtrie_node_t *node, const str * scan_prefix,
150                 flag_t flags, flag_t mask, const str * full_prefix, int max_targets, double prob,
151                 const str * rewrite_hostpart, int strip, const str * rewrite_local_prefix,
152                 const str * rewrite_local_suffix, int status, int hash_index, 
153                 int backup, int * backed_up, const str * comment) {
154         void **ret;
155         struct route_flags *rf;
156
157         ret = dtrie_contains(node, scan_prefix->s, scan_prefix->len, cr_match_mode);
158
159         rf = add_route_flags((struct route_flags **)ret, flags, mask);
160         if (rf == NULL) {
161                 LM_ERR("cannot insert route flags into list\n");
162                 return -1;
163         }
164
165         if (ret == NULL) {
166                 /* node does not exist */
167                 if (dtrie_insert(node, scan_prefix->s, scan_prefix->len, rf, cr_match_mode) != 0) {
168                         LM_ERR("cannot insert route flags into d-trie\n");
169                         return -1;
170                 }
171         }
172
173         /* Now add rule to flags */
174         return add_route_rule(rf, full_prefix, max_targets, prob, rewrite_hostpart, strip,
175                                                                                                 rewrite_local_prefix, rewrite_local_suffix, status, hash_index,
176                                                                                                 backup, backed_up, comment);
177 }
178
179
180 /**
181  * Adds the given failure route information to the failure prefix tree identified by
182  * failure_node. scan_prefix, host, reply_code, flags identifies the number for which
183  * the information is and the next_domain parameters defines where to continue
184  * routing in case of a match.
185  *
186  * @param failure_node the root of the failure routing tree
187  * @param scan_prefix the prefix for which to add the rule (must not contain non-digits)
188  * @param full_prefix the whole scan prefix
189  * @param host the hostname last tried
190  * @param reply_code the reply code 
191  * @param flags user defined flags
192  * @param mask mask for user defined flags
193  * @param next_domain continue routing with this domain id
194  * @param comment a comment for the route rule
195  *
196  * @return 0 on success, -1 on failure
197  *
198  * @see add_route()
199  */
200 int add_failure_route_to_tree(struct dtrie_node_t * failure_node, const str * scan_prefix,
201                 const str * full_prefix, const str * host, const str * reply_code,
202                 const flag_t flags, const flag_t mask, const int next_domain, const str * comment) {
203         void **ret;
204         struct failure_route_rule *frr;
205
206         ret = dtrie_contains(failure_node, scan_prefix->s, scan_prefix->len, cr_match_mode);
207
208         frr = add_failure_route_rule((struct failure_route_rule **)ret, full_prefix, host, reply_code, flags, mask, next_domain, comment);
209         if (frr == NULL) {
210                 LM_ERR("cannot insert failure route rule into list\n");
211                 return -1;
212                 }
213
214         if (ret == NULL) {
215                 /* node does not exist */
216                 if (dtrie_insert(failure_node, scan_prefix->s, scan_prefix->len, frr, cr_match_mode) != 0) {
217                         LM_ERR("cannot insert failure route rule into d-trie\n");
218                         return -1;
219                 }
220         }
221
222         return 0;
223 }
224
225
226 /**
227  * Compares the IDs of two domain data structures.
228  * A NULL pointer is always greater than any ID.
229  *
230  * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
231  */
232 int compare_domain_data(const void *v1, const void *v2) {
233   struct domain_data_t *d1 = *(struct domain_data_t * const *)v1;
234         struct domain_data_t *d2 = *(struct domain_data_t * const *)v2;
235         if (d1 == NULL) {
236                 if (d2 == NULL) return 0;
237                 else return 1;
238         }
239         else {
240                 if (d2 == NULL) return -1;
241                 else {
242                         if (d1->id < d2->id) return -1;
243                         else if (d1->id > d2->id) return 1;
244                         else return 0;
245                 }
246         }
247 }