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