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_wrapper.h"
48 #include "nr_socket_buffered_stun.h"
49 #include "nr_socket_multi_tcp.h"
50 #include "ice_reg.h"
51 #include "nr_crypto.h"
52 #include "r_time.h"
53
54 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);
55 static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp);
56 void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp);
57 void nr_ice_component_consent_destroy(nr_ice_component *comp);
58
59 /* This function takes ownership of the contents of req (but not req itself) */
nr_ice_pre_answer_request_create(nr_transport_addr * dst,nr_stun_server_request * req,nr_ice_pre_answer_request ** parp)60 static int nr_ice_pre_answer_request_create(nr_transport_addr *dst, nr_stun_server_request *req, nr_ice_pre_answer_request **parp)
61 {
62 int r, _status;
63 nr_ice_pre_answer_request *par = 0;
64 nr_stun_message_attribute *attr;
65
66 if (!(par = RCALLOC(sizeof(nr_ice_pre_answer_request))))
67 ABORT(R_NO_MEMORY);
68
69 par->req = *req; /* Struct assignment */
70 memset(req, 0, sizeof(*req)); /* Zero contents to avoid confusion */
71
72 if (r=nr_transport_addr_copy(&par->local_addr, dst))
73 ABORT(r);
74 if (!nr_stun_message_has_attribute(par->req.request, NR_STUN_ATTR_USERNAME, &attr))
75 ABORT(R_INTERNAL);
76 if (!(par->username = r_strdup(attr->u.username)))
77 ABORT(R_NO_MEMORY);
78
79 *parp=par;
80 _status=0;
81 abort:
82 if (_status) {
83 /* Erase the request so we don't free it */
84 memset(&par->req, 0, sizeof(nr_stun_server_request));
85 nr_ice_pre_answer_request_destroy(&par);
86 }
87
88 return(_status);
89 }
90
nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request ** parp)91 static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp)
92 {
93 nr_ice_pre_answer_request *par;
94
95 if (!parp || !*parp)
96 return(0);
97
98 par = *parp;
99 *parp = 0;
100
101 nr_stun_message_destroy(&par->req.request);
102 nr_stun_message_destroy(&par->req.response);
103
104 RFREE(par->username);
105 RFREE(par);
106
107 return(0);
108 }
109
nr_ice_component_create(nr_ice_media_stream * stream,int component_id,nr_ice_component ** componentp)110 int nr_ice_component_create(nr_ice_media_stream *stream, int component_id, nr_ice_component **componentp)
111 {
112 int _status;
113 nr_ice_component *comp=0;
114
115 if(!(comp=RCALLOC(sizeof(nr_ice_component))))
116 ABORT(R_NO_MEMORY);
117
118 comp->state=NR_ICE_COMPONENT_UNPAIRED;
119 comp->component_id=component_id;
120 comp->stream=stream;
121 comp->ctx=stream->ctx;
122
123 STAILQ_INIT(&comp->sockets);
124 TAILQ_INIT(&comp->candidates);
125 STAILQ_INIT(&comp->pre_answer_reqs);
126
127 STAILQ_INSERT_TAIL(&stream->components,comp,entry);
128
129 _status=0;
130 abort:
131 return(_status);
132 }
133
nr_ice_component_destroy(nr_ice_component ** componentp)134 int nr_ice_component_destroy(nr_ice_component **componentp)
135 {
136 nr_ice_component *component;
137 nr_ice_socket *s1,*s2;
138 nr_ice_candidate *c1,*c2;
139 nr_ice_pre_answer_request *r1,*r2;
140
141 if(!componentp || !*componentp)
142 return(0);
143
144 component=*componentp;
145 *componentp=0;
146
147 nr_ice_component_consent_destroy(component);
148
149 /* Detach ourselves from the sockets */
150 if (component->local_component){
151 nr_ice_socket *isock=STAILQ_FIRST(&component->local_component->sockets);
152 while(isock){
153 nr_stun_server_remove_client(isock->stun_server, component);
154 isock=STAILQ_NEXT(isock, entry);
155 }
156 }
157
158 /* candidates MUST be destroyed before the sockets so that
159 they can deregister */
160 TAILQ_FOREACH_SAFE(c1, &component->candidates, entry_comp, c2){
161 TAILQ_REMOVE(&component->candidates,c1,entry_comp);
162 nr_ice_candidate_destroy(&c1);
163 }
164
165 STAILQ_FOREACH_SAFE(s1, &component->sockets, entry, s2){
166 STAILQ_REMOVE(&component->sockets,s1,nr_ice_socket_,entry);
167 nr_ice_socket_destroy(&s1);
168 }
169
170 STAILQ_FOREACH_SAFE(r1, &component->pre_answer_reqs, entry, r2){
171 STAILQ_REMOVE(&component->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry);
172 nr_ice_pre_answer_request_destroy(&r1);
173 }
174
175 RFREE(component);
176 return(0);
177 }
178
nr_ice_component_create_stun_server_ctx(nr_ice_component * component,nr_ice_socket * isock,nr_socket * sock,nr_transport_addr * addr,char * lufrag,Data * pwd)179 static int nr_ice_component_create_stun_server_ctx(nr_ice_component *component, nr_ice_socket *isock, nr_socket *sock, nr_transport_addr *addr, char *lufrag, Data *pwd)
180 {
181 char label[256];
182 int r,_status;
183
184 /* Create a STUN server context for this socket */
185 snprintf(label, sizeof(label), "server(%s)", addr->as_string);
186 if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
187 ABORT(r);
188 if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
189 ABORT(r);
190
191 /* Add the default STUN credentials so that we can respond before
192 we hear about the peer.*/
193 if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
194 ABORT(r);
195
196 _status = 0;
197 abort:
198 return(_status);
199 }
200
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)201 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)
202 {
203 nr_socket *sock;
204 nr_ice_socket *isock=0;
205 nr_ice_candidate *cand=0;
206 int i;
207 int j;
208 int r,_status;
209
210 if(ctx->flags & NR_ICE_CTX_FLAGS_ONLY_PROXY) {
211 /* No UDP support if we must use a proxy */
212 return 0;
213 }
214
215 /* Now one ice_socket for each address */
216 for(i=0;i<addr_ct;i++){
217 char suppress;
218
219 if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
220 if(r!=R_NOT_FOUND)
221 ABORT(r);
222 }
223 else{
224 if(suppress)
225 continue;
226 }
227 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): host address %s",ctx->label,addrs[i].addr.as_string);
228 if((r=nr_socket_factory_create_socket(ctx->socket_factory,&addrs[i].addr,&sock))){
229 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): couldn't create socket for address %s",ctx->label,addrs[i].addr.as_string);
230 continue;
231 }
232
233 if(r=nr_ice_socket_create(ctx,component,sock,NR_ICE_SOCKET_TYPE_DGRAM,&isock))
234 ABORT(r);
235
236 if (!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY)) {
237 /* Create one host candidate */
238 if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,0,
239 component->component_id,&cand))
240 ABORT(r);
241
242 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
243 component->candidate_ct++;
244 cand=0;
245
246 /* And a srvrflx candidate for each STUN server */
247 for(j=0;j<ctx->stun_server_ct;j++){
248 /* Skip non-UDP */
249 if(ctx->stun_servers[j].transport!=IPPROTO_UDP)
250 continue;
251
252 if (ctx->stun_servers[j].type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
253 if (nr_transport_addr_check_compatibility(
254 &addrs[i].addr,
255 &ctx->stun_servers[j].u.addr)) {
256 r_log(LOG_ICE,LOG_INFO,"ICE(%s): Skipping STUN server because of link local mis-match",ctx->label);
257 continue;
258 }
259 }
260
261 /* Ensure id is set (nr_ice_ctx_set_stun_servers does not) */
262 ctx->stun_servers[j].id = j;
263 if(r=nr_ice_candidate_create(ctx,component,
264 isock,sock,SERVER_REFLEXIVE,0,
265 &ctx->stun_servers[j],component->component_id,&cand))
266 ABORT(r);
267 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
268 component->candidate_ct++;
269 cand=0;
270 }
271 }
272 else{
273 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): relay only option results in no host candidate for %s",ctx->label,addrs[i].addr.as_string);
274 }
275
276 #ifdef USE_TURN
277 if ((ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) &&
278 (ctx->turn_server_ct == 0)) {
279 r_log(LOG_ICE,LOG_ERR,"ICE(%s): relay only option is set without any TURN server configured",ctx->label);
280 }
281 /* And both a srvrflx and relayed candidate for each TURN server (unless
282 we're in relay-only mode, in which case just the relayed one) */
283 for(j=0;j<ctx->turn_server_ct;j++){
284 nr_socket *turn_sock;
285 nr_ice_candidate *srvflx_cand=0;
286
287 /* Skip non-UDP */
288 if (ctx->turn_servers[j].turn_server.transport != IPPROTO_UDP)
289 continue;
290
291 if (ctx->turn_servers[j].turn_server.type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
292 if (nr_transport_addr_check_compatibility(
293 &addrs[i].addr,
294 &ctx->turn_servers[j].turn_server.u.addr)) {
295 r_log(LOG_ICE,LOG_INFO,"ICE(%s): Skipping TURN server because of link local mis-match",ctx->label);
296 continue;
297 }
298 }
299
300 if (!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY)) {
301 /* Ensure id is set with a unique value */
302 ctx->turn_servers[j].turn_server.id = j + ctx->stun_server_ct;
303 /* srvrflx */
304 if(r=nr_ice_candidate_create(ctx,component,
305 isock,sock,SERVER_REFLEXIVE,0,
306 &ctx->turn_servers[j].turn_server,component->component_id,&cand))
307 ABORT(r);
308 cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
309 cand->done_cb=nr_ice_gather_finished_cb;
310 cand->cb_arg=cand;
311
312 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
313 component->candidate_ct++;
314 srvflx_cand=cand;
315 cand=0;
316 }
317 /* relayed*/
318 if(r=nr_socket_turn_create(sock, &turn_sock))
319 ABORT(r);
320 if(r=nr_ice_candidate_create(ctx,component,
321 isock,turn_sock,RELAYED,0,
322 &ctx->turn_servers[j].turn_server,component->component_id,&cand))
323 ABORT(r);
324 if (srvflx_cand) {
325 cand->u.relayed.srvflx_candidate=srvflx_cand;
326 srvflx_cand->u.srvrflx.relay_candidate=cand;
327 }
328 cand->u.relayed.server=&ctx->turn_servers[j];
329 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
330 component->candidate_ct++;
331
332 cand=0;
333 }
334 #endif /* USE_TURN */
335
336 /* Create a STUN server context for this socket */
337 if ((r=nr_ice_component_create_stun_server_ctx(component,isock,sock,&addrs[i].addr,lufrag,pwd)))
338 ABORT(r);
339
340 STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
341 }
342
343 _status = 0;
344 abort:
345 return(_status);
346 }
347
nr_ice_component_get_port_from_ephemeral_range(uint16_t * port)348 static int nr_ice_component_get_port_from_ephemeral_range(uint16_t *port)
349 {
350 int _status, r;
351 void *buf = port;
352 if(r=nr_crypto_random_bytes(buf, 2))
353 ABORT(r);
354 *port|=49152; /* make it fit into IANA ephemeral port range >= 49152 */
355 _status=0;
356 abort:
357 return(_status);
358 }
359
nr_ice_component_create_tcp_host_candidate(struct nr_ice_ctx_ * ctx,nr_ice_component * component,nr_transport_addr * interface_addr,nr_socket_tcp_type tcp_type,int backlog,int so_sock_ct,char * lufrag,Data * pwd,nr_ice_socket ** isock)360 static int nr_ice_component_create_tcp_host_candidate(struct nr_ice_ctx_ *ctx,
361 nr_ice_component *component, nr_transport_addr *interface_addr, nr_socket_tcp_type tcp_type,
362 int backlog, int so_sock_ct, char *lufrag, Data *pwd, nr_ice_socket **isock)
363 {
364 int r,_status;
365 nr_ice_candidate *cand=0;
366 int tries=3;
367 nr_ice_socket *isock_tmp=0;
368 nr_socket *nrsock=0;
369 nr_transport_addr addr;
370 uint16_t local_port;
371
372 if ((r=nr_transport_addr_copy(&addr,interface_addr)))
373 ABORT(r);
374 addr.protocol=IPPROTO_TCP;
375
376 do{
377 if (!tries--)
378 ABORT(r);
379
380 if((r=nr_ice_component_get_port_from_ephemeral_range(&local_port)))
381 ABORT(r);
382
383 if ((r=nr_transport_addr_set_port(&addr, local_port)))
384 ABORT(r);
385
386 if((r=nr_transport_addr_fmt_addr_string(&addr)))
387 ABORT(r);
388
389 /* It would be better to stop trying if there is error other than
390 port already used, but it'd require significant work to support this. */
391 r=nr_socket_multi_tcp_create(ctx,&addr,tcp_type,so_sock_ct,NR_STUN_MAX_MESSAGE_SIZE,&nrsock);
392
393 } while(r);
394
395 if((tcp_type == TCP_TYPE_PASSIVE) && (r=nr_socket_listen(nrsock,backlog)))
396 ABORT(r);
397
398 if((r=nr_ice_socket_create(ctx,component,nrsock,NR_ICE_SOCKET_TYPE_STREAM_TCP,&isock_tmp)))
399 ABORT(r);
400
401 /* nr_ice_socket took ownership of nrsock */
402 nrsock=NULL;
403
404 /* Create a STUN server context for this socket */
405 if ((r=nr_ice_component_create_stun_server_ctx(component,isock_tmp,isock_tmp->sock,&addr,lufrag,pwd)))
406 ABORT(r);
407
408 if((r=nr_ice_candidate_create(ctx,component,isock_tmp,isock_tmp->sock,HOST,tcp_type,0,
409 component->component_id,&cand)))
410 ABORT(r);
411
412 if (isock)
413 *isock=isock_tmp;
414
415 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
416 component->candidate_ct++;
417
418 STAILQ_INSERT_TAIL(&component->sockets,isock_tmp,entry);
419
420 _status=0;
421 abort:
422 if (_status) {
423 nr_ice_socket_destroy(&isock_tmp);
424 nr_socket_destroy(&nrsock);
425 }
426 return(_status);
427 }
428
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)429 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)
430 {
431 nr_ice_candidate *cand=0;
432 int i;
433 int j;
434 int r,_status;
435 int so_sock_ct=0;
436 int backlog=10;
437 char ice_tcp_disabled=1;
438
439 r_log(LOG_ICE,LOG_DEBUG,"nr_ice_component_initialize_tcp");
440
441 if(r=NR_reg_get_int4(NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT,&so_sock_ct)){
442 if(r!=R_NOT_FOUND)
443 ABORT(r);
444 }
445
446 if(r=NR_reg_get_int4(NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,&backlog)){
447 if(r!=R_NOT_FOUND)
448 ABORT(r);
449 }
450
451 if ((r=NR_reg_get_char(NR_ICE_REG_ICE_TCP_DISABLE, &ice_tcp_disabled))) {
452 if (r != R_NOT_FOUND)
453 ABORT(r);
454 }
455 if ((ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) ||
456 (ctx->flags & NR_ICE_CTX_FLAGS_ONLY_PROXY)) {
457 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): relay/proxy only option results in ICE TCP being disabled",ctx->label);
458 ice_tcp_disabled = 1;
459 }
460
461 for(i=0;i<addr_ct;i++){
462 char suppress;
463 nr_ice_socket *isock_psv=0;
464 nr_ice_socket *isock_so=0;
465
466 if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
467 if(r!=R_NOT_FOUND)
468 ABORT(r);
469 }
470 else if(suppress) {
471 continue;
472 }
473
474 if (!ice_tcp_disabled) {
475 /* passive host candidate */
476 if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
477 TCP_TYPE_PASSIVE, backlog, 0, lufrag, pwd, &isock_psv))) {
478 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to create passive TCP host candidate: %d",ctx->label,r);
479 }
480
481 /* active host candidate */
482 if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
483 TCP_TYPE_ACTIVE, 0, 0, lufrag, pwd, NULL))) {
484 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to create active TCP host candidate: %d",ctx->label,r);
485 }
486
487 /* simultaneous-open host candidate */
488 if (so_sock_ct) {
489 if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
490 TCP_TYPE_SO, 0, so_sock_ct, lufrag, pwd, &isock_so))) {
491 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to create simultanous open TCP host candidate: %d",ctx->label,r);
492 }
493 }
494
495 /* And srvrflx candidates for each STUN server */
496 for(j=0;j<ctx->stun_server_ct;j++){
497 if (ctx->stun_servers[j].transport!=IPPROTO_TCP)
498 continue;
499
500 if (isock_psv) {
501 if(r=nr_ice_candidate_create(ctx,component,
502 isock_psv,isock_psv->sock,SERVER_REFLEXIVE,TCP_TYPE_PASSIVE,
503 &ctx->stun_servers[j],component->component_id,&cand))
504 ABORT(r);
505 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
506 component->candidate_ct++;
507 cand=0;
508 }
509
510 if (isock_so) {
511 if(r=nr_ice_candidate_create(ctx,component,
512 isock_so,isock_so->sock,SERVER_REFLEXIVE,TCP_TYPE_SO,
513 &ctx->stun_servers[j],component->component_id,&cand))
514 ABORT(r);
515 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
516 component->candidate_ct++;
517 cand=0;
518 }
519 }
520 }
521
522 #ifdef USE_TURN
523 /* Create a new relayed candidate for each addr/TURN server pair */
524 for(j=0;j<ctx->turn_server_ct;j++){
525 nr_transport_addr addr;
526 nr_socket *local_sock;
527 nr_socket *buffered_sock;
528 nr_socket *turn_sock;
529 nr_ice_socket *turn_isock;
530
531 /* Skip non-TCP */
532 if (ctx->turn_servers[j].turn_server.transport != IPPROTO_TCP)
533 continue;
534
535 /* Create relay candidate */
536 if ((r=nr_transport_addr_copy(&addr, &addrs[i].addr)))
537 ABORT(r);
538 addr.protocol = IPPROTO_TCP;
539
540 if (ctx->turn_servers[j].turn_server.type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
541 if (nr_transport_addr_check_compatibility(
542 &addr,
543 &ctx->turn_servers[j].turn_server.u.addr)) {
544 r_log(LOG_ICE,LOG_INFO,"ICE(%s): Skipping TURN server because of link local mis-match",ctx->label);
545 continue;
546 }
547 }
548
549 if (!ice_tcp_disabled) {
550 /* Use TURN server to get srflx candidates */
551 if (isock_psv) {
552 if(r=nr_ice_candidate_create(ctx,component,
553 isock_psv,isock_psv->sock,SERVER_REFLEXIVE,TCP_TYPE_PASSIVE,
554 &ctx->turn_servers[j].turn_server,component->component_id,&cand))
555 ABORT(r);
556 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
557 component->candidate_ct++;
558 cand=0;
559 }
560
561 if (isock_so) {
562 if(r=nr_ice_candidate_create(ctx,component,
563 isock_so,isock_so->sock,SERVER_REFLEXIVE,TCP_TYPE_SO,
564 &ctx->turn_servers[j].turn_server,component->component_id,&cand))
565 ABORT(r);
566 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
567 component->candidate_ct++;
568 cand=0;
569 }
570 }
571
572 /* If we're going to use TLS, make sure that's recorded */
573 if (ctx->turn_servers[j].turn_server.tls) {
574 strncpy(addr.tls_host,
575 ctx->turn_servers[j].turn_server.u.dnsname.host,
576 sizeof(addr.tls_host) - 1);
577 }
578
579 if ((r=nr_transport_addr_fmt_addr_string(&addr)))
580 ABORT(r);
581 /* Create a local socket */
582 if((r=nr_socket_factory_create_socket(ctx->socket_factory,&addr,&local_sock))){
583 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create socket for address %s",ctx->label,addr.as_string);
584 continue;
585 }
586
587 r_log(LOG_ICE,LOG_DEBUG,"nr_ice_component_initialize_tcp creating TURN TCP wrappers");
588
589 if (ctx->turn_tcp_socket_wrapper) {
590 /* The HTTP proxy socket */
591 if((r=nr_socket_wrapper_factory_wrap(ctx->turn_tcp_socket_wrapper, local_sock, &local_sock)))
592 ABORT(r);
593 }
594
595 /* The TCP buffered socket */
596 if((r=nr_socket_buffered_stun_create(local_sock, NR_STUN_MAX_MESSAGE_SIZE, TURN_TCP_FRAMING, &buffered_sock)))
597 ABORT(r);
598
599 /* The TURN socket */
600 if(r=nr_socket_turn_create(buffered_sock, &turn_sock))
601 ABORT(r);
602
603 /* Create an ICE socket */
604 if((r=nr_ice_socket_create(ctx, component, buffered_sock, NR_ICE_SOCKET_TYPE_STREAM_TURN, &turn_isock)))
605 ABORT(r);
606
607 /* Attach ourselves to it */
608 if(r=nr_ice_candidate_create(ctx,component,
609 turn_isock,turn_sock,RELAYED,TCP_TYPE_NONE,
610 &ctx->turn_servers[j].turn_server,component->component_id,&cand))
611 ABORT(r);
612 cand->u.relayed.srvflx_candidate=NULL;
613 cand->u.relayed.server=&ctx->turn_servers[j];
614 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
615 component->candidate_ct++;
616 cand=0;
617
618 /* Create a STUN server context for this socket */
619 if ((r=nr_ice_component_create_stun_server_ctx(component,turn_isock,local_sock,&addr,lufrag,pwd)))
620 ABORT(r);
621
622 STAILQ_INSERT_TAIL(&component->sockets,turn_isock,entry);
623 }
624 #endif /* USE_TURN */
625 }
626
627 _status = 0;
628 abort:
629 return(_status);
630 }
631
632
633 /* Make all the candidates we can make at the beginning */
nr_ice_component_initialize(struct nr_ice_ctx_ * ctx,nr_ice_component * component)634 int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component)
635 {
636 int r,_status;
637 nr_local_addr *addrs=ctx->local_addrs;
638 int addr_ct=ctx->local_addr_ct;
639 char *lufrag;
640 char *lpwd;
641 Data pwd;
642 nr_ice_candidate *cand;
643
644 if (component->candidate_ct) {
645 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): component with id %d already has candidates, probably restarting gathering because of a new stream",ctx->label,component->component_id);
646 return(0);
647 }
648
649 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): initializing component with id %d",ctx->label,component->component_id);
650
651 if(addr_ct==0){
652 r_log(LOG_ICE,LOG_ERR,"ICE(%s): no local addresses available",ctx->label);
653 ABORT(R_NOT_FOUND);
654 }
655
656 /* Note: we need to recompute these because
657 we have not yet computed the values in the peer media stream.*/
658 lufrag=component->stream->ufrag ? component->stream->ufrag : ctx->ufrag;
659 assert(lufrag);
660 if (!lufrag)
661 ABORT(R_INTERNAL);
662 lpwd=component->stream->pwd ? component->stream->pwd :ctx->pwd;
663 assert(lpwd);
664 if (!lpwd)
665 ABORT(R_INTERNAL);
666 INIT_DATA(pwd, (UCHAR *)lpwd, strlen(lpwd));
667
668 /* Initialize the UDP candidates */
669 if (r=nr_ice_component_initialize_udp(ctx, component, addrs, addr_ct, lufrag, &pwd))
670 r_log(LOG_ICE,LOG_INFO,"ICE(%s): failed to create UDP candidates with error %d",ctx->label,r);
671 /* And the TCP candidates */
672 if (r=nr_ice_component_initialize_tcp(ctx, component, addrs, addr_ct, lufrag, &pwd))
673 r_log(LOG_ICE,LOG_INFO,"ICE(%s): failed to create TCP candidates with error %d",ctx->label,r);
674
675 /* count the candidates that will be initialized */
676 cand=TAILQ_FIRST(&component->candidates);
677 if(!cand){
678 r_log(LOG_ICE,LOG_ERR,"ICE(%s): couldn't create any valid candidates",ctx->label);
679 ABORT(R_NOT_FOUND);
680 }
681
682 while(cand){
683 ctx->uninitialized_candidates++;
684 cand=TAILQ_NEXT(cand,entry_comp);
685 }
686
687 /* Now initialize all the candidates */
688 cand=TAILQ_FIRST(&component->candidates);
689 while(cand){
690 if(cand->state!=NR_ICE_CAND_STATE_INITIALIZING){
691 nr_ice_candidate_initialize(cand,nr_ice_gather_finished_cb,cand);
692 }
693 cand=TAILQ_NEXT(cand,entry_comp);
694 }
695 _status=0;
696 abort:
697 return(_status);
698 }
699
nr_ice_any_peer_paired(nr_ice_candidate * cand)700 static int nr_ice_any_peer_paired(nr_ice_candidate* cand) {
701 nr_ice_peer_ctx* pctx=STAILQ_FIRST(&cand->ctx->peers);
702 while(pctx && pctx->state == NR_ICE_PEER_STATE_UNPAIRED){
703 /* Is it worth actually looking through the check lists? Probably not. */
704 pctx=STAILQ_NEXT(pctx,entry);
705 }
706 return pctx != NULL;
707 }
708
709 /*
710 Compare this newly initialized candidate against the other initialized
711 candidates and discard the lower-priority one if they are redundant.
712
713 This algorithm combined with the other algorithms, favors
714 host > srflx > relay
715 */
nr_ice_component_maybe_prune_candidate(nr_ice_ctx * ctx,nr_ice_component * comp,nr_ice_candidate * c1,int * was_pruned)716 int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned)
717 {
718 nr_ice_candidate *c2, *tmp = NULL;
719
720 *was_pruned = 0;
721 c2 = TAILQ_FIRST(&comp->candidates);
722 while(c2){
723 if((c1 != c2) &&
724 (c2->state == NR_ICE_CAND_STATE_INITIALIZED) &&
725 !nr_transport_addr_cmp(&c1->base,&c2->base,NR_TRANSPORT_ADDR_CMP_MODE_ALL) &&
726 !nr_transport_addr_cmp(&c1->addr,&c2->addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
727
728 if((c1->type == c2->type) ||
729 (!(ctx->flags & NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES) &&
730 ((c1->type==HOST && c2->type == SERVER_REFLEXIVE) ||
731 (c2->type==HOST && c1->type == SERVER_REFLEXIVE)))){
732
733 /*
734 These are redundant. Remove the lower pri one, or if pairing has
735 already occurred, remove the newest one.
736
737 Since this algorithmis run whenever a new candidate
738 is initialized, there should at most one duplicate.
739 */
740 if ((c1->priority <= c2->priority) || nr_ice_any_peer_paired(c2)) {
741 tmp = c1;
742 *was_pruned = 1;
743 }
744 else {
745 tmp = c2;
746 }
747 break;
748 }
749 }
750
751 c2=TAILQ_NEXT(c2,entry_comp);
752 }
753
754 if (tmp) {
755 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): Removing redundant candidate",
756 ctx->label,tmp->label);
757
758 TAILQ_REMOVE(&comp->candidates,tmp,entry_comp);
759 comp->candidate_ct--;
760 TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock);
761
762 nr_ice_candidate_destroy(&tmp);
763 }
764
765 return 0;
766 }
767
nr_ice_component_pair_matches_check(nr_ice_component * comp,nr_ice_cand_pair * pair,nr_transport_addr * local_addr,nr_stun_server_request * req)768 static int nr_ice_component_pair_matches_check(nr_ice_component *comp, nr_ice_cand_pair *pair, nr_transport_addr *local_addr, nr_stun_server_request *req)
769 {
770 if(pair->remote->component->component_id!=comp->component_id)
771 return(0);
772
773 if(nr_transport_addr_cmp(&pair->local->base,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
774 return(0);
775
776 if(nr_transport_addr_cmp(&pair->remote->addr,&req->src_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
777 return(0);
778
779 return(1);
780 }
781
nr_ice_component_handle_triggered_check(nr_ice_component * comp,nr_ice_cand_pair * pair,nr_stun_server_request * req,int * error)782 static int nr_ice_component_handle_triggered_check(nr_ice_component *comp, nr_ice_cand_pair *pair, nr_stun_server_request *req, int *error)
783 {
784 nr_stun_message *sreq=req->request;
785 int r=0,_status;
786
787 if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_USE_CANDIDATE,0)){
788 if(comp->stream->pctx->controlling){
789 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);
790 }
791 else{
792 /* If this is the first time we've noticed this is nominated...*/
793 pair->peer_nominated=1;
794
795 if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED && !pair->nominated){
796 pair->nominated=1;
797
798 if(r=nr_ice_component_nominated_pair(pair->remote->component, pair)) {
799 *error=(r==R_NO_MEMORY)?500:400;
800 ABORT(r);
801 }
802 }
803 }
804 }
805
806 /* Note: the RFC says to trigger first and then nominate. But in that case
807 * the canceled trigger pair would get nominated and the cloned trigger pair
808 * would not get the nomination status cloned with it.*/
809 if(r=nr_ice_candidate_pair_do_triggered_check(comp->stream->pctx,pair)) {
810 *error=(r==R_NO_MEMORY)?500:400;
811 ABORT(r);
812 }
813
814 _status=0;
815 abort:
816 return(r);
817 }
818
819 /* Section 7.2.1 */
nr_ice_component_process_incoming_check(nr_ice_component * comp,nr_transport_addr * local_addr,nr_stun_server_request * req,int * error)820 static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_transport_addr *local_addr, nr_stun_server_request *req, int *error)
821 {
822 nr_ice_cand_pair *pair;
823 nr_ice_candidate *pcand=0;
824 nr_stun_message *sreq=req->request;
825 nr_stun_message_attribute *attr;
826 int r=0,_status;
827 int found_valid=0;
828
829 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);
830
831 if (comp->state == NR_ICE_COMPONENT_DISABLED)
832 ABORT(R_REJECTED);
833
834 /* Check for role conficts (7.2.1.1) */
835 if(comp->stream->pctx->controlling){
836 if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLING,&attr)){
837 /* OK, there is a conflict. Who's right? */
838 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlling",comp->stream->pctx->label);
839
840 if(attr->u.ice_controlling > comp->stream->pctx->tiebreaker){
841 /* Update the peer ctx. This will propagate to all candidate pairs
842 in the context. */
843 nr_ice_peer_ctx_switch_controlling_role(comp->stream->pctx);
844 }
845 else {
846 /* We are: throw an error */
847 r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
848
849 *error=487;
850 ABORT(R_REJECTED);
851 }
852 }
853 }
854 else{
855 if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLED,&attr)){
856 /* OK, there is a conflict. Who's right? */
857 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlled",comp->stream->pctx->label);
858
859 if(attr->u.ice_controlled < comp->stream->pctx->tiebreaker){
860 /* Update the peer ctx. This will propagate to all candidate pairs
861 in the context. */
862 nr_ice_peer_ctx_switch_controlling_role(comp->stream->pctx);
863 }
864 else {
865 /* We are: throw an error */
866 r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
867
868 *error=487;
869 ABORT(R_REJECTED);
870 }
871 }
872 }
873
874 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);
875
876 pair=TAILQ_FIRST(&comp->stream->check_list);
877 while(pair){
878 /* Since triggered checks create duplicate pairs (in this implementation)
879 * we are willing to handle multiple matches here. */
880 if(nr_ice_component_pair_matches_check(comp, pair, local_addr, req)){
881 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);
882 if(r=nr_ice_component_handle_triggered_check(comp, pair, req, error))
883 ABORT(r);
884 ++found_valid;
885 }
886 pair=TAILQ_NEXT(pair,check_queue_entry);
887 }
888
889 if(!found_valid){
890 /* There were no matching pairs, so we need to create a new peer
891 * reflexive candidate pair. */
892
893 if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){
894 r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label);
895 *error=400;
896 ABORT(R_BAD_DATA);
897 }
898
899 /* Find our local component candidate */
900 nr_ice_candidate *cand;
901
902 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): no matching pair",comp->stream->pctx->label);
903 cand=TAILQ_FIRST(&comp->local_component->candidates);
904 while(cand){
905 if(!nr_transport_addr_cmp(&cand->addr,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
906 break;
907
908 cand=TAILQ_NEXT(cand,entry_comp);
909 }
910
911 /* Well, this really shouldn't happen, but it's an error from the
912 other side, so we just throw an error and keep going */
913 if(!cand){
914 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);
915
916 *error=400;
917 ABORT(R_NOT_FOUND);
918 }
919
920 /* Now make a peer reflexive (remote) candidate */
921 if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) {
922 *error=(r==R_NO_MEMORY)?500:400;
923 ABORT(r);
924 }
925 pcand->priority=attr->u.priority;
926 pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
927
928 /* Finally, create the candidate pair, insert into the check list, and
929 * apply the incoming check to it. */
930 if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand,
931 &pair)) {
932 *error=(r==R_NO_MEMORY)?500:400;
933 ABORT(r);
934 }
935
936 nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FROZEN);
937 if(r=nr_ice_component_insert_pair(comp,pair)) {
938 *error=(r==R_NO_MEMORY)?500:400;
939 nr_ice_candidate_pair_destroy(&pair);
940 ABORT(r);
941 }
942
943 /* Do this last, since any call to ABORT will destroy pcand */
944 TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp);
945 pcand=0;
946
947 /* Finally start the trigger check if needed */
948 if(r=nr_ice_component_handle_triggered_check(comp, pair, req, error))
949 ABORT(r);
950 }
951
952 _status=0;
953 abort:
954 if(_status){
955 nr_ice_candidate_destroy(&pcand);
956 assert(*error != 0);
957 if(r!=R_NO_MEMORY) assert(*error != 500);
958 }
959 return(_status);
960 }
961
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)962 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)
963 {
964 nr_ice_component *comp=cb_arg;
965 nr_transport_addr local_addr;
966 int r,_status;
967
968 if(comp->state==NR_ICE_COMPONENT_FAILED) {
969 *error=400;
970 ABORT(R_REJECTED);
971 }
972
973 /* Find the candidate pair that this maps to */
974 if(r=nr_socket_getaddr(sock,&local_addr)) {
975 *error=500;
976 ABORT(r);
977 }
978
979 if (r=nr_ice_component_process_incoming_check(comp, &local_addr, req, error))
980 ABORT(r);
981
982 _status=0;
983 abort:
984 return(_status);
985 }
986
nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx * pctx,nr_ice_component * pcomp,char * username,int * serviced)987 int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced)
988 {
989 nr_ice_pre_answer_request *r1,*r2;
990 nr_ice_component *comp = pcomp->local_component;
991 int r,_status;
992
993 if (serviced)
994 *serviced = 0;
995
996 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);
997
998 STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2) {
999 if (!strcmp(r1->username, username)) {
1000 int error = 0;
1001
1002 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);
1003 r = nr_ice_component_process_incoming_check(pcomp, &r1->local_addr, &r1->req, &error);
1004 if (r) {
1005 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);
1006 }
1007 (*serviced)++;
1008 STAILQ_REMOVE(&comp->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry);
1009 nr_ice_pre_answer_request_destroy(&r1);
1010 }
1011 }
1012
1013 _status=0;
1014 return(_status);
1015 }
1016
nr_ice_component_can_candidate_tcptype_pair(nr_socket_tcp_type left,nr_socket_tcp_type right)1017 int nr_ice_component_can_candidate_tcptype_pair(nr_socket_tcp_type left, nr_socket_tcp_type right)
1018 {
1019 if (left && !right)
1020 return(0);
1021 if (!left && right)
1022 return(0);
1023 if (left == TCP_TYPE_ACTIVE && right != TCP_TYPE_PASSIVE)
1024 return(0);
1025 if (left == TCP_TYPE_SO && right != TCP_TYPE_SO)
1026 return(0);
1027 if (left == TCP_TYPE_PASSIVE)
1028 return(0);
1029
1030 return(1);
1031 }
1032
1033 /* filter out pairings which won't work. */
nr_ice_component_can_candidate_addr_pair(nr_transport_addr * local,nr_transport_addr * remote)1034 int nr_ice_component_can_candidate_addr_pair(nr_transport_addr *local, nr_transport_addr *remote)
1035 {
1036 if(local->ip_version != remote->ip_version)
1037 return(0);
1038 if(nr_transport_addr_is_link_local(local) !=
1039 nr_transport_addr_is_link_local(remote))
1040 return(0);
1041 /* This prevents our ice_unittest (or broken clients) from pairing a
1042 * loopback with a host candidate. */
1043 if(nr_transport_addr_is_loopback(local) !=
1044 nr_transport_addr_is_loopback(remote))
1045 return(0);
1046
1047 return(1);
1048 }
1049
nr_ice_component_pair_candidate(nr_ice_peer_ctx * pctx,nr_ice_component * pcomp,nr_ice_candidate * lcand,int pair_all_remote)1050 int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote)
1051 {
1052 int r, _status;
1053 nr_ice_candidate *pcand;
1054 nr_ice_cand_pair *pair=0;
1055 char codeword[5];
1056
1057 nr_ice_compute_codeword(lcand->label,strlen(lcand->label),codeword);
1058 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing local candidate %s",pctx->label,codeword,lcand->label);
1059
1060 switch(lcand->type){
1061 case HOST:
1062 break;
1063 case SERVER_REFLEXIVE:
1064 case PEER_REFLEXIVE:
1065 /* Don't actually pair these candidates */
1066 goto done;
1067 break;
1068 case RELAYED:
1069 break;
1070 default:
1071 assert(0);
1072 ABORT(R_INTERNAL);
1073 break;
1074 }
1075
1076 TAILQ_FOREACH(pcand, &pcomp->candidates, entry_comp){
1077 if(!nr_ice_component_can_candidate_addr_pair(&lcand->addr, &pcand->addr))
1078 continue;
1079 if(!nr_ice_component_can_candidate_tcptype_pair(lcand->tcp_type, pcand->tcp_type))
1080 continue;
1081
1082 /*
1083 Two modes, depending on |pair_all_remote|
1084
1085 1. Pair remote candidates which have not been paired
1086 (used in initial pairing or in processing the other side's
1087 trickle candidates).
1088 2. Pair any remote candidate (used when processing our own
1089 trickle candidates).
1090 */
1091 if (pair_all_remote || (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED)) {
1092 if (pair_all_remote) {
1093 /* When a remote candidate arrives after the start of checking, but
1094 * before the gathering of local candidates, it can be in UNPAIRED */
1095 pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
1096 }
1097
1098 nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
1099 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing with peer candidate %s", pctx->label, codeword, pcand->label);
1100
1101 if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
1102 ABORT(r);
1103
1104 if(r=nr_ice_component_insert_pair(pcomp, pair))
1105 ABORT(r);
1106 }
1107 }
1108
1109 done:
1110 _status = 0;
1111 abort:
1112 return(_status);
1113 }
1114
nr_ice_component_pair_candidates(nr_ice_peer_ctx * pctx,nr_ice_component * lcomp,nr_ice_component * pcomp)1115 int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp)
1116 {
1117 nr_ice_candidate *lcand, *pcand;
1118 nr_ice_socket *isock;
1119 int r,_status;
1120
1121 r_log(LOG_ICE,LOG_DEBUG,"Pairing candidates======");
1122
1123 /* Create the candidate pairs */
1124 lcand=TAILQ_FIRST(&lcomp->candidates);
1125
1126 if (!lcand) {
1127 /* No local candidates, initialized or not! */
1128 ABORT(R_FAILED);
1129 }
1130
1131 while(lcand){
1132 if (lcand->state == NR_ICE_CAND_STATE_INITIALIZED) {
1133 if ((r = nr_ice_component_pair_candidate(pctx, pcomp, lcand, 0)))
1134 ABORT(r);
1135 }
1136
1137 lcand=TAILQ_NEXT(lcand,entry_comp);
1138 }
1139
1140 /* Mark all peer candidates as paired */
1141 pcand=TAILQ_FIRST(&pcomp->candidates);
1142 while(pcand){
1143 pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
1144
1145 pcand=TAILQ_NEXT(pcand,entry_comp);
1146
1147 }
1148
1149 /* Now register the STUN server callback for this component.
1150 Note that this is a per-component CB so we only need to
1151 do this once.
1152 */
1153 if (pcomp->state != NR_ICE_COMPONENT_RUNNING) {
1154 isock=STAILQ_FIRST(&lcomp->sockets);
1155 while(isock){
1156 if(r=nr_stun_server_add_client(isock->stun_server,pctx->label,
1157 pcomp->stream->r2l_user,&pcomp->stream->r2l_pass,nr_ice_component_stun_server_cb,pcomp)) {
1158 ABORT(r);
1159 }
1160 isock=STAILQ_NEXT(isock,entry);
1161 }
1162 }
1163
1164 pcomp->state = NR_ICE_COMPONENT_RUNNING;
1165
1166 _status=0;
1167 abort:
1168 return(_status);
1169 }
1170
nr_ice_pre_answer_enqueue(nr_ice_component * comp,nr_socket * sock,nr_stun_server_request * req,int * dont_free)1171 int nr_ice_pre_answer_enqueue(nr_ice_component *comp, nr_socket *sock, nr_stun_server_request *req, int *dont_free)
1172 {
1173 int r = 0;
1174 int _status;
1175 nr_ice_pre_answer_request *r1, *r2;
1176 nr_transport_addr dst_addr;
1177 nr_ice_pre_answer_request *par = 0;
1178
1179 if (r=nr_socket_getaddr(sock, &dst_addr))
1180 ABORT(r);
1181
1182 STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2) {
1183 if (!nr_transport_addr_cmp(&r1->local_addr, &dst_addr,
1184 NR_TRANSPORT_ADDR_CMP_MODE_ALL) &&
1185 !nr_transport_addr_cmp(&r1->req.src_addr, &req->src_addr,
1186 NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
1187 return(0);
1188 }
1189 }
1190
1191 if (r=nr_ice_pre_answer_request_create(&dst_addr, req, &par))
1192 ABORT(r);
1193
1194 r_log(LOG_ICE,LOG_DEBUG, "ICE(%s)/STREAM(%s)/COMP(%d): Enqueuing STUN request pre-answer from %s",
1195 comp->ctx->label, comp->stream->label, comp->component_id,
1196 req->src_addr.as_string);
1197
1198 *dont_free = 1;
1199 STAILQ_INSERT_TAIL(&comp->pre_answer_reqs, par, entry);
1200
1201 _status=0;
1202 abort:
1203 return(_status);
1204 }
1205
1206 /* Fires when we have an incoming candidate that doesn't correspond to an existing
1207 remote peer. This is either pre-answer or just spurious. Store it in the
1208 component for use when we see the actual answer, at which point we need
1209 to do the procedures from S 7.2.1 in nr_ice_component_stun_server_cb.
1210 */
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)1211 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)
1212 {
1213 int r, _status;
1214 nr_ice_component *comp = (nr_ice_component *)cb_arg;
1215
1216 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Received STUN request pre-answer from %s",
1217 comp->ctx->label, comp->stream->label, comp->component_id,
1218 req->src_addr.as_string);
1219
1220 if (r=nr_ice_pre_answer_enqueue(comp, sock, req, dont_free)) {
1221 r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): Failed (%d) to enque pre-answer request from %s",
1222 comp->ctx->label, comp->stream->label, comp->component_id, r,
1223 req->src_addr.as_string);
1224 ABORT(r);
1225 }
1226
1227 _status=0;
1228 abort:
1229 return(_status);
1230 }
1231
1232 #define NR_ICE_CONSENT_TIMER_DEFAULT 5000
1233 #define NR_ICE_CONSENT_TIMEOUT_DEFAULT 30000
1234
nr_ice_component_consent_failed(nr_ice_component * comp)1235 static void nr_ice_component_consent_failed(nr_ice_component *comp)
1236 {
1237 if (!comp->can_send) {
1238 return;
1239 }
1240
1241 r_log(LOG_ICE,LOG_INFO,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh failed",
1242 comp->ctx->label, comp->stream->label, comp->component_id);
1243 comp->can_send = 0;
1244
1245 if (comp->consent_timeout) {
1246 NR_async_timer_cancel(comp->consent_timeout);
1247 comp->consent_timeout = 0;
1248 }
1249 if (comp->consent_timer) {
1250 NR_async_timer_cancel(comp->consent_timer);
1251 comp->consent_timer = 0;
1252 }
1253 /* We are turning the consent failure into a ICE component failure to
1254 * alert the browser via ICE connection state change about this event. */
1255 if (nr_ice_media_stream_component_failed(comp->stream, comp))
1256 r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): failed to mark component as failed",
1257 comp->ctx->label, comp->stream->label, comp->component_id);
1258 }
1259
nr_ice_component_consent_timeout_cb(NR_SOCKET s,int how,void * cb_arg)1260 static void nr_ice_component_consent_timeout_cb(NR_SOCKET s, int how, void *cb_arg)
1261 {
1262 nr_ice_component *comp=cb_arg;
1263
1264 comp->consent_timeout = 0;
1265
1266 r_log(LOG_ICE,LOG_WARNING,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh final time out",
1267 comp->ctx->label, comp->stream->label, comp->component_id);
1268 nr_ice_component_consent_failed(comp);
1269 }
1270
1271
nr_ice_component_disconnected(nr_ice_component * comp)1272 void nr_ice_component_disconnected(nr_ice_component *comp)
1273 {
1274 if (!comp->can_send) {
1275 return;
1276 }
1277
1278 if (comp->disconnected) {
1279 return;
1280 }
1281
1282 r_log(LOG_ICE,LOG_WARNING,"ICE(%s)/STREAM(%s)/COMP(%d): component disconnected",
1283 comp->ctx->label, comp->stream->label, comp->component_id);
1284 comp->disconnected = 1;
1285
1286 /* a single disconnected component disconnects the stream */
1287 nr_ice_media_stream_set_disconnected(comp->stream, NR_ICE_MEDIA_STREAM_DISCONNECTED);
1288 }
1289
nr_ice_component_consent_refreshed(nr_ice_component * comp)1290 static void nr_ice_component_consent_refreshed(nr_ice_component *comp)
1291 {
1292 uint16_t tval;
1293
1294 if (!comp->can_send) {
1295 return;
1296 }
1297
1298 gettimeofday(&comp->consent_last_seen, 0);
1299 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): consent_last_seen is now %lu",
1300 comp->ctx->label, comp->stream->label, comp->component_id,
1301 comp->consent_last_seen.tv_sec);
1302
1303 comp->disconnected = 0;
1304
1305 nr_ice_media_stream_check_if_connected(comp->stream);
1306
1307 if (comp->consent_timeout)
1308 NR_async_timer_cancel(comp->consent_timeout);
1309
1310 tval = NR_ICE_CONSENT_TIMEOUT_DEFAULT;
1311 if (comp->ctx->test_timer_divider)
1312 tval = tval / comp->ctx->test_timer_divider;
1313
1314 NR_ASYNC_TIMER_SET(tval, nr_ice_component_consent_timeout_cb, comp,
1315 &comp->consent_timeout);
1316 }
1317
nr_ice_component_refresh_consent_cb(NR_SOCKET s,int how,void * cb_arg)1318 static void nr_ice_component_refresh_consent_cb(NR_SOCKET s, int how, void *cb_arg)
1319 {
1320 nr_ice_component *comp=cb_arg;
1321
1322 switch (comp->consent_ctx->state) {
1323 case NR_STUN_CLIENT_STATE_FAILED:
1324 if (comp->consent_ctx->error_code == 403) {
1325 r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): Consent revoked by peer",
1326 comp->ctx->label, comp->stream->label, comp->component_id);
1327 nr_ice_component_consent_failed(comp);
1328 }
1329 break;
1330 case NR_STUN_CLIENT_STATE_DONE:
1331 r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): Consent refreshed",
1332 comp->ctx->label, comp->stream->label, comp->component_id);
1333 nr_ice_component_consent_refreshed(comp);
1334 break;
1335 case NR_STUN_CLIENT_STATE_TIMED_OUT:
1336 r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): A single consent refresh request timed out",
1337 comp->ctx->label, comp->stream->label, comp->component_id);
1338 nr_ice_component_disconnected(comp);
1339 break;
1340 default:
1341 break;
1342 }
1343 }
1344
nr_ice_component_refresh_consent(nr_stun_client_ctx * ctx,NR_async_cb finished_cb,void * cb_arg)1345 int nr_ice_component_refresh_consent(nr_stun_client_ctx *ctx, NR_async_cb finished_cb, void *cb_arg)
1346 {
1347 int r,_status;
1348
1349 nr_stun_client_reset(ctx);
1350
1351 if (r=nr_stun_client_start(ctx, NR_ICE_CLIENT_MODE_BINDING_REQUEST, finished_cb, cb_arg))
1352 ABORT(r);
1353
1354 _status=0;
1355 abort:
1356 return(_status);
1357 }
1358
nr_ice_component_consent_calc_consent_timer(nr_ice_component * comp)1359 void nr_ice_component_consent_calc_consent_timer(nr_ice_component *comp)
1360 {
1361 uint16_t trange, trand, tval;
1362
1363 trange = NR_ICE_CONSENT_TIMER_DEFAULT * 20 / 100;
1364 tval = NR_ICE_CONSENT_TIMER_DEFAULT - trange;
1365 if (!nr_crypto_random_bytes((UCHAR*)&trand, sizeof(trand)))
1366 tval += (trand % (trange * 2));
1367
1368 if (comp->ctx->test_timer_divider)
1369 tval = tval / comp->ctx->test_timer_divider;
1370
1371 /* The timeout of the transaction is the maximum time until we send the
1372 * next consent request. */
1373 comp->consent_ctx->maximum_transmits_timeout_ms = tval;
1374 }
1375
nr_ice_component_consent_timer_cb(NR_SOCKET s,int how,void * cb_arg)1376 static void nr_ice_component_consent_timer_cb(NR_SOCKET s, int how, void *cb_arg)
1377 {
1378 nr_ice_component *comp=cb_arg;
1379 int r;
1380
1381 if (!comp->consent_ctx) {
1382 return;
1383 }
1384
1385 if (comp->consent_timer) {
1386 NR_async_timer_cancel(comp->consent_timer);
1387 }
1388 comp->consent_timer = 0;
1389
1390 comp->consent_ctx->params.ice_binding_request.username =
1391 comp->stream->l2r_user;
1392 comp->consent_ctx->params.ice_binding_request.password =
1393 comp->stream->l2r_pass;
1394 comp->consent_ctx->params.ice_binding_request.control =
1395 comp->stream->pctx->controlling?
1396 NR_ICE_CONTROLLING:NR_ICE_CONTROLLED;
1397 comp->consent_ctx->params.ice_binding_request.tiebreaker =
1398 comp->stream->pctx->tiebreaker;
1399 comp->consent_ctx->params.ice_binding_request.priority =
1400 comp->active->local->priority;
1401
1402 nr_ice_component_consent_calc_consent_timer(comp);
1403
1404 if (r=nr_ice_component_refresh_consent(comp->consent_ctx,
1405 nr_ice_component_refresh_consent_cb,
1406 comp)) {
1407 r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): Refresh consent failed with %d",
1408 comp->ctx->label, comp->stream->label, comp->component_id, r);
1409 }
1410
1411 nr_ice_component_consent_schedule_consent_timer(comp);
1412
1413 }
1414
nr_ice_component_consent_schedule_consent_timer(nr_ice_component * comp)1415 void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp)
1416 {
1417 if (!comp->can_send) {
1418 return;
1419 }
1420
1421 NR_ASYNC_TIMER_SET(comp->consent_ctx->maximum_transmits_timeout_ms,
1422 nr_ice_component_consent_timer_cb, comp,
1423 &comp->consent_timer);
1424 }
1425
nr_ice_component_refresh_consent_now(nr_ice_component * comp)1426 void nr_ice_component_refresh_consent_now(nr_ice_component *comp)
1427 {
1428 nr_ice_component_consent_timer_cb(0, 0, comp);
1429 }
1430
nr_ice_component_consent_destroy(nr_ice_component * comp)1431 void nr_ice_component_consent_destroy(nr_ice_component *comp)
1432 {
1433 if (comp->consent_timer) {
1434 NR_async_timer_cancel(comp->consent_timer);
1435 comp->consent_timer = 0;
1436 }
1437 if (comp->consent_timeout) {
1438 NR_async_timer_cancel(comp->consent_timeout);
1439 comp->consent_timeout = 0;
1440 }
1441 if (comp->consent_handle) {
1442 nr_ice_socket_deregister(comp->active->local->isock,
1443 comp->consent_handle);
1444 comp->consent_handle = 0;
1445 }
1446 if (comp->consent_ctx) {
1447 nr_stun_client_ctx_destroy(&comp->consent_ctx);
1448 comp->consent_ctx = 0;
1449 }
1450 }
1451
nr_ice_component_setup_consent(nr_ice_component * comp)1452 int nr_ice_component_setup_consent(nr_ice_component *comp)
1453 {
1454 int r,_status;
1455
1456 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Setting up refresh consent",
1457 comp->ctx->label, comp->stream->label, comp->component_id);
1458
1459 nr_ice_component_consent_destroy(comp);
1460
1461 if (r=nr_stun_client_ctx_create("consent", comp->active->local->osock,
1462 &comp->active->remote->addr, 0,
1463 &comp->consent_ctx))
1464 ABORT(r);
1465 /* Consent request get send only once. */
1466 comp->consent_ctx->maximum_transmits = 1;
1467
1468 if (r=nr_ice_socket_register_stun_client(comp->active->local->isock,
1469 comp->consent_ctx, &comp->consent_handle))
1470 ABORT(r);
1471
1472 comp->can_send = 1;
1473 comp->disconnected = 0;
1474 nr_ice_component_consent_refreshed(comp);
1475
1476 nr_ice_component_consent_calc_consent_timer(comp);
1477 nr_ice_component_consent_schedule_consent_timer(comp);
1478
1479 _status=0;
1480 abort:
1481 return(_status);
1482 }
1483
nr_ice_component_nominated_pair(nr_ice_component * comp,nr_ice_cand_pair * pair)1484 int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
1485 {
1486 int r,_status;
1487 nr_ice_cand_pair *p2;
1488
1489 /* Are we changing what the nominated pair is? */
1490 if(comp->nominated){
1491 if(comp->nominated->priority >= pair->priority)
1492 return(0);
1493 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);
1494 /* As consent doesn't hold a reference to its isock this needs to happen
1495 * before making the new pair the active one. */
1496 nr_ice_component_consent_destroy(comp);
1497 }
1498
1499 /* Set the new nominated pair */
1500 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);
1501 comp->state=NR_ICE_COMPONENT_NOMINATED;
1502 comp->nominated=pair;
1503 comp->active=pair;
1504
1505 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);
1506
1507 /* Cancel checks in WAITING and FROZEN per ICE S 8.1.2 */
1508 p2=TAILQ_FIRST(&comp->stream->trigger_check_queue);
1509 while(p2){
1510 if((p2 != pair) &&
1511 (p2->remote->component->component_id == comp->component_id)) {
1512 assert(p2->state == NR_ICE_PAIR_STATE_WAITING ||
1513 p2->state == NR_ICE_PAIR_STATE_CANCELLED);
1514 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s in trigger check queue because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword);
1515
1516 if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2,0))
1517 ABORT(r);
1518 }
1519
1520 p2=TAILQ_NEXT(p2,triggered_check_queue_entry);
1521 }
1522 p2=TAILQ_FIRST(&comp->stream->check_list);
1523 while(p2){
1524 if((p2 != pair) &&
1525 (p2->remote->component->component_id == comp->component_id) &&
1526 ((p2->state == NR_ICE_PAIR_STATE_FROZEN) ||
1527 (p2->state == NR_ICE_PAIR_STATE_WAITING))) {
1528 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);
1529
1530 if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2,0))
1531 ABORT(r);
1532 }
1533
1534 p2=TAILQ_NEXT(p2,check_queue_entry);
1535 }
1536 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);
1537
1538 if(r=nr_ice_component_setup_consent(comp))
1539 ABORT(r);
1540
1541 if(r=nr_ice_media_stream_component_nominated(comp->stream,comp))
1542 ABORT(r);
1543
1544 _status=0;
1545 abort:
1546 return(_status);
1547 }
1548
nr_ice_component_have_all_pairs_failed(nr_ice_component * comp)1549 static int nr_ice_component_have_all_pairs_failed(nr_ice_component *comp)
1550 {
1551 nr_ice_cand_pair *p2;
1552
1553 p2=TAILQ_FIRST(&comp->stream->check_list);
1554 while(p2){
1555 if(comp->component_id==p2->local->component_id){
1556 switch(p2->state){
1557 case NR_ICE_PAIR_STATE_FROZEN:
1558 case NR_ICE_PAIR_STATE_WAITING:
1559 case NR_ICE_PAIR_STATE_IN_PROGRESS:
1560 case NR_ICE_PAIR_STATE_SUCCEEDED:
1561 return(0);
1562 case NR_ICE_PAIR_STATE_FAILED:
1563 case NR_ICE_PAIR_STATE_CANCELLED:
1564 /* states that will never be recovered from */
1565 break;
1566 default:
1567 assert(0);
1568 break;
1569 }
1570 }
1571
1572 p2=TAILQ_NEXT(p2,check_queue_entry);
1573 }
1574
1575 return(1);
1576 }
1577
nr_ice_component_failed_pair(nr_ice_component * comp,nr_ice_cand_pair * pair)1578 int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
1579 {
1580 return nr_ice_component_check_if_failed(comp);
1581 }
1582
nr_ice_component_check_if_failed(nr_ice_component * comp)1583 int nr_ice_component_check_if_failed(nr_ice_component *comp)
1584 {
1585 if (comp->state == NR_ICE_COMPONENT_RUNNING) {
1586 /* Don't do anything to streams that aren't currently running */
1587 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): Checking whether component needs to be marked failed.",comp->stream->pctx->label,comp->stream->label,comp->component_id);
1588
1589 if (!comp->stream->pctx->trickle_grace_period_timer &&
1590 nr_ice_component_have_all_pairs_failed(comp)) {
1591 r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): All pairs are failed, and grace period has elapsed. Marking component as failed.",comp->stream->pctx->label,comp->stream->label,comp->component_id);
1592 return nr_ice_media_stream_component_failed(comp->stream,comp);
1593 }
1594 }
1595
1596 return(0);
1597 }
1598
nr_ice_component_select_pair(nr_ice_peer_ctx * pctx,nr_ice_component * comp)1599 int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp)
1600 {
1601 nr_ice_cand_pair **pairs=0;
1602 int ct=0;
1603 nr_ice_cand_pair *pair;
1604 int r,_status;
1605
1606 /* Size the array */
1607 pair=TAILQ_FIRST(&comp->stream->check_list);
1608 while(pair){
1609 if (comp->component_id == pair->local->component_id)
1610 ct++;
1611
1612 pair=TAILQ_NEXT(pair,check_queue_entry);
1613 }
1614
1615 /* Make and fill the array */
1616 if(!(pairs=RCALLOC(sizeof(nr_ice_cand_pair *)*ct)))
1617 ABORT(R_NO_MEMORY);
1618
1619 ct=0;
1620 pair=TAILQ_FIRST(&comp->stream->check_list);
1621 while(pair){
1622 if (comp->component_id == pair->local->component_id)
1623 pairs[ct++]=pair;
1624
1625 pair=TAILQ_NEXT(pair,check_queue_entry);
1626 }
1627
1628 if (pctx->handler) {
1629 if(r=pctx->handler->vtbl->select_pair(pctx->handler->obj,
1630 comp->stream,comp->component_id,pairs,ct))
1631 ABORT(r);
1632 }
1633
1634 _status=0;
1635 abort:
1636 RFREE(pairs);
1637 return(_status);
1638 }
1639
1640
1641 /* Close the underlying sockets for everything but the nominated candidate */
nr_ice_component_finalize(nr_ice_component * lcomp,nr_ice_component * rcomp)1642 int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp)
1643 {
1644 nr_ice_socket *isock=0;
1645 nr_ice_socket *s1,*s2;
1646
1647 if(rcomp->state==NR_ICE_COMPONENT_NOMINATED){
1648 assert(rcomp->active == rcomp->nominated);
1649 isock=rcomp->nominated->local->isock;
1650 }
1651
1652 STAILQ_FOREACH_SAFE(s1, &lcomp->sockets, entry, s2){
1653 if(s1!=isock){
1654 STAILQ_REMOVE(&lcomp->sockets,s1,nr_ice_socket_,entry);
1655 nr_ice_socket_destroy(&s1);
1656 }
1657 }
1658
1659 return(0);
1660 }
1661
1662
nr_ice_component_insert_pair(nr_ice_component * pcomp,nr_ice_cand_pair * pair)1663 int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair)
1664 {
1665 int r,_status;
1666
1667 /* Pairs for peer reflexive are marked SUCCEEDED immediately */
1668 if (pair->state != NR_ICE_PAIR_STATE_FROZEN &&
1669 pair->state != NR_ICE_PAIR_STATE_SUCCEEDED){
1670 assert(0);
1671 ABORT(R_BAD_ARGS);
1672 }
1673
1674 if(r=nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,pair))
1675 ABORT(r);
1676
1677 /* Make sure the check timer is running, if the stream was previously
1678 * started. We will not start streams just because a pair was created,
1679 * unless it is the first pair to be created across all streams. */
1680 r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND-PAIR(%s): Ensure that check timer is running for new pair %s.",pair->remote->stream->pctx->label, pair->codeword, pair->as_string);
1681
1682 if(pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE ||
1683 (pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN &&
1684 !pair->remote->stream->pctx->checks_started)){
1685 if(nr_ice_media_stream_start_checks(pair->remote->stream->pctx, pair->remote->stream)) {
1686 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);
1687 ABORT(R_INTERNAL);
1688 }
1689 }
1690
1691 _status=0;
1692 abort:
1693 return(_status);
1694 }
1695
nr_ice_component_get_default_candidate(nr_ice_component * comp,nr_ice_candidate ** candp,int ip_version)1696 int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version)
1697 {
1698 int _status;
1699 nr_ice_candidate *cand;
1700 nr_ice_candidate *best_cand = NULL;
1701
1702 /* We have the component. Now find the "best" candidate, making
1703 use of the fact that more "reliable" candidate types have
1704 higher numbers. So, we sort by type and then priority within
1705 type
1706 */
1707 cand=TAILQ_FIRST(&comp->candidates);
1708 while(cand){
1709 if (!nr_ice_ctx_hide_candidate(comp->ctx, cand) &&
1710 cand->addr.ip_version == ip_version) {
1711 if (!best_cand) {
1712 best_cand = cand;
1713 }
1714 else if (best_cand->type < cand->type) {
1715 best_cand = cand;
1716 } else if (best_cand->type == cand->type &&
1717 best_cand->priority < cand->priority) {
1718 best_cand = cand;
1719 }
1720 }
1721
1722 cand=TAILQ_NEXT(cand,entry_comp);
1723 }
1724
1725 /* No candidates */
1726 if (!best_cand)
1727 ABORT(R_NOT_FOUND);
1728
1729 *candp = best_cand;
1730
1731 _status=0;
1732 abort:
1733 return(_status);
1734
1735 }
1736
1737