Mercurial > hg > freeDiameter
comparison extensions/rt_redirect/redir_fwd.c @ 1259:82280e745a89
Remove whitespace at end of line.
author | Thomas Klausner <tk@giga.or.at> |
---|---|
date | Mon, 24 Mar 2014 13:13:38 +0100 |
parents | 1af09cc156d6 |
children | 25fad6714991 |
comparison
equal
deleted
inserted
replaced
1258:97caad40b665 | 1259:82280e745a89 |
---|---|
56 struct redir_task task = { .answer = NULL, .rhu = 0, .rmct = 0, .rh = FD_LIST_INITIALIZER(task.rh) }; | 56 struct redir_task task = { .answer = NULL, .rhu = 0, .rmct = 0, .rh = FD_LIST_INITIALIZER(task.rh) }; |
57 DiamId_t nh; | 57 DiamId_t nh; |
58 size_t nhlen; | 58 size_t nhlen; |
59 int nbrh = 0; | 59 int nbrh = 0; |
60 struct redir_entry * entry; | 60 struct redir_entry * entry; |
61 | 61 |
62 TRACE_ENTRY("%p %p", cbdata, msg); | 62 TRACE_ENTRY("%p %p", cbdata, msg); |
63 | 63 |
64 CHECK_PARAMS(msg && *msg); | 64 CHECK_PARAMS(msg && *msg); |
65 | 65 |
66 m = *msg; | 66 m = *msg; |
67 | 67 |
68 /* First get the header */ | 68 /* First get the header */ |
69 CHECK_FCT( fd_msg_hdr(m, &hdr) ); | 69 CHECK_FCT( fd_msg_hdr(m, &hdr) ); |
70 | 70 |
71 /* Check if we have an error */ | 71 /* Check if we have an error */ |
72 ASSERT(!(hdr->msg_flags & CMD_FLAG_REQUEST)); | 72 ASSERT(!(hdr->msg_flags & CMD_FLAG_REQUEST)); |
73 if (!(hdr->msg_flags & CMD_FLAG_ERROR)) { | 73 if (!(hdr->msg_flags & CMD_FLAG_ERROR)) { |
74 /* This answer does not have the E flag, no need to process further */ | 74 /* This answer does not have the E flag, no need to process further */ |
75 return 0; | 75 return 0; |
76 } | 76 } |
77 | 77 |
78 /* Now get the AVPs we are interested in */ | 78 /* Now get the AVPs we are interested in */ |
79 CHECK_FCT( fd_msg_browse(m, MSG_BRW_FIRST_CHILD, &avp, NULL) ); | 79 CHECK_FCT( fd_msg_browse(m, MSG_BRW_FIRST_CHILD, &avp, NULL) ); |
80 while (avp) { | 80 while (avp) { |
81 struct avp_hdr * ahdr; | 81 struct avp_hdr * ahdr; |
82 | 82 |
83 CHECK_FCT( fd_msg_avp_hdr( avp, &ahdr ) ); | 83 CHECK_FCT( fd_msg_avp_hdr( avp, &ahdr ) ); |
84 if (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) { | 84 if (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) { |
85 switch (ahdr->avp_code) { | 85 switch (ahdr->avp_code) { |
86 case AC_ORIGIN_HOST: | 86 case AC_ORIGIN_HOST: |
87 /* Parse this AVP */ | 87 /* Parse this AVP */ |
88 CHECK_FCT( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict, NULL ) ); | 88 CHECK_FCT( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict, NULL ) ); |
89 ASSERT( ahdr->avp_value ); | 89 ASSERT( ahdr->avp_value ); |
90 a_oh = ahdr->avp_value; | 90 a_oh = ahdr->avp_value; |
91 break; | 91 break; |
92 | 92 |
93 case AC_RESULT_CODE: | 93 case AC_RESULT_CODE: |
94 /* Parse this AVP */ | 94 /* Parse this AVP */ |
95 CHECK_FCT( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict, NULL ) ); | 95 CHECK_FCT( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict, NULL ) ); |
96 ASSERT( ahdr->avp_value ); | 96 ASSERT( ahdr->avp_value ); |
97 a_rc = ahdr->avp_value; | 97 a_rc = ahdr->avp_value; |
98 | 98 |
99 if (a_rc->u32 != ER_DIAMETER_REDIRECT_INDICATION) { | 99 if (a_rc->u32 != ER_DIAMETER_REDIRECT_INDICATION) { |
100 /* It is not a REDIRECT error, we don't do anything */ | 100 /* It is not a REDIRECT error, we don't do anything */ |
101 goto out; | 101 goto out; |
102 } | 102 } |
103 break; | 103 break; |
104 | 104 |
105 case AC_REDIRECT_HOST: | 105 case AC_REDIRECT_HOST: |
106 { | 106 { |
107 struct redir_host * h = NULL; | 107 struct redir_host * h = NULL; |
108 DiamId_t id = NULL; | 108 DiamId_t id = NULL; |
109 size_t len = 0; | 109 size_t len = 0; |
110 int secure = 0; | 110 int secure = 0; |
111 uint16_t port = 0; | 111 uint16_t port = 0; |
112 int l4 = 0; | 112 int l4 = 0; |
113 char proto = 0; | 113 char proto = 0; |
114 | 114 |
115 /* Parse this AVP */ | 115 /* Parse this AVP */ |
116 CHECK_FCT( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict, NULL ) ); | 116 CHECK_FCT( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict, NULL ) ); |
117 ASSERT( ahdr->avp_value ); | 117 ASSERT( ahdr->avp_value ); |
118 | 118 |
119 nbrh++; | 119 nbrh++; |
120 | 120 |
121 CHECK_FCT_DO( fd_os_parse_DiameterURI(ahdr->avp_value->os.data, ahdr->avp_value->os.len, | 121 CHECK_FCT_DO( fd_os_parse_DiameterURI(ahdr->avp_value->os.data, ahdr->avp_value->os.len, |
122 &id, &len, &secure, &port, &l4, &proto), | 122 &id, &len, &secure, &port, &l4, &proto), |
123 { | 123 { |
124 TRACE_DEBUG(INFO, "Received an invalid Redirect-Host AVP value ('%.*s'), ignored", (int)ahdr->avp_value->os.len, ahdr->avp_value->os.data); | 124 TRACE_DEBUG(INFO, "Received an invalid Redirect-Host AVP value ('%.*s'), ignored", (int)ahdr->avp_value->os.len, ahdr->avp_value->os.data); |
125 break; | 125 break; |
126 } ); | 126 } ); |
127 | 127 |
128 /* Now check if the transport & protocol are supported */ | 128 /* Now check if the transport & protocol are supported */ |
129 if (proto && (proto != 'd')) { | 129 if (proto && (proto != 'd')) { |
130 TRACE_DEBUG(FULL, "Ignored unsupported non-Diameter Redirect-Host AVP (%.*s)", (int)ahdr->avp_value->os.len, ahdr->avp_value->os.data); | 130 TRACE_DEBUG(FULL, "Ignored unsupported non-Diameter Redirect-Host AVP (%.*s)", (int)ahdr->avp_value->os.len, ahdr->avp_value->os.data); |
131 free(id); | 131 free(id); |
132 break; | 132 break; |
134 if (l4 && (l4 == IPPROTO_UDP)) { | 134 if (l4 && (l4 == IPPROTO_UDP)) { |
135 TRACE_DEBUG(FULL, "Ignored unsupported UDP Redirect-Host AVP (%.*s)", (int)ahdr->avp_value->os.len, ahdr->avp_value->os.data); | 135 TRACE_DEBUG(FULL, "Ignored unsupported UDP Redirect-Host AVP (%.*s)", (int)ahdr->avp_value->os.len, ahdr->avp_value->os.data); |
136 free(id); | 136 free(id); |
137 break; | 137 break; |
138 } | 138 } |
139 | 139 |
140 /* It looks OK, save this entry. */ | 140 /* It looks OK, save this entry. */ |
141 | 141 |
142 CHECK_MALLOC( h = malloc(sizeof(struct redir_host)) ); | 142 CHECK_MALLOC( h = malloc(sizeof(struct redir_host)) ); |
143 memset(h, 0, sizeof(struct redir_host)); | 143 memset(h, 0, sizeof(struct redir_host)); |
144 fd_list_init(&h->chain, h); | 144 fd_list_init(&h->chain, h); |
145 h->id = id; | 145 h->id = id; |
146 h->len = len; | 146 h->len = len; |
147 /* later: secure, port */ | 147 /* later: secure, port */ |
148 | 148 |
149 /* The list is kept ordered by id so that it is faster to compare to candidates later */ | 149 /* The list is kept ordered by id so that it is faster to compare to candidates later */ |
150 for (li = task.rh.next; li != &task.rh; li = li->next) { | 150 for (li = task.rh.next; li != &task.rh; li = li->next) { |
151 struct redir_host * nhost = li->o; | 151 struct redir_host * nhost = li->o; |
152 if ( fd_os_cmp(id, len, nhost->id, nhost->len) <= 0 ) | 152 if ( fd_os_cmp(id, len, nhost->id, nhost->len) <= 0 ) |
153 break; | 153 break; |
180 } | 180 } |
181 | 181 |
182 /* Go to next AVP */ | 182 /* Go to next AVP */ |
183 CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) ); | 183 CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) ); |
184 } | 184 } |
185 | 185 |
186 /* Check we have received the necessary information */ | 186 /* Check we have received the necessary information */ |
187 if (!a_rc) { | 187 if (!a_rc) { |
188 TRACE_DEBUG(FULL, "Invalid Diameter answer without a Result-Code AVP, Redirect module gave up"); | 188 TRACE_DEBUG(FULL, "Invalid Diameter answer without a Result-Code AVP, Redirect module gave up"); |
189 goto out; | 189 goto out; |
190 } | 190 } |
191 | 191 |
192 if (!a_oh) { | 192 if (!a_oh) { |
193 TRACE_DEBUG(FULL, "Invalid Diameter answer without an Origin-Host AVP, Redirect module gave up"); | 193 TRACE_DEBUG(FULL, "Invalid Diameter answer without an Origin-Host AVP, Redirect module gave up"); |
194 goto out; | 194 goto out; |
195 } | 195 } |
196 | 196 |
197 if (FD_IS_LIST_EMPTY(&task.rh)) { | 197 if (FD_IS_LIST_EMPTY(&task.rh)) { |
198 TRACE_DEBUG(FULL, "Diameter answer with a DIAMETER_REDIRECT_INDICATION Result-Code AVP but no valid/supported Redirect-Host AVP, Redirect module gave up"); | 198 TRACE_DEBUG(FULL, "Diameter answer with a DIAMETER_REDIRECT_INDICATION Result-Code AVP but no valid/supported Redirect-Host AVP, Redirect module gave up"); |
199 goto out; | 199 goto out; |
200 } | 200 } |
201 | 201 |
202 if (a_rhu && (task.rhu != DONT_CACHE) && !a_rmct) { | 202 if (a_rhu && (task.rhu != DONT_CACHE) && !a_rmct) { |
203 TRACE_DEBUG(FULL, "Invalid Diameter Redirect answer with a Redirect-Host-Usage AVP but no Redirect-Max-Cache-Time, Redirect module gave up"); | 203 TRACE_DEBUG(FULL, "Invalid Diameter Redirect answer with a Redirect-Host-Usage AVP but no Redirect-Max-Cache-Time, Redirect module gave up"); |
204 goto out; | 204 goto out; |
205 } | 205 } |
206 | 206 |
207 /* It looks like we can process the Redirect indication */ | 207 /* It looks like we can process the Redirect indication */ |
208 | 208 |
209 /* Search for the peers we already know */ | 209 /* Search for the peers we already know */ |
210 for (li = task.rh.next; li != &task.rh; li = li->next) { | 210 for (li = task.rh.next; li != &task.rh; li = li->next) { |
211 struct redir_host * h = li->o; | 211 struct redir_host * h = li->o; |
212 struct peer_hdr * peer; | 212 struct peer_hdr * peer; |
213 | 213 |
214 CHECK_FCT( fd_peer_getbyid( h->id, h->len, 1, &peer ) ); | 214 CHECK_FCT( fd_peer_getbyid( h->id, h->len, 1, &peer ) ); |
215 if (peer) { | 215 if (peer) { |
216 known ++; | 216 known ++; |
217 memcpy(h->id, peer->info.pi_diamid, h->len); /* Overwrite the case so we can search case-sensitive from here on */ | 217 memcpy(h->id, peer->info.pi_diamid, h->len); /* Overwrite the case so we can search case-sensitive from here on */ |
218 if (fd_peer_get_state(peer) == STATE_OPEN) { | 218 if (fd_peer_get_state(peer) == STATE_OPEN) { |
219 actives ++; | 219 actives ++; |
220 } | 220 } |
221 } | 221 } |
222 } | 222 } |
223 | 223 |
224 TRACE_DEBUG(FULL, "Redirect module: received %d Redirect-Hosts, %d are known peers, %d have an OPEN connection", nbrh, known, actives); | 224 TRACE_DEBUG(FULL, "Redirect module: received %d Redirect-Hosts, %d are known peers, %d have an OPEN connection", nbrh, known, actives); |
225 | 225 |
226 /* in this version, we only redirect when there are known active peers. TODO: add new peers via fd_peer_add when no active peer is available */ | 226 /* in this version, we only redirect when there are known active peers. TODO: add new peers via fd_peer_add when no active peer is available */ |
227 | 227 |
228 if (!actives) { | 228 if (!actives) { |
229 TRACE_DEBUG(INFO, "Unable to comply to Redirect indication: none of the peers included is in OPEN state"); | 229 TRACE_DEBUG(INFO, "Unable to comply to Redirect indication: none of the peers included is in OPEN state"); |
230 goto out; | 230 goto out; |
231 } | 231 } |
232 | 232 |
233 /* From this point, we will re-send the query to a different peer, so stop forwarding the answer here */ | 233 /* From this point, we will re-send the query to a different peer, so stop forwarding the answer here */ |
234 *msg = NULL; | 234 *msg = NULL; |
235 | 235 |
236 /* Get the query's routing data & add the new error */ | 236 /* Get the query's routing data & add the new error */ |
237 CHECK_FCT( fd_msg_answ_getq(m, &q) ); | 237 CHECK_FCT( fd_msg_answ_getq(m, &q) ); |
238 CHECK_FCT( fd_msg_rt_get(q, &rtd) ); | 238 CHECK_FCT( fd_msg_rt_get(q, &rtd) ); |
239 CHECK_FCT( fd_msg_source_get( m, &nh, &nhlen ) ); | 239 CHECK_FCT( fd_msg_source_get( m, &nh, &nhlen ) ); |
240 CHECK_FCT( fd_rtd_error_add(rtd, nh, nhlen, a_oh->os.data, a_oh->os.len, a_rc->u32, NULL, NULL) ); | 240 CHECK_FCT( fd_rtd_error_add(rtd, nh, nhlen, a_oh->os.data, a_oh->os.len, a_rc->u32, NULL, NULL) ); |
241 | 241 |
242 /* Create a redir_rule */ | 242 /* Create a redir_rule */ |
243 CHECK_FCT( redir_entry_new(&entry, &task.rh, task.rhu, q, nh, nhlen, a_oh->os.data, a_oh->os.len) ); | 243 CHECK_FCT( redir_entry_new(&entry, &task.rh, task.rhu, q, nh, nhlen, a_oh->os.data, a_oh->os.len) ); |
244 | 244 |
245 CHECK_POSIX( pthread_mutex_lock(&redir_exp_peer_lock) ); | 245 CHECK_POSIX( pthread_mutex_lock(&redir_exp_peer_lock) ); |
246 /* Insert in the split list */ | 246 /* Insert in the split list */ |
247 CHECK_FCT( redir_entry_insert(entry) ); | 247 CHECK_FCT( redir_entry_insert(entry) ); |
248 /* Set the expiry */ | 248 /* Set the expiry */ |
249 CHECK_FCT( redir_exp_set(entry, task.rmct ?: DEFAULT_EXPIRE_TIME) ); | 249 CHECK_FCT( redir_exp_set(entry, task.rmct ?: DEFAULT_EXPIRE_TIME) ); |
250 CHECK_POSIX( pthread_mutex_unlock(&redir_exp_peer_lock) ); | 250 CHECK_POSIX( pthread_mutex_unlock(&redir_exp_peer_lock) ); |
251 | 251 |
252 /* Now we can get rid of the received answer and send again the query. */ | 252 /* Now we can get rid of the received answer and send again the query. */ |
253 CHECK_FCT( fd_msg_answ_detach(m) ); | 253 CHECK_FCT( fd_msg_answ_detach(m) ); |
254 CHECK_FCT( fd_msg_free(m) ); | 254 CHECK_FCT( fd_msg_free(m) ); |
255 | 255 |
256 /* Send it */ | 256 /* Send it */ |
257 CHECK_FCT( fd_msg_send(&q, NULL, NULL) ); | 257 CHECK_FCT( fd_msg_send(&q, NULL, NULL) ); |
258 | 258 |
259 /* Done! */ | 259 /* Done! */ |
260 | 260 |
261 out: | 261 out: |
262 while (!FD_IS_LIST_EMPTY(&task.rh)) { | 262 while (!FD_IS_LIST_EMPTY(&task.rh)) { |
263 struct redir_host * h = task.rh.next->o; | 263 struct redir_host * h = task.rh.next->o; |
264 fd_list_unlink(&h->chain); | 264 fd_list_unlink(&h->chain); |
265 free(h->id); | 265 free(h->id); |
266 free(h); | 266 free(h); |
267 } | 267 } |
268 | 268 |
269 return 0; | 269 return 0; |
270 | 270 |
271 } | 271 } |
272 | 272 |