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