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
"Welcome to our mercurial repository"