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 #include <csi_platform.h>
34 #include <assert.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/queue.h>
38 #include <sys/types.h>
39 #ifdef WIN32
40 #include <winsock2.h>
41 #else
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #endif
46 #include "nr_api.h"
47 #include "registry.h"
48 #include "nr_socket.h"
49 #include "async_timer.h"
50
51 #include "stun_client_ctx.h"
52 #include "stun_server_ctx.h"
53 #include "turn_client_ctx.h"
54 #include "ice_ctx.h"
55 #include "ice_candidate.h"
56 #include "ice_codeword.h"
57 #include "ice_reg.h"
58 #include "ice_util.h"
59 #include "nr_socket_turn.h"
60 #include "nr_socket.h"
61 #include "nr_socket_multi_tcp.h"
62
63 static int next_automatic_preference = 127;
64
65 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
66 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
67 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand);
68 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
69 #ifdef USE_TURN
70 static int nr_ice_start_relay_turn(nr_ice_candidate *cand);
71 static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg);
72 static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr);
73 #endif /* USE_TURN */
74
nr_ice_candidate_compute_codeword(nr_ice_candidate * cand)75 void nr_ice_candidate_compute_codeword(nr_ice_candidate *cand)
76 {
77 char as_string[1024];
78
79 snprintf(as_string,
80 sizeof(as_string),
81 "%s(%s)",
82 cand->addr.as_string,
83 cand->label);
84
85 nr_ice_compute_codeword(as_string,strlen(as_string),cand->codeword);
86 }
87
88 char *nr_ice_candidate_type_names[]={0,"host","srflx","prflx","relay",0};
89 char *nr_ice_candidate_tcp_type_names[]={0,"active","passive","so",0};
90
nr_ctype_name(nr_ice_candidate_type ctype)91 static const char *nr_ctype_name(nr_ice_candidate_type ctype) {
92 assert(ctype<CTYPE_MAX && ctype>0);
93 if (ctype <= 0 || ctype >= CTYPE_MAX) {
94 return "ERROR";
95 }
96 return nr_ice_candidate_type_names[ctype];
97 }
98
nr_tcp_type_name(nr_socket_tcp_type tcp_type)99 static const char *nr_tcp_type_name(nr_socket_tcp_type tcp_type) {
100 assert(tcp_type<TCP_TYPE_MAX && tcp_type>0);
101 if (tcp_type <= 0 || tcp_type >= TCP_TYPE_MAX) {
102 return "ERROR";
103 }
104 return nr_ice_candidate_tcp_type_names[tcp_type];
105 }
106
nr_ice_candidate_format_stun_label(char * label,size_t size,nr_ice_candidate * cand)107 static int nr_ice_candidate_format_stun_label(char *label, size_t size, nr_ice_candidate *cand)
108 {
109 int _status;
110
111 *label = 0;
112 switch(cand->stun_server->type) {
113 case NR_ICE_STUN_SERVER_TYPE_ADDR:
114 snprintf(label, size, "%s(%s|%s)", nr_ctype_name(cand->type), cand->base.as_string,
115 cand->stun_server->u.addr.as_string);
116 break;
117 case NR_ICE_STUN_SERVER_TYPE_DNSNAME:
118 snprintf(label, size, "%s(%s|%s:%u)", nr_ctype_name(cand->type), cand->base.as_string,
119 cand->stun_server->u.dnsname.host, cand->stun_server->u.dnsname.port);
120 break;
121 default:
122 assert(0);
123 ABORT(R_BAD_ARGS);
124 }
125
126 _status=0;
127 abort:
128 return(_status);
129 }
130
nr_ice_candidate_create(nr_ice_ctx * ctx,nr_ice_component * comp,nr_ice_socket * isock,nr_socket * osock,nr_ice_candidate_type ctype,nr_socket_tcp_type tcp_type,nr_ice_stun_server * stun_server,UCHAR component_id,nr_ice_candidate ** candp)131 int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_socket_tcp_type tcp_type, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp)
132 {
133 assert(!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) || ctype == RELAYED);
134 nr_ice_candidate *cand=0;
135 nr_ice_candidate *tmp=0;
136 int r,_status;
137 char label[512];
138
139 if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
140 ABORT(R_NO_MEMORY);
141 cand->state=NR_ICE_CAND_STATE_CREATED;
142 cand->ctx=ctx;
143 cand->isock=isock;
144 cand->osock=osock;
145 cand->type=ctype;
146 cand->tcp_type=tcp_type;
147 cand->stun_server=stun_server;
148 cand->component_id=component_id;
149 cand->component=comp;
150 cand->stream=comp->stream;
151
152 /* Extract the addr as the base */
153 if(r=nr_socket_getaddr(cand->isock->sock,&cand->base))
154 ABORT(r);
155
156 switch(ctype) {
157 case HOST:
158 snprintf(label, sizeof(label), "host(%s)", cand->base.as_string);
159 break;
160
161 case SERVER_REFLEXIVE:
162 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label), cand))
163 ABORT(r);
164 break;
165
166 case RELAYED:
167 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label), cand))
168 ABORT(r);
169 break;
170
171 case PEER_REFLEXIVE:
172 snprintf(label, sizeof(label), "prflx");
173 break;
174
175 default:
176 assert(0); /* Can't happen */
177 ABORT(R_BAD_ARGS);
178 }
179
180 if (tcp_type) {
181 const char* ttype = nr_tcp_type_name(tcp_type);
182 const int tlen = strlen(ttype)+1; /* plus space */
183 const size_t llen=strlen(label);
184 if (snprintf(label+llen, sizeof(label)-llen, " %s", ttype) != tlen) {
185 r_log(LOG_ICE,LOG_ERR,"ICE(%s): truncated tcp type added to buffer",
186 ctx->label);
187 }
188 }
189
190 if(!(cand->label=r_strdup(label)))
191 ABORT(R_NO_MEMORY);
192
193 if(r=nr_ice_get_foundation(ctx,cand))
194 ABORT(r);
195 if(r=nr_ice_candidate_compute_priority(cand))
196 ABORT(r);
197
198 TAILQ_FOREACH(tmp,&isock->candidates,entry_sock){
199 if(cand->priority==tmp->priority){
200 r_log(LOG_ICE,LOG_ERR,"ICE(%s): duplicate priority %u candidate %s and candidate %s",
201 ctx->label,cand->priority,cand->label,tmp->label);
202 }
203 }
204
205 if(ctype==RELAYED)
206 cand->u.relayed.turn_sock=osock;
207
208
209 /* Add the candidate to the isock list*/
210 TAILQ_INSERT_TAIL(&isock->candidates,cand,entry_sock);
211
212 nr_ice_candidate_compute_codeword(cand);
213
214 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): created candidate %s with type %s",
215 ctx->label,cand->codeword,cand->label,nr_ctype_name(ctype));
216
217 *candp=cand;
218
219 _status=0;
220 abort:
221 if (_status){
222 r_log(LOG_ICE,LOG_ERR,"ICE(%s): Failed to create candidate of type %s", ctx->label,nr_ctype_name(ctype));
223 nr_ice_candidate_destroy(&cand);
224 }
225 return(_status);
226 }
227
228
229 /* Create a peer reflexive candidate */
nr_ice_peer_peer_rflx_candidate_create(nr_ice_ctx * ctx,char * label,nr_ice_component * comp,nr_transport_addr * addr,nr_ice_candidate ** candp)230 int nr_ice_peer_peer_rflx_candidate_create(nr_ice_ctx *ctx,char *label, nr_ice_component *comp,nr_transport_addr *addr, nr_ice_candidate **candp)
231 {
232 nr_ice_candidate *cand=0;
233 nr_ice_candidate_type ctype=PEER_REFLEXIVE;
234 int r,_status;
235
236 if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
237 ABORT(R_NO_MEMORY);
238 if(!(cand->label=r_strdup(label)))
239 ABORT(R_NO_MEMORY);
240
241 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
242 cand->ctx=ctx;
243 cand->type=ctype;
244 cand->component_id=comp->component_id;
245 cand->component=comp;
246 cand->stream=comp->stream;
247
248
249 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): creating candidate with type %s",
250 ctx->label,label,nr_ctype_name(ctype));
251
252 if(r=nr_transport_addr_copy(&cand->base,addr))
253 ABORT(r);
254 if(r=nr_transport_addr_copy(&cand->addr,addr))
255 ABORT(r);
256 /* Bogus foundation */
257 if(!(cand->foundation=r_strdup(cand->addr.as_string)))
258 ABORT(R_NO_MEMORY);
259
260 nr_ice_candidate_compute_codeword(cand);
261
262 *candp=cand;
263
264 _status=0;
265 abort:
266 if (_status){
267 nr_ice_candidate_destroy(&cand);
268 }
269 return(_status);
270 }
271
nr_ice_candidate_mark_done(nr_ice_candidate * cand,int state)272 static void nr_ice_candidate_mark_done(nr_ice_candidate *cand, int state)
273 {
274 if (!cand || !cand->done_cb) {
275 assert(0);
276 return;
277 }
278
279 /* If this is a relay candidate, there's likely to be a srflx that is
280 * piggybacking on it. Make sure it is marked done too. */
281 if ((cand->type == RELAYED) && cand->u.relayed.srvflx_candidate) {
282 nr_ice_candidate *srflx=cand->u.relayed.srvflx_candidate;
283 if (state == NR_ICE_CAND_STATE_INITIALIZED &&
284 nr_turn_client_get_mapped_address(cand->u.relayed.turn,
285 &srflx->addr)) {
286 r_log(LOG_ICE, LOG_WARNING, "ICE(%s)/CAND(%s): Failed to get mapped address from TURN allocate response, srflx failed.", cand->ctx->label, cand->label);
287 nr_ice_candidate_mark_done(srflx, NR_ICE_CAND_STATE_FAILED);
288 } else {
289 nr_ice_candidate_mark_done(srflx, state);
290 }
291 }
292
293 NR_async_cb done_cb=cand->done_cb;
294 cand->done_cb=0;
295 cand->state=state;
296 /* This might destroy cand! */
297 done_cb(0,0,cand->cb_arg);
298 }
299
nr_ice_candidate_destroy(nr_ice_candidate ** candp)300 int nr_ice_candidate_destroy(nr_ice_candidate **candp)
301 {
302 nr_ice_candidate *cand=0;
303
304 if(!candp || !*candp)
305 return(0);
306
307 cand=*candp;
308
309 nr_ice_candidate_stop_gathering(cand);
310
311 switch(cand->type){
312 case HOST:
313 break;
314 #ifdef USE_TURN
315 case RELAYED:
316 // record stats back to the ice ctx on destruction
317 if (cand->u.relayed.turn) {
318 nr_accumulate_count(&(cand->ctx->stats.turn_401s), cand->u.relayed.turn->cnt_401s);
319 nr_accumulate_count(&(cand->ctx->stats.turn_403s), cand->u.relayed.turn->cnt_403s);
320 nr_accumulate_count(&(cand->ctx->stats.turn_438s), cand->u.relayed.turn->cnt_438s);
321
322 nr_turn_stun_ctx* stun_ctx;
323 stun_ctx = STAILQ_FIRST(&cand->u.relayed.turn->stun_ctxs);
324 while (stun_ctx) {
325 nr_accumulate_count(&(cand->ctx->stats.stun_retransmits), stun_ctx->stun->retransmit_ct);
326
327 stun_ctx = STAILQ_NEXT(stun_ctx, entry);
328 }
329 }
330 if (cand->u.relayed.turn_handle)
331 nr_ice_socket_deregister(cand->isock, cand->u.relayed.turn_handle);
332 if (cand->u.relayed.srvflx_candidate)
333 cand->u.relayed.srvflx_candidate->u.srvrflx.relay_candidate=0;
334 nr_turn_client_ctx_destroy(&cand->u.relayed.turn);
335 nr_socket_destroy(&cand->u.relayed.turn_sock);
336 break;
337 #endif /* USE_TURN */
338 case SERVER_REFLEXIVE:
339 if (cand->u.srvrflx.stun_handle)
340 nr_ice_socket_deregister(cand->isock, cand->u.srvrflx.stun_handle);
341 if (cand->u.srvrflx.relay_candidate)
342 cand->u.srvrflx.relay_candidate->u.relayed.srvflx_candidate=0;
343 nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
344 break;
345 default:
346 break;
347 }
348
349 RFREE(cand->mdns_addr);
350 RFREE(cand->foundation);
351 RFREE(cand->label);
352 RFREE(cand);
353
354 return(0);
355 }
356
nr_ice_candidate_stop_gathering(nr_ice_candidate * cand)357 void nr_ice_candidate_stop_gathering(nr_ice_candidate *cand)
358 {
359 if (cand->state == NR_ICE_CAND_STATE_INITIALIZING) {
360 /* Make sure the ICE ctx isn't still waiting around for this candidate
361 * to init. */
362 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
363 }
364
365 NR_async_timer_cancel(cand->delay_timer);
366 cand->delay_timer=0;
367 NR_async_timer_cancel(cand->ready_cb_timer);
368 cand->ready_cb_timer=0;
369
370 if(cand->resolver_handle){
371 nr_resolver_cancel(cand->ctx->resolver,cand->resolver_handle);
372 cand->resolver_handle=0;
373 }
374 }
375
376 /* This algorithm is not super-fast, but I don't think we need a hash
377 table just yet and it produces a small foundation string */
nr_ice_get_foundation(nr_ice_ctx * ctx,nr_ice_candidate * cand)378 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand)
379 {
380 nr_ice_foundation *foundation;
381 int i=0;
382 char fnd[20];
383 int _status;
384
385 foundation=STAILQ_FIRST(&ctx->foundations);
386 while(foundation){
387 if(nr_transport_addr_cmp(&cand->base,&foundation->addr,NR_TRANSPORT_ADDR_CMP_MODE_ADDR))
388 goto next;
389 // cast necessary because there is no guarantee that enum is signed.
390 // foundation->type should probably match nr_ice_candidate_type
391 if((int)cand->type != foundation->type)
392 goto next;
393 if(cand->stun_server != foundation->stun_server)
394 goto next;
395
396 snprintf(fnd,sizeof(fnd),"%d",i);
397 if(!(cand->foundation=r_strdup(fnd)))
398 ABORT(R_NO_MEMORY);
399 return(0);
400
401 next:
402 foundation=STAILQ_NEXT(foundation,entry);
403 i++;
404 }
405
406 if(!(foundation=RCALLOC(sizeof(nr_ice_foundation))))
407 ABORT(R_NO_MEMORY);
408 nr_transport_addr_copy(&foundation->addr,&cand->base);
409 foundation->type=cand->type;
410 foundation->stun_server=cand->stun_server;
411 STAILQ_INSERT_TAIL(&ctx->foundations,foundation,entry);
412
413 snprintf(fnd,sizeof(fnd),"%d",i);
414 if(!(cand->foundation=r_strdup(fnd)))
415 ABORT(R_NO_MEMORY);
416
417 _status=0;
418 abort:
419 return(_status);
420 }
421
nr_ice_candidate_compute_priority(nr_ice_candidate * cand)422 int nr_ice_candidate_compute_priority(nr_ice_candidate *cand)
423 {
424 UCHAR type_preference;
425 UCHAR interface_preference;
426 UCHAR stun_priority;
427 UCHAR direction_priority=0;
428 int r,_status;
429
430 if (cand->base.protocol != IPPROTO_UDP && cand->base.protocol != IPPROTO_TCP){
431 r_log(LOG_ICE,LOG_ERR,"Unknown protocol type %u",
432 (unsigned int)cand->base.protocol);
433 ABORT(R_INTERNAL);
434 }
435
436 switch(cand->type){
437 case HOST:
438 if(cand->base.protocol == IPPROTO_UDP) {
439 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST,&type_preference))
440 ABORT(r);
441 } else if(cand->base.protocol == IPPROTO_TCP) {
442 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST_TCP,&type_preference))
443 ABORT(r);
444 }
445 stun_priority=0;
446 break;
447 case RELAYED:
448 if(cand->base.protocol == IPPROTO_UDP) {
449 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED,&type_preference))
450 ABORT(r);
451 } else if(cand->base.protocol == IPPROTO_TCP) {
452 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED_TCP,&type_preference))
453 ABORT(r);
454 }
455 stun_priority=31-cand->stun_server->id;
456 break;
457 case SERVER_REFLEXIVE:
458 if(cand->base.protocol == IPPROTO_UDP) {
459 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX,&type_preference))
460 ABORT(r);
461 } else if(cand->base.protocol == IPPROTO_TCP) {
462 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP,&type_preference))
463 ABORT(r);
464 }
465 stun_priority=31-cand->stun_server->id;
466 break;
467 case PEER_REFLEXIVE:
468 if(cand->base.protocol == IPPROTO_UDP) {
469 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX,&type_preference))
470 ABORT(r);
471 } else if(cand->base.protocol == IPPROTO_TCP) {
472 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP,&type_preference))
473 ABORT(r);
474 }
475 stun_priority=0;
476 break;
477 default:
478 ABORT(R_INTERNAL);
479 }
480
481 if(cand->base.protocol == IPPROTO_TCP){
482 switch (cand->tcp_type) {
483 case TCP_TYPE_ACTIVE:
484 if (cand->type == HOST)
485 direction_priority=6;
486 else
487 direction_priority=4;
488 break;
489 case TCP_TYPE_PASSIVE:
490 if (cand->type == HOST)
491 direction_priority=4;
492 else
493 direction_priority=2;
494 break;
495 case TCP_TYPE_SO:
496 if (cand->type == HOST)
497 direction_priority=2;
498 else
499 direction_priority=6;
500 break;
501 case TCP_TYPE_NONE:
502 break;
503 case TCP_TYPE_MAX:
504 default:
505 assert(0);
506 ABORT(R_INTERNAL);
507 }
508 }
509
510 if(type_preference > 126)
511 r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference);
512
513 if(!cand->ctx->interface_prioritizer) {
514 /* Prioritizer is not set, read from registry */
515 if(r=NR_reg_get2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,
516 &interface_preference)) {
517 if (r==R_NOT_FOUND) {
518 if (next_automatic_preference == 1) {
519 r_log(LOG_ICE,LOG_ERR,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
520 ABORT(R_NOT_FOUND);
521 }
522 r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
523 next_automatic_preference);
524 if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
525 ABORT(r);
526 }
527 interface_preference=next_automatic_preference << 1;
528 next_automatic_preference--;
529 if (cand->base.ip_version == NR_IPV6) {
530 /* Prefer IPV6 over IPV4 on the same interface. */
531 interface_preference += 1;
532 }
533 }
534 else {
535 ABORT(r);
536 }
537 }
538 }
539 else {
540 char key_of_interface[MAXIFNAME + 41];
541 nr_transport_addr addr;
542
543 if(r=nr_socket_getaddr(cand->isock->sock, &addr))
544 ABORT(r);
545
546 if(r=nr_transport_addr_fmt_ifname_addr_string(&addr,key_of_interface,
547 sizeof(key_of_interface))) {
548 ABORT(r);
549 }
550 if(r=nr_interface_prioritizer_get_priority(cand->ctx->interface_prioritizer,
551 key_of_interface,&interface_preference)) {
552 ABORT(r);
553 }
554 }
555
556 assert(stun_priority < 32);
557 assert(direction_priority < 8);
558
559 cand->priority=
560 (type_preference << 24) |
561 (interface_preference << 16) |
562 (direction_priority << 13) |
563 (stun_priority << 8) |
564 (256 - cand->component_id);
565
566 /* S 4.1.2 */
567 assert(cand->priority>=1&&cand->priority<=2147483647);
568
569 _status=0;
570 abort:
571 return(_status);
572 }
573
nr_ice_candidate_fire_ready_cb(NR_SOCKET s,int how,void * cb_arg)574 static void nr_ice_candidate_fire_ready_cb(NR_SOCKET s, int how, void *cb_arg)
575 {
576 nr_ice_candidate *cand = cb_arg;
577
578 cand->ready_cb_timer = 0;
579 cand->ready_cb(0, 0, cand->ready_cb_arg);
580 }
581
nr_ice_candidate_initialize(nr_ice_candidate * cand,NR_async_cb ready_cb,void * cb_arg)582 int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg)
583 {
584 int r,_status;
585 int protocol=NR_RESOLVE_PROTOCOL_STUN;
586 cand->done_cb=ready_cb;
587 cand->cb_arg=cb_arg;
588 cand->state=NR_ICE_CAND_STATE_INITIALIZING;
589
590 switch(cand->type){
591 case HOST:
592 if(r=nr_socket_getaddr(cand->isock->sock,&cand->addr))
593 ABORT(r);
594 cand->osock=cand->isock->sock;
595 // Post this so that it doesn't happen in-line
596 cand->ready_cb = ready_cb;
597 cand->ready_cb_arg = cb_arg;
598 NR_ASYNC_TIMER_SET(0, nr_ice_candidate_fire_ready_cb, (void *)cand, &cand->ready_cb_timer);
599 break;
600 #ifdef USE_TURN
601 case RELAYED:
602 protocol=NR_RESOLVE_PROTOCOL_TURN;
603 /* Fall through */
604 #endif
605 case SERVER_REFLEXIVE:
606 if(cand->stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
607 if(nr_transport_addr_cmp(&cand->base,&cand->stun_server->u.addr,NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL)) {
608 r_log(LOG_ICE, LOG_INFO, "ICE-CANDIDATE(%s): Skipping srflx/relayed candidate because of IP version/transport mis-match with STUN/TURN server (%u/%s - %u/%s).", cand->label,cand->base.ip_version,cand->base.protocol==IPPROTO_UDP?"UDP":"TCP",cand->stun_server->u.addr.ip_version,cand->stun_server->u.addr.protocol==IPPROTO_UDP?"UDP":"TCP");
609 ABORT(R_NOT_FOUND); /* Same error code when DNS lookup fails */
610 }
611
612 /* Just copy the address */
613 if (r=nr_transport_addr_copy(&cand->stun_server_addr,
614 &cand->stun_server->u.addr)) {
615 r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not copy STUN server addr", cand->label);
616 ABORT(r);
617 }
618
619 if(r=nr_ice_candidate_initialize2(cand))
620 ABORT(r);
621 }
622 else {
623 nr_resolver_resource resource;
624 resource.domain_name=cand->stun_server->u.dnsname.host;
625 resource.port=cand->stun_server->u.dnsname.port;
626 resource.stun_turn=protocol;
627 resource.transport_protocol=cand->stun_server->transport;
628
629 switch (cand->base.ip_version) {
630 case NR_IPV4:
631 resource.address_family=AF_INET;
632 break;
633 case NR_IPV6:
634 resource.address_family=AF_INET6;
635 break;
636 default:
637 ABORT(R_BAD_ARGS);
638 }
639
640 /* Try to resolve */
641 if(!cand->ctx->resolver) {
642 r_log(LOG_ICE, LOG_ERR, "ICE-CANDIDATE(%s): Can't use DNS names without a resolver", cand->label);
643 ABORT(R_BAD_ARGS);
644 }
645
646 if(r=nr_resolver_resolve(cand->ctx->resolver,
647 &resource,
648 nr_ice_candidate_resolved_cb,
649 (void *)cand,
650 &cand->resolver_handle)){
651 r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not invoke DNS resolver",cand->label);
652 ABORT(r);
653 }
654 }
655 break;
656 default:
657 ABORT(R_INTERNAL);
658 }
659
660 nr_ice_candidate_compute_codeword(cand);
661
662 _status=0;
663 abort:
664 if(_status && _status!=R_WOULDBLOCK)
665 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
666 return(_status);
667 }
668
669
nr_ice_candidate_resolved_cb(void * cb_arg,nr_transport_addr * addr)670 static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr)
671 {
672 nr_ice_candidate *cand=cb_arg;
673 int r,_status;
674
675 cand->resolver_handle=0;
676
677 if(addr){
678 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): resolved candidate %s. addr=%s",
679 cand->ctx->label,cand->label,addr->as_string);
680 }
681 else {
682 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to resolve candidate %s.",
683 cand->ctx->label,cand->label);
684 ABORT(R_NOT_FOUND);
685 }
686
687 if (nr_transport_addr_check_compatibility(addr, &cand->base)) {
688 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Skipping STUN server because of link local mis-match for candidate %s",cand->ctx->label,cand->label);
689 ABORT(R_NOT_FOUND);
690 }
691
692 /* Copy the address */
693 if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr))
694 ABORT(r);
695
696 if (cand->tcp_type == TCP_TYPE_PASSIVE || cand->tcp_type == TCP_TYPE_SO){
697 if (r=nr_socket_multi_tcp_stun_server_connect(cand->osock, addr))
698 ABORT(r);
699 }
700
701 /* Now start initializing */
702 if(r=nr_ice_candidate_initialize2(cand))
703 ABORT(r);
704
705 _status=0;
706 abort:
707 if(_status && _status!=R_WOULDBLOCK) {
708 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
709 }
710 return(_status);
711 }
712
nr_ice_candidate_initialize2(nr_ice_candidate * cand)713 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand)
714 {
715 int r,_status;
716
717 switch(cand->type){
718 case HOST:
719 assert(0); /* Can't happen */
720 ABORT(R_INTERNAL);
721 break;
722 #ifdef USE_TURN
723 case RELAYED:
724 if(r=nr_ice_start_relay_turn(cand))
725 ABORT(r);
726 ABORT(R_WOULDBLOCK);
727 break;
728 #endif /* USE_TURN */
729 case SERVER_REFLEXIVE:
730 /* Need to start stun */
731 if(r=nr_ice_srvrflx_start_stun(cand))
732 ABORT(r);
733 cand->osock=cand->isock->sock;
734 ABORT(R_WOULDBLOCK);
735 break;
736 default:
737 ABORT(R_INTERNAL);
738 }
739
740 _status=0;
741 abort:
742 return(_status);
743 }
744
nr_ice_srvrflx_start_stun_timer_cb(NR_SOCKET s,int how,void * cb_arg)745 static void nr_ice_srvrflx_start_stun_timer_cb(NR_SOCKET s, int how, void *cb_arg)
746 {
747 nr_ice_candidate *cand=cb_arg;
748 int r,_status;
749
750 cand->delay_timer=0;
751
752 /* TODO: if the response is a BINDING-ERROR-RESPONSE, then restart
753 * TODO: using NR_STUN_CLIENT_MODE_BINDING_REQUEST because the
754 * TODO: server may not have understood the 0.96-style request */
755 if(r=nr_stun_client_start(cand->u.srvrflx.stun, NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH, nr_ice_srvrflx_stun_finished_cb, cand))
756 ABORT(r);
757
758 if(r=nr_ice_ctx_remember_id(cand->ctx, cand->u.srvrflx.stun->request))
759 ABORT(r);
760
761 if(r=nr_ice_socket_register_stun_client(cand->isock,cand->u.srvrflx.stun,&cand->u.srvrflx.stun_handle))
762 ABORT(r);
763
764 _status=0;
765 abort:
766 if (_status && (cand->u.srvrflx.stun->state==NR_STUN_CLIENT_STATE_RUNNING)) {
767 nr_stun_client_failed(cand->u.srvrflx.stun);
768 }
769 return;
770 }
771
nr_ice_srvrflx_start_stun(nr_ice_candidate * cand)772 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand)
773 {
774 int r,_status;
775
776 assert(!cand->delay_timer);
777 if(r=nr_stun_client_ctx_create(cand->label, cand->isock->sock,
778 &cand->stun_server_addr, cand->stream->ctx->gather_rto,
779 &cand->u.srvrflx.stun))
780 ABORT(r);
781
782 NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_srvrflx_start_stun_timer_cb,cand,&cand->delay_timer);
783 cand->stream->ctx->stun_delay += cand->stream->ctx->Ta;
784
785 _status=0;
786 abort:
787 return(_status);
788 }
789
790 #ifdef USE_TURN
nr_ice_start_relay_turn_timer_cb(NR_SOCKET s,int how,void * cb_arg)791 static void nr_ice_start_relay_turn_timer_cb(NR_SOCKET s, int how, void *cb_arg)
792 {
793 nr_ice_candidate *cand=cb_arg;
794 int r,_status;
795
796 cand->delay_timer=0;
797
798 if(r=nr_turn_client_allocate(cand->u.relayed.turn, nr_ice_turn_allocated_cb, cb_arg))
799 ABORT(r);
800
801 if(r=nr_ice_socket_register_turn_client(cand->isock, cand->u.relayed.turn,
802 cand->osock, &cand->u.relayed.turn_handle))
803 ABORT(r);
804
805 _status=0;
806 abort:
807 if(_status && (cand->u.relayed.turn->state==NR_TURN_CLIENT_STATE_ALLOCATING)){
808 nr_turn_client_failed(cand->u.relayed.turn);
809 }
810 return;
811 }
812
nr_ice_start_relay_turn(nr_ice_candidate * cand)813 static int nr_ice_start_relay_turn(nr_ice_candidate *cand)
814 {
815 int r,_status;
816 assert(!cand->delay_timer);
817 if(r=nr_turn_client_ctx_create(cand->label, cand->isock->sock,
818 cand->u.relayed.server->username,
819 cand->u.relayed.server->password,
820 &cand->stun_server_addr,
821 &cand->u.relayed.turn))
822 ABORT(r);
823
824 if(r=nr_socket_turn_set_ctx(cand->osock, cand->u.relayed.turn))
825 ABORT(r);
826
827 NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_start_relay_turn_timer_cb,cand,&cand->delay_timer);
828 cand->stream->ctx->stun_delay += cand->stream->ctx->Ta;
829
830 _status=0;
831 abort:
832 return(_status);
833 }
834 #endif /* USE_TURN */
835
nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock,int how,void * cb_arg)836 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg)
837 {
838 int _status;
839 nr_ice_candidate *cand=cb_arg;
840
841 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): %s",cand->ctx->label,cand->label,__FUNCTION__);
842
843 /* Deregister to suppress duplicates */
844 if(cand->u.srvrflx.stun_handle){ /* This test because we might have failed before CB registered */
845 nr_ice_socket_deregister(cand->isock,cand->u.srvrflx.stun_handle);
846 cand->u.srvrflx.stun_handle=0;
847 }
848
849 switch(cand->u.srvrflx.stun->state){
850 /* OK, we should have a mapped address */
851 case NR_STUN_CLIENT_STATE_DONE:
852 /* Copy the address */
853 nr_transport_addr_copy(&cand->addr, &cand->u.srvrflx.stun->results.stun_binding_response.mapped_addr);
854 cand->addr.protocol=cand->base.protocol;
855 nr_transport_addr_fmt_addr_string(&cand->addr);
856 nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
857 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_INITIALIZED);
858 cand=0;
859 break;
860
861 /* This failed, so go to the next STUN server if there is one */
862 case NR_STUN_CLIENT_STATE_FAILED:
863 ABORT(R_NOT_FOUND);
864 break;
865 default:
866 ABORT(R_INTERNAL);
867 }
868 _status = 0;
869 abort:
870 if(_status){
871 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
872 }
873 }
874
875 #ifdef USE_TURN
nr_ice_turn_allocated_cb(NR_SOCKET s,int how,void * cb_arg)876 static void nr_ice_turn_allocated_cb(NR_SOCKET s, int how, void *cb_arg)
877 {
878 int r,_status;
879 nr_ice_candidate *cand=cb_arg;
880 nr_turn_client_ctx *turn=cand->u.relayed.turn;
881 char *label;
882 nr_transport_addr relay_addr;
883
884 switch(turn->state){
885 /* OK, we should have a mapped address */
886 case NR_TURN_CLIENT_STATE_ALLOCATED:
887 if (r=nr_turn_client_get_relayed_address(turn, &relay_addr))
888 ABORT(r);
889
890 if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",
891 relay_addr.as_string,")",NULL))
892 ABORT(r);
893
894 r_log(LOG_ICE,LOG_DEBUG,"TURN-CLIENT(%s)/CAND(%s): Switching from TURN to RELAY (%s)",cand->u.relayed.turn->label,cand->label,label);
895
896 /* Copy the relayed address into the candidate addr and
897 into the candidate base. Note that we need to keep the
898 ifname in the base. */
899 if (r=nr_transport_addr_copy(&cand->addr, &relay_addr))
900 ABORT(r);
901 if (r=nr_transport_addr_copy_keep_ifname(&cand->base, &relay_addr)) /* Need to keep interface for priority calculation */
902 ABORT(r);
903
904 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): new relay base=%s addr=%s", cand->ctx->label, cand->label, cand->base.as_string, cand->addr.as_string);
905
906 RFREE(cand->label);
907 cand->label=label;
908 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_INITIALIZED);
909 cand = 0;
910
911 break;
912
913 case NR_TURN_CLIENT_STATE_FAILED:
914 case NR_TURN_CLIENT_STATE_CANCELLED:
915 r_log(NR_LOG_TURN, LOG_WARNING,
916 "ICE-CANDIDATE(%s): nr_turn_allocated_cb called with state %d",
917 cand->label, turn->state);
918 /* This failed, so go to the next TURN server if there is one */
919 ABORT(R_NOT_FOUND);
920 break;
921 default:
922 assert(0); /* should never happen */
923 ABORT(R_INTERNAL);
924 }
925
926 _status=0;
927 abort:
928 if(_status){
929 if (cand) {
930 r_log(NR_LOG_TURN, LOG_WARNING,
931 "ICE-CANDIDATE(%s): nr_turn_allocated_cb failed", cand->label);
932 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
933 }
934 }
935 }
936 #endif /* USE_TURN */
937
938 /* Format the candidate attribute as per ICE S 15.1 */
nr_ice_format_candidate_attribute(nr_ice_candidate * cand,char * attr,int maxlen,int obfuscate_srflx_addr)939 int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen, int obfuscate_srflx_addr)
940 {
941 int r,_status;
942 char addr[64];
943 int port;
944 int len;
945 nr_transport_addr *raddr;
946
947 assert(!strcmp(nr_ice_candidate_type_names[HOST], "host"));
948 assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay"));
949
950 if (cand->mdns_addr) {
951 /* mdns_addr is NSID_LENGTH which is 39, - 2 for removing the "{" and "}"
952 + 6 for ".local" for a total of 43. */
953 strncpy(addr, cand->mdns_addr, sizeof(addr) - 1);
954 } else {
955 if(r=nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr)))
956 ABORT(r);
957 }
958 if(r=nr_transport_addr_get_port(&cand->addr,&port))
959 ABORT(r);
960 /* https://tools.ietf.org/html/rfc6544#section-4.5 */
961 if (cand->base.protocol==IPPROTO_TCP && cand->tcp_type==TCP_TYPE_ACTIVE)
962 port=9;
963 snprintf(attr,maxlen,"candidate:%s %d %s %u %s %d typ %s",
964 cand->foundation, cand->component_id, cand->addr.protocol==IPPROTO_UDP?"UDP":"TCP",cand->priority, addr, port,
965 nr_ctype_name(cand->type));
966
967 len=strlen(attr); attr+=len; maxlen-=len;
968
969 /* raddr, rport */
970 raddr = (cand->stream->ctx->flags &
971 (NR_ICE_CTX_FLAGS_RELAY_ONLY |
972 NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES)) ?
973 &cand->addr : &cand->base;
974
975 switch(cand->type){
976 case HOST:
977 break;
978 case SERVER_REFLEXIVE:
979 if (obfuscate_srflx_addr) {
980 snprintf(attr,maxlen," raddr 0.0.0.0 rport 0");
981 } else {
982 if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
983 ABORT(r);
984 if(r=nr_transport_addr_get_port(raddr,&port))
985 ABORT(r);
986 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
987 }
988 break;
989 case PEER_REFLEXIVE:
990 if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
991 ABORT(r);
992 if(r=nr_transport_addr_get_port(raddr,&port))
993 ABORT(r);
994 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
995 break;
996 case RELAYED:
997 // comes from XorMappedAddress via AllocateResponse
998 if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
999 ABORT(r);
1000 if(r=nr_transport_addr_get_port(raddr,&port))
1001 ABORT(r);
1002
1003 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
1004 break;
1005 default:
1006 assert(0);
1007 ABORT(R_INTERNAL);
1008 break;
1009 }
1010
1011 if (cand->base.protocol==IPPROTO_TCP && cand->tcp_type){
1012 len=strlen(attr);
1013 attr+=len;
1014 maxlen-=len;
1015 snprintf(attr,maxlen," tcptype %s",nr_tcp_type_name(cand->tcp_type));
1016 }
1017
1018 _status=0;
1019 abort:
1020 return(_status);
1021 }
1022
1023