Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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.
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.
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 */
35 static char *RCSSTRING __UNUSED__="$Id: ice_candidate.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
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"
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"
66 static int next_automatic_preference = 224;
68 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
69 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
70 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand);
71 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
72 #ifdef USE_TURN
73 static int nr_ice_start_relay_turn(nr_ice_candidate *cand);
74 static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg);
75 static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr);
76 #endif /* USE_TURN */
78 void nr_ice_candidate_compute_codeword(nr_ice_candidate *cand)
79 {
80 char as_string[1024];
82 snprintf(as_string,
83 sizeof(as_string),
84 "%s(%s)",
85 cand->addr.as_string,
86 cand->label);
88 nr_ice_compute_codeword(as_string,strlen(as_string),cand->codeword);
89 }
91 char *nr_ice_candidate_type_names[]={0,"host","srflx","prflx","relay",0};
93 static const char *nr_ctype_name(nr_ice_candidate_type ctype) {
94 assert(ctype<CTYPE_MAX && ctype>0);
95 if (ctype <= 0 || ctype >= CTYPE_MAX) {
96 return "ERROR";
97 }
98 return nr_ice_candidate_type_names[ctype];
99 }
101 static int nr_ice_candidate_format_stun_label(char *label, size_t size, nr_ice_candidate *cand)
102 {
103 int _status;
105 *label = 0;
106 switch(cand->stun_server->type) {
107 case NR_ICE_STUN_SERVER_TYPE_ADDR:
108 snprintf(label, size, "%s(%s|%s)", nr_ctype_name(cand->type), cand->base.as_string,
109 cand->stun_server->u.addr.as_string);
110 break;
111 case NR_ICE_STUN_SERVER_TYPE_DNSNAME:
112 snprintf(label, size, "%s(%s|%s:%u)", nr_ctype_name(cand->type), cand->base.as_string,
113 cand->stun_server->u.dnsname.host, cand->stun_server->u.dnsname.port);
114 break;
115 default:
116 assert(0);
117 ABORT(R_BAD_ARGS);
118 }
120 _status=0;
121 abort:
122 return(_status);
123 }
125 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_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp)
126 {
127 nr_ice_candidate *cand=0;
128 nr_ice_candidate *tmp=0;
129 int r,_status;
130 char label[512];
132 if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
133 ABORT(R_NO_MEMORY);
134 cand->state=NR_ICE_CAND_STATE_CREATED;
135 cand->ctx=ctx;
136 cand->isock=isock;
137 cand->osock=osock;
138 cand->type=ctype;
139 cand->stun_server=stun_server;
140 cand->component_id=component_id;
141 cand->component=comp;
142 cand->stream=comp->stream;
144 /* Extract the addr as the base */
145 if(r=nr_socket_getaddr(cand->isock->sock,&cand->base))
146 ABORT(r);
148 switch(ctype) {
149 case HOST:
150 snprintf(label, sizeof(label), "host(%s)", cand->base.as_string);
151 break;
153 case SERVER_REFLEXIVE:
154 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label),cand))
155 ABORT(r);
156 break;
158 case RELAYED:
159 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label),cand))
160 ABORT(r);
161 break;
163 case PEER_REFLEXIVE:
164 snprintf(label, sizeof(label), "prflx");
165 break;
167 default:
168 assert(0); /* Can't happen */
169 ABORT(R_BAD_ARGS);
170 }
171 if(!(cand->label=r_strdup(label)))
172 ABORT(R_NO_MEMORY);
174 if(r=nr_ice_get_foundation(ctx,cand))
175 ABORT(r);
176 if(r=nr_ice_candidate_compute_priority(cand))
177 ABORT(r);
179 TAILQ_FOREACH(tmp,&isock->candidates,entry_sock){
180 if(cand->priority==tmp->priority){
181 r_log(LOG_ICE,LOG_ERR,"ICE(%s): duplicate priority %u candidate %s and candidate %s",
182 ctx->label,cand->priority,cand->label,tmp->label);
183 }
184 }
186 if(ctype==RELAYED)
187 cand->u.relayed.turn_sock=osock;
190 /* Add the candidate to the isock list*/
191 TAILQ_INSERT_TAIL(&isock->candidates,cand,entry_sock);
193 nr_ice_candidate_compute_codeword(cand);
195 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): created candidate %s with type %s",
196 ctx->label,cand->label,nr_ctype_name(ctype));
198 *candp=cand;
200 _status=0;
201 abort:
202 if (_status){
203 r_log(LOG_ICE,LOG_ERR,"ICE(%s): Failed to create candidate of type %s", ctx->label,nr_ctype_name(ctype));
204 nr_ice_candidate_destroy(&cand);
205 }
206 return(_status);
207 }
210 /* Create a peer reflexive candidate */
211 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)
212 {
213 nr_ice_candidate *cand=0;
214 nr_ice_candidate_type ctype=PEER_REFLEXIVE;
215 int r,_status;
217 if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
218 ABORT(R_NO_MEMORY);
219 if(!(cand->label=r_strdup(label)))
220 ABORT(R_NO_MEMORY);
222 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
223 cand->ctx=ctx;
224 cand->type=ctype;
225 cand->component_id=comp->component_id;
226 cand->component=comp;
227 cand->stream=comp->stream;
230 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): creating candidate with type %s",
231 ctx->label,label,nr_ctype_name(ctype));
233 if(r=nr_transport_addr_copy(&cand->base,addr))
234 ABORT(r);
235 if(r=nr_transport_addr_copy(&cand->addr,addr))
236 ABORT(r);
237 /* Bogus foundation */
238 if(!(cand->foundation=r_strdup(cand->addr.as_string)))
239 ABORT(R_NO_MEMORY);
241 nr_ice_candidate_compute_codeword(cand);
243 *candp=cand;
245 _status=0;
246 abort:
247 if (_status){
248 nr_ice_candidate_destroy(&cand);
249 }
250 return(_status);
251 }
253 int nr_ice_candidate_destroy(nr_ice_candidate **candp)
254 {
255 nr_ice_candidate *cand=0;
257 if(!candp || !*candp)
258 return(0);
260 cand=*candp;
262 switch(cand->type){
263 case HOST:
264 break;
265 #ifdef USE_TURN
266 case RELAYED:
267 if (cand->u.relayed.turn_handle)
268 nr_ice_socket_deregister(cand->isock, cand->u.relayed.turn_handle);
269 nr_turn_client_ctx_destroy(&cand->u.relayed.turn);
270 nr_socket_destroy(&cand->u.relayed.turn_sock);
271 break;
272 #endif /* USE_TURN */
273 case SERVER_REFLEXIVE:
274 if (cand->u.srvrflx.stun_handle)
275 nr_ice_socket_deregister(cand->isock, cand->u.srvrflx.stun_handle);
276 nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
277 break;
278 default:
279 break;
280 }
282 NR_async_timer_cancel(cand->delay_timer);
283 NR_async_timer_cancel(cand->ready_cb_timer);
284 if(cand->resolver_handle){
285 nr_resolver_cancel(cand->ctx->resolver,cand->resolver_handle);
286 }
288 RFREE(cand->foundation);
289 RFREE(cand->label);
290 RFREE(cand);
292 return(0);
293 }
295 void nr_ice_candidate_destroy_cb(NR_SOCKET s, int h, void *cb_arg)
296 {
297 nr_ice_candidate *cand=cb_arg;
298 nr_ice_candidate_destroy(&cand);
299 }
301 /* This algorithm is not super-fast, but I don't think we need a hash
302 table just yet and it produces a small foundation string */
303 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand)
304 {
305 nr_ice_foundation *foundation;
306 int i=0;
307 char fnd[20];
308 int _status;
310 foundation=STAILQ_FIRST(&ctx->foundations);
311 while(foundation){
312 if(nr_transport_addr_cmp(&cand->base,&foundation->addr,NR_TRANSPORT_ADDR_CMP_MODE_ADDR))
313 goto next;
314 if(cand->type != foundation->type)
315 goto next;
316 if(cand->stun_server != foundation->stun_server)
317 goto next;
319 snprintf(fnd,sizeof(fnd),"%d",i);
320 if(!(cand->foundation=r_strdup(fnd)))
321 ABORT(R_NO_MEMORY);
322 return(0);
324 next:
325 foundation=STAILQ_NEXT(foundation,entry);
326 i++;
327 }
329 if(!(foundation=RCALLOC(sizeof(nr_ice_foundation))))
330 ABORT(R_NO_MEMORY);
331 nr_transport_addr_copy(&foundation->addr,&cand->base);
332 foundation->type=cand->type;
333 foundation->stun_server=cand->stun_server;
334 STAILQ_INSERT_TAIL(&ctx->foundations,foundation,entry);
336 snprintf(fnd,sizeof(fnd),"%d",i);
337 if(!(cand->foundation=r_strdup(fnd)))
338 ABORT(R_NO_MEMORY);
340 _status=0;
341 abort:
342 return(_status);
343 }
345 int nr_ice_candidate_compute_priority(nr_ice_candidate *cand)
346 {
347 UCHAR type_preference;
348 UCHAR interface_preference;
349 UCHAR stun_priority;
350 int r,_status;
352 switch(cand->type){
353 case HOST:
354 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST,&type_preference))
355 ABORT(r);
356 stun_priority=0;
357 break;
358 case RELAYED:
359 if(cand->base.protocol == IPPROTO_UDP) {
360 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED,&type_preference))
361 ABORT(r);
362 }
363 else if(cand->base.protocol == IPPROTO_TCP) {
364 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED_TCP,&type_preference))
365 ABORT(r);
367 }
368 else {
369 r_log(LOG_ICE,LOG_ERR,"Unknown protocol type %u",
370 (unsigned int)cand->base.protocol);
371 ABORT(R_INTERNAL);
372 }
373 stun_priority=255-cand->stun_server->index;
374 break;
375 case SERVER_REFLEXIVE:
376 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX,&type_preference))
377 ABORT(r);
378 stun_priority=255-cand->stun_server->index;
379 break;
380 case PEER_REFLEXIVE:
381 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX,&type_preference))
382 ABORT(r);
383 stun_priority=0;
384 break;
385 default:
386 ABORT(R_INTERNAL);
387 }
389 if(type_preference > 126)
390 r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference);
392 if(!cand->ctx->interface_prioritizer) {
393 /* Prioritizer is not set, read from registry */
394 if(r=NR_reg_get2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,
395 &interface_preference)) {
396 if (r==R_NOT_FOUND) {
397 if (next_automatic_preference == 1) {
398 r_log(LOG_ICE,LOG_ERR,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
399 ABORT(R_NOT_FOUND);
400 }
401 r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
402 next_automatic_preference);
403 if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
404 ABORT(r);
405 }
406 interface_preference=next_automatic_preference;
407 next_automatic_preference--;
408 }
409 else {
410 ABORT(r);
411 }
412 }
413 }
414 else {
415 char key_of_interface[MAXIFNAME + 41];
416 nr_transport_addr addr;
418 if(r=nr_socket_getaddr(cand->isock->sock, &addr))
419 ABORT(r);
421 if(r=nr_transport_addr_fmt_ifname_addr_string(&addr,key_of_interface,
422 sizeof(key_of_interface))) {
423 ABORT(r);
424 }
425 if(r=nr_interface_prioritizer_get_priority(cand->ctx->interface_prioritizer,
426 key_of_interface,&interface_preference)) {
427 ABORT(r);
428 }
429 }
431 cand->priority=
432 (type_preference << 24) |
433 (interface_preference << 16) |
434 (stun_priority << 8) |
435 (256 - cand->component_id);
437 /* S 4.1.2 */
438 assert(cand->priority>=1&&cand->priority<=2147483647);
440 _status=0;
441 abort:
442 return(_status);
443 }
445 static void nr_ice_candidate_fire_ready_cb(NR_SOCKET s, int how, void *cb_arg)
446 {
447 nr_ice_candidate *cand = cb_arg;
449 cand->ready_cb_timer = 0;
450 cand->ready_cb(0, 0, cand->ready_cb_arg);
451 }
453 int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg)
454 {
455 int r,_status;
456 int protocol=NR_RESOLVE_PROTOCOL_STUN;
457 int transport=IPPROTO_UDP;
458 cand->done_cb=ready_cb;
459 cand->cb_arg=cb_arg;
461 switch(cand->type){
462 case HOST:
463 if(r=nr_socket_getaddr(cand->isock->sock,&cand->addr))
464 ABORT(r);
465 cand->osock=cand->isock->sock;
466 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
467 // Post this so that it doesn't happen in-line
468 cand->ready_cb = ready_cb;
469 cand->ready_cb_arg = cb_arg;
470 NR_ASYNC_TIMER_SET(0, nr_ice_candidate_fire_ready_cb, (void *)cand, &cand->ready_cb_timer);
471 break;
472 #ifdef USE_TURN
473 case RELAYED:
474 protocol=NR_RESOLVE_PROTOCOL_TURN;
475 transport=cand->u.relayed.server->transport;
476 /* Fall through */
477 #endif
478 case SERVER_REFLEXIVE:
479 cand->state=NR_ICE_CAND_STATE_INITIALIZING;
481 if(cand->stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
482 /* Just copy the address */
483 if (r=nr_transport_addr_copy(&cand->stun_server_addr,
484 &cand->stun_server->u.addr)) {
485 r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not copy STUN server addr", cand->label);
486 ABORT(r);
487 }
489 if(r=nr_ice_candidate_initialize2(cand))
490 ABORT(r);
491 }
492 else {
493 nr_resolver_resource resource;
494 resource.domain_name=cand->stun_server->u.dnsname.host;
495 resource.port=cand->stun_server->u.dnsname.port;
496 resource.stun_turn=protocol;
497 resource.transport_protocol=transport;
499 /* Try to resolve */
500 if(!cand->ctx->resolver) {
501 r_log(LOG_ICE, LOG_ERR, "ICE-CANDIDATE(%s): Can't use DNS names without a resolver", cand->label);
502 ABORT(R_BAD_ARGS);
503 }
505 if(r=nr_resolver_resolve(cand->ctx->resolver,
506 &resource,
507 nr_ice_candidate_resolved_cb,
508 (void *)cand,
509 &cand->resolver_handle)){
510 r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not invoke DNS resolver",cand->label);
511 ABORT(r);
512 }
513 }
514 break;
515 default:
516 ABORT(R_INTERNAL);
517 }
519 nr_ice_candidate_compute_codeword(cand);
521 _status=0;
522 abort:
523 if(_status && _status!=R_WOULDBLOCK)
524 cand->state=NR_ICE_CAND_STATE_FAILED;
525 return(_status);
526 }
529 static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr)
530 {
531 nr_ice_candidate *cand=cb_arg;
532 int r,_status;
534 cand->resolver_handle=0;
536 if(addr){
537 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): resolved candidate %s. addr=%s",
538 cand->ctx->label,cand->label,addr->as_string);
539 }
540 else {
541 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to resolve candidate %s.",
542 cand->ctx->label,cand->label);
543 ABORT(R_NOT_FOUND);
544 }
546 /* Copy the address */
547 if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr))
548 ABORT(r);
550 /* Now start initializing */
551 if(r=nr_ice_candidate_initialize2(cand))
552 ABORT(r);
554 _status=0;
555 abort:
556 if(_status && _status!=R_WOULDBLOCK) {
557 cand->state=NR_ICE_CAND_STATE_FAILED;
558 cand->done_cb(0,0,cand->cb_arg);
559 }
560 return(_status);
561 }
563 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand)
564 {
565 int r,_status;
567 switch(cand->type){
568 case HOST:
569 assert(0); /* Can't happen */
570 ABORT(R_INTERNAL);
571 break;
572 #ifdef USE_TURN
573 case RELAYED:
574 if(r=nr_ice_start_relay_turn(cand))
575 ABORT(r);
576 ABORT(R_WOULDBLOCK);
577 break;
578 #endif /* USE_TURN */
579 case SERVER_REFLEXIVE:
580 /* Need to start stun */
581 if(r=nr_ice_srvrflx_start_stun(cand))
582 ABORT(r);
583 cand->osock=cand->isock->sock;
584 ABORT(R_WOULDBLOCK);
585 break;
586 default:
587 ABORT(R_INTERNAL);
588 }
590 _status=0;
591 abort:
592 if(_status && _status!=R_WOULDBLOCK)
593 cand->state=NR_ICE_CAND_STATE_FAILED;
594 return(_status);
595 }
597 static void nr_ice_srvrflx_start_stun_timer_cb(NR_SOCKET s, int how, void *cb_arg)
598 {
599 nr_ice_candidate *cand=cb_arg;
600 int r,_status;
602 cand->delay_timer=0;
604 /* TODO: if the response is a BINDING-ERROR-RESPONSE, then restart
605 * TODO: using NR_STUN_CLIENT_MODE_BINDING_REQUEST because the
606 * TODO: server may not have understood the 0.96-style request */
607 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))
608 ABORT(r);
610 if(r=nr_ice_ctx_remember_id(cand->ctx, cand->u.srvrflx.stun->request))
611 ABORT(r);
613 if(r=nr_ice_socket_register_stun_client(cand->isock,cand->u.srvrflx.stun,&cand->u.srvrflx.stun_handle))
614 ABORT(r);
616 _status=0;
617 abort:
618 if(_status){
619 cand->state=NR_ICE_CAND_STATE_FAILED;
620 }
622 return;
623 }
625 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand)
626 {
627 int r,_status;
629 assert(!cand->delay_timer);
630 if(r=nr_stun_client_ctx_create(cand->label, cand->isock->sock,
631 &cand->stun_server_addr, cand->stream->ctx->gather_rto,
632 &cand->u.srvrflx.stun))
633 ABORT(r);
635 NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_srvrflx_start_stun_timer_cb,cand,&cand->delay_timer);
636 cand->stream->ctx->stun_delay += cand->stream->ctx->Ta;
638 _status=0;
639 abort:
640 if(_status){
641 cand->state=NR_ICE_CAND_STATE_FAILED;
642 }
643 return(_status);
644 }
646 #ifdef USE_TURN
647 static void nr_ice_start_relay_turn_timer_cb(NR_SOCKET s, int how, void *cb_arg)
648 {
649 nr_ice_candidate *cand=cb_arg;
650 int r,_status;
652 cand->delay_timer=0;
654 if(r=nr_turn_client_allocate(cand->u.relayed.turn, nr_ice_turn_allocated_cb, cb_arg))
655 ABORT(r);
657 if(r=nr_ice_socket_register_turn_client(cand->isock, cand->u.relayed.turn,
658 cand->osock, &cand->u.relayed.turn_handle))
659 ABORT(r);
661 _status=0;
662 abort:
663 if(_status){
664 cand->state=NR_ICE_CAND_STATE_FAILED;
665 }
666 return;
667 }
669 static int nr_ice_start_relay_turn(nr_ice_candidate *cand)
670 {
671 int r,_status;
672 assert(!cand->delay_timer);
673 if(r=nr_turn_client_ctx_create(cand->label, cand->isock->sock,
674 cand->u.relayed.server->username,
675 cand->u.relayed.server->password,
676 &cand->stun_server_addr,
677 &cand->u.relayed.turn))
678 ABORT(r);
680 if(r=nr_socket_turn_set_ctx(cand->osock, cand->u.relayed.turn))
681 ABORT(r);
683 NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_start_relay_turn_timer_cb,cand,&cand->delay_timer);
684 cand->stream->ctx->stun_delay += cand->stream->ctx->Ta;
686 _status=0;
687 abort:
688 if(_status){
689 cand->state=NR_ICE_CAND_STATE_FAILED;
690 }
691 return(_status);
692 }
693 #endif /* USE_TURN */
695 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg)
696 {
697 int _status;
698 nr_ice_candidate *cand=cb_arg;
700 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): %s",cand->ctx->label,cand->label,__FUNCTION__);
702 /* Deregister to suppress duplicates */
703 if(cand->u.srvrflx.stun_handle){ /* This test because we might have failed before CB registered */
704 nr_ice_socket_deregister(cand->isock,cand->u.srvrflx.stun_handle);
705 cand->u.srvrflx.stun_handle=0;
706 }
708 switch(cand->u.srvrflx.stun->state){
709 /* OK, we should have a mapped address */
710 case NR_STUN_CLIENT_STATE_DONE:
711 /* Copy the address */
712 nr_transport_addr_copy(&cand->addr, &cand->u.srvrflx.stun->results.stun_binding_response.mapped_addr);
713 nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
714 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
715 /* Execute the ready callback */
716 cand->done_cb(0,0,cand->cb_arg);
717 break;
719 /* This failed, so go to the next STUN server if there is one */
720 case NR_STUN_CLIENT_STATE_FAILED:
721 ABORT(R_NOT_FOUND);
722 break;
723 default:
724 ABORT(R_INTERNAL);
725 }
726 _status = 0;
727 abort:
728 if(_status){
729 cand->state=NR_ICE_CAND_STATE_FAILED;
730 cand->done_cb(0,0,cand->cb_arg);
731 }
732 }
734 #ifdef USE_TURN
735 static void nr_ice_turn_allocated_cb(NR_SOCKET s, int how, void *cb_arg)
736 {
737 int r,_status;
738 nr_ice_candidate *cand=cb_arg;
739 nr_turn_client_ctx *turn=cand->u.relayed.turn;
740 char *label;
741 nr_transport_addr relay_addr;
743 switch(turn->state){
744 /* OK, we should have a mapped address */
745 case NR_TURN_CLIENT_STATE_ALLOCATED:
746 if (r=nr_turn_client_get_relayed_address(turn, &relay_addr))
747 ABORT(r);
749 if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",
750 relay_addr.as_string,")",NULL))
751 ABORT(r);
753 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);
755 /* Copy the relayed address into the candidate addr and
756 into the candidate base. Note that we need to keep the
757 ifname in the base. */
758 if (r=nr_transport_addr_copy(&cand->addr, &relay_addr))
759 ABORT(r);
760 if (r=nr_transport_addr_copy_keep_ifname(&cand->base, &relay_addr)) /* Need to keep interface for priority calculation */
761 ABORT(r);
763 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);
765 RFREE(cand->label);
766 cand->label=label;
767 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
769 /* We also need to activate the associated STUN candidate */
770 if(cand->u.relayed.srvflx_candidate){
771 nr_ice_candidate *cand2=cand->u.relayed.srvflx_candidate;
773 if (r=nr_turn_client_get_mapped_address(cand->u.relayed.turn, &cand2->addr))
774 ABORT(r);
776 cand2->state=NR_ICE_CAND_STATE_INITIALIZED;
777 cand2->done_cb(0,0,cand2->cb_arg);
778 }
780 /* Execute the ready callback */
781 cand->done_cb(0,0,cand->cb_arg);
782 cand = 0;
784 break;
786 case NR_TURN_CLIENT_STATE_FAILED:
787 case NR_TURN_CLIENT_STATE_CANCELLED:
788 r_log(NR_LOG_TURN, LOG_WARNING,
789 "ICE-CANDIDATE(%s): nr_turn_allocated_cb called with state %d",
790 cand->label, turn->state);
791 /* This failed, so go to the next TURN server if there is one */
792 ABORT(R_NOT_FOUND);
793 break;
794 default:
795 assert(0); /* should never happen */
796 ABORT(R_INTERNAL);
797 }
799 _status=0;
800 abort:
801 if(_status){
802 if (cand) {
803 r_log(NR_LOG_TURN, LOG_WARNING,
804 "ICE-CANDIDATE(%s): nr_turn_allocated_cb failed", cand->label);
805 cand->state=NR_ICE_CAND_STATE_FAILED;
806 cand->done_cb(0,0,cand->cb_arg);
808 if(cand->u.relayed.srvflx_candidate){
809 nr_ice_candidate *cand2=cand->u.relayed.srvflx_candidate;
811 cand2->state=NR_ICE_CAND_STATE_FAILED;
812 cand2->done_cb(0,0,cand2->cb_arg);
813 }
814 }
815 }
816 }
817 #endif /* USE_TURN */
819 /* Format the candidate attribute as per ICE S 15.1 */
820 int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen)
821 {
822 int r,_status;
823 char addr[64];
824 int port;
825 int len;
827 assert(!strcmp(nr_ice_candidate_type_names[HOST], "host"));
828 assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay"));
830 if(r=nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr)))
831 ABORT(r);
832 if(r=nr_transport_addr_get_port(&cand->addr,&port))
833 ABORT(r);
834 snprintf(attr,maxlen,"candidate:%s %d UDP %u %s %d typ %s",
835 cand->foundation, cand->component_id, cand->priority, addr, port,
836 nr_ctype_name(cand->type));
838 len=strlen(attr); attr+=len; maxlen-=len;
840 /* raddr, rport */
841 switch(cand->type){
842 case HOST:
843 break;
844 case SERVER_REFLEXIVE:
845 case PEER_REFLEXIVE:
846 if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr)))
847 ABORT(r);
848 if(r=nr_transport_addr_get_port(&cand->base,&port))
849 ABORT(r);
851 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
852 break;
853 case RELAYED:
854 // comes from XorMappedAddress via AllocateResponse
855 if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr)))
856 ABORT(r);
857 if(r=nr_transport_addr_get_port(&cand->base,&port))
858 ABORT(r);
860 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
861 break;
862 default:
863 assert(0);
864 ABORT(R_INTERNAL);
865 break;
866 }
867 _status=0;
868 abort:
869 return(_status);
870 }