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

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial