diff options
Diffstat (limited to 'media/mtransport/third_party/nICEr/upstream.diff')
-rw-r--r-- | media/mtransport/third_party/nICEr/upstream.diff | 2449 |
1 files changed, 2449 insertions, 0 deletions
diff --git a/media/mtransport/third_party/nICEr/upstream.diff b/media/mtransport/third_party/nICEr/upstream.diff new file mode 100644 index 000000000..a664fd9d2 --- /dev/null +++ b/media/mtransport/third_party/nICEr/upstream.diff @@ -0,0 +1,2449 @@ +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 <assert.h> + #include <string.h> + #include <nr_api.h> + #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 <string.h> + #include <assert.h> + #include <nr_api.h> + #include <r_assoc.h> + #include <async_timer.h> + #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<components;i++){ + /* component-id must be > 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;index<attrct;index++){ + RFREE(attrs[index]); + } + RFREE(attrs); + } + } + return(_status); + } + ++ ++/* Get a default candidate per 4.1.4 */ ++int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp) ++ { ++ int _status; ++ nr_ice_component *comp; ++ nr_ice_candidate *cand; ++ nr_ice_candidate *best_cand = NULL; ++ ++ comp=STAILQ_FIRST(&stream->components); ++ 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 <csi_platform.h> + #include <sys/types.h> + #ifdef WIN32 + #include <winsock2.h> + #else + #include <sys/socket.h> + #include <netinet/in.h> + #include <arpa/inet.h> ++#include <strings.h> + #endif + #include <string.h> + #include <assert.h> + #include <ctype.h> + #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 <string.h> + #include <assert.h> + #include <nr_api.h> + #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;i<attr_ct;i++){ + if(!strncmp(attrs[i],"ice-",4)){ +- if(r=nr_ice_peer_ctx_parse_media_stream_attribute(pctx,pstream,attrs[i])) ++ if(r=nr_ice_peer_ctx_parse_media_stream_attribute(pctx,pstream,attrs[i])) { ++ r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified bogus ICE attribute",pctx->ctx->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 <sys/types.h> + #ifdef WIN32 + #include <winsock2.h> + #include <ws2tcpip.h> + #else + #include <sys/socket.h> + #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 <csi_platform.h> + #include <stdio.h> ++#include <string.h> + #include <memory.h> + #include <sys/types.h> + #ifdef WIN32 + #include <winsock2.h> + #else ++#include <strings.h> + #include <unistd.h> + #include <sys/socket.h> + #include <netinet/in.h> + #include <arpa/inet.h> + #endif + #include <assert.h> + #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 <sys/sysctl.h> + #include <sys/param.h> + #include <sys/socket.h> + #include <sys/syslog.h> + #include <net/if.h> + #ifndef LINUX + #include <net/if_var.h> + #include <net/if_dl.h> + #include <net/if_types.h> + #include <sys/sockio.h> ++#else ++#include <linux/if.h> + #endif + #include <net/route.h> + + /* IP */ + #include <netinet/in.h> + #ifdef LINUX + #include "sys/ioctl.h" + #else + #include <netinet/in_var.h> + #endif +@@ -105,20 +107,23 @@ + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + #include <err.h> + + 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 <string.h> + + #include <nr_api.h> + #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 <time.h> + #else /* UNIX */ + #include <string.h> + #endif /* end UNIX */ + #include <assert.h> + + #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 <stdarg.h> + + + static char *RCSSTRING __UNUSED__="$Id: ice_util.c,v 1.2 2008/04/28 17:59:05 ekr Exp $"; + + #include <stdarg.h> + #include <string.h> + #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 |