LCOV - code coverage report
Current view: top level - media/mtransport/third_party/nICEr/src/ice - ice_candidate.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 494 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13