media/mtransport/third_party/nICEr/src/ice/ice_component.c

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:19e5720bd826
1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16 * Neither the name of Adobe Systems, Network Resonance nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33
34
35 static char *RCSSTRING __UNUSED__="$Id: ice_component.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
36
37 #include <string.h>
38 #include <assert.h>
39 #include <nr_api.h>
40 #include <registry.h>
41 #include <async_timer.h>
42 #include "ice_ctx.h"
43 #include "ice_codeword.h"
44 #include "stun.h"
45 #include "nr_socket_local.h"
46 #include "nr_socket_turn.h"
47 #include "nr_socket_buffered_stun.h"
48 #include "ice_reg.h"
49
50 static int nr_ice_component_stun_server_default_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error);
51 static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp);
52
53 /* This function takes ownership of the contents of req (but not req itself) */
54 static int nr_ice_pre_answer_request_create(nr_socket *sock, nr_stun_server_request *req, nr_ice_pre_answer_request **parp)
55 {
56 int r, _status;
57 nr_ice_pre_answer_request *par = 0;
58 nr_stun_message_attribute *attr;
59
60 if (!(par = RCALLOC(sizeof(nr_ice_pre_answer_request))))
61 ABORT(R_NO_MEMORY);
62
63 par->req = *req; /* Struct assignment */
64 memset(req, 0, sizeof(*req)); /* Zero contents to avoid confusion */
65
66 if (r=nr_socket_getaddr(sock, &par->local_addr))
67 ABORT(r);
68 if (!nr_stun_message_has_attribute(par->req.request, NR_STUN_ATTR_USERNAME, &attr))
69 ABORT(R_INTERNAL);
70 if (!(par->username = r_strdup(attr->u.username)))
71 ABORT(R_NO_MEMORY);
72
73 *parp=par;
74 _status=0;
75 abort:
76 if (_status) {
77 /* Erase the request so we don't free it */
78 memset(&par->req, 0, sizeof(nr_stun_server_request));
79 nr_ice_pre_answer_request_destroy(&par);
80 }
81
82 return(_status);
83 }
84
85 static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp)
86 {
87 nr_ice_pre_answer_request *par;
88
89 if (!parp || !*parp)
90 return(0);
91
92 par = *parp;
93 *parp = 0;
94
95 nr_stun_message_destroy(&par->req.request);
96 nr_stun_message_destroy(&par->req.response);
97
98 RFREE(par->username);
99
100 return(0);
101 }
102
103 int nr_ice_component_create(nr_ice_media_stream *stream, int component_id, nr_ice_component **componentp)
104 {
105 int _status;
106 nr_ice_component *comp=0;
107
108 if(!(comp=RCALLOC(sizeof(nr_ice_component))))
109 ABORT(R_NO_MEMORY);
110
111 comp->state=NR_ICE_COMPONENT_UNPAIRED;
112 comp->component_id=component_id;
113 comp->stream=stream;
114 comp->ctx=stream->ctx;
115
116 STAILQ_INIT(&comp->sockets);
117 TAILQ_INIT(&comp->candidates);
118 STAILQ_INIT(&comp->pre_answer_reqs);
119
120 STAILQ_INSERT_TAIL(&stream->components,comp,entry);
121
122 _status=0;
123 abort:
124 return(_status);
125 }
126
127 int nr_ice_component_destroy(nr_ice_component **componentp)
128 {
129 nr_ice_component *component;
130 nr_ice_socket *s1,*s2;
131 nr_ice_candidate *c1,*c2;
132 nr_ice_pre_answer_request *r1,*r2;
133
134 if(!componentp || !*componentp)
135 return(0);
136
137 component=*componentp;
138 *componentp=0;
139
140 /* Detach ourselves from the sockets */
141 if (component->local_component){
142 nr_ice_socket *isock=STAILQ_FIRST(&component->local_component->sockets);
143 while(isock){
144 nr_stun_server_remove_client(isock->stun_server, component);
145 isock=STAILQ_NEXT(isock, entry);
146 }
147 }
148
149 /* candidates MUST be destroyed before the sockets so that
150 they can deregister */
151 TAILQ_FOREACH_SAFE(c1, &component->candidates, entry_comp, c2){
152 TAILQ_REMOVE(&component->candidates,c1,entry_comp);
153 nr_ice_candidate_destroy(&c1);
154 }
155
156 STAILQ_FOREACH_SAFE(s1, &component->sockets, entry, s2){
157 STAILQ_REMOVE(&component->sockets,s1,nr_ice_socket_,entry);
158 nr_ice_socket_destroy(&s1);
159 }
160
161 STAILQ_FOREACH_SAFE(r1, &component->pre_answer_reqs, entry, r2){
162 STAILQ_REMOVE(&component->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry);
163 nr_ice_pre_answer_request_destroy(&r1);
164 }
165
166 if(component->keepalive_timer)
167 NR_async_timer_cancel(component->keepalive_timer);
168 nr_stun_client_ctx_destroy(&component->keepalive_ctx);
169
170 RFREE(component);
171 return(0);
172 }
173
174 static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_local_addr *addrs, int addr_ct, char *lufrag, Data *pwd)
175 {
176 nr_socket *sock;
177 nr_ice_socket *isock=0;
178 nr_ice_candidate *cand=0;
179 int i;
180 int j;
181 char label[256];
182 int r,_status;
183
184 /* Now one ice_socket for each address */
185 for(i=0;i<addr_ct;i++){
186 char suppress;
187
188 if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
189 if(r!=R_NOT_FOUND)
190 ABORT(r);
191 }
192 else{
193 if(suppress)
194 continue;
195 }
196 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): host address %s",ctx->label,addrs[i].addr.as_string);
197 if(r=nr_socket_local_create(&addrs[i].addr,&sock)){
198 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): couldn't create socket for address %s",ctx->label,addrs[i].addr.as_string);
199 continue;
200 }
201
202 if(r=nr_ice_socket_create(ctx,component,sock,&isock))
203 ABORT(r);
204 /* Create one host candidate */
205 if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,
206 component->component_id,&cand))
207 ABORT(r);
208
209 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
210 component->candidate_ct++;
211 cand=0;
212
213 /* And a srvrflx candidate for each STUN server */
214 for(j=0;j<ctx->stun_server_ct;j++){
215 if(r=nr_ice_candidate_create(ctx,component,
216 isock,sock,SERVER_REFLEXIVE,
217 &ctx->stun_servers[j],component->component_id,&cand))
218 ABORT(r);
219 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
220 component->candidate_ct++;
221 cand=0;
222 }
223
224 #ifdef USE_TURN
225 /* And both a srvrflx and relayed candidate for each TURN server */
226 for(j=0;j<ctx->turn_server_ct;j++){
227 nr_socket *turn_sock;
228 nr_ice_candidate *srvflx_cand;
229
230 /* Skip non-UDP */
231 if (ctx->turn_servers[j].transport != IPPROTO_UDP)
232 continue;
233
234 /* srvrflx */
235 if(r=nr_ice_candidate_create(ctx,component,
236 isock,sock,SERVER_REFLEXIVE,
237 &ctx->turn_servers[j].turn_server,component->component_id,&cand))
238 ABORT(r);
239 cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
240 cand->done_cb=nr_ice_initialize_finished_cb;
241 cand->cb_arg=cand;
242
243 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
244 component->candidate_ct++;
245 srvflx_cand=cand;
246
247 /* relayed*/
248 if(r=nr_socket_turn_create(sock, &turn_sock))
249 ABORT(r);
250 if(r=nr_ice_candidate_create(ctx,component,
251 isock,turn_sock,RELAYED,
252 &ctx->turn_servers[j].turn_server,component->component_id,&cand))
253 ABORT(r);
254 cand->u.relayed.srvflx_candidate=srvflx_cand;
255 cand->u.relayed.server=&ctx->turn_servers[j];
256 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
257 component->candidate_ct++;
258
259 cand=0;
260 }
261 #endif /* USE_TURN */
262
263 /* Create a STUN server context for this socket */
264 snprintf(label, sizeof(label), "server(%s)", addrs[i].addr.as_string);
265 if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
266 ABORT(r);
267 if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
268 ABORT(r);
269
270 /* Add the default STUN credentials so that we can respond before
271 we hear about the peer. */
272 if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
273 ABORT(r);
274
275 STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
276 }
277
278 _status = 0;
279 abort:
280 return(_status);
281 }
282
283 static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_local_addr *addrs, int addr_ct, char *lufrag, Data *pwd)
284 {
285 nr_ice_socket *isock=0;
286 nr_ice_candidate *cand=0;
287 int i;
288 int j;
289 char label[256];
290 int r,_status;
291
292 /* Create a new relayed candidate for each addr/TURN server pair */
293 for(i=0;i<addr_ct;i++){
294 char suppress;
295
296 if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
297 if(r!=R_NOT_FOUND)
298 ABORT(r);
299 }
300 else{
301 if(suppress)
302 continue;
303 }
304
305 #ifdef USE_TURN
306 for(j=0;j<ctx->turn_server_ct;j++){
307 nr_transport_addr addr;
308 nr_socket *sock;
309 nr_socket *buffered_sock;
310 nr_socket *turn_sock;
311
312 /* Skip non-TCP */
313 if (ctx->turn_servers[j].transport != IPPROTO_TCP)
314 continue;
315
316 /* Create a local socket */
317 if ((r=nr_transport_addr_copy(&addr, &addrs[i].addr)))
318 ABORT(r);
319 addr.protocol = IPPROTO_TCP;
320 if ((r=nr_transport_addr_fmt_addr_string(&addr)))
321 ABORT(r);
322 if((r=nr_socket_local_create(&addr, &sock))){
323 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create socket for address %s",ctx->label,addr.as_string);
324 continue;
325 }
326 /* Wrap it */
327 if((r=nr_socket_buffered_stun_create(sock, NR_STUN_MAX_MESSAGE_SIZE, &buffered_sock)))
328 ABORT(r);
329
330 /* The TURN socket */
331 if(r=nr_socket_turn_create(buffered_sock, &turn_sock))
332 ABORT(r);
333
334 /* Create an ICE socket */
335 if((r=nr_ice_socket_create(ctx, component, buffered_sock, &isock)))
336 ABORT(r);
337
338 /* Attach ourselves to it */
339 if(r=nr_ice_candidate_create(ctx,component,
340 isock,turn_sock,RELAYED,
341 &ctx->turn_servers[j].turn_server,component->component_id,&cand))
342 ABORT(r);
343 cand->u.relayed.srvflx_candidate=NULL;
344 cand->u.relayed.server=&ctx->turn_servers[j];
345 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
346 component->candidate_ct++;
347 cand=0;
348
349 /* Create a STUN server context for this socket */
350 snprintf(label, sizeof(label), "server(%s)", addr.as_string);
351 if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
352 ABORT(r);
353 if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
354 ABORT(r);
355
356 /* Add the default STUN credentials so that we can respond before
357 we hear about the peer.*/
358 if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
359 ABORT(r);
360
361 STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
362 }
363 }
364 #endif
365
366 _status = 0;
367 abort:
368 return(_status);
369 }
370
371
372 /* Make all the candidates we can make at the beginning */
373 int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component)
374 {
375 int r,_status;
376 nr_local_addr *addrs=ctx->local_addrs;
377 int addr_ct=ctx->local_addr_ct;
378 char *lufrag;
379 char *lpwd;
380 Data pwd;
381 nr_ice_candidate *cand;
382
383 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): initializing component with id %d",ctx->label,component->component_id);
384
385 if(addr_ct==0){
386 r_log(LOG_ICE,LOG_ERR,"ICE(%s): no local addresses available",ctx->label);
387 ABORT(R_NOT_FOUND);
388 }
389
390 /* Note: we need to recompute these because
391 we have not yet computed the values in the peer media stream.*/
392 lufrag=component->stream->ufrag ? component->stream->ufrag : ctx->ufrag;
393 assert(lufrag);
394 if (!lufrag)
395 ABORT(R_INTERNAL);
396 lpwd=component->stream->pwd ? component->stream->pwd :ctx->pwd;
397 assert(lpwd);
398 if (!lpwd)
399 ABORT(R_INTERNAL);
400 INIT_DATA(pwd, (UCHAR *)lpwd, strlen(lpwd));
401
402 /* Initialize the UDP candidates */
403 if (r=nr_ice_component_initialize_udp(ctx, component, addrs, addr_ct, lufrag, &pwd))
404 ABORT(r);
405 /* And the TCP candidates */
406 if (r=nr_ice_component_initialize_tcp(ctx, component, addrs, addr_ct, lufrag, &pwd))
407 ABORT(r);
408
409 /* count the candidates that will be initialized */
410 cand=TAILQ_FIRST(&component->candidates);
411 if(!cand){
412 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create any valid candidates",ctx->label);
413 ABORT(R_NOT_FOUND);
414 }
415
416 while(cand){
417 ctx->uninitialized_candidates++;
418 cand=TAILQ_NEXT(cand,entry_comp);
419 }
420
421 /* Now initialize all the candidates */
422 cand=TAILQ_FIRST(&component->candidates);
423 while(cand){
424 if(cand->state!=NR_ICE_CAND_STATE_INITIALIZING){
425 if(r=nr_ice_candidate_initialize(cand,nr_ice_initialize_finished_cb,cand)){
426 if(r!=R_WOULDBLOCK){
427 ctx->uninitialized_candidates--;
428 cand->state=NR_ICE_CAND_STATE_FAILED;
429 }
430 }
431 }
432 cand=TAILQ_NEXT(cand,entry_comp);
433 }
434 _status=0;
435 abort:
436 return(_status);
437 }
438
439 static int nr_ice_any_peer_paired(nr_ice_candidate* cand) {
440 nr_ice_peer_ctx* pctx=STAILQ_FIRST(&cand->ctx->peers);
441 while(pctx && pctx->state == NR_ICE_PEER_STATE_UNPAIRED){
442 /* Is it worth actually looking through the check lists? Probably not. */
443 pctx=STAILQ_NEXT(pctx,entry);
444 }
445 return pctx != NULL;
446 }
447
448 /*
449 Compare this newly initialized candidate against the other initialized
450 candidates and discard the lower-priority one if they are redundant.
451
452 This algorithm combined with the other algorithms, favors
453 host > srflx > relay
454 */
455 int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned)
456 {
457 nr_ice_candidate *c2, *tmp = NULL;
458
459 *was_pruned = 0;
460 c2 = TAILQ_FIRST(&comp->candidates);
461 while(c2){
462 if((c1 != c2) &&
463 (c2->state == NR_ICE_CAND_STATE_INITIALIZED) &&
464 !nr_transport_addr_cmp(&c1->base,&c2->base,NR_TRANSPORT_ADDR_CMP_MODE_ALL) &&
465 !nr_transport_addr_cmp(&c1->addr,&c2->addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
466
467 if((c1->type == c2->type) ||
468 (c1->type==HOST && c2->type == SERVER_REFLEXIVE) ||
469 (c2->type==HOST && c1->type == SERVER_REFLEXIVE)){
470
471 /*
472 These are redundant. Remove the lower pri one, or if pairing has
473 already occurred, remove the newest one.
474
475 Since this algorithmis run whenever a new candidate
476 is initialized, there should at most one duplicate.
477 */
478 if ((c1->priority <= c2->priority) || nr_ice_any_peer_paired(c2)) {
479 tmp = c1;
480 *was_pruned = 1;
481 }
482 else {
483 tmp = c2;
484 }
485 break;
486 }
487 }
488
489 c2=TAILQ_NEXT(c2,entry_comp);
490 }
491
492 if (tmp) {
493 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): Removing redundant candidate",
494 ctx->label,tmp->label);
495
496 TAILQ_REMOVE(&comp->candidates,tmp,entry_comp);
497 comp->candidate_ct--;
498 TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock);
499
500 nr_ice_candidate_destroy(&tmp);
501 }
502
503 return 0;
504 }
505
506 /* Section 7.2.1 */
507 static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_transport_addr *local_addr, nr_stun_server_request *req, int *error)
508 {
509 nr_ice_cand_pair *pair;
510 nr_ice_candidate *pcand=0;
511 nr_stun_message *sreq=req->request;
512 nr_stun_message_attribute *attr;
513 int component_id_matched;
514 int local_addr_matched;
515 int remote_addr_matched;
516 nr_ice_cand_pair *found_invalid=0;
517 int r=0,_status;
518
519 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): received request from %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,req->src_addr.as_string);
520
521 if (comp->state == NR_ICE_COMPONENT_DISABLED)
522 ABORT(R_REJECTED);
523
524 /* Check for role conficts (7.2.1.1) */
525 if(comp->stream->pctx->controlling){
526 if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLING,&attr)){
527 /* OK, there is a conflict. Who's right? */
528 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlling",comp->stream->pctx->label);
529
530 if(attr->u.ice_controlling > comp->stream->pctx->tiebreaker){
531 /* They are: switch */
532 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): switching to controlled",comp->stream->pctx->label);
533
534 comp->stream->pctx->controlling=0;
535 }
536 else {
537 /* We are: throw an error */
538 r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
539
540 *error=487;
541 ABORT(R_REJECTED);
542 }
543 }
544 }
545 else{
546 if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLED,&attr)){
547 /* OK, there is a conflict. Who's right? */
548 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlled",comp->stream->pctx->label);
549
550 if(attr->u.ice_controlling < comp->stream->pctx->tiebreaker){
551 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): switching to controlling",comp->stream->pctx->label);
552
553 /* They are: switch */
554 comp->stream->pctx->controlling=1;
555 }
556 else {
557 /* We are: throw an error */
558 r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
559
560 *error=487;
561 ABORT(R_REJECTED);
562 }
563 }
564 }
565
566 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): This STUN request appears to map to local addr %s",comp->stream->pctx->label,local_addr->as_string);
567
568 pair=TAILQ_FIRST(&comp->stream->check_list);
569 while(pair){
570 component_id_matched = 0;
571 local_addr_matched = 0;
572 remote_addr_matched = 0;
573
574 if(pair->remote->component->component_id!=comp->component_id)
575 goto next_pair;
576 component_id_matched = 1;
577
578 if(nr_transport_addr_cmp(&pair->local->base,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
579 goto next_pair;
580 local_addr_matched=1;
581
582
583 if(nr_transport_addr_cmp(&pair->remote->addr,&req->src_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
584 goto next_pair;
585 remote_addr_matched = 1;
586
587 if(pair->state==NR_ICE_PAIR_STATE_FAILED){
588 found_invalid=pair;
589 goto next_pair;
590 }
591
592 if (local_addr_matched && remote_addr_matched){
593 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND_PAIR(%s): Found a matching pair for received check: %s",comp->stream->pctx->label,pair->codeword,pair->as_string);
594 break; /* OK, this is a known pair */
595 }
596
597 next_pair:
598 pair=TAILQ_NEXT(pair,entry);
599 }
600
601 if(!pair){
602 if(!found_invalid){
603 /* First find our local component candidate */
604 nr_ice_candidate *cand;
605
606 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): no matching pair",comp->stream->pctx->label);
607 cand=TAILQ_FIRST(&comp->local_component->candidates);
608 while(cand){
609 if(!nr_transport_addr_cmp(&cand->addr,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
610 break;
611
612 cand=TAILQ_NEXT(cand,entry_comp);
613 }
614
615 /* Well, this really shouldn't happen, but it's an error from the
616 other side, so we just throw an error and keep going */
617 if(!cand){
618 r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): stun request to unknown local address %s, discarding",comp->stream->pctx->label,local_addr->as_string);
619
620 *error=400;
621 ABORT(R_NOT_FOUND);
622 }
623
624 /* We now need to make a peer reflexive */
625 if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) {
626 *error=(r==R_NO_MEMORY)?500:400;
627 ABORT(r);
628 }
629 if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){
630 r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label);
631 *error=487;
632 ABORT(R_BAD_DATA);
633 }
634 pcand->priority=attr->u.priority;
635 pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
636
637 if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand,
638 &pair)) {
639 *error=(r==R_NO_MEMORY)?500:400;
640 ABORT(r);
641 }
642 nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FROZEN);
643
644 if(r=nr_ice_component_insert_pair(comp,pair)) {
645 *error=(r==R_NO_MEMORY)?500:400;
646 nr_ice_candidate_pair_destroy(&pair);
647 ABORT(r);
648 }
649
650 /* Do this last, since any call to ABORT will destroy pcand */
651 TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp);
652 pcand=0;
653 }
654 else{
655 /* OK, there was a pair, it's just invalid: According to Section
656 7.2.1.4, we need to resurrect it
657 */
658 if(found_invalid->state == NR_ICE_PAIR_STATE_FAILED){
659 pair=found_invalid;
660
661 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): received STUN check on invalid pair, resurrecting: %s",comp->stream->pctx->label,pair->codeword,pair->as_string);
662 nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_WAITING);
663 }
664 else{
665 /* This shouldn't happen */
666 r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s)/CAND-PAIR(%s): received STUN check on invalid pair that was not in state FAILED; this should not happen: %s",comp->stream->pctx->label,pair->codeword,pair->as_string);
667 *error=500;
668 ABORT(R_BAD_DATA);
669 }
670 }
671 }
672
673 /* OK, we've got a pair to work with. Turn it on */
674 assert(pair);
675 if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_USE_CANDIDATE,0)){
676 if(comp->stream->pctx->controlling){
677 r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND_PAIR(%s): Peer sent USE-CANDIDATE but is controlled",comp->stream->pctx->label, pair->codeword);
678 }
679 else{
680 /* If this is the first time we've noticed this is nominated...*/
681 pair->peer_nominated=1;
682
683 if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED && !pair->nominated){
684 pair->nominated=1;
685
686 if(r=nr_ice_component_nominated_pair(pair->remote->component, pair)) {
687 *error=(r==R_NO_MEMORY)?500:400;
688 ABORT(r);
689 }
690 }
691 }
692 }
693
694 if(r=nr_ice_candidate_pair_do_triggered_check(comp->stream->pctx,pair)) {
695 *error=(r==R_NO_MEMORY)?500:400;
696 ABORT(r);
697 }
698
699 _status=0;
700 abort:
701 if(_status){
702 nr_ice_candidate_destroy(&pcand);
703 assert(*error != 0);
704 if(r!=R_NO_MEMORY) assert(*error != 500);
705 }
706 return(_status);
707 }
708
709 static int nr_ice_component_stun_server_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error)
710 {
711 nr_ice_component *comp=cb_arg;
712 nr_transport_addr local_addr;
713 int r,_status;
714
715 /* Find the candidate pair that this maps to */
716 if(r=nr_socket_getaddr(sock,&local_addr)) {
717 *error=500;
718 ABORT(r);
719 }
720
721 if (r=nr_ice_component_process_incoming_check(comp, &local_addr, req, error))
722 ABORT(r);
723
724 _status=0;
725 abort:
726 return(_status);
727 }
728
729 int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced)
730 {
731 nr_ice_pre_answer_request *r1,*r2;
732 nr_ice_component *comp = pcomp->local_component;
733 int r,_status;
734
735 if (serviced)
736 *serviced = 0;
737
738 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): looking for pre-answer requests",pctx->label,comp->stream->label,comp->component_id);
739
740 STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2) {
741 if (!strcmp(r1->username, username)) {
742 int error = 0;
743
744 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): found pre-answer request",pctx->label,comp->stream->label,comp->component_id);
745 r = nr_ice_component_process_incoming_check(pcomp, &r1->local_addr, &r1->req, &error);
746 if (r) {
747 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): error processing pre-answer request. Would have returned %d",pctx->label,comp->stream->label,comp->component_id, error);
748 }
749 (*serviced)++;
750 STAILQ_REMOVE(&comp->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry);
751 nr_ice_pre_answer_request_destroy(&r1);
752 }
753 }
754
755 _status=0;
756 return(_status);
757 }
758
759 int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote)
760 {
761 int r, _status;
762 nr_ice_candidate *pcand;
763 nr_ice_cand_pair *pair=0;
764 char codeword[5];
765
766 nr_ice_compute_codeword(lcand->label,strlen(lcand->label),codeword);
767 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing local candidate %s",pctx->label,codeword,lcand->label);
768
769 switch(lcand->type){
770 case HOST:
771 break;
772 case SERVER_REFLEXIVE:
773 case PEER_REFLEXIVE:
774 /* Don't actually pair these candidates */
775 goto done;
776 break;
777 case RELAYED:
778 break;
779 default:
780 assert(0);
781 ABORT(R_INTERNAL);
782 break;
783 }
784
785 pcand=TAILQ_FIRST(&pcomp->candidates);
786 while(pcand){
787 /*
788 Two modes, depending on |pair_all_remote|
789
790 1. Pair remote candidates which have not been paired
791 (used in initial pairing or in processing the other side's
792 trickle candidates).
793 2. Pair any remote candidate (used when processing our own
794 trickle candidates).
795 */
796 if (pair_all_remote || (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED)) {
797 /* If we are pairing our own trickle candidates, the remote candidate should
798 all be paired */
799 if (pair_all_remote)
800 assert (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_PAIRED);
801
802 nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
803 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing with peer candidate %s", pctx->label, codeword, pcand->label);
804
805 if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
806 ABORT(r);
807
808 if(r=nr_ice_component_insert_pair(pcomp, pair))
809 ABORT(r);
810 }
811
812 pcand=TAILQ_NEXT(pcand,entry_comp);
813 }
814
815 done:
816 _status = 0;
817 abort:
818 return(_status);
819 }
820
821 int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp)
822 {
823 nr_ice_candidate *lcand, *pcand;
824 nr_ice_socket *isock;
825 int r,_status;
826
827 r_log(LOG_ICE,LOG_DEBUG,"Pairing candidates======");
828
829 /* Create the candidate pairs */
830 lcand=TAILQ_FIRST(&lcomp->candidates);
831 while(lcand){
832 if (lcand->state == NR_ICE_CAND_STATE_INITIALIZED) {
833 if ((r = nr_ice_component_pair_candidate(pctx, pcomp, lcand, 0)))
834 ABORT(r);
835 }
836
837 lcand=TAILQ_NEXT(lcand,entry_comp);
838 }
839
840 /* Mark all peer candidates as paired */
841 pcand=TAILQ_FIRST(&pcomp->candidates);
842 while(pcand){
843 pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
844
845 pcand=TAILQ_NEXT(pcand,entry_comp);
846
847 }
848
849 /* Now register the STUN server callback for this component.
850 Note that this is a per-component CB so we only need to
851 do this once.
852 */
853 if (pcomp->state != NR_ICE_COMPONENT_RUNNING) {
854 isock=STAILQ_FIRST(&lcomp->sockets);
855 while(isock){
856 if(r=nr_stun_server_add_client(isock->stun_server,pctx->label,
857 pcomp->stream->r2l_user,&pcomp->stream->r2l_pass,nr_ice_component_stun_server_cb,pcomp)) {
858 ABORT(r);
859 }
860 isock=STAILQ_NEXT(isock,entry);
861 }
862 }
863
864 pcomp->state = NR_ICE_COMPONENT_RUNNING;
865
866 _status=0;
867 abort:
868 return(_status);
869 }
870
871 /* Fires when we have an incoming candidate that doesn't correspond to an existing
872 remote peer. This is either pre-answer or just spurious. Store it in the
873 component for use when we see the actual answer, at which point we need
874 to do the procedures from S 7.2.1 in nr_ice_component_stun_server_cb.
875 */
876 static int nr_ice_component_stun_server_default_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error)
877 {
878 int r, _status;
879 nr_ice_component *comp = (nr_ice_component *)cb_arg;
880 nr_ice_pre_answer_request *par = 0;
881 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Received STUN request pre-answer from %s",
882 comp->ctx->label, comp->stream->label, comp->component_id, req->src_addr.as_string);
883
884 if (r=nr_ice_pre_answer_request_create(sock, req, &par))
885 ABORT(r);
886
887 *dont_free = 1;
888 STAILQ_INSERT_TAIL(&comp->pre_answer_reqs, par, entry);
889
890 _status=0;
891 abort:
892 return 0;
893 }
894
895 int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
896 {
897 int r,_status;
898 int fire_cb=0;
899 nr_ice_cand_pair *p2;
900
901 if(!comp->nominated)
902 fire_cb=1;
903
904 /* Are we changing what the nominated pair is? */
905 if(comp->nominated){
906 if(comp->nominated->priority > pair->priority)
907 return(0);
908 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): replacing pair %s with CAND-PAIR(%s)",comp->stream->pctx->label,comp->stream->label,comp->component_id,comp->nominated->codeword,comp->nominated->as_string,pair->codeword);
909 }
910
911 /* Set the new nominated pair */
912 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): nominated pair is %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->codeword,pair->as_string);
913 comp->state=NR_ICE_COMPONENT_NOMINATED;
914 comp->nominated=pair;
915 comp->active=pair;
916
917 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling all pairs but %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->codeword,pair->as_string);
918
919 /* Cancel checks in WAITING and FROZEN per ICE S 8.1.2 */
920 p2=TAILQ_FIRST(&comp->stream->check_list);
921 while(p2){
922 if((p2 != pair) &&
923 (p2->remote->component->component_id == comp->component_id) &&
924 ((p2->state == NR_ICE_PAIR_STATE_FROZEN) ||
925 (p2->state == NR_ICE_PAIR_STATE_WAITING))) {
926 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword);
927
928 if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2))
929 ABORT(r);
930 }
931
932 p2=TAILQ_NEXT(p2,entry);
933 }
934 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): cancelling done",comp->stream->pctx->label,comp->stream->label,comp->component_id);
935
936 if(r=nr_ice_media_stream_component_nominated(comp->stream,comp))
937 ABORT(r);
938
939 _status=0;
940 abort:
941 return(_status);
942 }
943
944 int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
945 {
946 int r,_status;
947 nr_ice_cand_pair *p2;
948
949 assert(pair->state == NR_ICE_PAIR_STATE_FAILED);
950
951 p2=TAILQ_FIRST(&comp->stream->check_list);
952 while(p2){
953 if(comp->component_id==p2->local->component_id){
954 switch(p2->state){
955 case NR_ICE_PAIR_STATE_FROZEN:
956 case NR_ICE_PAIR_STATE_WAITING:
957 case NR_ICE_PAIR_STATE_IN_PROGRESS:
958 /* answer component status cannot be determined yet */
959 goto done;
960 break;
961 case NR_ICE_PAIR_STATE_SUCCEEDED:
962 /* the component will succeed */
963 goto done;
964 break;
965 case NR_ICE_PAIR_STATE_FAILED:
966 case NR_ICE_PAIR_STATE_CANCELLED:
967 /* states that will never be recovered from */
968 break;
969 default:
970 assert(0);
971 break;
972 }
973 }
974
975 p2=TAILQ_NEXT(p2,entry);
976 }
977
978 /* all the pairs in the component are in their final states with
979 * none of them being SUCCEEDED, so the component fails entirely,
980 * tell the media stream that this component has failed */
981
982 if(r=nr_ice_media_stream_component_failed(comp->stream,comp))
983 ABORT(r);
984
985 done:
986 _status=0;
987 abort:
988 return(_status);
989 }
990
991 int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp)
992 {
993 nr_ice_cand_pair **pairs=0;
994 int ct=0;
995 nr_ice_cand_pair *pair;
996 int r,_status;
997
998 /* Size the array */
999 pair=TAILQ_FIRST(&comp->stream->check_list);
1000 while(pair){
1001 if (comp->component_id == pair->local->component_id)
1002 ct++;
1003
1004 pair=TAILQ_NEXT(pair,entry);
1005 }
1006
1007 /* Make and fill the array */
1008 if(!(pairs=RCALLOC(sizeof(nr_ice_cand_pair *)*ct)))
1009 ABORT(R_NO_MEMORY);
1010
1011 ct=0;
1012 pair=TAILQ_FIRST(&comp->stream->check_list);
1013 while(pair){
1014 if (comp->component_id == pair->local->component_id)
1015 pairs[ct++]=pair;
1016
1017 pair=TAILQ_NEXT(pair,entry);
1018 }
1019
1020 if (pctx->handler) {
1021 if(r=pctx->handler->vtbl->select_pair(pctx->handler->obj,
1022 comp->stream,comp->component_id,pairs,ct))
1023 ABORT(r);
1024 }
1025
1026 _status=0;
1027 abort:
1028 RFREE(pairs);
1029 return(_status);
1030 }
1031
1032
1033 static void nr_ice_component_keepalive_cb(NR_SOCKET s, int how, void *cb_arg)
1034 {
1035 nr_ice_component *comp=cb_arg;
1036 UINT4 keepalive_timeout;
1037
1038 assert(comp->keepalive_ctx);
1039
1040 if(NR_reg_get_uint4(NR_ICE_REG_KEEPALIVE_TIMER,&keepalive_timeout)){
1041 keepalive_timeout=15000; /* Default */
1042 }
1043
1044
1045 if(comp->keepalive_needed)
1046 nr_stun_client_force_retransmit(comp->keepalive_ctx);
1047
1048 comp->keepalive_needed=1;
1049 NR_ASYNC_TIMER_SET(keepalive_timeout,nr_ice_component_keepalive_cb,cb_arg,&comp->keepalive_timer);
1050 }
1051
1052
1053 /* Close the underlying sockets for everything but the nominated candidate */
1054 int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp)
1055 {
1056 nr_ice_socket *isock=0;
1057 int r,_status;
1058 nr_ice_socket *s1,*s2;
1059
1060 if(rcomp->state==NR_ICE_COMPONENT_NOMINATED){
1061 assert(rcomp->active == rcomp->nominated);
1062 isock=rcomp->nominated->local->isock;
1063 }
1064
1065 STAILQ_FOREACH_SAFE(s1, &lcomp->sockets, entry, s2){
1066 if(s1!=isock){
1067 STAILQ_REMOVE(&lcomp->sockets,s1,nr_ice_socket_,entry);
1068 nr_ice_socket_destroy(&s1);
1069 }
1070 }
1071
1072 /* Set up the keepalives for the chosen socket */
1073 if(r=nr_stun_client_ctx_create("keepalive",rcomp->nominated->local->osock,
1074 &rcomp->nominated->remote->addr,0,&rcomp->keepalive_ctx))
1075 ABORT(r);
1076 if(r=nr_stun_client_start(rcomp->keepalive_ctx,NR_STUN_CLIENT_MODE_KEEPALIVE,0,0))
1077 ABORT(r);
1078 nr_ice_component_keepalive_cb(0,0,rcomp);
1079
1080
1081 _status=0;
1082 abort:
1083
1084 return(_status);
1085 }
1086
1087
1088 int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair)
1089 {
1090 int r,_status;
1091
1092 /* Pairs for peer reflexive are marked SUCCEEDED immediately */
1093 if (pair->state != NR_ICE_PAIR_STATE_FROZEN &&
1094 pair->state != NR_ICE_PAIR_STATE_SUCCEEDED){
1095 assert(0);
1096 ABORT(R_BAD_ARGS);
1097 }
1098
1099 if(r=nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,pair))
1100 ABORT(r);
1101
1102 /* Make sure the check timer is running, if the stream was previously
1103 * started. We will not start streams just because a pair was created. */
1104 if(pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE){
1105 if(nr_ice_media_stream_start_checks(pair->remote->stream->pctx, pair->remote->stream)) {
1106 r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND-PAIR(%s): Could not restart checks for new pair %s.",pair->remote->stream->pctx->label, pair->codeword, pair->as_string);
1107 ABORT(R_INTERNAL);
1108 }
1109 }
1110
1111 _status=0;
1112 abort:
1113 return(_status);
1114 }
1115

mercurial