1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9 * Redistributions of source code must retain the above copyright
10   notice, this list of conditions and the following disclaimer.
11 
12 * Redistributions in binary form must reproduce the above copyright
13   notice, this list of conditions and the following disclaimer in the
14   documentation and/or other materials provided with the distribution.
15 
16 * Neither the name of Adobe Systems, Network Resonance nor the names of its
17   contributors may be used to endorse or promote products derived from
18   this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 
33 
34 
35 static char *RCSSTRING __UNUSED__="$Id: ice_peer_ctx.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
36 
37 #include <string.h>
38 #include <assert.h>
39 #include <registry.h>
40 #include <nr_api.h>
41 #include "ice_ctx.h"
42 #include "ice_peer_ctx.h"
43 #include "ice_media_stream.h"
44 #include "ice_util.h"
45 #include "nr_crypto.h"
46 #include "async_timer.h"
47 #include "ice_reg.h"
48 
49 static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg);
50 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);
51 static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate, int trickled);
52 static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx);
53 
nr_ice_peer_ctx_create(nr_ice_ctx * ctx,nr_ice_handler * handler,char * label,nr_ice_peer_ctx ** pctxp)54 int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp)
55   {
56     int r,_status;
57     nr_ice_peer_ctx *pctx=0;
58 
59     if(!(pctx=RCALLOC(sizeof(nr_ice_peer_ctx))))
60       ABORT(R_NO_MEMORY);
61 
62     pctx->state = NR_ICE_PEER_STATE_UNPAIRED;
63 
64     if(!(pctx->label=r_strdup(label)))
65       ABORT(R_NO_MEMORY);
66 
67     pctx->ctx=ctx;
68     pctx->handler=handler;
69 
70     /* Decide controlling vs. controlled */
71     if(ctx->flags & NR_ICE_CTX_FLAGS_LITE){
72       pctx->controlling=0;
73     } else {
74       pctx->controlling=1;
75     }
76     if(r=nr_crypto_random_bytes((UCHAR *)&pctx->tiebreaker,8))
77       ABORT(r);
78 
79     STAILQ_INIT(&pctx->peer_streams);
80 
81     STAILQ_INSERT_TAIL(&ctx->peers,pctx,entry);
82 
83     *pctxp=pctx;
84 
85     _status = 0;
86   abort:
87     if(_status){
88       nr_ice_peer_ctx_destroy_cb(0,0,pctx);
89     }
90     return(_status);
91   }
92 
93 
94 
nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx * pctx,nr_ice_media_stream * stream,char ** attrs,int attr_ct)95 int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct)
96   {
97     nr_ice_media_stream *pstream=0;
98     nr_ice_component *comp,*comp2;
99     char *lufrag,*rufrag;
100     char *lpwd,*rpwd;
101     int r,_status;
102 
103     /*
104       Note: use component_ct from our own stream since components other
105       than this offered by the other side are unusable */
106     if(r=nr_ice_media_stream_create(pctx->ctx,stream->label,stream->component_ct,&pstream))
107       ABORT(r);
108 
109     /* Match up the local and remote components */
110     comp=STAILQ_FIRST(&stream->components);
111     comp2=STAILQ_FIRST(&pstream->components);
112     while(comp){
113       comp2->local_component=comp;
114 
115       comp=STAILQ_NEXT(comp,entry);
116       comp2=STAILQ_NEXT(comp2,entry);
117     }
118 
119     pstream->local_stream=stream;
120     pstream->pctx=pctx;
121 
122     if (r=nr_ice_peer_ctx_parse_stream_attributes_int(pctx,stream,pstream,attrs,attr_ct))
123       ABORT(r);
124 
125     /* Now that we have the ufrag and password, compute all the username/password
126        pairs */
127     lufrag=stream->ufrag?stream->ufrag:pctx->ctx->ufrag;
128     lpwd=stream->pwd?stream->pwd:pctx->ctx->pwd;
129     assert(lufrag);
130     assert(lpwd);
131     rufrag=pstream->ufrag?pstream->ufrag:pctx->peer_ufrag;
132     rpwd=pstream->pwd?pstream->pwd:pctx->peer_pwd;
133     if (!rufrag || !rpwd)
134       ABORT(R_BAD_DATA);
135 
136     if(r=nr_concat_strings(&pstream->r2l_user,lufrag,":",rufrag,NULL))
137       ABORT(r);
138     if(r=nr_concat_strings(&pstream->l2r_user,rufrag,":",lufrag,NULL))
139       ABORT(r);
140     if(r=r_data_make(&pstream->r2l_pass, (UCHAR *)lpwd, strlen(lpwd)))
141       ABORT(r);
142     if(r=r_data_make(&pstream->l2r_pass, (UCHAR *)rpwd, strlen(rpwd)))
143       ABORT(r);
144 
145     STAILQ_INSERT_TAIL(&pctx->peer_streams,pstream,entry);
146 
147     _status=0;
148   abort:
149     return(_status);
150   }
151 
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)152 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)
153   {
154     int r;
155     int i;
156 
157     for(i=0;i<attr_ct;i++){
158       if(!strncmp(attrs[i],"ice-",4)){
159         if(r=nr_ice_peer_ctx_parse_media_stream_attribute(pctx,pstream,attrs[i])) {
160           r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) specified bogus ICE attribute",pctx->ctx->label,pctx->label);
161           continue;
162         }
163       }
164       else if (!strncmp(attrs[i],"candidate",9)){
165         if(r=nr_ice_ctx_parse_candidate(pctx,pstream,attrs[i],0)) {
166           r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) specified bogus candidate",pctx->ctx->label,pctx->label);
167           continue;
168         }
169       }
170       else {
171         r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) specified bogus attribute: %s",pctx->ctx->label,pctx->label,attrs[i]);
172       }
173     }
174 
175     /* Doesn't fail because we just skip errors */
176     return(0);
177   }
178 
nr_ice_ctx_parse_candidate(nr_ice_peer_ctx * pctx,nr_ice_media_stream * pstream,char * candidate,int trickled)179 static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate, int trickled)
180   {
181     nr_ice_candidate *cand=0;
182     nr_ice_component *comp;
183     int j;
184     int r, _status;
185 
186     if(r=nr_ice_peer_candidate_from_attribute(pctx->ctx,candidate,pstream,&cand))
187       ABORT(r);
188     if(cand->component_id-1>=pstream->component_ct){
189       r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified too many components",pctx->ctx->label,pctx->label);
190       ABORT(R_BAD_DATA);
191     }
192 
193     /* set the trickled flag on the candidate */
194     cand->trickled = trickled;
195 
196     /* Not the fastest way to find a component, but it's what we got */
197     j=1;
198     for(comp=STAILQ_FIRST(&pstream->components);comp;comp=STAILQ_NEXT(comp,entry)){
199       if(j==cand->component_id)
200         break;
201 
202       j++;
203     }
204 
205     if(!comp){
206       r_log(LOG_ICE,LOG_WARNING,"Peer answered with more components than we offered");
207       ABORT(R_BAD_DATA);
208     }
209 
210     if (comp->state == NR_ICE_COMPONENT_DISABLED) {
211       r_log(LOG_ICE,LOG_WARNING,"Peer offered candidates for disabled remote component");
212       ABORT(R_BAD_DATA);
213     }
214     if (comp->local_component->state == NR_ICE_COMPONENT_DISABLED) {
215       r_log(LOG_ICE,LOG_WARNING,"Peer offered candidates for disabled local component");
216       ABORT(R_BAD_DATA);
217     }
218 
219     cand->component=comp;
220 
221     TAILQ_INSERT_TAIL(&comp->candidates,cand,entry_comp);
222 
223     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): creating peer candidate",
224       pctx->label,cand->label);
225 
226     _status=0;
227  abort:
228     if (_status) {
229       nr_ice_candidate_destroy(&cand);
230     }
231     return(_status);
232   }
233 
nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx * pctx,nr_ice_media_stream * stream,nr_ice_media_stream ** pstreamp)234 int nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream **pstreamp)
235   {
236     int _status;
237     nr_ice_media_stream *pstream;
238 
239     /* Because we don't have forward pointers, iterate through all the
240        peer streams to find one that matches us */
241      pstream=STAILQ_FIRST(&pctx->peer_streams);
242      while(pstream) {
243        if (pstream->local_stream == stream)
244          break;
245 
246        pstream = STAILQ_NEXT(pstream, entry);
247      }
248      if (!pstream) {
249        r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label);
250        ABORT(R_NOT_FOUND);
251      }
252 
253     *pstreamp = pstream;
254 
255     _status=0;
256  abort:
257     return(_status);
258   }
259 
nr_ice_peer_ctx_remove_pstream(nr_ice_peer_ctx * pctx,nr_ice_media_stream ** pstreamp)260 int nr_ice_peer_ctx_remove_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream **pstreamp)
261   {
262     int r,_status;
263 
264     STAILQ_REMOVE(&pctx->peer_streams,*pstreamp,nr_ice_media_stream_,entry);
265 
266     if(r=nr_ice_media_stream_destroy(pstreamp)) {
267       ABORT(r);
268     }
269 
270     _status=0;
271  abort:
272     return(_status);
273   }
274 
nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx * pctx,nr_ice_media_stream * stream,char * candidate)275 int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate)
276   {
277     nr_ice_media_stream *pstream;
278     int r,_status;
279     int needs_pairing = 0;
280 
281     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): peer (%s) parsing trickle ICE candidate %s",pctx->ctx->label,pctx->label,candidate);
282     r = nr_ice_peer_ctx_find_pstream(pctx, stream, &pstream);
283     if (r)
284       ABORT(r);
285 
286     switch(pstream->ice_state) {
287       case NR_ICE_MEDIA_STREAM_UNPAIRED:
288         break;
289       case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN:
290       case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE:
291         needs_pairing = 1;
292         break;
293       default:
294         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);
295         ABORT(R_ALREADY);
296         break;
297     }
298 
299     if(r=nr_ice_ctx_parse_candidate(pctx,pstream,candidate,1)){
300       ABORT(r);
301     }
302 
303     /* If ICE is running (i.e., we are in FROZEN or ACTIVE states)
304        then we need to pair this new candidate. For now we
305        just re-pair the stream which is inefficient but still
306        fine because we suppress duplicate pairing */
307     if (needs_pairing) {
308       if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) {
309         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);
310         ABORT(r);
311       }
312 
313       /* Start the remote trickle grace timeout if it hasn't been started by
314          another trickled candidate or from the SDP. */
315       if (!pctx->trickle_grace_period_timer) {
316         nr_ice_peer_ctx_start_trickle_timer(pctx);
317       }
318 
319       /* Start checks if this stream is not checking yet or if it has checked
320          all the available candidates but not had a completed check for all
321          components.
322 
323          Note that this is not compliant with RFC 5245, but consistent with
324          the libjingle trickle ICE behavior. Note that we will not restart
325          checks if either (a) the stream has failed or (b) all components
326          have a successful pair because the switch statement above jumps
327          will in both states.
328 
329          TODO(ekr@rtfm.com): restart checks.
330          TODO(ekr@rtfm.com): update when the trickle ICE RFC is published
331       */
332       if (!pstream->timer) {
333         if(r=nr_ice_media_stream_start_checks(pctx, pstream)) {
334           r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) failed to start checks",pctx->ctx->label,pctx->label,stream->label);
335           ABORT(r);
336         }
337       }
338     }
339 
340     _status=0;
341  abort:
342     return(_status);
343 
344   }
345 
346 
nr_ice_peer_ctx_trickle_wait_cb(NR_SOCKET s,int how,void * cb_arg)347 static void nr_ice_peer_ctx_trickle_wait_cb(NR_SOCKET s, int how, void *cb_arg)
348   {
349     nr_ice_peer_ctx *pctx=cb_arg;
350     nr_ice_media_stream *stream;
351     nr_ice_component *comp;
352 
353     pctx->trickle_grace_period_timer=0;
354 
355     r_log(LOG_ICE,LOG_INFO,"ICE(%s): peer (%s) Trickle grace period is over; marking every component with only failed pairs as failed.",pctx->ctx->label,pctx->label);
356 
357     stream=STAILQ_FIRST(&pctx->peer_streams);
358     while(stream){
359       comp=STAILQ_FIRST(&stream->components);
360       while(comp){
361         nr_ice_component_check_if_failed(comp);
362         comp=STAILQ_NEXT(comp,entry);
363       }
364       stream=STAILQ_NEXT(stream,entry);
365     }
366   }
367 
nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx * pctx)368 static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx)
369   {
370     UINT4 grace_period_timeout=0;
371 
372     if(pctx->trickle_grace_period_timer) {
373       NR_async_timer_cancel(pctx->trickle_grace_period_timer);
374       pctx->trickle_grace_period_timer=0;
375     }
376 
377     NR_reg_get_uint4(NR_ICE_REG_TRICKLE_GRACE_PERIOD,&grace_period_timeout);
378 
379     if (grace_period_timeout) {
380       /* If we're doing trickle, we need to allow a grace period for new
381        * trickle candidates to arrive in case the pairs we have fail quickly. */
382        NR_ASYNC_TIMER_SET(grace_period_timeout,nr_ice_peer_ctx_trickle_wait_cb,pctx,&pctx->trickle_grace_period_timer);
383     }
384   }
385 
nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx * pctx)386 int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
387   {
388     nr_ice_media_stream *stream;
389     int r,_status;
390 
391     if(pctx->peer_lite && !pctx->controlling) {
392       if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_LITE){
393         r_log(LOG_ICE,LOG_ERR,"Both sides are ICE-Lite");
394         ABORT(R_BAD_DATA);
395       }
396       nr_ice_peer_ctx_switch_controlling_role(pctx);
397     }
398 
399     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): peer (%s) pairing candidates",pctx->ctx->label,pctx->label);
400 
401     if(STAILQ_EMPTY(&pctx->peer_streams)) {
402         r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) received no media stream attributes",pctx->ctx->label,pctx->label);
403         ABORT(R_FAILED);
404     }
405 
406     /* Set this first; if we fail partway through, we do not want to end
407      * up in UNPAIRED after creating some pairs. */
408     pctx->state = NR_ICE_PEER_STATE_PAIRED;
409 
410     stream=STAILQ_FIRST(&pctx->peer_streams);
411     while(stream){
412       if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream,
413         stream))
414         ABORT(r);
415 
416       stream=STAILQ_NEXT(stream,entry);
417     }
418 
419 
420     _status=0;
421   abort:
422     return(_status);
423   }
424 
425 
nr_ice_peer_ctx_pair_new_trickle_candidate(nr_ice_ctx * ctx,nr_ice_peer_ctx * pctx,nr_ice_candidate * cand)426 int nr_ice_peer_ctx_pair_new_trickle_candidate(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx, nr_ice_candidate *cand)
427   {
428     int r, _status;
429     nr_ice_media_stream *pstream;
430 
431     r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) pairing local trickle ICE candidate %s",pctx->ctx->label,pctx->label,cand->label);
432     if ((r = nr_ice_peer_ctx_find_pstream(pctx, cand->stream, &pstream)))
433       ABORT(r);
434 
435     if ((r = nr_ice_media_stream_pair_new_trickle_candidate(pctx, pstream, cand)))
436       ABORT(r);
437 
438     /* Start the remote trickle grace timeout if it hasn't been started
439        already. */
440     if (!pctx->trickle_grace_period_timer) {
441       nr_ice_peer_ctx_start_trickle_timer(pctx);
442     }
443 
444     _status=0;
445  abort:
446     return _status;
447   }
448 
nr_ice_peer_ctx_disable_component(nr_ice_peer_ctx * pctx,nr_ice_media_stream * lstream,int component_id)449 int nr_ice_peer_ctx_disable_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *lstream, int component_id)
450   {
451     int r, _status;
452     nr_ice_media_stream *pstream;
453     nr_ice_component *component;
454 
455     if ((r=nr_ice_peer_ctx_find_pstream(pctx, lstream, &pstream)))
456       ABORT(r);
457 
458     /* We shouldn't be calling this after we have started pairing */
459     if (pstream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED)
460       ABORT(R_FAILED);
461 
462     if ((r=nr_ice_media_stream_find_component(pstream, component_id,
463                                               &component)))
464       ABORT(r);
465 
466     component->state = NR_ICE_COMPONENT_DISABLED;
467 
468     _status=0;
469  abort:
470     return(_status);
471   }
472 
nr_ice_peer_ctx_destroy_cb(NR_SOCKET s,int how,void * cb_arg)473 static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg)
474   {
475     nr_ice_peer_ctx *pctx=cb_arg;
476     nr_ice_media_stream *str1,*str2;
477 
478     NR_async_timer_cancel(pctx->connected_cb_timer);
479     RFREE(pctx->label);
480     RFREE(pctx->peer_ufrag);
481     RFREE(pctx->peer_pwd);
482 
483     STAILQ_FOREACH_SAFE(str1, &pctx->peer_streams, entry, str2){
484       STAILQ_REMOVE(&pctx->peer_streams,str1,nr_ice_media_stream_,entry);
485       nr_ice_media_stream_destroy(&str1);
486     }
487     assert(pctx->ctx);
488     if (pctx->ctx)
489       STAILQ_REMOVE(&pctx->ctx->peers, pctx, nr_ice_peer_ctx_, entry);
490 
491     if(pctx->trickle_grace_period_timer) {
492       NR_async_timer_cancel(pctx->trickle_grace_period_timer);
493       pctx->trickle_grace_period_timer=0;
494     }
495 
496     RFREE(pctx);
497   }
498 
nr_ice_peer_ctx_destroy(nr_ice_peer_ctx ** pctxp)499 int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp)
500   {
501 
502     if(!pctxp || !*pctxp)
503       return(0);
504 
505     /* Stop calling the handler */
506     (*pctxp)->handler = 0;
507 
508     NR_ASYNC_SCHEDULE(nr_ice_peer_ctx_destroy_cb,*pctxp);
509 
510     *pctxp=0;
511 
512     return(0);
513   }
514 
515 
516 /* Start the checks for the first media stream (S 5.7)
517    The rest remain FROZEN */
nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx * pctx)518 int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx)
519   {
520     return nr_ice_peer_ctx_start_checks2(pctx, 0);
521   }
522 
523 /* Start checks for some media stream.
524 
525    If allow_non_first == 0, then we only look at the first stream,
526    which is 5245-complaint.
527 
528    If allow_non_first == 1 then we find the first non-empty stream
529    This is not compliant with RFC 5245 but is necessary to make trickle ICE
530    work plausibly
531 */
nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx * pctx,int allow_non_first)532 int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first)
533   {
534     int r,_status;
535     nr_ice_media_stream *stream;
536     int started = 0;
537 
538     /* Might have added some streams */
539     pctx->reported_connected = 0;
540     NR_async_timer_cancel(pctx->connected_cb_timer);
541     pctx->connected_cb_timer = 0;
542     pctx->checks_started = 0;
543 
544     if((r=nr_ice_peer_ctx_check_if_connected(pctx))) {
545       r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) initial connected check failed",pctx->ctx->label,pctx->label);
546       ABORT(r);
547     }
548 
549     if (pctx->reported_connected) {
550       r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) in %s all streams were done",pctx->ctx->label,pctx->label,__FUNCTION__);
551       return (0);
552     }
553 
554     stream=STAILQ_FIRST(&pctx->peer_streams);
555     if(!stream)
556       ABORT(R_FAILED);
557 
558     while (stream) {
559       assert(stream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED);
560 
561       if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN) {
562         if(!TAILQ_EMPTY(&stream->check_list))
563           break;
564 
565         if(!allow_non_first){
566           /* This test applies if:
567 
568              1. allow_non_first is 0 (i.e., non-trickle ICE)
569              2. the first stream has an empty check list.
570 
571              But in the non-trickle ICE case, the other side should have provided
572              some candidates or ICE is pretty much not going to work and we're
573              just going to fail. Hence R_FAILED as opposed to R_NOT_FOUND and
574              immediate termination here.
575           */
576           r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) first stream has empty check list",pctx->ctx->label,pctx->label);
577           ABORT(R_FAILED);
578         }
579       }
580 
581       stream=STAILQ_NEXT(stream, entry);
582     }
583 
584     if (!stream) {
585       /*
586          We fail above if we aren't doing trickle, and this is not all that
587          unusual in the trickle case.
588        */
589       r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): peer (%s) no streams with non-empty check lists",pctx->ctx->label,pctx->label);
590     }
591     else if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN) {
592       if(r=nr_ice_media_stream_unfreeze_pairs(pctx,stream))
593         ABORT(r);
594       if(r=nr_ice_media_stream_start_checks(pctx,stream))
595         ABORT(r);
596       ++started;
597     }
598 
599     stream=STAILQ_FIRST(&pctx->peer_streams);
600     while (stream) {
601       int serviced = 0;
602       if (r=nr_ice_media_stream_service_pre_answer_requests(pctx, stream->local_stream, stream, &serviced))
603         ABORT(r);
604 
605       if (serviced) {
606         ++started;
607       }
608       else {
609         r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): peer (%s) no streams with pre-answer requests",pctx->ctx->label,pctx->label);
610       }
611 
612 
613       stream=STAILQ_NEXT(stream, entry);
614     }
615 
616     if (!started) {
617       r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): peer (%s) no checks to start",pctx->ctx->label,pctx->label);
618       ABORT(R_NOT_FOUND);
619     }
620     else {
621       /* Start grace period timer for more remote trickle candidates. */
622       nr_ice_peer_ctx_start_trickle_timer(pctx);
623     }
624 
625     _status=0;
626   abort:
627     return(_status);
628   }
629 
nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx * pctx,nr_ice_media_stream * stream)630 void nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
631   {
632     if (!pctx->checks_started) {
633       r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): peer (%s) is now checking",pctx->ctx->label,pctx->label);
634       pctx->checks_started = 1;
635       if (pctx->handler && pctx->handler->vtbl->ice_checking) {
636         pctx->handler->vtbl->ice_checking(pctx->handler->obj, pctx);
637       }
638     }
639   }
640 
641 #ifndef NDEBUG
nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx * pctx,FILE * out)642 int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out)
643   {
644     int r,_status;
645     nr_ice_media_stream *stream;
646 
647     fprintf(out,"PEER %s STATE DUMP\n",pctx->label);
648     fprintf(out,"==========================================\n");
649     stream=STAILQ_FIRST(&pctx->peer_streams);
650     while(stream){
651       if(r=nr_ice_media_stream_dump_state(pctx,stream,out))
652         ABORT(r);
653 
654       stream=STAILQ_NEXT(stream,entry);
655     }
656     fprintf(out,"==========================================\n");
657 
658     _status=0;
659   abort:
660     return(_status);
661   }
662 #endif
663 
nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx * pctx)664 void nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx *pctx)
665   {
666     nr_ice_media_stream *str;
667 
668     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): refreshing consent on all streams",pctx->label);
669 
670     str=STAILQ_FIRST(&pctx->peer_streams);
671     while(str) {
672       nr_ice_media_stream_refresh_consent_all(str);
673       str=STAILQ_NEXT(str,entry);
674     }
675   }
676 
nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx * pctx)677 void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx)
678   {
679     if (pctx->reported_connected &&
680         pctx->handler &&
681         pctx->handler->vtbl->ice_disconnected) {
682       pctx->handler->vtbl->ice_disconnected(pctx->handler->obj, pctx);
683 
684       pctx->reported_connected = 0;
685     }
686   }
687 
nr_ice_peer_ctx_disconnect_all_streams(nr_ice_peer_ctx * pctx)688 void nr_ice_peer_ctx_disconnect_all_streams(nr_ice_peer_ctx *pctx)
689   {
690     nr_ice_media_stream *str;
691 
692     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): disconnecting all streams",pctx->label);
693 
694     str=STAILQ_FIRST(&pctx->peer_streams);
695     while(str) {
696       nr_ice_media_stream_disconnect_all_components(str);
697 
698       /* The first stream to be disconnected will cause the peer ctx to signal
699          the disconnect up. */
700       nr_ice_media_stream_set_disconnected(str, NR_ICE_MEDIA_STREAM_DISCONNECTED);
701 
702       str=STAILQ_NEXT(str,entry);
703     }
704   }
705 
nr_ice_peer_ctx_connected(nr_ice_peer_ctx * pctx)706 void nr_ice_peer_ctx_connected(nr_ice_peer_ctx *pctx)
707   {
708     /* Fire the handler callback to say we're done */
709     if (pctx->reported_connected &&
710         pctx->handler &&
711         pctx->handler->vtbl->ice_connected) {
712       pctx->handler->vtbl->ice_connected(pctx->handler->obj, pctx);
713     }
714   }
715 
nr_ice_peer_ctx_fire_connected(NR_SOCKET s,int how,void * cb_arg)716 static void nr_ice_peer_ctx_fire_connected(NR_SOCKET s, int how, void *cb_arg)
717   {
718     nr_ice_peer_ctx *pctx=cb_arg;
719 
720     pctx->connected_cb_timer=0;
721 
722     nr_ice_peer_ctx_connected(pctx);
723   }
724 
725 /* Examine all the streams to see if we're
726    maybe miraculously connected */
nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx * pctx)727 int nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx)
728   {
729     int _status;
730     nr_ice_media_stream *str;
731     int failed=0;
732     int succeeded=0;
733 
734     str=STAILQ_FIRST(&pctx->peer_streams);
735     while(str){
736       if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED){
737         succeeded++;
738       }
739       else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED){
740         failed++;
741       }
742       else{
743         break;
744       }
745       str=STAILQ_NEXT(str,entry);
746     }
747 
748     if(str)
749       goto done;  /* Something isn't done */
750 
751     /* OK, we're finished, one way or another */
752     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): all checks completed success=%d fail=%d",pctx->label,succeeded,failed);
753 
754     /* Schedule a connected notification for the first connected event.
755        IMPORTANT: This is done in a callback because we expect destructors
756        of various kinds to be fired from here */
757     if (!pctx->reported_connected) {
758       pctx->reported_connected = 1;
759       assert(!pctx->connected_cb_timer);
760       NR_ASYNC_TIMER_SET(0,nr_ice_peer_ctx_fire_connected,pctx,&pctx->connected_cb_timer);
761     }
762 
763   done:
764     _status=0;
765     return(_status);
766   }
767 
768 
769 /* Given a component in the main ICE ctx, find the relevant component in
770    the peer_ctx */
nr_ice_peer_ctx_find_component(nr_ice_peer_ctx * pctx,nr_ice_media_stream * str,int component_id,nr_ice_component ** compp)771 int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp)
772   {
773     nr_ice_media_stream *pstr;
774     int r,_status;
775 
776     pstr=STAILQ_FIRST(&pctx->peer_streams);
777     while(pstr){
778       if(pstr->local_stream==str)
779         break;
780 
781       pstr=STAILQ_NEXT(pstr,entry);
782     }
783     if(!pstr)
784       ABORT(R_BAD_ARGS);
785 
786     if(r=nr_ice_media_stream_find_component(pstr,component_id,compp))
787       ABORT(r);
788 
789     _status=0;
790   abort:
791     return(_status);
792   }
793 
794 /*
795    This packet may be for us.
796 
797    1. Find the matching peer component
798    2. Examine the packet source address to see if it matches
799    one of the peer candidates.
800    3. Fire the relevant callback handler if there is a match
801 
802    Return 0 if match, R_REJECTED if no match, other errors
803    if we can't even find the component or something like that.
804 */
805 
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)806 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)
807   {
808     nr_ice_component *peer_comp;
809     nr_ice_candidate *cand;
810     int r,_status;
811 
812     if(r=nr_ice_peer_ctx_find_component(pctx, comp->stream, comp->component_id,
813       &peer_comp))
814       ABORT(r);
815 
816     /* OK, we've found the component, now look for matches */
817     cand=TAILQ_FIRST(&peer_comp->candidates);
818     while(cand){
819       if(!nr_transport_addr_cmp(source_addr,&cand->addr,
820         NR_TRANSPORT_ADDR_CMP_MODE_ALL))
821         break;
822 
823       cand=TAILQ_NEXT(cand,entry_comp);
824     }
825 
826     if(!cand)
827       ABORT(R_REJECTED);
828 
829     // accumulate the received bytes for the active candidate pair
830     if (peer_comp->active) {
831       peer_comp->active->bytes_recvd += len;
832       gettimeofday(&peer_comp->active->last_recvd, 0);
833     }
834 
835     /* OK, there's a match. Call the handler */
836 
837     if (pctx->handler) {
838       r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Delivering data", pctx->label);
839 
840       pctx->handler->vtbl->msg_recvd(pctx->handler->obj,
841         pctx,comp->stream,comp->component_id,data,len);
842     }
843 
844     _status=0;
845   abort:
846     return(_status);
847   }
848 
nr_ice_peer_ctx_switch_controlling_role(nr_ice_peer_ctx * pctx)849 void nr_ice_peer_ctx_switch_controlling_role(nr_ice_peer_ctx *pctx)
850   {
851     int controlling = !(pctx->controlling);
852     if(pctx->controlling_conflict_resolved) {
853       r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) %s called more than once; "
854             "this probably means the peer is confused. Not switching roles.",
855             pctx->ctx->label,pctx->label,__FUNCTION__);
856       return;
857     }
858 
859     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): detected "
860           "role conflict. Switching to %s",
861           pctx->label,
862           controlling ? "controlling" : "controlled");
863 
864     pctx->controlling = controlling;
865     pctx->controlling_conflict_resolved = 1;
866 
867     if(pctx->state == NR_ICE_PEER_STATE_PAIRED) {
868       /*  We have formed candidate pairs. We need to inform them. */
869       nr_ice_media_stream *pstream=STAILQ_FIRST(&pctx->peer_streams);
870       while(pstream) {
871         nr_ice_media_stream_role_change(pstream);
872         pstream = STAILQ_NEXT(pstream, entry);
873       }
874     }
875   }
876 
877