diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate.c src/ice/ice_candidate.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate.c 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_candidate.c 2012-10-06 08:30:22.000000000 -0700 @@ -54,36 +54,38 @@ #include "stun_client_ctx.h" #include "stun_server_ctx.h" #include "turn_client_ctx.h" #include "ice_ctx.h" #include "ice_candidate.h" #include "ice_reg.h" #include "ice_util.h" #include "nr_socket_turn.h" +static int next_automatic_preference = 224; + static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand); static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg); -static void nr_ice_srvrflx_stun_finished_cb(int sock, int how, void *cb_arg); +static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg); #ifdef USE_TURN static int nr_ice_start_relay_turn(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg); -static void nr_ice_turn_allocated_cb(int sock, int how, void *cb_arg); +static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg); #endif /* USE_TURN */ char *nr_ice_candidate_type_names[]={0,"host","srflx","prflx","relay",0}; int nr_ice_candidate_create(nr_ice_ctx *ctx,char *label,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) { nr_ice_candidate *cand=0; nr_ice_candidate *tmp=0; int r,_status; - + if(!(cand=RCALLOC(sizeof(nr_ice_candidate)))) ABORT(R_NO_MEMORY); if(!(cand->label=r_strdup(label))) ABORT(R_NO_MEMORY); cand->state=NR_ICE_CAND_STATE_CREATED; cand->ctx=ctx; cand->isock=isock; cand->osock=osock; cand->type=ctype; cand->stun_server=stun_server; @@ -189,21 +191,21 @@ if(cand->delay_timer) NR_async_timer_cancel(cand->delay_timer); RFREE(cand->foundation); RFREE(cand->label); RFREE(cand); return(0); } -void nr_ice_candidate_destroy_cb(int s, int h, void *cb_arg) +void nr_ice_candidate_destroy_cb(NR_SOCKET s, int h, void *cb_arg) { nr_ice_candidate *cand=cb_arg; nr_ice_candidate_destroy(&cand); } /* This algorithm is not super-fast, but I don't think we need a hash table just yet and it produces a small foundation string */ static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand) { nr_ice_foundation *foundation; @@ -276,22 +278,38 @@ break; default: ABORT(R_INTERNAL); } if(type_preference > 126) r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference); if(r=NR_reg_get2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname, - &interface_preference)) - ABORT(r); + &interface_preference)) { + if (r==R_NOT_FOUND) { + if (next_automatic_preference == 1) { + r_log(LOG_ICE,LOG_DEBUG,"Out of preference values. Can't assign one for interface %s",cand->base.ifname); + ABORT(R_NOT_FOUND); + } + r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname, + next_automatic_preference); + if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){ + ABORT(r); + } + interface_preference=next_automatic_preference; + next_automatic_preference--; + } + else { + ABORT(r); + } + } cand->priority= (type_preference << 24) | (interface_preference << 16) | (stun_priority << 8) | (256 - cand->component_id); /* S 4.1.2 */ assert(cand->priority>=1&&cand->priority<=2147483647); @@ -306,21 +324,22 @@ cand->done_cb=ready_cb; cand->cb_arg=cb_arg; switch(cand->type){ case HOST: if(r=nr_socket_getaddr(cand->isock->sock,&cand->addr)) ABORT(r); cand->osock=cand->isock->sock; cand->state=NR_ICE_CAND_STATE_INITIALIZED; - ready_cb(0,0,cb_arg); + // Post this so that it doesn't happen in-line + NR_ASYNC_SCHEDULE(ready_cb,cb_arg); break; #ifdef USE_TURN case RELAYED: if(r=nr_ice_start_relay_turn(cand,ready_cb,cb_arg)) ABORT(r); ABORT(R_WOULDBLOCK); break; #endif /* USE_TURN */ case SERVER_REFLEXIVE: /* Need to start stun */ @@ -333,21 +352,21 @@ ABORT(R_INTERNAL); } _status=0; abort: if(_status && _status!=R_WOULDBLOCK) cand->state=NR_ICE_CAND_STATE_FAILED; return(_status); } -static void nr_ice_srvrflx_start_stun_timer_cb(int s, int how, void *cb_arg) +static void nr_ice_srvrflx_start_stun_timer_cb(NR_SOCKET s, int how, void *cb_arg) { nr_ice_candidate *cand=cb_arg; int r,_status; cand->delay_timer=0; /* TODO: if the response is a BINDING-ERROR-RESPONSE, then restart * TODO: using NR_STUN_CLIENT_MODE_BINDING_REQUEST because the * TODO: server may not have understood the 0.96-style request */ if(r=nr_stun_client_start(cand->u.srvrflx.stun, NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96, nr_ice_srvrflx_stun_finished_cb, cand)) @@ -387,21 +406,21 @@ _status=0; abort: if(_status){ cand->state=NR_ICE_CAND_STATE_FAILED; } return(_status); } #ifdef USE_TURN -static void nr_ice_start_relay_turn_timer_cb(int s, int how, void *cb_arg) +static void nr_ice_start_relay_turn_timer_cb(NR_SOCKET s, int how, void *cb_arg) { nr_ice_candidate *cand=cb_arg; int r,_status; int i; cand->delay_timer=0; if(r=nr_turn_client_allocate(cand->u.relayed.turn, cand->u.relayed.server->username, cand->u.relayed.server->password, cand->u.relayed.server->bandwidth_kbps, cand->u.relayed.server->lifetime_secs, nr_ice_turn_allocated_cb, cand)) ABORT(r); @@ -443,21 +462,21 @@ _status=0; abort: if(_status){ cand->state=NR_ICE_CAND_STATE_FAILED; } return(_status); } #endif /* USE_TURN */ -static void nr_ice_srvrflx_stun_finished_cb(int sock, int how, void *cb_arg) +static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg) { int _status; nr_ice_candidate *cand=cb_arg; /* Deregister to suppress duplicates */ if(cand->u.srvrflx.stun_handle){ /* This test because we might have failed before CB registered */ nr_ice_socket_deregister(cand->isock,cand->u.srvrflx.stun_handle); cand->u.srvrflx.stun_handle=0; } @@ -481,40 +500,40 @@ } _status = 0; abort: if(_status){ cand->state=NR_ICE_CAND_STATE_FAILED; cand->done_cb(0,0,cand->cb_arg); } } #ifdef USE_TURN -static void nr_ice_turn_allocated_cb(int s, int how, void *cb_arg) +static void nr_ice_turn_allocated_cb(NR_SOCKET s, int how, void *cb_arg) { int r,_status; nr_ice_candidate *cand=cb_arg; nr_turn_client_ctx *turn=cand->u.relayed.turn; int i; char *label; /* Deregister to suppress duplicates */ if(cand->u.relayed.turn_handle){ /* This test because we might have failed before CB registered */ nr_ice_socket_deregister(cand->isock,cand->u.relayed.turn_handle); cand->u.relayed.turn_handle=0; } switch(turn->state){ /* OK, we should have a mapped address */ case NR_TURN_CLIENT_STATE_ALLOCATED: /* switch candidate from TURN mode to STUN mode */ - if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",turn->relay_addr.as_string,")",0)) + if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",turn->relay_addr.as_string,")",NULL)) ABORT(r); r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Switching from TURN (%s) to RELAY (%s)",cand->u.relayed.turn->label,cand->label,label); /* Copy out mapped address and relay address */ nr_transport_addr_copy(&turn->relay_addr, &cand->u.relayed.turn->stun_ctx[NR_TURN_CLIENT_PHASE_ALLOCATE_REQUEST2]->results.allocate_response2.relay_addr); nr_transport_addr_copy(&cand->addr, &turn->relay_addr); r_log(LOG_ICE,LOG_DEBUG,"ICE-CANDIDATE(%s): base=%s, candidate=%s", cand->label, cand->base.as_string, cand->addr.as_string); diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate.h src/ice/ice_candidate.h --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate.h 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_candidate.h 2012-10-06 08:30:22.000000000 -0700 @@ -41,21 +41,22 @@ typedef enum {HOST=1, SERVER_REFLEXIVE, PEER_REFLEXIVE, RELAYED} nr_ice_candidate_type; struct nr_ice_candidate_ { char *label; int state; #define NR_ICE_CAND_STATE_CREATED 1 #define NR_ICE_CAND_STATE_INITIALIZING 2 #define NR_ICE_CAND_STATE_INITIALIZED 3 #define NR_ICE_CAND_STATE_FAILED 4 -#define NR_ICE_CAND_PEER_CANDIDATE 10 +#define NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED 9 +#define NR_ICE_CAND_PEER_CANDIDATE_PAIRED 10 struct nr_ice_ctx_ *ctx; nr_ice_socket *isock; /* The socket to read from (it contains all other candidates on this socket) */ nr_socket *osock; /* The socket to write to */ nr_ice_media_stream *stream; /* The media stream this is associated with */ nr_ice_component *component; /* The component this is associated with */ nr_ice_candidate_type type; /* The type of the candidate (S 4.1.1) */ UCHAR component_id; /* The component id (S 4.1.2.1) */ nr_transport_addr addr; /* The advertised address; @@ -89,21 +90,21 @@ TAILQ_ENTRY(nr_ice_candidate_) entry_comp; }; extern char *nr_ice_candidate_type_names[]; int nr_ice_candidate_create(struct nr_ice_ctx_ *ctx,char *label, nr_ice_component *component, 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); int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg); int nr_ice_candidate_process_stun(nr_ice_candidate *cand, UCHAR *msg, int len, nr_transport_addr *faddr); int nr_ice_candidate_destroy(nr_ice_candidate **candp); -void nr_ice_candidate_destroy_cb(int s, int h, void *cb_arg); +void nr_ice_candidate_destroy_cb(NR_SOCKET s, int h, void *cb_arg); int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen); int nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *attr,nr_ice_media_stream *stream,nr_ice_candidate **candp); 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); int nr_ice_candidate_compute_priority(nr_ice_candidate *cand); #ifdef __cplusplus } #endif /* __cplusplus */ #endif diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate_pair.c src/ice/ice_candidate_pair.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate_pair.c 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_candidate_pair.c 2012-10-06 08:30:22.000000000 -0700 @@ -37,21 +37,21 @@ #include #include #include #include "ice_ctx.h" #include "ice_util.h" #include "ice_codeword.h" #include "stun.h" static char *nr_ice_cand_pair_states[]={"UNKNOWN","FROZEN","WAITING","IN_PROGRESS","FAILED","SUCCEEDED","CANCELLED"}; -static void nr_ice_candidate_pair_restart_stun_controlled_cb(int s, int how, void *cb_arg); +static void nr_ice_candidate_pair_restart_stun_controlled_cb(NR_SOCKET s, int how, void *cb_arg); static void nr_ice_candidate_pair_compute_codeword(nr_ice_cand_pair *pair, nr_ice_candidate *lcand, nr_ice_candidate *rcand); int nr_ice_candidate_pair_create(nr_ice_peer_ctx *pctx, nr_ice_candidate *lcand,nr_ice_candidate *rcand,nr_ice_cand_pair **pairp) { nr_ice_cand_pair *pair=0; UINT8 o_priority, a_priority; char *lufrag,*rufrag; char *lpwd,*rpwd; char *l2ruser=0,*r2lpass=0; @@ -61,21 +61,21 @@ UINT8 t_priority; if(!(pair=RCALLOC(sizeof(nr_ice_cand_pair)))) ABORT(R_NO_MEMORY); pair->pctx=pctx; nr_ice_candidate_pair_compute_codeword(pair,lcand,rcand); if(r=nr_concat_strings(&pair->as_string,pair->codeword,"|",lcand->addr.as_string,"|", - rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")",0)) + rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")", NULL)) ABORT(r); nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_FROZEN); pair->local=lcand; pair->remote=rcand; /* Priority computation S 5.7.2 */ if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_OFFERER) { assert(!(pctx->ctx->flags & NR_ICE_CTX_FLAGS_ANSWERER)); @@ -87,21 +87,21 @@ o_priority=rcand->priority; a_priority=lcand->priority; } pair->priority=(MIN(o_priority, a_priority))<<32 | (MAX(o_priority, a_priority))<<1 | (o_priority > a_priority?0:1); r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Pairing candidate %s (%x):%s (%x) priority=%llu (%llx) codeword=%s",pctx->ctx->label,lcand->addr.as_string,lcand->priority,rcand->addr.as_string,rcand->priority,pair->priority,pair->priority,pair->codeword); /* Foundation */ if(r=nr_concat_strings(&pair->foundation,lcand->foundation,"|", - rcand->foundation,0)) + rcand->foundation,NULL)) ABORT(r); /* OK, now the STUN data */ lufrag=lcand->stream->ufrag?lcand->stream->ufrag:pctx->ctx->ufrag; lpwd=lcand->stream->pwd?lcand->stream->pwd:pctx->ctx->pwd; rufrag=rcand->stream->ufrag?rcand->stream->ufrag:pctx->peer_ufrag; rpwd=rcand->stream->pwd?rcand->stream->pwd:pctx->peer_pwd; @@ -110,39 +110,39 @@ /* Make a bogus candidate to compute a theoretical peer reflexive * priority per S 7.1.1.1 */ memcpy(&tmpcand, lcand, sizeof(tmpcand)); tmpcand.type = PEER_REFLEXIVE; if (r=nr_ice_candidate_compute_priority(&tmpcand)) ABORT(r); t_priority = tmpcand.priority; /* Our sending context */ - if(r=nr_concat_strings(&l2ruser,lufrag,":",rufrag,0)) + if(r=nr_concat_strings(&l2ruser,lufrag,":",rufrag,NULL)) ABORT(r); if(r=nr_stun_client_ctx_create(pair->as_string, lcand->osock, &rcand->addr,RTO,&pair->stun_client)) ABORT(r); if(!(pair->stun_client->params.ice_binding_request.username=r_strdup(l2ruser))) ABORT(R_NO_MEMORY); if(r=r_data_make(&pair->stun_client->params.ice_binding_request.password,(UCHAR *)lpwd,strlen(lpwd))) ABORT(r); pair->stun_client->params.ice_binding_request.priority=t_priority; pair->stun_client->params.ice_binding_request.control = pctx->controlling? NR_ICE_CONTROLLING:NR_ICE_CONTROLLED; pair->stun_client->params.ice_binding_request.tiebreaker=pctx->tiebreaker; /* Our receiving username/passwords. Stash these for later injection into the stun server ctx*/ - if(r=nr_concat_strings(&pair->r2l_user,rufrag,":",lufrag,0)) + if(r=nr_concat_strings(&pair->r2l_user,rufrag,":",lufrag,NULL)) ABORT(r); if(!(r2lpass=r_strdup(rpwd))) ABORT(R_NO_MEMORY); INIT_DATA(pair->r2l_pwd,(UCHAR *)r2lpass,strlen(r2lpass)); *pairp=pair; _status=0; abort: RFREE(l2ruser); @@ -178,21 +178,21 @@ int nr_ice_candidate_pair_unfreeze(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair) { assert(pair->state==NR_ICE_PAIR_STATE_FROZEN); nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_WAITING); return(0); } -static void nr_ice_candidate_pair_stun_cb(int s, int how, void *cb_arg) +static void nr_ice_candidate_pair_stun_cb(NR_SOCKET s, int how, void *cb_arg) { int r,_status; nr_ice_cand_pair *pair=cb_arg,*orig_pair; nr_ice_candidate *cand=0; nr_stun_message *sres; nr_transport_addr *request_src; nr_transport_addr *request_dst; nr_transport_addr *response_src; nr_transport_addr response_dst; nr_stun_message_attribute *attr; @@ -457,32 +457,47 @@ abort: return(_status); } int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state) { int r,_status; r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): setting pair %s to %s", pctx->label,pair->as_string,nr_ice_cand_pair_states[state]); - pair->state=state; - if(pctx->state!=NR_ICE_PAIR_STATE_WAITING){ + /* NOTE: This function used to reference pctx->state instead of + pair->state and the assignment to pair->state was at the top + of this function. Because pctx->state was never changed, this seems to have + been a typo. The natural logic is "if the state changed + decrement the counter" so this implies we should be checking + the pair state rather than the pctx->state. + + This didn't cause big problems because waiting_pairs was only + used for pacing, so the pacing just was kind of broken. + + This note is here as a reminder until we do more testing + and make sure that in fact this was a typo. + */ + if(pair->state!=NR_ICE_PAIR_STATE_WAITING){ if(state==NR_ICE_PAIR_STATE_WAITING) pctx->waiting_pairs++; } else{ if(state!=NR_ICE_PAIR_STATE_WAITING) pctx->waiting_pairs--; assert(pctx->waiting_pairs>=0); } + pair->state=state; + + if(pair->state==NR_ICE_PAIR_STATE_FAILED){ if(r=nr_ice_component_failed_pair(pair->remote->component, pair)) ABORT(r); } _status=0; abort: return(_status); } @@ -505,42 +520,42 @@ break; } c1=TAILQ_NEXT(c1,entry); } if(!c1) TAILQ_INSERT_TAIL(head,pair,entry); return(0); } -void nr_ice_candidate_pair_restart_stun_nominated_cb(int s, int how, void *cb_arg) +void nr_ice_candidate_pair_restart_stun_nominated_cb(NR_SOCKET s, int how, void *cb_arg) { nr_ice_cand_pair *pair=cb_arg; int r,_status; r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s):%d: Restarting pair %s as nominated",pair->pctx->label,pair->local->stream->label,pair->remote->component->component_id,pair->as_string); nr_stun_client_reset(pair->stun_client); pair->stun_client->params.ice_binding_request.control=NR_ICE_CONTROLLING; if(r=nr_stun_client_start(pair->stun_client,NR_ICE_CLIENT_MODE_USE_CANDIDATE,nr_ice_candidate_pair_stun_cb,pair)) ABORT(r); if(r=nr_ice_ctx_remember_id(pair->pctx->ctx, pair->stun_client->request)) ABORT(r); _status=0; abort: return; } -static void nr_ice_candidate_pair_restart_stun_controlled_cb(int s, int how, void *cb_arg) +static void nr_ice_candidate_pair_restart_stun_controlled_cb(NR_SOCKET s, int how, void *cb_arg) { nr_ice_cand_pair *pair=cb_arg; int r,_status; r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s):%d: Restarting pair %s as CONTROLLED",pair->pctx->label,pair->local->stream->label,pair->remote->component->component_id,pair->as_string); nr_stun_client_reset(pair->stun_client); pair->stun_client->params.ice_binding_request.control=NR_ICE_CONTROLLED; if(r=nr_stun_client_start(pair->stun_client,NR_ICE_CLIENT_MODE_BINDING_REQUEST,nr_ice_candidate_pair_stun_cb,pair)) @@ -556,21 +571,21 @@ static void nr_ice_candidate_pair_compute_codeword(nr_ice_cand_pair *pair, nr_ice_candidate *lcand, nr_ice_candidate *rcand) { int r,_status; char *as_string=0; if(r=nr_concat_strings(&as_string,lcand->addr.as_string,"|", - rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")",0)) + rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")",NULL)) ABORT(r); nr_ice_compute_codeword(as_string,strlen(as_string),pair->codeword); _status=0; abort: RFREE(as_string); return; } diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate_pair.h src/ice/ice_candidate_pair.h --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate_pair.h 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_candidate_pair.h 2012-10-06 08:30:22.000000000 -0700 @@ -72,18 +72,18 @@ int nr_ice_candidate_pair_create(nr_ice_peer_ctx *pctx, nr_ice_candidate *lcand,nr_ice_candidate *rcand,nr_ice_cand_pair **pairp); int nr_ice_candidate_pair_unfreeze(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair); int nr_ice_candidate_pair_start(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair); int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state); int nr_ice_candidate_pair_dump_state(nr_ice_cand_pair *pair, FILE *out); int nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair); int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair); int nr_ice_candidate_pair_do_triggered_check(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair); int nr_ice_candidate_pair_insert(nr_ice_cand_pair_head *head,nr_ice_cand_pair *pair); -void nr_ice_candidate_pair_restart_stun_nominated_cb(int s, int how, void *cb_arg); +void nr_ice_candidate_pair_restart_stun_nominated_cb(NR_SOCKET s, int how, void *cb_arg); int nr_ice_candidate_pair_destroy(nr_ice_cand_pair **pairp); #ifdef __cplusplus } #endif /* __cplusplus */ #endif diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_component.c src/ice/ice_component.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_component.c 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_component.c 2012-10-06 08:30:22.000000000 -0700 @@ -451,21 +451,21 @@ if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) { *error=(r==R_NO_MEMORY)?500:400; ABORT(r); } if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){ r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label); *error=487; ABORT(R_BAD_DATA); } pcand->priority=attr->u.priority; - pcand->state=NR_ICE_CAND_PEER_CANDIDATE; + pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED;; TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp); if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand, &pair)) { *error=(r==R_NO_MEMORY)?500:400; ABORT(r); } nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FROZEN); if(r=nr_ice_candidate_pair_insert(&comp->stream->check_list,pair)) { @@ -563,30 +563,38 @@ break; } /* PAIR with each peer*/ if(TAILQ_EMPTY(&pcomp->candidates)) { /* can happen if our peer proposes no (or all bogus) candidates */ goto next_cand; } pcand=TAILQ_FIRST(&pcomp->candidates); while(pcand){ - nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword); - r_log(LOG_ICE,LOG_DEBUG,"Examining peer candidate %s:%s",codeword,pcand->label); - - if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair)) - ABORT(r); - - if(r=nr_ice_candidate_pair_insert(&pcomp->stream->check_list, - pair)) - ABORT(r); + /* Only pair peer candidates which have not yet been paired. + This allows "trickle ICE". (Not yet standardized, but + part of WebRTC). + + TODO(ekr@rtfm.com): Add refernece to the spec when there + is one. + */ + if (pcand->state = NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED) { + nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword); + r_log(LOG_ICE,LOG_DEBUG,"Examining peer candidate %s:%s",codeword,pcand->label); + + if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair)) + ABORT(r); + if(r=nr_ice_candidate_pair_insert(&pcomp->stream->check_list, + pair)) + ABORT(r); + } pcand=TAILQ_NEXT(pcand,entry_comp); } if(!pair) ABORT(R_INTERNAL); /* Add the stun username/password pair from the last pair (any would do) to the stun contexts */ isock=STAILQ_FIRST(&lcomp->sockets); while(isock){ @@ -594,20 +602,28 @@ pair->r2l_user,&pair->r2l_pwd,nr_ice_component_stun_server_cb,pcomp)) ABORT(r); isock=STAILQ_NEXT(isock,entry); } next_cand: lcand=TAILQ_NEXT(lcand,entry_comp); } + /* Mark all peer candidates as paired */ + pcand=TAILQ_FIRST(&pcomp->candidates); + while(pcand){ + pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED; + + pcand=TAILQ_NEXT(pcand,entry_comp); + } + _status=0; abort: return(_status); } int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair) { int r,_status; int fire_cb=0; nr_ice_cand_pair *p2; @@ -616,32 +632,32 @@ fire_cb=1; /* Are we changing what the nominated pair is? */ if(comp->nominated){ if(comp->nominated->priority > pair->priority) return(0); r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): replacing pair %s with pair %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,comp->nominated->as_string,pair->as_string); } /* Set the new nominated pair */ - r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): nominated pair is %s (0x%x)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,(int)pair); + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): nominated pair is %s (0x%p)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,pair); comp->state=NR_ICE_COMPONENT_NOMINATED; comp->nominated=pair; comp->active=pair; - r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling all pairs but %s (0x%x)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,(int)pair); + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling all pairs but %s (0x%p)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,pair); /* OK, we need to cancel off everything on this component */ p2=TAILQ_FIRST(&comp->stream->check_list); while(p2){ if((p2 != pair) && (p2->remote->component->component_id == comp->component_id)){ - r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling pair %s (0x%x)",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->as_string,(int)p2); + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling pair %s (0x%p)",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->as_string,p2); if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2)) ABORT(r); } p2=TAILQ_NEXT(p2,entry); } r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling done",comp->stream->pctx->label,comp->stream->label,comp->component_id); if(r=nr_ice_media_stream_component_nominated(comp->stream,comp)) @@ -734,21 +750,21 @@ ABORT(r); } _status=0; abort: RFREE(pairs); return(_status); } -static void nr_ice_component_keepalive_cb(int s, int how, void *cb_arg) +static void nr_ice_component_keepalive_cb(NR_SOCKET s, int how, void *cb_arg) { nr_ice_component *comp=cb_arg; UINT4 keepalive_timeout; assert(comp->keepalive_ctx); if(NR_reg_get_uint4(NR_ICE_REG_KEEPALIVE_TIMER,&keepalive_timeout)){ keepalive_timeout=15000; /* Default */ } diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_ctx.c src/ice/ice_ctx.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_ctx.c 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_ctx.c 2012-10-06 08:30:22.000000000 -0700 @@ -56,21 +56,21 @@ #include "util.h" int LOG_ICE = 0; static int nr_ice_random_string(char *str, int len); static int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out); #ifdef USE_TURN static int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out); #endif /* USE_TURN */ -static void nr_ice_ctx_destroy_cb(int s, int how, void *cb_arg); +static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg); int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out) { int r,_status; nr_ice_stun_server *servers = 0; int i; NR_registry child; char *addr=0; UINT2 port; in_addr_t addr_int; @@ -271,21 +271,21 @@ *ctxp=ctx; _status=0; abort: if(_status) nr_ice_ctx_destroy_cb(0,0,ctx); return(_status); } -static void nr_ice_ctx_destroy_cb(int s, int how, void *cb_arg) +static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg) { nr_ice_ctx *ctx=cb_arg; nr_ice_foundation *f1,*f2; nr_ice_media_stream *s1,*s2; int i; nr_ice_stun_id *id1,*id2; RFREE(ctx->label); RFREE(ctx->stun_servers); @@ -323,21 +323,21 @@ if(!ctxp || !*ctxp) return(0); NR_ASYNC_SCHEDULE(nr_ice_ctx_destroy_cb,*ctxp); *ctxp=0; return(0); } -void nr_ice_initialize_finished_cb(int s, int h, void *cb_arg) +void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg) { nr_ice_ctx *ctx=cb_arg; /* r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Candidate %s %s",ctx->label, cand->label, cand->state==NR_ICE_CAND_STATE_INITIALIZED?"INITIALIZED":"FAILED"); */ ctx->uninitialized_candidates--; if(ctx->uninitialized_candidates==0){ r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): All candidates initialized",ctx->label); @@ -368,21 +368,22 @@ stream=STAILQ_FIRST(&ctx->streams); while(stream){ if(r=nr_ice_media_stream_initialize(ctx,stream)) ABORT(r); stream=STAILQ_NEXT(stream,entry); } if(ctx->uninitialized_candidates) ABORT(R_WOULDBLOCK); - + + _status=0; abort: return(_status); } int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp) { int r,_status; if(r=nr_ice_media_stream_create(ctx,label,components,streamp)) diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_ctx.h src/ice/ice_ctx.h --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_ctx.h 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_ctx.h 2012-10-06 08:30:22.000000000 -0700 @@ -92,23 +92,23 @@ UCHAR id[12]; STAILQ_ENTRY(nr_ice_stun_id_) entry; } nr_ice_stun_id; typedef STAILQ_HEAD(nr_ice_stun_id_head_,nr_ice_stun_id_) nr_ice_stun_id_head; struct nr_ice_ctx_ { UINT4 flags; int state; -#define NR_ICE_STATE_CREATED 1 -#define NR_ICE_STATE_INITIALIZING 2 -#define NR_ICE_STATE_INITIALIZED 3 +#define NR_ICE_STATE_CREATED 1 +#define NR_ICE_STATE_INITIALIZING 2 +#define NR_ICE_STATE_INITIALIZED 3 char *label; char *ufrag; char *pwd; UINT4 Ta; nr_ice_stun_server *stun_servers; /* The list of stun servers */ int stun_server_ct; nr_ice_turn_server *turn_servers; /* The list of turn servers */ @@ -133,21 +133,21 @@ int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp); #define NR_ICE_CTX_FLAGS_OFFERER 1 #define NR_ICE_CTX_FLAGS_ANSWERER (1<<1) #define NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION (1<<2) #define NR_ICE_CTX_FLAGS_LITE (1<<3) int nr_ice_ctx_destroy(nr_ice_ctx **ctxp); int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg); int nr_ice_add_candidate(nr_ice_ctx *ctx, nr_ice_candidate *cand); -void nr_ice_initialize_finished_cb(int s, int h, void *cb_arg); +void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg); int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp); int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp); int nr_ice_ctx_deliver_packet(nr_ice_ctx *ctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len); int nr_ice_ctx_is_known_id(nr_ice_ctx *ctx, UCHAR id[12]); int nr_ice_ctx_remember_id(nr_ice_ctx *ctx, nr_stun_message *msg); int nr_ice_ctx_finalize(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx); extern int LOG_ICE; #ifdef __cplusplus diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_media_stream.c src/ice/ice_media_stream.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_media_stream.c 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_media_stream.c 2012-10-06 08:30:22.000000000 -0700 @@ -35,21 +35,21 @@ static char *RCSSTRING __UNUSED__="$Id: ice_media_stream.c,v 1.2 2008/04/28 17:59:01 ekr Exp $"; #include #include #include #include #include #include "ice_ctx.h" static char *nr_ice_media_stream_states[]={"INVALID", - "FROZEN","ACTIVE","COMPLETED","FAILED" + "UNPAIRED","FROZEN","ACTIVE","COMPLETED","FAILED" }; int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state); int nr_ice_media_stream_create(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp) { int r,_status; nr_ice_media_stream *stream=0; nr_ice_component *comp=0; int i; @@ -66,29 +66,29 @@ for(i=0;i 0, so increment by 1 */ if(r=nr_ice_component_create(stream, i+1, &comp)) ABORT(r); } TAILQ_INIT(&stream->check_list); stream->component_ct=components; - + stream->ice_state = NR_ICE_MEDIA_STREAM_UNPAIRED; *streamp=stream; _status=0; abort: if(_status){ nr_ice_media_stream_destroy(&stream); } - return(_status); + return(_status); } int nr_ice_media_stream_destroy(nr_ice_media_stream **streamp) { nr_ice_media_stream *stream; nr_ice_component *c1,*c2; nr_ice_cand_pair *p1,*p2; if(!streamp || !*streamp) return(0); @@ -200,85 +200,148 @@ if(attrs){ for(index=0;indexcomponents); + while(comp){ + if (comp->component_id == component) + break; + + comp=STAILQ_NEXT(comp,entry); + } + + if (!comp) + ABORT(R_NOT_FOUND); + + /* We have the component. Now find the "best" candidate, making + use of the fact that more "reliable" candidate types have + higher numbers. So, we sort by type and then priority within + type + */ + cand=TAILQ_FIRST(&comp->candidates); + while(cand){ + if (!best_cand) { + best_cand = cand; + } + else { + if (best_cand->type < cand->type) { + best_cand = cand; + } else if (best_cand->type == cand->type) { + if (best_cand->priority < cand->priority) + best_cand = cand; + } + } + + cand=TAILQ_NEXT(cand,entry_comp); + } + + /* No candidates */ + if (!best_cand) + ABORT(R_NOT_FOUND); + + *candp = best_cand; + + _status=0; + abort: + return(_status); + } + + int nr_ice_media_stream_pair_candidates(nr_ice_peer_ctx *pctx,nr_ice_media_stream *lstream,nr_ice_media_stream *pstream) { int r,_status; nr_ice_component *pcomp,*lcomp; pcomp=STAILQ_FIRST(&pstream->components); lcomp=STAILQ_FIRST(&lstream->components); while(pcomp){ if(r=nr_ice_component_pair_candidates(pctx,lcomp,pcomp)) ABORT(r); - + lcomp=STAILQ_NEXT(lcomp,entry); pcomp=STAILQ_NEXT(pcomp,entry); }; + if (pstream->ice_state == NR_ICE_MEDIA_STREAM_UNPAIRED) { + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): unfreezing stream %s",pstream->pctx->label,pstream->label); + pstream->ice_state = NR_ICE_MEDIA_STREAM_CHECKS_FROZEN; + } + _status=0; abort: return(_status); } /* S 5.8 -- run the highest priority WAITING pair or if not available FROZEN pair */ -static void nr_ice_media_stream_check_timer_cb(int s, int h, void *cb_arg) +static void nr_ice_media_stream_check_timer_cb(NR_SOCKET s, int h, void *cb_arg) { int r,_status; nr_ice_media_stream *stream=cb_arg; nr_ice_cand_pair *pair; int timer_val; assert(stream->pctx->active_streams!=0); timer_val=stream->pctx->ctx->Ta*stream->pctx->active_streams; + if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED) { + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): bogus state for stream %s",stream->pctx->label,stream->label); + } assert(stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED); r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): check timer expired for media stream %s",stream->pctx->label,stream->label); stream->timer=0; - /* Find the highest priority WAITING check and move it to RUNNING */ pair=TAILQ_FIRST(&stream->check_list); while(pair){ if(pair->state==NR_ICE_PAIR_STATE_WAITING) break; pair=TAILQ_NEXT(pair,entry); } /* Hmmm... No WAITING. Let's look for FROZEN */ if(!pair){ pair=TAILQ_FIRST(&stream->check_list); - + while(pair){ if(pair->state==NR_ICE_PAIR_STATE_FROZEN){ if(r=nr_ice_candidate_pair_unfreeze(stream->pctx,pair)) ABORT(r); break; } pair=TAILQ_NEXT(pair,entry); } } if(pair){ nr_ice_candidate_pair_start(pair->pctx,pair); /* Ignore failures */ NR_ASYNC_TIMER_SET(timer_val,nr_ice_media_stream_check_timer_cb,cb_arg,&stream->timer); } + /* TODO(ekr@rtfm.com): Report on the special case where there are no checks to + run at all */ _status=0; abort: return; } /* Start checks for this media stream (aka check list) */ int nr_ice_media_stream_start_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream) { assert(stream->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FROZEN); @@ -476,21 +539,23 @@ /* All done... */ r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/ICE-STREAM(%s): all components have nominated candidate pairs",stream->pctx->label,stream->label); nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED); /* Cancel our timer */ if(stream->timer){ NR_async_timer_cancel(stream->timer); stream->timer=0; } - stream->pctx->handler->vtbl->stream_ready(stream->pctx->handler->obj,stream->local_stream); + if (stream->pctx->handler) { + stream->pctx->handler->vtbl->stream_ready(stream->pctx->handler->obj,stream->local_stream); + } /* Now tell the peer_ctx that we're done */ if(r=nr_ice_peer_ctx_stream_done(stream->pctx,stream)) ABORT(r); done: _status=0; abort: return(_status); } @@ -515,21 +580,23 @@ p2=TAILQ_NEXT(p2,entry); } /* Cancel our timer */ if(stream->timer){ NR_async_timer_cancel(stream->timer); stream->timer=0; } - stream->pctx->handler->vtbl->stream_failed(stream->pctx->handler->obj,stream->local_stream); + if (stream->pctx->handler) { + stream->pctx->handler->vtbl->stream_failed(stream->pctx->handler->obj,stream->local_stream); + } /* Now tell the peer_ctx that we're done */ if(r=nr_ice_peer_ctx_stream_done(stream->pctx,stream)) ABORT(r); _status=0; abort: return(_status); } diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_media_stream.h src/ice/ice_media_stream.h --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_media_stream.h 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_media_stream.h 2012-10-06 08:30:22.000000000 -0700 @@ -45,40 +45,43 @@ struct nr_ice_peer_ctx_ *pctx; struct nr_ice_media_stream_ *local_stream; /* used when this is a peer */ int component_ct; nr_ice_component_head components; char *ufrag; /* ICE username */ char *pwd; /* ICE password */ int ice_state; -#define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN 1 -#define NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE 2 -#define NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED 3 -#define NR_ICE_MEDIA_STREAM_CHECKS_FAILED 4 + +#define NR_ICE_MEDIA_STREAM_UNPAIRED 1 +#define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN 2 +#define NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE 3 +#define NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED 4 +#define NR_ICE_MEDIA_STREAM_CHECKS_FAILED 5 nr_ice_cand_pair_head check_list; void *timer; /* Check list periodic timer */ // nr_ice_cand_pair_head valid_list; - + STAILQ_ENTRY(nr_ice_media_stream_) entry; }; typedef STAILQ_HEAD(nr_ice_media_stream_head_,nr_ice_media_stream_) nr_ice_media_stream_head; int nr_ice_media_stream_create(struct nr_ice_ctx_ *ctx,char *label, int components, nr_ice_media_stream **streamp); int nr_ice_media_stream_destroy(nr_ice_media_stream **streamp); int nr_ice_media_stream_finalize(nr_ice_media_stream *lstr,nr_ice_media_stream *rstr); int nr_ice_media_stream_initialize(struct nr_ice_ctx_ *ctx, nr_ice_media_stream *stream); int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attrsp,int *attrctp); +int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp); int nr_ice_media_stream_pair_candidates(nr_ice_peer_ctx *pctx,nr_ice_media_stream *lstream,nr_ice_media_stream *pstream); int nr_ice_media_stream_start_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream); int nr_ice_media_stream_unfreeze_pairs(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream); int nr_ice_media_stream_unfreeze_pairs_foundation(nr_ice_media_stream *stream, char *foundation); int nr_ice_media_stream_dump_state(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream,FILE *out); int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component); int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component); int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state); int nr_ice_media_stream_get_best_candidate(nr_ice_media_stream *str, int component, nr_ice_candidate **candp); int nr_ice_media_stream_send(nr_ice_peer_ctx *pctx,nr_ice_media_stream *str, int component, UCHAR *data, int len); diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_parser.c src/ice/ice_parser.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_parser.c 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_parser.c 2012-10-06 08:30:22.000000000 -0700 @@ -35,20 +35,21 @@ static char *RCSSTRING __UNUSED__="$Id: ice_parser.c,v 1.2 2008/04/28 17:59:01 ekr Exp $"; #include #include #ifdef WIN32 #include #else #include #include #include +#include #endif #include #include #include #include "nr_api.h" #include "ice_ctx.h" #include "ice_candidate.h" #include "ice_reg.h" static void @@ -125,21 +126,21 @@ char *rel_addr=0; if(!(cand=RCALLOC(sizeof(nr_ice_candidate)))) ABORT(R_NO_MEMORY); if(!(cand->label=r_strdup(orig))) ABORT(R_NO_MEMORY); cand->ctx=ctx; cand->isock=0; - cand->state=NR_ICE_CAND_PEER_CANDIDATE; + cand->state=NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED; cand->stream=stream; skip_whitespace(&str); /* Candidate attr */ if (strncasecmp(str, "candidate:", 10)) ABORT(R_BAD_DATA); fast_forward(&str, 10); if (*str == '\0') ABORT(R_BAD_DATA); @@ -311,26 +312,31 @@ /* it's expected to be at EOD at this point */ break; default: ABORT(R_INTERNAL); break; } skip_whitespace(&str); - assert(strlen(str) == 0); - + /* This used to be an assert, but we don't want to exit on invalid + remote data */ + if (strlen(str) != 0) { + ABORT(R_BAD_DATA); + } + *candp=cand; _status=0; abort: + /* TODO(ekr@rtfm.com): Fix memory leak if we have a parse error */ if (_status) r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Error parsing attribute: %s",ctx->label,orig); RFREE(connection_address); RFREE(rel_addr); return(_status); } int diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_peer_ctx.c src/ice/ice_peer_ctx.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_peer_ctx.c 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_peer_ctx.c 2012-10-06 08:30:22.000000000 -0700 @@ -35,33 +35,35 @@ static char *RCSSTRING __UNUSED__="$Id: ice_peer_ctx.c,v 1.2 2008/04/28 17:59:01 ekr Exp $"; #include #include #include #include "ice_ctx.h" #include "ice_peer_ctx.h" #include "nr_crypto.h" #include "async_timer.h" -static void nr_ice_peer_ctx_destroy_cb(int s, int how, void *cb_arg); +static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg); +static int nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct); +static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate); int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp) { int r,_status; nr_ice_peer_ctx *pctx=0; if(!(pctx=RCALLOC(sizeof(nr_ice_peer_ctx)))) ABORT(R_NO_MEMORY); if(!(pctx->label=r_strdup(label))) ABORT(R_NO_MEMORY); - + pctx->ctx=ctx; pctx->handler=handler; /* Decide controlling vs. controlled */ if(ctx->flags & NR_ICE_CTX_FLAGS_LITE){ if(pctx->peer_lite){ r_log(LOG_ICE,LOG_ERR,"Both sides are ICE-Lite"); ABORT(R_BAD_DATA); } @@ -88,85 +90,177 @@ nr_ice_peer_ctx_destroy_cb(0,0,pctx); } return(_status); } int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct) { nr_ice_media_stream *pstream=0; - nr_ice_candidate *cand=0; nr_ice_component *comp,*comp2; int r,_status; - int i,j; - /* Note: use component_ct from our own stream since components other - than this offered by the other side are unusable */ + /* + Note: use component_ct from our own stream since components other + than this offered by the other side are unusable */ if(r=nr_ice_media_stream_create(pctx->ctx,stream->label,stream->component_ct,&pstream)) ABORT(r); - - /* Match up the local and remote components */ + + /* Match up the local and remote components */ comp=STAILQ_FIRST(&stream->components); comp2=STAILQ_FIRST(&pstream->components); while(comp){ comp2->local_component=comp; comp=STAILQ_NEXT(comp,entry); comp2=STAILQ_NEXT(comp2,entry); } - - pstream->ice_state=NR_ICE_MEDIA_STREAM_CHECKS_FROZEN; pstream->local_stream=stream; pstream->pctx=pctx; + if (r=nr_ice_peer_ctx_parse_stream_attributes_int(pctx,stream,pstream,attrs,attr_ct)) + ABORT(r); + + + STAILQ_INSERT_TAIL(&pctx->peer_streams,pstream,entry); + + _status=0; + abort: + return(_status); + } + +static int nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct) + { + int r; + int i; + for(i=0;ictx->label,pctx->label); continue; - continue; + } } - - if(r=nr_ice_peer_candidate_from_attribute(pctx->ctx,attrs[i],pstream,&cand)) - continue; - if(cand->component_id-1>=pstream->component_ct){ - r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified too many components",pctx->ctx->label,pctx->label); - continue; + else if (!strncmp(attrs[i],"candidate",9)){ + if(r=nr_ice_ctx_parse_candidate(pctx,pstream,attrs[i])) { + r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified bogus candidate",pctx->ctx->label,pctx->label); + continue; + } + } + else { + r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified bogus attribute",pctx->ctx->label,pctx->label); } + } - /* Not the fastest way to find a component, but it's what we got */ - j=1; - for(comp=STAILQ_FIRST(&pstream->components);comp;comp=STAILQ_NEXT(comp,entry)){ - if(j==cand->component_id) - break; + /* Doesn't fail because we just skip errors */ + return(0); + } - j++; - } - - if(!comp){ - r_log(LOG_ICE,LOG_ERR,"Peer answered with more components than we offered"); - ABORT(R_BAD_DATA); - } - - cand->component=comp; +static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate) + { + nr_ice_candidate *cand=0; + nr_ice_component *comp; + int j; + int r, _status; - TAILQ_INSERT_TAIL(&comp->candidates,cand,entry_comp); + if(r=nr_ice_peer_candidate_from_attribute(pctx->ctx,candidate,pstream,&cand)) + ABORT(r); + if(cand->component_id-1>=pstream->component_ct){ + r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified too many components",pctx->ctx->label,pctx->label); + ABORT(R_BAD_DATA); } - STAILQ_INSERT_TAIL(&pctx->peer_streams,pstream,entry); + /* Not the fastest way to find a component, but it's what we got */ + j=1; + for(comp=STAILQ_FIRST(&pstream->components);comp;comp=STAILQ_NEXT(comp,entry)){ + if(j==cand->component_id) + break; + + j++; + } + + if(!comp){ + r_log(LOG_ICE,LOG_ERR,"Peer answered with more components than we offered"); + ABORT(R_BAD_DATA); + } + + cand->component=comp; + + TAILQ_INSERT_TAIL(&comp->candidates,cand,entry_comp); _status=0; - abort: + abort: + if (_status) { + nr_ice_candidate_destroy(&cand); + } return(_status); } + + +int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate) + { + /* First need to find the stream. Because we don't have forward pointers, + iterate through all the peer streams to find one that matches us */ + nr_ice_media_stream *pstream; + int r,_status; + int needs_pairing = 0; + + pstream=STAILQ_FIRST(&pctx->peer_streams); + while(pstream) { + if (pstream->local_stream == stream) + break; + + pstream = STAILQ_NEXT(pstream, entry); + } + if (!pstream) { + r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label); + ABORT(R_NOT_FOUND); + } + + switch(pstream->ice_state) { + case NR_ICE_MEDIA_STREAM_UNPAIRED: + break; + case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN: + case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE: + needs_pairing = 1; + break; + default: + r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) tried to trickle ICE in inappropriate state %d",pctx->ctx->label,pctx->label,stream->label,pstream->ice_state); + ABORT(R_ALREADY); + break; + } + + if(r=nr_ice_ctx_parse_candidate(pctx,pstream,candidate)){ + ABORT(r); + } + + /* If ICE is running (i.e., we are in FROZEN or ACTIVE states) + then we need to pair this new candidate. For now we + just re-pair the stream which is inefficient but still + fine because we suppress duplicate pairing */ + if (needs_pairing) { + if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) { + r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) failed to pair trickle ICE candidates",pctx->ctx->label,pctx->label,stream->label); + ABORT(r); + } + } + + _status =0; + abort: + return(_status); + + } + + int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx) { nr_ice_media_stream *stream; int r,_status; if(STAILQ_EMPTY(&pctx->peer_streams)) { r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) received no media stream attribributes",pctx->ctx->label,pctx->label); ABORT(R_FAILED); } @@ -177,21 +271,21 @@ ABORT(r); stream=STAILQ_NEXT(stream,entry); } _status=0; abort: return(_status); } -static void nr_ice_peer_ctx_destroy_cb(int s, int how, void *cb_arg) +static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg) { nr_ice_peer_ctx *pctx=cb_arg; nr_ice_media_stream *str1,*str2; RFREE(pctx->label); RFREE(pctx->peer_ufrag); RFREE(pctx->peer_pwd); STAILQ_FOREACH_SAFE(str1, &pctx->peer_streams, entry, str2){ STAILQ_REMOVE(&pctx->peer_streams,str1,nr_ice_media_stream_,entry); @@ -199,44 +293,79 @@ } RFREE(pctx); } int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp) { if(!pctxp || !*pctxp) return(0); - + + /* Stop calling the handler */ + (*pctxp)->handler = 0; + NR_ASYNC_SCHEDULE(nr_ice_peer_ctx_destroy_cb,*pctxp); *pctxp=0; return(0); } + /* Start the checks for the first media stream (S 5.7) The rest remain FROZEN */ int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx) { + return nr_ice_peer_ctx_start_checks2(pctx, 0); + } + +/* Start checks for some media stream. + + If allow_non_first == 0, then we only look at the first stream, + which is 5245-complaint. + + If allow_non_first == 1 then we find the first non-empty stream + This is not compliant with RFC 5245 but is necessary to make trickle ICE + work plausibly +*/ +int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first) + { int r,_status; nr_ice_media_stream *stream; stream=STAILQ_FIRST(&pctx->peer_streams); if(!stream) ABORT(R_FAILED); + while (stream) { + if(!TAILQ_EMPTY(&stream->check_list)) + break; + + if(!allow_non_first){ + r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) first stream has empty check list",pctx->ctx->label,pctx->label); + ABORT(R_FAILED); + } + + stream=STAILQ_NEXT(stream, entry); + } + + if (!stream) { + r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) no streams with non-empty check lists",pctx->ctx->label,pctx->label); + ABORT(R_NOT_FOUND); + } + if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN) { - if(r=nr_ice_media_stream_unfreeze_pairs(pctx,stream)) - ABORT(r); - if(r=nr_ice_media_stream_start_checks(pctx,stream)) - ABORT(r); + if(r=nr_ice_media_stream_unfreeze_pairs(pctx,stream)) + ABORT(r); + if(r=nr_ice_media_stream_start_checks(pctx,stream)) + ABORT(r); } _status=0; abort: return(_status); } #ifndef NDEBUG int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out) { @@ -253,26 +382,28 @@ stream=STAILQ_NEXT(stream,entry); } fprintf(out,"==========================================\n"); _status=0; abort: return(_status); } #endif -static void nr_ice_peer_ctx_fire_done(int s, int how, void *cb_arg) +static void nr_ice_peer_ctx_fire_done(NR_SOCKET s, int how, void *cb_arg) { nr_ice_peer_ctx *pctx=cb_arg; /* Fire the handler callback to say we're done */ - pctx->handler->vtbl->ice_completed(pctx->handler->obj, pctx); + if (pctx->handler) { + pctx->handler->vtbl->ice_completed(pctx->handler->obj, pctx); + } } /* OK, a stream just went ready. Examine all the streams to see if we're maybe miraculously done */ int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream) { int _status; nr_ice_media_stream *str; int failed=0; @@ -365,21 +496,24 @@ NR_TRANSPORT_ADDR_CMP_MODE_ALL)) break; cand=TAILQ_NEXT(cand,entry_comp); } if(!cand) ABORT(R_REJECTED); /* OK, there's a match. Call the handler */ - r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Delivering data", pctx->label); - pctx->handler->vtbl->msg_recvd(pctx->handler->obj, - pctx,comp->stream,comp->component_id,data,len); + if (pctx->handler) { + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Delivering data", pctx->label); + + pctx->handler->vtbl->msg_recvd(pctx->handler->obj, + pctx,comp->stream,comp->component_id,data,len); + } _status=0; abort: return(_status); } diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_peer_ctx.h src/ice/ice_peer_ctx.h --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_peer_ctx.h 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_peer_ctx.h 2012-10-06 08:30:22.000000000 -0700 @@ -33,23 +33,21 @@ #ifndef _ice_peer_ctx_h #define _ice_peer_ctx_h #ifdef __cplusplus using namespace std; extern "C" { #endif /* __cplusplus */ struct nr_ice_peer_ctx_ { - int state; char *label; - nr_ice_ctx *ctx; nr_ice_handler *handler; UCHAR controlling; /* 1 for controlling, 0 for controlled */ UINT8 tiebreaker; char *peer_ufrag; char *peer_pwd; int peer_lite; int peer_ice_mismatch; @@ -59,23 +57,26 @@ int waiting_pairs; STAILQ_ENTRY(nr_ice_peer_ctx_) entry; }; typedef STAILQ_HEAD(nr_ice_peer_ctx_head_, nr_ice_peer_ctx_) nr_ice_peer_ctx_head; int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp); int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp); int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct); +int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *cand); + int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx); int nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs, int attr_ct); int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx); +int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first); int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out); int nr_ice_peer_ctx_log_state(nr_ice_peer_ctx *pctx); int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream); int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp); int nr_ice_peer_ctx_deliver_packet_maybe(nr_ice_peer_ctx *pctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len); #ifdef __cplusplus } #endif /* __cplusplus */ #endif diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_socket.c src/ice/ice_socket.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_socket.c 2012-09-16 16:26:08.000000000 -0700 +++ src/ice/ice_socket.c 2012-10-06 08:30:22.000000000 -0700 @@ -216,28 +216,34 @@ RFREE(s1); } RFREE(isock); return(0); } int nr_ice_socket_close(nr_ice_socket *isock) { +#ifdef NR_SOCKET_IS_VOID_PTR + NR_SOCKET fd=NULL; + NR_SOCKET no_socket = NULL; +#else NR_SOCKET fd=-1; + NR_SOCKET no_socket = -1; +#endif if (!isock||!isock->sock) return(0); nr_socket_getfd(isock->sock,&fd); assert(isock->sock!=0); - if(fd!=-1){ + if(fd != no_socket){ NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_READ); NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_WRITE); nr_socket_destroy(&isock->sock); } return(0); } int nr_ice_socket_register_stun_client(nr_ice_socket *sock, nr_stun_client_ctx *srv,void **handle) { diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/net/nr_socket.h src/net/nr_socket.h --- /Users/ekr/dev/mtransport-import-references/nICEr/src/net/nr_socket.h 2012-09-16 16:26:09.000000000 -0700 +++ src/net/nr_socket.h 2012-10-06 08:30:22.000000000 -0700 @@ -38,21 +38,23 @@ #include #ifdef WIN32 #include #include #else #include #endif #include "transport_addr.h" -#ifdef WIN32 +#ifdef __cplusplus +#define restrict +#elif defined(WIN32) #define restrict __restrict #endif typedef struct nr_socket_vtbl_ { int (*destroy)(void **obj); int (*ssendto)(void *obj,const void *msg, size_t len, int flags, nr_transport_addr *addr); int (*srecvfrom)(void *obj,void * restrict buf, size_t maxlen, size_t *len, int flags, nr_transport_addr *addr); int (*getfd)(void *obj, NR_SOCKET *fd); diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/net/transport_addr_reg.c src/net/transport_addr_reg.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/net/transport_addr_reg.c 2012-09-16 16:26:09.000000000 -0700 +++ src/net/transport_addr_reg.c 2012-10-06 08:30:22.000000000 -0700 @@ -29,25 +29,27 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static char *RCSSTRING __UNUSED__="$Id: transport_addr_reg.c,v 1.2 2008/04/28 17:59:03 ekr Exp $"; #include #include +#include #include #include #ifdef WIN32 #include #else +#include #include #include #include #include #endif #include #include "nr_api.h" #include "transport_addr.h" #include "transport_addr_reg.h" @@ -83,20 +85,22 @@ if ((r=NR_reg_get2_uint2(prefix, "port", &port))) { if (r != R_NOT_FOUND) ABORT(r); port = 0; } if ((r=NR_reg_alloc2_string(prefix, "protocol", &protocol))) { if (r != R_NOT_FOUND) ABORT(r); + p = IPPROTO_UDP; + protocol = 0; } else { if (!strcasecmp("tcp", protocol)) p = IPPROTO_TCP; else if (!strcasecmp("udp", protocol)) p = IPPROTO_UDP; else ABORT(R_BAD_DATA); } diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/addrs.c src/stun/addrs.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/addrs.c 2012-09-16 16:26:10.000000000 -0700 +++ src/stun/addrs.c 2012-10-06 09:42:43.000000000 -0700 @@ -46,20 +46,22 @@ #include #include #include #include #include #ifndef LINUX #include #include #include #include +#else +#include #endif #include /* IP */ #include #ifdef LINUX #include "sys/ioctl.h" #else #include #endif @@ -105,20 +107,23 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include static void stun_rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *); static int stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_transport_addr addrs[], int maxaddrs, int *count); +static int +nr_stun_is_duplicate_addr(nr_transport_addr addrs[], int count, nr_transport_addr *addr); + /* * Expand the compacted form of addresses as returned via the * configuration read via sysctl(). */ #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) static void @@ -135,21 +140,21 @@ continue; rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; ADVANCE(cp, sa); } } static int stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_transport_addr addrs[], int maxaddrs, int *count) { int r,_status; - NR_SOCKET s = -1; + int s = -1; struct ifreq ifr; struct rt_addrinfo info; struct sockaddr_in *sin; ifr.ifr_addr.sa_family = AF_INET; strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) { r_log(NR_LOG_STUN, LOG_WARNING, "unable to obtain addresses from socket"); ABORT(R_FAILED); @@ -180,21 +185,20 @@ addrcount--; if (*count >= maxaddrs) { r_log(NR_LOG_STUN, LOG_WARNING, "Address list truncated at %d out of entries", maxaddrs, maxaddrs+addrcount); break; } ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); } - _status = 0; abort: if (s != -1) close(s); return _status; } static int stun_get_mib_addrs(nr_transport_addr addrs[], int maxaddrs, int *count) { int _status; @@ -551,44 +555,48 @@ #else static int stun_get_siocgifconf_addrs(nr_transport_addr addrs[], int maxaddrs, int *count) { struct ifconf ifc; int _status; int s = socket( AF_INET, SOCK_DGRAM, 0 ); int len = 100 * sizeof(struct ifreq); int r; + int e; + char *ptr; + int tl; + int n; + struct ifreq ifr2; char buf[ len ]; ifc.ifc_len = len; ifc.ifc_buf = buf; - int e = ioctl(s,SIOCGIFCONF,&ifc); - char *ptr = buf; - int tl = ifc.ifc_len; - int n=0; + e = ioctl(s,SIOCGIFCONF,&ifc); + ptr = buf; + tl = ifc.ifc_len; + n=0; while ( (tl > 0) && ( n < maxaddrs) ) { struct ifreq* ifr = (struct ifreq *)ptr; #ifdef LINUX - int si = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr); + int si = sizeof(struct ifreq); #else int si = sizeof(ifr->ifr_name) + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)); #endif tl -= si; ptr += si; - struct ifreq ifr2; ifr2 = *ifr; e = ioctl(s,SIOCGIFADDR,&ifr2); if ( e == -1 ) { continue; } //r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e); @@ -603,21 +611,21 @@ close(s); *count = n; _status = 0; return _status; } #endif -int +static int nr_stun_is_duplicate_addr(nr_transport_addr addrs[], int count, nr_transport_addr *addr) { int i; int different; for (i = 0; i < count; ++i) { different = nr_transport_addr_cmp(&addrs[i], addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL); if (!different) return 1; /* duplicate */ } diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/nr_socket_turn.c src/stun/nr_socket_turn.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/nr_socket_turn.c 2012-09-16 16:26:10.000000000 -0700 +++ src/stun/nr_socket_turn.c 2012-10-06 08:30:22.000000000 -0700 @@ -246,17 +246,19 @@ default: assert(0); break; } return R_FAILED; } static int nr_socket_turn_close(void *obj) { +#ifndef NDEBUG nr_socket_turn *sturn=obj; assert(sturn->magic_cookie == nr_socket_turn_magic_cookie); +#endif return 0; } #endif /* USE_TURN */ diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_client_ctx.c src/stun/stun_client_ctx.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_client_ctx.c 2012-09-16 16:26:10.000000000 -0700 +++ src/stun/stun_client_ctx.c 2012-10-06 08:30:22.000000000 -0700 @@ -38,21 +38,22 @@ #include #include #include "stun.h" #include "async_timer.h" #include "registry.h" #include "stun_reg.h" #include "r_time.h" static int nr_stun_client_send_request(nr_stun_client_ctx *ctx); -static void nr_stun_client_timer_expired_cb(int a, int b, void *cb_arg); +static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg); +static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password); int nr_stun_client_ctx_create(char *label, nr_socket *sock, nr_transport_addr *peer, UINT4 RTO, nr_stun_client_ctx **ctxp) { nr_stun_client_ctx *ctx=0; int r,_status; if ((r=nr_stun_startup())) ABORT(r); if(!(ctx=RCALLOC(sizeof(nr_stun_client_ctx)))) @@ -185,21 +186,21 @@ ctx->finished_cb = 0; ctx->cb_arg = 0; ctx->request_ct = 0; ctx->timeout_ms = 0; ctx->state = NR_STUN_CLIENT_STATE_INITTED; return 0; } -static void nr_stun_client_timer_expired_cb(int a, int b, void *cb_arg) +static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg) { int _status; nr_stun_client_ctx *ctx=cb_arg; struct timeval now; INT8 ms_waited; /* Prevent this timer from being cancelled later */ ctx->timer_handle=0; /* Shouldn't happen */ @@ -387,21 +388,21 @@ } _status=0; abort: if (_status) { ctx->state=NR_STUN_CLIENT_STATE_FAILED; } return(_status); } -int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password) +static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password) { *password = (Data*)arg; if (!arg) return(R_NOT_FOUND); return(0); } int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr) { int r,_status; diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_codec.c src/stun/stun_codec.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_codec.c 2012-09-16 16:26:10.000000000 -0700 +++ src/stun/stun_codec.c 2012-10-06 08:30:22.000000000 -0700 @@ -73,20 +73,22 @@ static int nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data); static int nr_stun_decode(int length, UCHAR *buf, int buflen, int *offset, UCHAR *data); static int nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, int len, void *data, int max_bytes, int max_chars); static int nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); static int nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); static int nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); static int nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); static int nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); +static int +nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data); int nr_stun_encode_htons(UINT2 data, int buflen, UCHAR *buf, int *offset) { UINT2 d = htons(data); if (*offset + sizeof(d) >= buflen) { r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d >= %d", *offset, sizeof(d), buflen); return R_BAD_DATA; @@ -632,21 +634,21 @@ } fingerprint->checksum = checksum ^ 0x5354554e; r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", fingerprint->checksum); fingerprint->valid = 1; return nr_stun_attr_codec_UINT4.encode(attr_info, &fingerprint->checksum, offset, buflen, buf, attrlen); } -int +static int nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) { int r,_status; nr_stun_attr_fingerprint *fingerprint = data; nr_stun_message_header *header = (nr_stun_message_header*)buf; int length; UINT4 checksum; if ((r=nr_stun_attr_codec_UINT4.decode(attr_info, attrlen, buf, offset, buflen, &fingerprint->checksum))) ABORT(r); diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_proc.c src/stun/stun_proc.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_proc.c 2012-09-16 16:26:10.000000000 -0700 +++ src/stun/stun_proc.c 2012-10-06 08:30:22.000000000 -0700 @@ -43,20 +43,22 @@ #include #else /* UNIX */ #include #endif /* end UNIX */ #include #include "stun.h" #include "stun_reg.h" #include "registry.h" +static int +nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res); /* draft-ietf-behave-rfc3489bis-10.txt S 7.3 */ int nr_stun_receive_message(nr_stun_message *req, nr_stun_message *msg) { int _status; nr_stun_message_attribute *attr; #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE /* if this message was generated by an RFC 3489 impementation, @@ -371,21 +373,21 @@ /* nothing to check in this case */ break; #endif /* USE_STUND_0_96 */ } _status=0; abort: return _status; } -int +static int nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res) { int r,_status; char *realm = 0; char *nonce; UINT2 size; if ((r=NR_reg_alloc_string(NR_STUN_REG_PREF_SERVER_REALM, &realm))) ABORT(r); diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_server_ctx.c src/stun/stun_server_ctx.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_server_ctx.c 2012-09-16 16:26:10.000000000 -0700 +++ src/stun/stun_server_ctx.c 2012-10-06 08:30:22.000000000 -0700 @@ -114,21 +114,21 @@ STAILQ_INSERT_TAIL(&ctx->clients,clnt,entry); _status=0; abort: if(_status){ nr_stun_server_destroy_client(clnt); } return(_status); } -int nr_stun_server_get_password(void *arg, nr_stun_message *msg, Data **password) +static int nr_stun_server_get_password(void *arg, nr_stun_message *msg, Data **password) { int _status; nr_stun_server_ctx *ctx = (nr_stun_server_ctx*)arg; nr_stun_server_client *clnt = 0; nr_stun_message_attribute *username_attribute; if ((nr_stun_get_message_client(ctx, msg, &clnt))) { if (! nr_stun_message_has_attribute(msg, NR_STUN_ATTR_USERNAME, &username_attribute)) { r_log(NR_LOG_STUN,LOG_NOTICE,"STUN-SERVER(%s): Missing Username",ctx->label); ABORT(R_NOT_FOUND); diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_util.c src/stun/stun_util.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_util.c 2012-09-16 16:26:10.000000000 -0700 +++ src/stun/stun_util.c 2012-10-06 08:30:22.000000000 -0700 @@ -94,21 +94,20 @@ _status = 0; abort: return _status; } int nr_stun_find_local_addresses(nr_transport_addr addrs[], int maxaddrs, int *count) { int r,_status; NR_registry *children = 0; - int i; if ((r=NR_reg_get_child_count(NR_STUN_REG_PREF_ADDRESS_PRFX, (unsigned int*)count))) if (r == R_NOT_FOUND) *count = 0; else ABORT(r); if (*count == 0) { if ((r=nr_stun_get_addrs(addrs, maxaddrs, 1, count))) ABORT(r); diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/turn_client_ctx.c src/stun/turn_client_ctx.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/turn_client_ctx.c 2012-09-16 16:26:10.000000000 -0700 +++ src/stun/turn_client_ctx.c 2012-10-06 08:30:22.000000000 -0700 @@ -55,21 +55,24 @@ }; static int TURN_PHASE_MODE[NUMBER_OF_STUN_CTX] = { NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1, NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2, NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST }; static int nr_turn_client_next_action(nr_turn_client_ctx *ctx, int stun_ctx_state); -static void nr_turn_client_cb(int s, int how, void *cb_arg); +static void nr_turn_client_cb(NR_SOCKET s, int how, void *cb_arg); +static int +nr_turn_client_prepare_start(nr_turn_client_ctx *ctx, char *username, Data *password, UINT4 bandwidth_kbps, UINT4 lifetime_secs, NR_async_cb finished_cb, void *cb_arg); + int nr_turn_client_next_action(nr_turn_client_ctx *ctx, int stun_ctx_state) { int r,_status; assert(ctx->phase >= -1 && ctx->phase < NUMBER_OF_STUN_CTX); switch (ctx->state) { //case NR_TURN_CLIENT_STATE_ALLOCATING: @@ -147,21 +150,21 @@ * because as a side effect this ctx may be operated on in the * callback */ finished_cb(0,0,ctx->cb_arg); } } return(_status); } void -nr_turn_client_cb(int s, int how, void *cb_arg) +nr_turn_client_cb(NR_SOCKET s, int how, void *cb_arg) { int r,_status; nr_turn_client_ctx *ctx = (nr_turn_client_ctx*)cb_arg; nr_stun_client_ctx *stun_ctx = ctx->stun_ctx[ctx->phase]; assert(ctx->phase >= 0); if ((r=nr_turn_client_next_action(ctx, stun_ctx->state))) ABORT(r); @@ -234,21 +237,21 @@ RFREE(ctx->username); r_data_destroy(&ctx->password); RFREE(ctx->label); RFREE(ctx); return(0); } -int +static int nr_turn_client_prepare_start(nr_turn_client_ctx *ctx, char *username, Data *password, UINT4 bandwidth_kbps, UINT4 lifetime_secs, NR_async_cb finished_cb, void *cb_arg) { int r,_status; nr_stun_client_allocate_request1_params *allocate_request1 = 0; nr_stun_client_allocate_request2_params *allocate_request2 = 0; nr_stun_client_allocate_response1_results *allocate_response1 = 0; // nr_stun_client_allocate_response2_results *allocate_response2; if (ctx->state != NR_TURN_CLIENT_STATE_INITTED) ABORT(R_NOT_PERMITTED); diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/util/ice_util.c src/util/ice_util.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/util/ice_util.c 2012-09-16 16:26:10.000000000 -0700 +++ src/util/ice_util.c 2012-10-06 08:30:22.000000000 -0700 @@ -31,20 +31,21 @@ */ #include static char *RCSSTRING __UNUSED__="$Id: ice_util.c,v 1.2 2008/04/28 17:59:05 ekr Exp $"; #include #include #include "nr_api.h" +#include "ice_util.h" int nr_concat_strings(char **outp,...) { va_list ap; char *s,*out=0; int len=0; int _status; va_start(ap,outp); while(s=va_arg(ap,char *)){ diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/util/mbslen.c src/util/mbslen.c --- /Users/ekr/dev/mtransport-import-references/nICEr/src/util/mbslen.c 2012-09-16 16:26:10.000000000 -0700 +++ src/util/mbslen.c 2012-10-06 08:31:01.000000000 -0700 @@ -56,21 +56,21 @@ { #ifdef DARWIN static locale_t loc = 0; static int initialized = 0; #endif /* DARWIN */ #ifdef WIN32 char *my_locale=0; unsigned int i; #endif /* WIN32 */ int _status; - int nbytes; + size_t nbytes; int nchars; mbstate_t mbs; #ifdef DARWIN if (! initialized) { initialized = 1; loc = newlocale(LC_CTYPE_MASK, "UTF-8", LC_GLOBAL_LOCALE); } if (loc == 0) { @@ -102,25 +102,28 @@ memset(&mbs, 0, sizeof(mbs)); nchars = 0; #ifdef DARWIN while (*s != '\0' && (nbytes = mbrlen_l(s, strlen(s), &mbs, loc)) != 0) #else while (*s != '\0' && (nbytes = mbrlen(s, strlen(s), &mbs)) != 0) #endif /* DARWIN */ { - assert(nbytes >= 0); - if (nbytes == (size_t)-1) /* should never happen */ + if (nbytes == (size_t)-1) /* should never happen */ { + assert(0); ABORT(R_INTERNAL); - if (nbytes == (size_t)-2) /* encoding error */ + } + if (nbytes == (size_t)-2) /* encoding error */ { + assert(0); ABORT(R_BAD_DATA); + } s += nbytes; ++nchars; } *ncharsp = nchars; _status = 0; abort: #ifdef WIN32