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