summaryrefslogtreecommitdiffstats
path: root/media/mtransport/third_party/nICEr/upstream.diff
diff options
context:
space:
mode:
Diffstat (limited to 'media/mtransport/third_party/nICEr/upstream.diff')
-rw-r--r--media/mtransport/third_party/nICEr/upstream.diff2449
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