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