media/mtransport/third_party/nICEr/src/ice/ice_candidate.c

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:61bac89c953d
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
66 static int next_automatic_preference = 224;
67
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 */
77
78 void nr_ice_candidate_compute_codeword(nr_ice_candidate *cand)
79 {
80 char as_string[1024];
81
82 snprintf(as_string,
83 sizeof(as_string),
84 "%s(%s)",
85 cand->addr.as_string,
86 cand->label);
87
88 nr_ice_compute_codeword(as_string,strlen(as_string),cand->codeword);
89 }
90
91 char *nr_ice_candidate_type_names[]={0,"host","srflx","prflx","relay",0};
92
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 }
100
101 static int nr_ice_candidate_format_stun_label(char *label, size_t size, nr_ice_candidate *cand)
102 {
103 int _status;
104
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 }
119
120 _status=0;
121 abort:
122 return(_status);
123 }
124
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];
131
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;
143
144 /* Extract the addr as the base */
145 if(r=nr_socket_getaddr(cand->isock->sock,&cand->base))
146 ABORT(r);
147
148 switch(ctype) {
149 case HOST:
150 snprintf(label, sizeof(label), "host(%s)", cand->base.as_string);
151 break;
152
153 case SERVER_REFLEXIVE:
154 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label),cand))
155 ABORT(r);
156 break;
157
158 case RELAYED:
159 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label),cand))
160 ABORT(r);
161 break;
162
163 case PEER_REFLEXIVE:
164 snprintf(label, sizeof(label), "prflx");
165 break;
166
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);
173
174 if(r=nr_ice_get_foundation(ctx,cand))
175 ABORT(r);
176 if(r=nr_ice_candidate_compute_priority(cand))
177 ABORT(r);
178
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 }
185
186 if(ctype==RELAYED)
187 cand->u.relayed.turn_sock=osock;
188
189
190 /* Add the candidate to the isock list*/
191 TAILQ_INSERT_TAIL(&isock->candidates,cand,entry_sock);
192
193 nr_ice_candidate_compute_codeword(cand);
194
195 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): created candidate %s with type %s",
196 ctx->label,cand->label,nr_ctype_name(ctype));
197
198 *candp=cand;
199
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 }
208
209
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;
216
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);
221
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;
228
229
230 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): creating candidate with type %s",
231 ctx->label,label,nr_ctype_name(ctype));
232
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);
240
241 nr_ice_candidate_compute_codeword(cand);
242
243 *candp=cand;
244
245 _status=0;
246 abort:
247 if (_status){
248 nr_ice_candidate_destroy(&cand);
249 }
250 return(_status);
251 }
252
253 int nr_ice_candidate_destroy(nr_ice_candidate **candp)
254 {
255 nr_ice_candidate *cand=0;
256
257 if(!candp || !*candp)
258 return(0);
259
260 cand=*candp;
261
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 }
281
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 }
287
288 RFREE(cand->foundation);
289 RFREE(cand->label);
290 RFREE(cand);
291
292 return(0);
293 }
294
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 }
300
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;
309
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;
318
319 snprintf(fnd,sizeof(fnd),"%d",i);
320 if(!(cand->foundation=r_strdup(fnd)))
321 ABORT(R_NO_MEMORY);
322 return(0);
323
324 next:
325 foundation=STAILQ_NEXT(foundation,entry);
326 i++;
327 }
328
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);
335
336 snprintf(fnd,sizeof(fnd),"%d",i);
337 if(!(cand->foundation=r_strdup(fnd)))
338 ABORT(R_NO_MEMORY);
339
340 _status=0;
341 abort:
342 return(_status);
343 }
344
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;
351
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);
366
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 }
388
389 if(type_preference > 126)
390 r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference);
391
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;
417
418 if(r=nr_socket_getaddr(cand->isock->sock, &addr))
419 ABORT(r);
420
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 }
430
431 cand->priority=
432 (type_preference << 24) |
433 (interface_preference << 16) |
434 (stun_priority << 8) |
435 (256 - cand->component_id);
436
437 /* S 4.1.2 */
438 assert(cand->priority>=1&&cand->priority<=2147483647);
439
440 _status=0;
441 abort:
442 return(_status);
443 }
444
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;
448
449 cand->ready_cb_timer = 0;
450 cand->ready_cb(0, 0, cand->ready_cb_arg);
451 }
452
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;
460
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;
480
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 }
488
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;
498
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 }
504
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 }
518
519 nr_ice_candidate_compute_codeword(cand);
520
521 _status=0;
522 abort:
523 if(_status && _status!=R_WOULDBLOCK)
524 cand->state=NR_ICE_CAND_STATE_FAILED;
525 return(_status);
526 }
527
528
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;
533
534 cand->resolver_handle=0;
535
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 }
545
546 /* Copy the address */
547 if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr))
548 ABORT(r);
549
550 /* Now start initializing */
551 if(r=nr_ice_candidate_initialize2(cand))
552 ABORT(r);
553
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 }
562
563 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand)
564 {
565 int r,_status;
566
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 }
589
590 _status=0;
591 abort:
592 if(_status && _status!=R_WOULDBLOCK)
593 cand->state=NR_ICE_CAND_STATE_FAILED;
594 return(_status);
595 }
596
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;
601
602 cand->delay_timer=0;
603
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);
609
610 if(r=nr_ice_ctx_remember_id(cand->ctx, cand->u.srvrflx.stun->request))
611 ABORT(r);
612
613 if(r=nr_ice_socket_register_stun_client(cand->isock,cand->u.srvrflx.stun,&cand->u.srvrflx.stun_handle))
614 ABORT(r);
615
616 _status=0;
617 abort:
618 if(_status){
619 cand->state=NR_ICE_CAND_STATE_FAILED;
620 }
621
622 return;
623 }
624
625 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand)
626 {
627 int r,_status;
628
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);
634
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;
637
638 _status=0;
639 abort:
640 if(_status){
641 cand->state=NR_ICE_CAND_STATE_FAILED;
642 }
643 return(_status);
644 }
645
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;
651
652 cand->delay_timer=0;
653
654 if(r=nr_turn_client_allocate(cand->u.relayed.turn, nr_ice_turn_allocated_cb, cb_arg))
655 ABORT(r);
656
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);
660
661 _status=0;
662 abort:
663 if(_status){
664 cand->state=NR_ICE_CAND_STATE_FAILED;
665 }
666 return;
667 }
668
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);
679
680 if(r=nr_socket_turn_set_ctx(cand->osock, cand->u.relayed.turn))
681 ABORT(r);
682
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;
685
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 */
694
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;
699
700 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): %s",cand->ctx->label,cand->label,__FUNCTION__);
701
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 }
707
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;
718
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 }
733
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;
742
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);
748
749 if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",
750 relay_addr.as_string,")",NULL))
751 ABORT(r);
752
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);
754
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);
762
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);
764
765 RFREE(cand->label);
766 cand->label=label;
767 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
768
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;
772
773 if (r=nr_turn_client_get_mapped_address(cand->u.relayed.turn, &cand2->addr))
774 ABORT(r);
775
776 cand2->state=NR_ICE_CAND_STATE_INITIALIZED;
777 cand2->done_cb(0,0,cand2->cb_arg);
778 }
779
780 /* Execute the ready callback */
781 cand->done_cb(0,0,cand->cb_arg);
782 cand = 0;
783
784 break;
785
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 }
798
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);
807
808 if(cand->u.relayed.srvflx_candidate){
809 nr_ice_candidate *cand2=cand->u.relayed.srvflx_candidate;
810
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 */
818
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;
826
827 assert(!strcmp(nr_ice_candidate_type_names[HOST], "host"));
828 assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay"));
829
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));
837
838 len=strlen(attr); attr+=len; maxlen-=len;
839
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);
850
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);
859
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 }
871

mercurial