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