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