Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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.
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.
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 */
35 static char *RCSSTRING __UNUSED__="$Id: ice_component.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
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"
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);
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;
60 if (!(par = RCALLOC(sizeof(nr_ice_pre_answer_request))))
61 ABORT(R_NO_MEMORY);
63 par->req = *req; /* Struct assignment */
64 memset(req, 0, sizeof(*req)); /* Zero contents to avoid confusion */
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);
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 }
82 return(_status);
83 }
85 static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp)
86 {
87 nr_ice_pre_answer_request *par;
89 if (!parp || !*parp)
90 return(0);
92 par = *parp;
93 *parp = 0;
95 nr_stun_message_destroy(&par->req.request);
96 nr_stun_message_destroy(&par->req.response);
98 RFREE(par->username);
100 return(0);
101 }
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;
108 if(!(comp=RCALLOC(sizeof(nr_ice_component))))
109 ABORT(R_NO_MEMORY);
111 comp->state=NR_ICE_COMPONENT_UNPAIRED;
112 comp->component_id=component_id;
113 comp->stream=stream;
114 comp->ctx=stream->ctx;
116 STAILQ_INIT(&comp->sockets);
117 TAILQ_INIT(&comp->candidates);
118 STAILQ_INIT(&comp->pre_answer_reqs);
120 STAILQ_INSERT_TAIL(&stream->components,comp,entry);
122 _status=0;
123 abort:
124 return(_status);
125 }
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;
134 if(!componentp || !*componentp)
135 return(0);
137 component=*componentp;
138 *componentp=0;
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 }
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 }
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 }
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 }
166 if(component->keepalive_timer)
167 NR_async_timer_cancel(component->keepalive_timer);
168 nr_stun_client_ctx_destroy(&component->keepalive_ctx);
170 RFREE(component);
171 return(0);
172 }
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;
184 /* Now one ice_socket for each address */
185 for(i=0;i<addr_ct;i++){
186 char suppress;
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 }
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);
209 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
210 component->candidate_ct++;
211 cand=0;
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 }
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;
230 /* Skip non-UDP */
231 if (ctx->turn_servers[j].transport != IPPROTO_UDP)
232 continue;
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;
243 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
244 component->candidate_ct++;
245 srvflx_cand=cand;
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++;
259 cand=0;
260 }
261 #endif /* USE_TURN */
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);
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);
275 STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
276 }
278 _status = 0;
279 abort:
280 return(_status);
281 }
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;
292 /* Create a new relayed candidate for each addr/TURN server pair */
293 for(i=0;i<addr_ct;i++){
294 char suppress;
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 }
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;
312 /* Skip non-TCP */
313 if (ctx->turn_servers[j].transport != IPPROTO_TCP)
314 continue;
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);
330 /* The TURN socket */
331 if(r=nr_socket_turn_create(buffered_sock, &turn_sock))
332 ABORT(r);
334 /* Create an ICE socket */
335 if((r=nr_ice_socket_create(ctx, component, buffered_sock, &isock)))
336 ABORT(r);
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;
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);
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);
361 STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
362 }
363 }
364 #endif
366 _status = 0;
367 abort:
368 return(_status);
369 }
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;
383 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): initializing component with id %d",ctx->label,component->component_id);
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 }
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));
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);
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 }
416 while(cand){
417 ctx->uninitialized_candidates++;
418 cand=TAILQ_NEXT(cand,entry_comp);
419 }
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 }
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 }
448 /*
449 Compare this newly initialized candidate against the other initialized
450 candidates and discard the lower-priority one if they are redundant.
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;
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)){
467 if((c1->type == c2->type) ||
468 (c1->type==HOST && c2->type == SERVER_REFLEXIVE) ||
469 (c2->type==HOST && c1->type == SERVER_REFLEXIVE)){
471 /*
472 These are redundant. Remove the lower pri one, or if pairing has
473 already occurred, remove the newest one.
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 }
489 c2=TAILQ_NEXT(c2,entry_comp);
490 }
492 if (tmp) {
493 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): Removing redundant candidate",
494 ctx->label,tmp->label);
496 TAILQ_REMOVE(&comp->candidates,tmp,entry_comp);
497 comp->candidate_ct--;
498 TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock);
500 nr_ice_candidate_destroy(&tmp);
501 }
503 return 0;
504 }
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;
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);
521 if (comp->state == NR_ICE_COMPONENT_DISABLED)
522 ABORT(R_REJECTED);
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);
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);
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);
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);
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);
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);
560 *error=487;
561 ABORT(R_REJECTED);
562 }
563 }
564 }
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);
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;
574 if(pair->remote->component->component_id!=comp->component_id)
575 goto next_pair;
576 component_id_matched = 1;
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;
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;
587 if(pair->state==NR_ICE_PAIR_STATE_FAILED){
588 found_invalid=pair;
589 goto next_pair;
590 }
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 }
597 next_pair:
598 pair=TAILQ_NEXT(pair,entry);
599 }
601 if(!pair){
602 if(!found_invalid){
603 /* First find our local component candidate */
604 nr_ice_candidate *cand;
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;
612 cand=TAILQ_NEXT(cand,entry_comp);
613 }
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);
620 *error=400;
621 ABORT(R_NOT_FOUND);
622 }
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;
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);
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 }
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;
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 }
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;
683 if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED && !pair->nominated){
684 pair->nominated=1;
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 }
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 }
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 }
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;
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 }
721 if (r=nr_ice_component_process_incoming_check(comp, &local_addr, req, error))
722 ABORT(r);
724 _status=0;
725 abort:
726 return(_status);
727 }
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;
735 if (serviced)
736 *serviced = 0;
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);
740 STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2) {
741 if (!strcmp(r1->username, username)) {
742 int error = 0;
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 }
755 _status=0;
756 return(_status);
757 }
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];
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);
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 }
785 pcand=TAILQ_FIRST(&pcomp->candidates);
786 while(pcand){
787 /*
788 Two modes, depending on |pair_all_remote|
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);
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);
805 if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
806 ABORT(r);
808 if(r=nr_ice_component_insert_pair(pcomp, pair))
809 ABORT(r);
810 }
812 pcand=TAILQ_NEXT(pcand,entry_comp);
813 }
815 done:
816 _status = 0;
817 abort:
818 return(_status);
819 }
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;
827 r_log(LOG_ICE,LOG_DEBUG,"Pairing candidates======");
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 }
837 lcand=TAILQ_NEXT(lcand,entry_comp);
838 }
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;
845 pcand=TAILQ_NEXT(pcand,entry_comp);
847 }
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 }
864 pcomp->state = NR_ICE_COMPONENT_RUNNING;
866 _status=0;
867 abort:
868 return(_status);
869 }
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);
884 if (r=nr_ice_pre_answer_request_create(sock, req, &par))
885 ABORT(r);
887 *dont_free = 1;
888 STAILQ_INSERT_TAIL(&comp->pre_answer_reqs, par, entry);
890 _status=0;
891 abort:
892 return 0;
893 }
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;
901 if(!comp->nominated)
902 fire_cb=1;
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 }
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;
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);
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);
928 if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2))
929 ABORT(r);
930 }
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);
936 if(r=nr_ice_media_stream_component_nominated(comp->stream,comp))
937 ABORT(r);
939 _status=0;
940 abort:
941 return(_status);
942 }
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;
949 assert(pair->state == NR_ICE_PAIR_STATE_FAILED);
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 }
975 p2=TAILQ_NEXT(p2,entry);
976 }
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 */
982 if(r=nr_ice_media_stream_component_failed(comp->stream,comp))
983 ABORT(r);
985 done:
986 _status=0;
987 abort:
988 return(_status);
989 }
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;
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++;
1004 pair=TAILQ_NEXT(pair,entry);
1005 }
1007 /* Make and fill the array */
1008 if(!(pairs=RCALLOC(sizeof(nr_ice_cand_pair *)*ct)))
1009 ABORT(R_NO_MEMORY);
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;
1017 pair=TAILQ_NEXT(pair,entry);
1018 }
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 }
1026 _status=0;
1027 abort:
1028 RFREE(pairs);
1029 return(_status);
1030 }
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;
1038 assert(comp->keepalive_ctx);
1040 if(NR_reg_get_uint4(NR_ICE_REG_KEEPALIVE_TIMER,&keepalive_timeout)){
1041 keepalive_timeout=15000; /* Default */
1042 }
1045 if(comp->keepalive_needed)
1046 nr_stun_client_force_retransmit(comp->keepalive_ctx);
1048 comp->keepalive_needed=1;
1049 NR_ASYNC_TIMER_SET(keepalive_timeout,nr_ice_component_keepalive_cb,cb_arg,&comp->keepalive_timer);
1050 }
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;
1060 if(rcomp->state==NR_ICE_COMPONENT_NOMINATED){
1061 assert(rcomp->active == rcomp->nominated);
1062 isock=rcomp->nominated->local->isock;
1063 }
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 }
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);
1081 _status=0;
1082 abort:
1084 return(_status);
1085 }
1088 int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair)
1089 {
1090 int r,_status;
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 }
1099 if(r=nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,pair))
1100 ABORT(r);
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 }
1111 _status=0;
1112 abort:
1113 return(_status);
1114 }