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

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /*
michael@0 2 Copyright (c) 2007, Adobe Systems, Incorporated
michael@0 3 All rights reserved.
michael@0 4
michael@0 5 Redistribution and use in source and binary forms, with or without
michael@0 6 modification, are permitted provided that the following conditions are
michael@0 7 met:
michael@0 8
michael@0 9 * Redistributions of source code must retain the above copyright
michael@0 10 notice, this list of conditions and the following disclaimer.
michael@0 11
michael@0 12 * Redistributions in binary form must reproduce the above copyright
michael@0 13 notice, this list of conditions and the following disclaimer in the
michael@0 14 documentation and/or other materials provided with the distribution.
michael@0 15
michael@0 16 * Neither the name of Adobe Systems, Network Resonance nor the names of its
michael@0 17 contributors may be used to endorse or promote products derived from
michael@0 18 this software without specific prior written permission.
michael@0 19
michael@0 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 31 */
michael@0 32
michael@0 33
michael@0 34
michael@0 35 static char *RCSSTRING __UNUSED__="$Id: ice_candidate.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
michael@0 36
michael@0 37 #include <csi_platform.h>
michael@0 38 #include <assert.h>
michael@0 39 #include <stdio.h>
michael@0 40 #include <string.h>
michael@0 41 #include <sys/queue.h>
michael@0 42 #include <sys/types.h>
michael@0 43 #ifdef WIN32
michael@0 44 #include <winsock2.h>
michael@0 45 #else
michael@0 46 #include <sys/socket.h>
michael@0 47 #include <netinet/in.h>
michael@0 48 #include <arpa/inet.h>
michael@0 49 #endif
michael@0 50 #include "nr_api.h"
michael@0 51 #include "registry.h"
michael@0 52 #include "nr_socket.h"
michael@0 53 #include "async_timer.h"
michael@0 54
michael@0 55 #include "stun_client_ctx.h"
michael@0 56 #include "stun_server_ctx.h"
michael@0 57 #include "turn_client_ctx.h"
michael@0 58 #include "ice_ctx.h"
michael@0 59 #include "ice_candidate.h"
michael@0 60 #include "ice_codeword.h"
michael@0 61 #include "ice_reg.h"
michael@0 62 #include "ice_util.h"
michael@0 63 #include "nr_socket_turn.h"
michael@0 64 #include "nr_socket.h"
michael@0 65
michael@0 66 static int next_automatic_preference = 224;
michael@0 67
michael@0 68 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
michael@0 69 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
michael@0 70 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand);
michael@0 71 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
michael@0 72 #ifdef USE_TURN
michael@0 73 static int nr_ice_start_relay_turn(nr_ice_candidate *cand);
michael@0 74 static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg);
michael@0 75 static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr);
michael@0 76 #endif /* USE_TURN */
michael@0 77
michael@0 78 void nr_ice_candidate_compute_codeword(nr_ice_candidate *cand)
michael@0 79 {
michael@0 80 char as_string[1024];
michael@0 81
michael@0 82 snprintf(as_string,
michael@0 83 sizeof(as_string),
michael@0 84 "%s(%s)",
michael@0 85 cand->addr.as_string,
michael@0 86 cand->label);
michael@0 87
michael@0 88 nr_ice_compute_codeword(as_string,strlen(as_string),cand->codeword);
michael@0 89 }
michael@0 90
michael@0 91 char *nr_ice_candidate_type_names[]={0,"host","srflx","prflx","relay",0};
michael@0 92
michael@0 93 static const char *nr_ctype_name(nr_ice_candidate_type ctype) {
michael@0 94 assert(ctype<CTYPE_MAX && ctype>0);
michael@0 95 if (ctype <= 0 || ctype >= CTYPE_MAX) {
michael@0 96 return "ERROR";
michael@0 97 }
michael@0 98 return nr_ice_candidate_type_names[ctype];
michael@0 99 }
michael@0 100
michael@0 101 static int nr_ice_candidate_format_stun_label(char *label, size_t size, nr_ice_candidate *cand)
michael@0 102 {
michael@0 103 int _status;
michael@0 104
michael@0 105 *label = 0;
michael@0 106 switch(cand->stun_server->type) {
michael@0 107 case NR_ICE_STUN_SERVER_TYPE_ADDR:
michael@0 108 snprintf(label, size, "%s(%s|%s)", nr_ctype_name(cand->type), cand->base.as_string,
michael@0 109 cand->stun_server->u.addr.as_string);
michael@0 110 break;
michael@0 111 case NR_ICE_STUN_SERVER_TYPE_DNSNAME:
michael@0 112 snprintf(label, size, "%s(%s|%s:%u)", nr_ctype_name(cand->type), cand->base.as_string,
michael@0 113 cand->stun_server->u.dnsname.host, cand->stun_server->u.dnsname.port);
michael@0 114 break;
michael@0 115 default:
michael@0 116 assert(0);
michael@0 117 ABORT(R_BAD_ARGS);
michael@0 118 }
michael@0 119
michael@0 120 _status=0;
michael@0 121 abort:
michael@0 122 return(_status);
michael@0 123 }
michael@0 124
michael@0 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)
michael@0 126 {
michael@0 127 nr_ice_candidate *cand=0;
michael@0 128 nr_ice_candidate *tmp=0;
michael@0 129 int r,_status;
michael@0 130 char label[512];
michael@0 131
michael@0 132 if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
michael@0 133 ABORT(R_NO_MEMORY);
michael@0 134 cand->state=NR_ICE_CAND_STATE_CREATED;
michael@0 135 cand->ctx=ctx;
michael@0 136 cand->isock=isock;
michael@0 137 cand->osock=osock;
michael@0 138 cand->type=ctype;
michael@0 139 cand->stun_server=stun_server;
michael@0 140 cand->component_id=component_id;
michael@0 141 cand->component=comp;
michael@0 142 cand->stream=comp->stream;
michael@0 143
michael@0 144 /* Extract the addr as the base */
michael@0 145 if(r=nr_socket_getaddr(cand->isock->sock,&cand->base))
michael@0 146 ABORT(r);
michael@0 147
michael@0 148 switch(ctype) {
michael@0 149 case HOST:
michael@0 150 snprintf(label, sizeof(label), "host(%s)", cand->base.as_string);
michael@0 151 break;
michael@0 152
michael@0 153 case SERVER_REFLEXIVE:
michael@0 154 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label),cand))
michael@0 155 ABORT(r);
michael@0 156 break;
michael@0 157
michael@0 158 case RELAYED:
michael@0 159 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label),cand))
michael@0 160 ABORT(r);
michael@0 161 break;
michael@0 162
michael@0 163 case PEER_REFLEXIVE:
michael@0 164 snprintf(label, sizeof(label), "prflx");
michael@0 165 break;
michael@0 166
michael@0 167 default:
michael@0 168 assert(0); /* Can't happen */
michael@0 169 ABORT(R_BAD_ARGS);
michael@0 170 }
michael@0 171 if(!(cand->label=r_strdup(label)))
michael@0 172 ABORT(R_NO_MEMORY);
michael@0 173
michael@0 174 if(r=nr_ice_get_foundation(ctx,cand))
michael@0 175 ABORT(r);
michael@0 176 if(r=nr_ice_candidate_compute_priority(cand))
michael@0 177 ABORT(r);
michael@0 178
michael@0 179 TAILQ_FOREACH(tmp,&isock->candidates,entry_sock){
michael@0 180 if(cand->priority==tmp->priority){
michael@0 181 r_log(LOG_ICE,LOG_ERR,"ICE(%s): duplicate priority %u candidate %s and candidate %s",
michael@0 182 ctx->label,cand->priority,cand->label,tmp->label);
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 if(ctype==RELAYED)
michael@0 187 cand->u.relayed.turn_sock=osock;
michael@0 188
michael@0 189
michael@0 190 /* Add the candidate to the isock list*/
michael@0 191 TAILQ_INSERT_TAIL(&isock->candidates,cand,entry_sock);
michael@0 192
michael@0 193 nr_ice_candidate_compute_codeword(cand);
michael@0 194
michael@0 195 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): created candidate %s with type %s",
michael@0 196 ctx->label,cand->label,nr_ctype_name(ctype));
michael@0 197
michael@0 198 *candp=cand;
michael@0 199
michael@0 200 _status=0;
michael@0 201 abort:
michael@0 202 if (_status){
michael@0 203 r_log(LOG_ICE,LOG_ERR,"ICE(%s): Failed to create candidate of type %s", ctx->label,nr_ctype_name(ctype));
michael@0 204 nr_ice_candidate_destroy(&cand);
michael@0 205 }
michael@0 206 return(_status);
michael@0 207 }
michael@0 208
michael@0 209
michael@0 210 /* Create a peer reflexive candidate */
michael@0 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)
michael@0 212 {
michael@0 213 nr_ice_candidate *cand=0;
michael@0 214 nr_ice_candidate_type ctype=PEER_REFLEXIVE;
michael@0 215 int r,_status;
michael@0 216
michael@0 217 if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
michael@0 218 ABORT(R_NO_MEMORY);
michael@0 219 if(!(cand->label=r_strdup(label)))
michael@0 220 ABORT(R_NO_MEMORY);
michael@0 221
michael@0 222 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
michael@0 223 cand->ctx=ctx;
michael@0 224 cand->type=ctype;
michael@0 225 cand->component_id=comp->component_id;
michael@0 226 cand->component=comp;
michael@0 227 cand->stream=comp->stream;
michael@0 228
michael@0 229
michael@0 230 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): creating candidate with type %s",
michael@0 231 ctx->label,label,nr_ctype_name(ctype));
michael@0 232
michael@0 233 if(r=nr_transport_addr_copy(&cand->base,addr))
michael@0 234 ABORT(r);
michael@0 235 if(r=nr_transport_addr_copy(&cand->addr,addr))
michael@0 236 ABORT(r);
michael@0 237 /* Bogus foundation */
michael@0 238 if(!(cand->foundation=r_strdup(cand->addr.as_string)))
michael@0 239 ABORT(R_NO_MEMORY);
michael@0 240
michael@0 241 nr_ice_candidate_compute_codeword(cand);
michael@0 242
michael@0 243 *candp=cand;
michael@0 244
michael@0 245 _status=0;
michael@0 246 abort:
michael@0 247 if (_status){
michael@0 248 nr_ice_candidate_destroy(&cand);
michael@0 249 }
michael@0 250 return(_status);
michael@0 251 }
michael@0 252
michael@0 253 int nr_ice_candidate_destroy(nr_ice_candidate **candp)
michael@0 254 {
michael@0 255 nr_ice_candidate *cand=0;
michael@0 256
michael@0 257 if(!candp || !*candp)
michael@0 258 return(0);
michael@0 259
michael@0 260 cand=*candp;
michael@0 261
michael@0 262 switch(cand->type){
michael@0 263 case HOST:
michael@0 264 break;
michael@0 265 #ifdef USE_TURN
michael@0 266 case RELAYED:
michael@0 267 if (cand->u.relayed.turn_handle)
michael@0 268 nr_ice_socket_deregister(cand->isock, cand->u.relayed.turn_handle);
michael@0 269 nr_turn_client_ctx_destroy(&cand->u.relayed.turn);
michael@0 270 nr_socket_destroy(&cand->u.relayed.turn_sock);
michael@0 271 break;
michael@0 272 #endif /* USE_TURN */
michael@0 273 case SERVER_REFLEXIVE:
michael@0 274 if (cand->u.srvrflx.stun_handle)
michael@0 275 nr_ice_socket_deregister(cand->isock, cand->u.srvrflx.stun_handle);
michael@0 276 nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
michael@0 277 break;
michael@0 278 default:
michael@0 279 break;
michael@0 280 }
michael@0 281
michael@0 282 NR_async_timer_cancel(cand->delay_timer);
michael@0 283 NR_async_timer_cancel(cand->ready_cb_timer);
michael@0 284 if(cand->resolver_handle){
michael@0 285 nr_resolver_cancel(cand->ctx->resolver,cand->resolver_handle);
michael@0 286 }
michael@0 287
michael@0 288 RFREE(cand->foundation);
michael@0 289 RFREE(cand->label);
michael@0 290 RFREE(cand);
michael@0 291
michael@0 292 return(0);
michael@0 293 }
michael@0 294
michael@0 295 void nr_ice_candidate_destroy_cb(NR_SOCKET s, int h, void *cb_arg)
michael@0 296 {
michael@0 297 nr_ice_candidate *cand=cb_arg;
michael@0 298 nr_ice_candidate_destroy(&cand);
michael@0 299 }
michael@0 300
michael@0 301 /* This algorithm is not super-fast, but I don't think we need a hash
michael@0 302 table just yet and it produces a small foundation string */
michael@0 303 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand)
michael@0 304 {
michael@0 305 nr_ice_foundation *foundation;
michael@0 306 int i=0;
michael@0 307 char fnd[20];
michael@0 308 int _status;
michael@0 309
michael@0 310 foundation=STAILQ_FIRST(&ctx->foundations);
michael@0 311 while(foundation){
michael@0 312 if(nr_transport_addr_cmp(&cand->base,&foundation->addr,NR_TRANSPORT_ADDR_CMP_MODE_ADDR))
michael@0 313 goto next;
michael@0 314 if(cand->type != foundation->type)
michael@0 315 goto next;
michael@0 316 if(cand->stun_server != foundation->stun_server)
michael@0 317 goto next;
michael@0 318
michael@0 319 snprintf(fnd,sizeof(fnd),"%d",i);
michael@0 320 if(!(cand->foundation=r_strdup(fnd)))
michael@0 321 ABORT(R_NO_MEMORY);
michael@0 322 return(0);
michael@0 323
michael@0 324 next:
michael@0 325 foundation=STAILQ_NEXT(foundation,entry);
michael@0 326 i++;
michael@0 327 }
michael@0 328
michael@0 329 if(!(foundation=RCALLOC(sizeof(nr_ice_foundation))))
michael@0 330 ABORT(R_NO_MEMORY);
michael@0 331 nr_transport_addr_copy(&foundation->addr,&cand->base);
michael@0 332 foundation->type=cand->type;
michael@0 333 foundation->stun_server=cand->stun_server;
michael@0 334 STAILQ_INSERT_TAIL(&ctx->foundations,foundation,entry);
michael@0 335
michael@0 336 snprintf(fnd,sizeof(fnd),"%d",i);
michael@0 337 if(!(cand->foundation=r_strdup(fnd)))
michael@0 338 ABORT(R_NO_MEMORY);
michael@0 339
michael@0 340 _status=0;
michael@0 341 abort:
michael@0 342 return(_status);
michael@0 343 }
michael@0 344
michael@0 345 int nr_ice_candidate_compute_priority(nr_ice_candidate *cand)
michael@0 346 {
michael@0 347 UCHAR type_preference;
michael@0 348 UCHAR interface_preference;
michael@0 349 UCHAR stun_priority;
michael@0 350 int r,_status;
michael@0 351
michael@0 352 switch(cand->type){
michael@0 353 case HOST:
michael@0 354 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST,&type_preference))
michael@0 355 ABORT(r);
michael@0 356 stun_priority=0;
michael@0 357 break;
michael@0 358 case RELAYED:
michael@0 359 if(cand->base.protocol == IPPROTO_UDP) {
michael@0 360 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED,&type_preference))
michael@0 361 ABORT(r);
michael@0 362 }
michael@0 363 else if(cand->base.protocol == IPPROTO_TCP) {
michael@0 364 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED_TCP,&type_preference))
michael@0 365 ABORT(r);
michael@0 366
michael@0 367 }
michael@0 368 else {
michael@0 369 r_log(LOG_ICE,LOG_ERR,"Unknown protocol type %u",
michael@0 370 (unsigned int)cand->base.protocol);
michael@0 371 ABORT(R_INTERNAL);
michael@0 372 }
michael@0 373 stun_priority=255-cand->stun_server->index;
michael@0 374 break;
michael@0 375 case SERVER_REFLEXIVE:
michael@0 376 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX,&type_preference))
michael@0 377 ABORT(r);
michael@0 378 stun_priority=255-cand->stun_server->index;
michael@0 379 break;
michael@0 380 case PEER_REFLEXIVE:
michael@0 381 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX,&type_preference))
michael@0 382 ABORT(r);
michael@0 383 stun_priority=0;
michael@0 384 break;
michael@0 385 default:
michael@0 386 ABORT(R_INTERNAL);
michael@0 387 }
michael@0 388
michael@0 389 if(type_preference > 126)
michael@0 390 r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference);
michael@0 391
michael@0 392 if(!cand->ctx->interface_prioritizer) {
michael@0 393 /* Prioritizer is not set, read from registry */
michael@0 394 if(r=NR_reg_get2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,
michael@0 395 &interface_preference)) {
michael@0 396 if (r==R_NOT_FOUND) {
michael@0 397 if (next_automatic_preference == 1) {
michael@0 398 r_log(LOG_ICE,LOG_ERR,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
michael@0 399 ABORT(R_NOT_FOUND);
michael@0 400 }
michael@0 401 r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
michael@0 402 next_automatic_preference);
michael@0 403 if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
michael@0 404 ABORT(r);
michael@0 405 }
michael@0 406 interface_preference=next_automatic_preference;
michael@0 407 next_automatic_preference--;
michael@0 408 }
michael@0 409 else {
michael@0 410 ABORT(r);
michael@0 411 }
michael@0 412 }
michael@0 413 }
michael@0 414 else {
michael@0 415 char key_of_interface[MAXIFNAME + 41];
michael@0 416 nr_transport_addr addr;
michael@0 417
michael@0 418 if(r=nr_socket_getaddr(cand->isock->sock, &addr))
michael@0 419 ABORT(r);
michael@0 420
michael@0 421 if(r=nr_transport_addr_fmt_ifname_addr_string(&addr,key_of_interface,
michael@0 422 sizeof(key_of_interface))) {
michael@0 423 ABORT(r);
michael@0 424 }
michael@0 425 if(r=nr_interface_prioritizer_get_priority(cand->ctx->interface_prioritizer,
michael@0 426 key_of_interface,&interface_preference)) {
michael@0 427 ABORT(r);
michael@0 428 }
michael@0 429 }
michael@0 430
michael@0 431 cand->priority=
michael@0 432 (type_preference << 24) |
michael@0 433 (interface_preference << 16) |
michael@0 434 (stun_priority << 8) |
michael@0 435 (256 - cand->component_id);
michael@0 436
michael@0 437 /* S 4.1.2 */
michael@0 438 assert(cand->priority>=1&&cand->priority<=2147483647);
michael@0 439
michael@0 440 _status=0;
michael@0 441 abort:
michael@0 442 return(_status);
michael@0 443 }
michael@0 444
michael@0 445 static void nr_ice_candidate_fire_ready_cb(NR_SOCKET s, int how, void *cb_arg)
michael@0 446 {
michael@0 447 nr_ice_candidate *cand = cb_arg;
michael@0 448
michael@0 449 cand->ready_cb_timer = 0;
michael@0 450 cand->ready_cb(0, 0, cand->ready_cb_arg);
michael@0 451 }
michael@0 452
michael@0 453 int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg)
michael@0 454 {
michael@0 455 int r,_status;
michael@0 456 int protocol=NR_RESOLVE_PROTOCOL_STUN;
michael@0 457 int transport=IPPROTO_UDP;
michael@0 458 cand->done_cb=ready_cb;
michael@0 459 cand->cb_arg=cb_arg;
michael@0 460
michael@0 461 switch(cand->type){
michael@0 462 case HOST:
michael@0 463 if(r=nr_socket_getaddr(cand->isock->sock,&cand->addr))
michael@0 464 ABORT(r);
michael@0 465 cand->osock=cand->isock->sock;
michael@0 466 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
michael@0 467 // Post this so that it doesn't happen in-line
michael@0 468 cand->ready_cb = ready_cb;
michael@0 469 cand->ready_cb_arg = cb_arg;
michael@0 470 NR_ASYNC_TIMER_SET(0, nr_ice_candidate_fire_ready_cb, (void *)cand, &cand->ready_cb_timer);
michael@0 471 break;
michael@0 472 #ifdef USE_TURN
michael@0 473 case RELAYED:
michael@0 474 protocol=NR_RESOLVE_PROTOCOL_TURN;
michael@0 475 transport=cand->u.relayed.server->transport;
michael@0 476 /* Fall through */
michael@0 477 #endif
michael@0 478 case SERVER_REFLEXIVE:
michael@0 479 cand->state=NR_ICE_CAND_STATE_INITIALIZING;
michael@0 480
michael@0 481 if(cand->stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
michael@0 482 /* Just copy the address */
michael@0 483 if (r=nr_transport_addr_copy(&cand->stun_server_addr,
michael@0 484 &cand->stun_server->u.addr)) {
michael@0 485 r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not copy STUN server addr", cand->label);
michael@0 486 ABORT(r);
michael@0 487 }
michael@0 488
michael@0 489 if(r=nr_ice_candidate_initialize2(cand))
michael@0 490 ABORT(r);
michael@0 491 }
michael@0 492 else {
michael@0 493 nr_resolver_resource resource;
michael@0 494 resource.domain_name=cand->stun_server->u.dnsname.host;
michael@0 495 resource.port=cand->stun_server->u.dnsname.port;
michael@0 496 resource.stun_turn=protocol;
michael@0 497 resource.transport_protocol=transport;
michael@0 498
michael@0 499 /* Try to resolve */
michael@0 500 if(!cand->ctx->resolver) {
michael@0 501 r_log(LOG_ICE, LOG_ERR, "ICE-CANDIDATE(%s): Can't use DNS names without a resolver", cand->label);
michael@0 502 ABORT(R_BAD_ARGS);
michael@0 503 }
michael@0 504
michael@0 505 if(r=nr_resolver_resolve(cand->ctx->resolver,
michael@0 506 &resource,
michael@0 507 nr_ice_candidate_resolved_cb,
michael@0 508 (void *)cand,
michael@0 509 &cand->resolver_handle)){
michael@0 510 r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not invoke DNS resolver",cand->label);
michael@0 511 ABORT(r);
michael@0 512 }
michael@0 513 }
michael@0 514 break;
michael@0 515 default:
michael@0 516 ABORT(R_INTERNAL);
michael@0 517 }
michael@0 518
michael@0 519 nr_ice_candidate_compute_codeword(cand);
michael@0 520
michael@0 521 _status=0;
michael@0 522 abort:
michael@0 523 if(_status && _status!=R_WOULDBLOCK)
michael@0 524 cand->state=NR_ICE_CAND_STATE_FAILED;
michael@0 525 return(_status);
michael@0 526 }
michael@0 527
michael@0 528
michael@0 529 static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr)
michael@0 530 {
michael@0 531 nr_ice_candidate *cand=cb_arg;
michael@0 532 int r,_status;
michael@0 533
michael@0 534 cand->resolver_handle=0;
michael@0 535
michael@0 536 if(addr){
michael@0 537 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): resolved candidate %s. addr=%s",
michael@0 538 cand->ctx->label,cand->label,addr->as_string);
michael@0 539 }
michael@0 540 else {
michael@0 541 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to resolve candidate %s.",
michael@0 542 cand->ctx->label,cand->label);
michael@0 543 ABORT(R_NOT_FOUND);
michael@0 544 }
michael@0 545
michael@0 546 /* Copy the address */
michael@0 547 if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr))
michael@0 548 ABORT(r);
michael@0 549
michael@0 550 /* Now start initializing */
michael@0 551 if(r=nr_ice_candidate_initialize2(cand))
michael@0 552 ABORT(r);
michael@0 553
michael@0 554 _status=0;
michael@0 555 abort:
michael@0 556 if(_status && _status!=R_WOULDBLOCK) {
michael@0 557 cand->state=NR_ICE_CAND_STATE_FAILED;
michael@0 558 cand->done_cb(0,0,cand->cb_arg);
michael@0 559 }
michael@0 560 return(_status);
michael@0 561 }
michael@0 562
michael@0 563 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand)
michael@0 564 {
michael@0 565 int r,_status;
michael@0 566
michael@0 567 switch(cand->type){
michael@0 568 case HOST:
michael@0 569 assert(0); /* Can't happen */
michael@0 570 ABORT(R_INTERNAL);
michael@0 571 break;
michael@0 572 #ifdef USE_TURN
michael@0 573 case RELAYED:
michael@0 574 if(r=nr_ice_start_relay_turn(cand))
michael@0 575 ABORT(r);
michael@0 576 ABORT(R_WOULDBLOCK);
michael@0 577 break;
michael@0 578 #endif /* USE_TURN */
michael@0 579 case SERVER_REFLEXIVE:
michael@0 580 /* Need to start stun */
michael@0 581 if(r=nr_ice_srvrflx_start_stun(cand))
michael@0 582 ABORT(r);
michael@0 583 cand->osock=cand->isock->sock;
michael@0 584 ABORT(R_WOULDBLOCK);
michael@0 585 break;
michael@0 586 default:
michael@0 587 ABORT(R_INTERNAL);
michael@0 588 }
michael@0 589
michael@0 590 _status=0;
michael@0 591 abort:
michael@0 592 if(_status && _status!=R_WOULDBLOCK)
michael@0 593 cand->state=NR_ICE_CAND_STATE_FAILED;
michael@0 594 return(_status);
michael@0 595 }
michael@0 596
michael@0 597 static void nr_ice_srvrflx_start_stun_timer_cb(NR_SOCKET s, int how, void *cb_arg)
michael@0 598 {
michael@0 599 nr_ice_candidate *cand=cb_arg;
michael@0 600 int r,_status;
michael@0 601
michael@0 602 cand->delay_timer=0;
michael@0 603
michael@0 604 /* TODO: if the response is a BINDING-ERROR-RESPONSE, then restart
michael@0 605 * TODO: using NR_STUN_CLIENT_MODE_BINDING_REQUEST because the
michael@0 606 * TODO: server may not have understood the 0.96-style request */
michael@0 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))
michael@0 608 ABORT(r);
michael@0 609
michael@0 610 if(r=nr_ice_ctx_remember_id(cand->ctx, cand->u.srvrflx.stun->request))
michael@0 611 ABORT(r);
michael@0 612
michael@0 613 if(r=nr_ice_socket_register_stun_client(cand->isock,cand->u.srvrflx.stun,&cand->u.srvrflx.stun_handle))
michael@0 614 ABORT(r);
michael@0 615
michael@0 616 _status=0;
michael@0 617 abort:
michael@0 618 if(_status){
michael@0 619 cand->state=NR_ICE_CAND_STATE_FAILED;
michael@0 620 }
michael@0 621
michael@0 622 return;
michael@0 623 }
michael@0 624
michael@0 625 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand)
michael@0 626 {
michael@0 627 int r,_status;
michael@0 628
michael@0 629 assert(!cand->delay_timer);
michael@0 630 if(r=nr_stun_client_ctx_create(cand->label, cand->isock->sock,
michael@0 631 &cand->stun_server_addr, cand->stream->ctx->gather_rto,
michael@0 632 &cand->u.srvrflx.stun))
michael@0 633 ABORT(r);
michael@0 634
michael@0 635 NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_srvrflx_start_stun_timer_cb,cand,&cand->delay_timer);
michael@0 636 cand->stream->ctx->stun_delay += cand->stream->ctx->Ta;
michael@0 637
michael@0 638 _status=0;
michael@0 639 abort:
michael@0 640 if(_status){
michael@0 641 cand->state=NR_ICE_CAND_STATE_FAILED;
michael@0 642 }
michael@0 643 return(_status);
michael@0 644 }
michael@0 645
michael@0 646 #ifdef USE_TURN
michael@0 647 static void nr_ice_start_relay_turn_timer_cb(NR_SOCKET s, int how, void *cb_arg)
michael@0 648 {
michael@0 649 nr_ice_candidate *cand=cb_arg;
michael@0 650 int r,_status;
michael@0 651
michael@0 652 cand->delay_timer=0;
michael@0 653
michael@0 654 if(r=nr_turn_client_allocate(cand->u.relayed.turn, nr_ice_turn_allocated_cb, cb_arg))
michael@0 655 ABORT(r);
michael@0 656
michael@0 657 if(r=nr_ice_socket_register_turn_client(cand->isock, cand->u.relayed.turn,
michael@0 658 cand->osock, &cand->u.relayed.turn_handle))
michael@0 659 ABORT(r);
michael@0 660
michael@0 661 _status=0;
michael@0 662 abort:
michael@0 663 if(_status){
michael@0 664 cand->state=NR_ICE_CAND_STATE_FAILED;
michael@0 665 }
michael@0 666 return;
michael@0 667 }
michael@0 668
michael@0 669 static int nr_ice_start_relay_turn(nr_ice_candidate *cand)
michael@0 670 {
michael@0 671 int r,_status;
michael@0 672 assert(!cand->delay_timer);
michael@0 673 if(r=nr_turn_client_ctx_create(cand->label, cand->isock->sock,
michael@0 674 cand->u.relayed.server->username,
michael@0 675 cand->u.relayed.server->password,
michael@0 676 &cand->stun_server_addr,
michael@0 677 &cand->u.relayed.turn))
michael@0 678 ABORT(r);
michael@0 679
michael@0 680 if(r=nr_socket_turn_set_ctx(cand->osock, cand->u.relayed.turn))
michael@0 681 ABORT(r);
michael@0 682
michael@0 683 NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_start_relay_turn_timer_cb,cand,&cand->delay_timer);
michael@0 684 cand->stream->ctx->stun_delay += cand->stream->ctx->Ta;
michael@0 685
michael@0 686 _status=0;
michael@0 687 abort:
michael@0 688 if(_status){
michael@0 689 cand->state=NR_ICE_CAND_STATE_FAILED;
michael@0 690 }
michael@0 691 return(_status);
michael@0 692 }
michael@0 693 #endif /* USE_TURN */
michael@0 694
michael@0 695 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg)
michael@0 696 {
michael@0 697 int _status;
michael@0 698 nr_ice_candidate *cand=cb_arg;
michael@0 699
michael@0 700 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): %s",cand->ctx->label,cand->label,__FUNCTION__);
michael@0 701
michael@0 702 /* Deregister to suppress duplicates */
michael@0 703 if(cand->u.srvrflx.stun_handle){ /* This test because we might have failed before CB registered */
michael@0 704 nr_ice_socket_deregister(cand->isock,cand->u.srvrflx.stun_handle);
michael@0 705 cand->u.srvrflx.stun_handle=0;
michael@0 706 }
michael@0 707
michael@0 708 switch(cand->u.srvrflx.stun->state){
michael@0 709 /* OK, we should have a mapped address */
michael@0 710 case NR_STUN_CLIENT_STATE_DONE:
michael@0 711 /* Copy the address */
michael@0 712 nr_transport_addr_copy(&cand->addr, &cand->u.srvrflx.stun->results.stun_binding_response.mapped_addr);
michael@0 713 nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
michael@0 714 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
michael@0 715 /* Execute the ready callback */
michael@0 716 cand->done_cb(0,0,cand->cb_arg);
michael@0 717 break;
michael@0 718
michael@0 719 /* This failed, so go to the next STUN server if there is one */
michael@0 720 case NR_STUN_CLIENT_STATE_FAILED:
michael@0 721 ABORT(R_NOT_FOUND);
michael@0 722 break;
michael@0 723 default:
michael@0 724 ABORT(R_INTERNAL);
michael@0 725 }
michael@0 726 _status = 0;
michael@0 727 abort:
michael@0 728 if(_status){
michael@0 729 cand->state=NR_ICE_CAND_STATE_FAILED;
michael@0 730 cand->done_cb(0,0,cand->cb_arg);
michael@0 731 }
michael@0 732 }
michael@0 733
michael@0 734 #ifdef USE_TURN
michael@0 735 static void nr_ice_turn_allocated_cb(NR_SOCKET s, int how, void *cb_arg)
michael@0 736 {
michael@0 737 int r,_status;
michael@0 738 nr_ice_candidate *cand=cb_arg;
michael@0 739 nr_turn_client_ctx *turn=cand->u.relayed.turn;
michael@0 740 char *label;
michael@0 741 nr_transport_addr relay_addr;
michael@0 742
michael@0 743 switch(turn->state){
michael@0 744 /* OK, we should have a mapped address */
michael@0 745 case NR_TURN_CLIENT_STATE_ALLOCATED:
michael@0 746 if (r=nr_turn_client_get_relayed_address(turn, &relay_addr))
michael@0 747 ABORT(r);
michael@0 748
michael@0 749 if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",
michael@0 750 relay_addr.as_string,")",NULL))
michael@0 751 ABORT(r);
michael@0 752
michael@0 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);
michael@0 754
michael@0 755 /* Copy the relayed address into the candidate addr and
michael@0 756 into the candidate base. Note that we need to keep the
michael@0 757 ifname in the base. */
michael@0 758 if (r=nr_transport_addr_copy(&cand->addr, &relay_addr))
michael@0 759 ABORT(r);
michael@0 760 if (r=nr_transport_addr_copy_keep_ifname(&cand->base, &relay_addr)) /* Need to keep interface for priority calculation */
michael@0 761 ABORT(r);
michael@0 762
michael@0 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);
michael@0 764
michael@0 765 RFREE(cand->label);
michael@0 766 cand->label=label;
michael@0 767 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
michael@0 768
michael@0 769 /* We also need to activate the associated STUN candidate */
michael@0 770 if(cand->u.relayed.srvflx_candidate){
michael@0 771 nr_ice_candidate *cand2=cand->u.relayed.srvflx_candidate;
michael@0 772
michael@0 773 if (r=nr_turn_client_get_mapped_address(cand->u.relayed.turn, &cand2->addr))
michael@0 774 ABORT(r);
michael@0 775
michael@0 776 cand2->state=NR_ICE_CAND_STATE_INITIALIZED;
michael@0 777 cand2->done_cb(0,0,cand2->cb_arg);
michael@0 778 }
michael@0 779
michael@0 780 /* Execute the ready callback */
michael@0 781 cand->done_cb(0,0,cand->cb_arg);
michael@0 782 cand = 0;
michael@0 783
michael@0 784 break;
michael@0 785
michael@0 786 case NR_TURN_CLIENT_STATE_FAILED:
michael@0 787 case NR_TURN_CLIENT_STATE_CANCELLED:
michael@0 788 r_log(NR_LOG_TURN, LOG_WARNING,
michael@0 789 "ICE-CANDIDATE(%s): nr_turn_allocated_cb called with state %d",
michael@0 790 cand->label, turn->state);
michael@0 791 /* This failed, so go to the next TURN server if there is one */
michael@0 792 ABORT(R_NOT_FOUND);
michael@0 793 break;
michael@0 794 default:
michael@0 795 assert(0); /* should never happen */
michael@0 796 ABORT(R_INTERNAL);
michael@0 797 }
michael@0 798
michael@0 799 _status=0;
michael@0 800 abort:
michael@0 801 if(_status){
michael@0 802 if (cand) {
michael@0 803 r_log(NR_LOG_TURN, LOG_WARNING,
michael@0 804 "ICE-CANDIDATE(%s): nr_turn_allocated_cb failed", cand->label);
michael@0 805 cand->state=NR_ICE_CAND_STATE_FAILED;
michael@0 806 cand->done_cb(0,0,cand->cb_arg);
michael@0 807
michael@0 808 if(cand->u.relayed.srvflx_candidate){
michael@0 809 nr_ice_candidate *cand2=cand->u.relayed.srvflx_candidate;
michael@0 810
michael@0 811 cand2->state=NR_ICE_CAND_STATE_FAILED;
michael@0 812 cand2->done_cb(0,0,cand2->cb_arg);
michael@0 813 }
michael@0 814 }
michael@0 815 }
michael@0 816 }
michael@0 817 #endif /* USE_TURN */
michael@0 818
michael@0 819 /* Format the candidate attribute as per ICE S 15.1 */
michael@0 820 int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen)
michael@0 821 {
michael@0 822 int r,_status;
michael@0 823 char addr[64];
michael@0 824 int port;
michael@0 825 int len;
michael@0 826
michael@0 827 assert(!strcmp(nr_ice_candidate_type_names[HOST], "host"));
michael@0 828 assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay"));
michael@0 829
michael@0 830 if(r=nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr)))
michael@0 831 ABORT(r);
michael@0 832 if(r=nr_transport_addr_get_port(&cand->addr,&port))
michael@0 833 ABORT(r);
michael@0 834 snprintf(attr,maxlen,"candidate:%s %d UDP %u %s %d typ %s",
michael@0 835 cand->foundation, cand->component_id, cand->priority, addr, port,
michael@0 836 nr_ctype_name(cand->type));
michael@0 837
michael@0 838 len=strlen(attr); attr+=len; maxlen-=len;
michael@0 839
michael@0 840 /* raddr, rport */
michael@0 841 switch(cand->type){
michael@0 842 case HOST:
michael@0 843 break;
michael@0 844 case SERVER_REFLEXIVE:
michael@0 845 case PEER_REFLEXIVE:
michael@0 846 if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr)))
michael@0 847 ABORT(r);
michael@0 848 if(r=nr_transport_addr_get_port(&cand->base,&port))
michael@0 849 ABORT(r);
michael@0 850
michael@0 851 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
michael@0 852 break;
michael@0 853 case RELAYED:
michael@0 854 // comes from XorMappedAddress via AllocateResponse
michael@0 855 if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr)))
michael@0 856 ABORT(r);
michael@0 857 if(r=nr_transport_addr_get_port(&cand->base,&port))
michael@0 858 ABORT(r);
michael@0 859
michael@0 860 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
michael@0 861 break;
michael@0 862 default:
michael@0 863 assert(0);
michael@0 864 ABORT(R_INTERNAL);
michael@0 865 break;
michael@0 866 }
michael@0 867 _status=0;
michael@0 868 abort:
michael@0 869 return(_status);
michael@0 870 }
michael@0 871

mercurial