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