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