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