Bug Summary

File:root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_peer_ctx.cpp
Warning:line 163, column 12
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ice_peer_ctx.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media/webrtc/transport/third_party/nICEr/nicer_nicer -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media/webrtc/transport/third_party/nICEr/nicer_nicer -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D _FILE_OFFSET_BITS=64 -D CHROMIUM_BUILD -D USE_LIBJPEG_TURBO=1 -D USE_NSS=1 -D ENABLE_ONE_CLICK_SIGNIN -D GTK_DISABLE_SINGLE_INCLUDES=1 -D _ISOC99_SOURCE=1 -D ENABLE_REMOTING=1 -D ENABLE_WEBRTC=1 -D ENABLE_CONFIGURATION_POLICY -D ENABLE_INPUT_SPEECH -D ENABLE_NOTIFICATIONS -D ENABLE_GPU=1 -D ENABLE_EGLIMAGE=1 -D USE_SKIA=1 -D ENABLE_TASK_MANAGER=1 -D ENABLE_WEB_INTENTS=1 -D ENABLE_EXTENSIONS=1 -D ENABLE_PLUGIN_INSTALLATION=1 -D ENABLE_PROTECTOR_SERVICE=1 -D ENABLE_SESSION_SERVICE=1 -D ENABLE_THEMES=1 -D ENABLE_BACKGROUND=1 -D ENABLE_AUTOMATION=1 -D ENABLE_PRINTING=1 -D ENABLE_CAPTIVE_PORTAL_DETECTION=1 -D SANITY_CHECKS -D USE_TURN -D USE_ICE -D USE_RFC_3489_BACKWARDS_COMPATIBLE -D USE_STUN_PEDANTIC -D NR_SOCKET_IS_VOID_PTR -D restrict= -D R_PLATFORM_INT_TYPES=<stdint.h> -D R_DEFINED_INT2=int16_t -D R_DEFINED_UINT2=uint16_t -D R_DEFINED_INT4=int32_t -D R_DEFINED_UINT4=uint32_t -D R_DEFINED_INT8=int64_t -D R_DEFINED_UINT8=uint64_t -D LINUX -D HAVE_LIBM=1 -D HAVE_STRDUP=1 -D HAVE_STRLCPY=1 -D HAVE_SYS_TIME_H=1 -D HAVE_VFPRINTF=1 -D NEW_STDIORETSIGTYPE=void -D TIME_WITH_SYS_TIME_H=1 -D __UNUSED__=__attribute__((unused)) -D DYNAMIC_ANNOTATIONS_ENABLED=1 -D WTF_USE_DYNAMIC_ANNOTATIONS=1 -D _DEBUG -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media/webrtc/transport/third_party/nICEr/nicer_nicer -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/event -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/log -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/registry -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/share -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/util -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/util/libekr -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/port/generic/include -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/crypto -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/net -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/stun -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/util -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/port/linux/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-parentheses -Wno-format -Wno-format-security -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c++ /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_peer_ctx.cpp
1/*
2Copyright (c) 2007, Adobe Systems, Incorporated
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
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
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30OF 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
45static 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);
46static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate, int trickled, const char *resolved_address);
47static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx);
48
49int 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=R_NEW(nr_ice_peer_ctx)(nr_ice_peer_ctx*)calloc(1,sizeof(nr_ice_peer_ctx))))
55 ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
56
57 pctx->state = NR_ICE_PEER_STATE_UNPAIRED1;
58
59 if(!(pctx->label=strdup(label)))
60 ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
61
62 pctx->ctx=ctx;
63 pctx->handler=handler;
64
65 /* Decide controlling vs. controlled */
66 if(ctx->flags & NR_ICE_CTX_FLAGS_LITE(1<<1)){
67 pctx->controlling=0;
68 } else {
69 pctx->controlling=1;
70 }
71 if(r=nr_crypto_random_bytes((UCHAR *)&pctx->tiebreaker,8)nr_crypto_vtbl->random_bytes((UCHAR *)&pctx->tiebreaker
,8)
)
72 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
73
74 STAILQ_INIT(&pctx->peer_streams)do { (((&pctx->peer_streams))->stqh_first) = __null
; (&pctx->peer_streams)->stqh_last = &(((&pctx
->peer_streams))->stqh_first); } while (0)
;
75
76 STAILQ_INSERT_TAIL(&ctx->peers,pctx,entry)do { (((pctx))->entry.stqe_next) = __null; *(&ctx->
peers)->stqh_last = (pctx); (&ctx->peers)->stqh_last
= &(((pctx))->entry.stqe_next); } while (0)
;
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
88int nr_ice_peer_ctx_aggressive_nomination(nr_ice_peer_ctx *pctx)
89 {
90 return (pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION(1)) &&
91 !pctx->peer_lite;
92 }
93
94
95
96int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct)
97 {
98 nr_ice_media_stream *pstream=0;
99 nr_ice_component *comp,*comp2;
100 char *lufrag,*rufrag;
101 char *lpwd,*rpwd;
102 int r,_status;
103
104 /*
105 Note: use component_ct from our own stream since components other
106 than this offered by the other side are unusable */
107 if(r=nr_ice_media_stream_create(pctx->ctx,stream->label,"","",stream->component_ct,&pstream))
108 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
109
110 /* Match up the local and remote components */
111 comp=STAILQ_FIRST(&stream->components)((&stream->components)->stqh_first);
112 comp2=STAILQ_FIRST(&pstream->components)((&pstream->components)->stqh_first);
113 while(comp){
114 comp2->local_component=comp;
115
116 comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next);
117 comp2=STAILQ_NEXT(comp2,entry)((comp2)->entry.stqe_next);
118 }
119
120 pstream->local_stream=stream;
121 pstream->pctx=pctx;
122
123 nr_ice_peer_ctx_parse_stream_attributes_int(pctx,stream,pstream,attrs,attr_ct);
124
125 /* Now that we have the ufrag and password, compute all the username/password
126 pairs */
127 lufrag=stream->ufrag;
128 lpwd=stream->pwd;
129 assert(lufrag)(static_cast <bool> (lufrag) ? void (0) : __assert_fail
("lufrag", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
130 assert(lpwd)(static_cast <bool> (lpwd) ? void (0) : __assert_fail (
"lpwd", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
131 rufrag=pstream->ufrag;
132 rpwd=pstream->pwd;
133 if (!rufrag || !rpwd)
134 ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
135
136 if(r=nr_concat_strings(&pstream->r2l_user,lufrag,":",rufrag,NULL__null))
137 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
138 if(r=nr_concat_strings(&pstream->l2r_user,rufrag,":",lufrag,NULL__null))
139 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
140 if(r=r_data_make(&pstream->r2l_pass, (UCHAR *)lpwd, strlen(lpwd)))
141 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
142 if(r=r_data_make(&pstream->l2r_pass, (UCHAR *)rpwd, strlen(rpwd)))
143 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
144
145 STAILQ_INSERT_TAIL(&pctx->peer_streams,pstream,entry)do { (((pstream))->entry.stqe_next) = __null; *(&pctx->
peer_streams)->stqh_last = (pstream); (&pctx->peer_streams
)->stqh_last = &(((pstream))->entry.stqe_next); } while
(0)
;
146 pstream=0;
147
148 _status=0;
149 abort:
150 if (_status) {
151 nr_ice_media_stream_destroy(&pstream);
152 }
153 return(_status);
154 }
155
156static 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)
157 {
158 int r;
159 int i;
160
161 for(i=0;i<attr_ct;i++){
162 if(!strncmp(attrs[i],"ice-",4)){
163 if(r=nr_ice_peer_ctx_parse_media_stream_attribute(pctx,pstream,attrs[i])) {
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'
164 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) specified bogus ICE attribute",pctx->ctx->label,pctx->label);
165 continue;
166 }
167 }
168 else if (!strncmp(attrs[i],"candidate",9)){
169 if(r=nr_ice_ctx_parse_candidate(pctx,pstream,attrs[i],0,0)) {
170 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) specified bogus candidate",pctx->ctx->label,pctx->label);
171 continue;
172 }
173 }
174 else {
175 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) specified bogus attribute: %s",pctx->ctx->label,pctx->label,attrs[i]);
176 }
177 }
178
179 /* Doesn't fail because we just skip errors */
180 }
181
182static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate, int trickled, const char *resolved_address)
183 {
184 nr_ice_candidate *cand=0;
185 nr_ice_component *comp;
186 int j;
187 int r, _status;
188
189 if(r=nr_ice_peer_candidate_from_attribute(pctx->ctx,candidate,pstream,resolved_address,&cand))
190 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
191
192 /* set the trickled flag on the candidate */
193 cand->trickled = trickled;
194
195 /* Not the fastest way to find a component, but it's what we got */
196 j=1;
197 for(comp=STAILQ_FIRST(&pstream->components)((&pstream->components)->stqh_first);comp;comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next)){
198 if(j==cand->component_id)
199 break;
200
201 j++;
202 }
203
204 if(!comp){
205 /* Very common for the answerer when it uses rtcp-mux */
206 r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) no such component for candidate %s",pctx->ctx->label,pctx->label, candidate);
207 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
208 }
209
210 if (comp->state == NR_ICE_COMPONENT_DISABLED4) {
211 r_log(LOG_ICE,LOG_WARNING4,"Peer offered candidate for disabled remote component: %s", candidate);
212 ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
213 }
214 if (comp->local_component->state == NR_ICE_COMPONENT_DISABLED4) {
215 r_log(LOG_ICE,LOG_WARNING4,"Peer offered candidate for disabled local component: %s", candidate);
216 ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
217 }
218
219 cand->component=comp;
220
221 TAILQ_INSERT_TAIL(&comp->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&comp->candidates)->tqh_last
; *(&comp->candidates)->tqh_last = (cand); (&comp
->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
222
223 r_log(LOG_ICE,LOG_DEBUG7,"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
234int 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)((&pctx->peer_streams)->stqh_first);
242
243 if(!pstream) {
244 /* No peer streams at all, presumably because they do not exist yet.
245 * Don't log a warning here. */
246 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
247 }
248
249 while(pstream) {
250 if (pstream->local_stream == stream)
251 break;
252
253 pstream = STAILQ_NEXT(pstream, entry)((pstream)->entry.stqe_next);
254 }
255
256 if (!pstream) {
257 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label);
258 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
259 }
260
261 *pstreamp = pstream;
262
263 _status=0;
264 abort:
265 return(_status);
266 }
267
268int nr_ice_peer_ctx_remove_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream **pstreamp)
269 {
270 int r,_status;
271
272 /* Update pctx->active_streams, which paces the check timers. Not
273 done through nr_ice_media_stream_set_state(), since there is no state
274 that means "gone". */
275 if((*pstreamp)->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3) {
276 pctx->active_streams--;
277 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s): removing stream %s while it is checking; %d active streams",pctx->label,(*pstreamp)->label,pctx->active_streams);
278 }
279
280 STAILQ_REMOVE(&pctx->peer_streams,*pstreamp,nr_ice_media_stream_,entry)do { if ((((&pctx->peer_streams))->stqh_first) == (
*pstreamp)) { do { if ((((((&pctx->peer_streams)))->
stqh_first) = ((((((&pctx->peer_streams)))->stqh_first
))->entry.stqe_next)) == __null) ((&pctx->peer_streams
))->stqh_last = &((((&pctx->peer_streams)))->
stqh_first); } while (0); } else { struct nr_ice_media_stream_
*curelm = (((&pctx->peer_streams))->stqh_first); while
(((curelm)->entry.stqe_next) != (*pstreamp)) curelm = ((curelm
)->entry.stqe_next); if ((((curelm)->entry.stqe_next) =
((((curelm)->entry.stqe_next))->entry.stqe_next)) == __null
) (&pctx->peer_streams)->stqh_last = &(((curelm
))->entry.stqe_next); } } while (0)
;
281
282 if(r=nr_ice_media_stream_destroy(pstreamp)) {
283 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
284 }
285
286 /* The removed stream may have been the one the others were frozen
287 behind, or the last one holding up completion. */
288 nr_ice_peer_ctx_react_to_stream_change(pctx);
289
290 _status=0;
291 abort:
292 return(_status);
293 }
294
295int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate, const char *resolved_address)
296 {
297 nr_ice_media_stream *pstream;
298 int r,_status;
299 int needs_pairing = 0;
300
301 if (stream->obsolete) {
302 return 0;
303 }
304
305 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): peer (%s) parsing trickle ICE candidate %s",pctx->ctx->label,pctx->label,candidate);
306 r = nr_ice_peer_ctx_find_pstream(pctx, stream, &pstream);
307 if (r)
308 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
309
310 switch(pstream->ice_state) {
311 case NR_ICE_MEDIA_STREAM_UNPAIRED1:
312 break;
313 case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2:
314 case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3:
315 needs_pairing = 1;
316 break;
317 default:
318 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s), stream(%s) tried to trickle ICE in inappropriate state %d",pctx->ctx->label,pctx->label,stream->label,pstream->ice_state);
319 ABORT(R_ALREADY)do { int _r=4; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
320 break;
321 }
322
323 if(r=nr_ice_ctx_parse_candidate(pctx,pstream,candidate,1,resolved_address)){
324 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
325 }
326
327 /* If ICE is running (i.e., we are in FROZEN or ACTIVE states)
328 then we need to pair this new candidate. For now we
329 just re-pair the stream which is inefficient but still
330 fine because we suppress duplicate pairing */
331 if (needs_pairing) {
332 /* Start the remote trickle grace timeout if it hasn't been started by
333 another trickled candidate or from the SDP. */
334 if (!pctx->trickle_grace_period_timer) {
335 nr_ice_peer_ctx_start_trickle_timer(pctx);
336 }
337
338 if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) {
339 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s), stream(%s) failed to pair trickle ICE candidates",pctx->ctx->label,pctx->label,stream->label);
340 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
341 }
342
343 /* Start checks if this stream is not checking yet or if it has checked
344 all the available candidates but not had a completed check for all
345 components.
346
347 Note that this is not compliant with RFC 5245, but consistent with
348 the libjingle trickle ICE behavior. Note that we will not restart
349 checks if either (a) the stream has failed or (b) all components
350 have a successful pair because the switch statement above jumps
351 will in both states.
352
353 TODO(ekr@rtfm.com): restart checks.
354 TODO(ekr@rtfm.com): update when the trickle ICE RFC is published
355 */
356 if (!pstream->timer) {
357 if(r=nr_ice_media_stream_start_checks(pctx, pstream)) {
358 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s), stream(%s) failed to start checks",pctx->ctx->label,pctx->label,stream->label);
359 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
360 }
361 }
362 }
363
364 _status=0;
365 abort:
366 return(_status);
367
368 }
369
370
371static void nr_ice_peer_ctx_trickle_wait_cb(NR_SOCKET s, int how, void *cb_arg)
372 {
373 nr_ice_peer_ctx *pctx=(nr_ice_peer_ctx*)cb_arg;
374 nr_ice_media_stream *stream;
375 nr_ice_component *comp;
376
377 pctx->trickle_grace_period_timer=0;
378
379 r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) Trickle grace period is over; marking every component with only failed pairs as failed.",pctx->ctx->label,pctx->label);
380
381 stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
382 while(stream){
383 comp=STAILQ_FIRST(&stream->components)((&stream->components)->stqh_first);
384 while(comp){
385 nr_ice_component_check_if_failed(comp);
386 comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next);
387 }
388 stream=STAILQ_NEXT(stream,entry)((stream)->entry.stqe_next);
389 }
390 }
391
392static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx)
393 {
394 UINT4 grace_period_timeout=0;
395
396 if(pctx->trickle_grace_period_timer) {
397 NR_async_timer_cancel(pctx->trickle_grace_period_timer);
398 pctx->trickle_grace_period_timer=0;
399 }
400
401 NR_reg_get_uint4(NR_ICE_REG_TRICKLE_GRACE_PERIOD"ice.trickle_grace_period",&grace_period_timeout);
402
403 if (grace_period_timeout) {
404 r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) starting grace period timer for %u ms",pctx->ctx->label,pctx->label, grace_period_timeout);
405 /* If we're doing trickle, we need to allow a grace period for new
406 * trickle candidates to arrive in case the pairs we have fail quickly. */
407 NR_ASYNC_TIMER_SET(grace_period_timeout,nr_ice_peer_ctx_trickle_wait_cb,pctx,&pctx->trickle_grace_period_timer)NR_async_timer_set(grace_period_timeout,nr_ice_peer_ctx_trickle_wait_cb
,pctx,(char *)__FUNCTION__,407,&pctx->trickle_grace_period_timer
)
;
408 }
409 }
410
411int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
412 {
413 nr_ice_media_stream *stream;
414 int r,_status;
415
416 if(pctx->peer_lite && !pctx->controlling) {
417 if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_LITE(1<<1)){
418 r_log(LOG_ICE,LOG_ERR3,"Both sides are ICE-Lite");
419 ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
420 }
421 nr_ice_peer_ctx_switch_controlling_role(pctx);
422 }
423
424 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): peer (%s) pairing candidates",pctx->ctx->label,pctx->label);
425
426 if(STAILQ_EMPTY(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first == __null)) {
427 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) received no media stream attributes",pctx->ctx->label,pctx->label);
428 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
429 }
430
431 /* Set this first; if we fail partway through, we do not want to end
432 * up in UNPAIRED after creating some pairs. */
433 pctx->state = NR_ICE_PEER_STATE_PAIRED2;
434
435 stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
436 while(stream){
437 if(!stream->local_stream->obsolete) {
438 if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream,
439 stream))
440 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
441 }
442
443 stream=STAILQ_NEXT(stream,entry)((stream)->entry.stqe_next);
444 }
445
446
447 _status=0;
448 abort:
449 return(_status);
450 }
451
452
453int nr_ice_peer_ctx_pair_new_trickle_candidate(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx, nr_ice_candidate *cand)
454 {
455 int r, _status;
456 nr_ice_media_stream *pstream;
457
458 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) pairing local trickle ICE candidate %s",pctx->ctx->label,pctx->label,cand->label);
459 if ((r = nr_ice_peer_ctx_find_pstream(pctx, cand->stream, &pstream)))
460 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
461
462 /* Start the remote trickle grace timeout if it hasn't been started
463 already. */
464 if (!pctx->trickle_grace_period_timer) {
465 nr_ice_peer_ctx_start_trickle_timer(pctx);
466 }
467
468 if ((r = nr_ice_media_stream_pair_new_trickle_candidate(pctx, pstream, cand)))
469 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
470
471 _status=0;
472 abort:
473 return _status;
474 }
475
476 void nr_ice_peer_ctx_destroy(nr_ice_peer_ctx** pctxp) {
477 if (!pctxp || !*pctxp) return;
478
479 nr_ice_peer_ctx* pctx = *pctxp;
480 nr_ice_media_stream *str1,*str2;
481
482 /* Stop calling the handler */
483 pctx->handler = 0;
484
485 NR_async_timer_cancel(pctx->connected_cb_timer);
486 free(pctx->label);
487
488 STAILQ_FOREACH_SAFE(str1, &pctx->peer_streams, entry, str2)for ((str1) = (((&pctx->peer_streams))->stqh_first)
; (str1) && ((str2) = (((str1))->entry.stqe_next),
1); (str1) = (str2))
{
489 STAILQ_REMOVE(&pctx->peer_streams,str1,nr_ice_media_stream_,entry)do { if ((((&pctx->peer_streams))->stqh_first) == (
str1)) { do { if ((((((&pctx->peer_streams)))->stqh_first
) = ((((((&pctx->peer_streams)))->stqh_first))->
entry.stqe_next)) == __null) ((&pctx->peer_streams))->
stqh_last = &((((&pctx->peer_streams)))->stqh_first
); } while (0); } else { struct nr_ice_media_stream_ *curelm =
(((&pctx->peer_streams))->stqh_first); while (((curelm
)->entry.stqe_next) != (str1)) curelm = ((curelm)->entry
.stqe_next); if ((((curelm)->entry.stqe_next) = ((((curelm
)->entry.stqe_next))->entry.stqe_next)) == __null) (&
pctx->peer_streams)->stqh_last = &(((curelm))->entry
.stqe_next); } } while (0)
;
490 nr_ice_media_stream_destroy(&str1);
491 }
492 assert(pctx->ctx)(static_cast <bool> (pctx->ctx) ? void (0) : __assert_fail
("pctx->ctx", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
493 if (pctx->ctx)
494 STAILQ_REMOVE(&pctx->ctx->peers, pctx, nr_ice_peer_ctx_, entry)do { if ((((&pctx->ctx->peers))->stqh_first) == (
pctx)) { do { if ((((((&pctx->ctx->peers)))->stqh_first
) = ((((((&pctx->ctx->peers)))->stqh_first))->
entry.stqe_next)) == __null) ((&pctx->ctx->peers))->
stqh_last = &((((&pctx->ctx->peers)))->stqh_first
); } while (0); } else { struct nr_ice_peer_ctx_ *curelm = ((
(&pctx->ctx->peers))->stqh_first); while (((curelm
)->entry.stqe_next) != (pctx)) curelm = ((curelm)->entry
.stqe_next); if ((((curelm)->entry.stqe_next) = ((((curelm
)->entry.stqe_next))->entry.stqe_next)) == __null) (&
pctx->ctx->peers)->stqh_last = &(((curelm))->
entry.stqe_next); } } while (0)
;
495
496 if(pctx->trickle_grace_period_timer) {
497 NR_async_timer_cancel(pctx->trickle_grace_period_timer);
498 pctx->trickle_grace_period_timer=0;
499 }
500
501 free(pctx);
502
503 *pctxp=0;
504 }
505
506/* Unless some stream is already checking, unfreeze and start the first
507 frozen stream that has a check list (RFC 5245 S 5.7, S 7.1.3.2.3).
508 Returns R_NOT_FOUND if there was nothing to start.
509
510 RFC 5245 only does this at startup, and unfreezes the rest by foundation
511 as checks succeed. Here it also runs whenever a stream reaches a final
512 state (see nr_ice_peer_ctx_react_to_stream_change), so that a stream that fails or
513 is removed before any of its pairs succeed does not strand the streams
514 frozen behind it. RFC 8445 avoids the problem differently, by running
515 every checklist from the start (S 6.1.4.2). */
516static int nr_ice_peer_ctx_start_next_stream(nr_ice_peer_ctx *pctx)
517 {
518 int r;
519 nr_ice_media_stream *str;
520 nr_ice_media_stream *first_frozen = nullptr;
521
522 str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
523 while(str){
524 if(!str->local_stream->obsolete){
525 if(str->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3)
526 return R_NOT_FOUND2;
527
528 if(!first_frozen &&
529 str->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2 &&
530 !TAILQ_EMPTY(&str->check_list)((&str->check_list)->tqh_first == __null)) {
531 first_frozen = str;
532 }
533 }
534 str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next);
535 }
536
537 if(!first_frozen)
538 return R_NOT_FOUND2;
539
540 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): starting checks for stream %s",pctx->label,first_frozen->label);
541 if(r=nr_ice_media_stream_unfreeze_pairs(pctx,first_frozen))
542 return r;
543 if(r=nr_ice_media_stream_start_checks(pctx,first_frozen))
544 return r;
545
546 return 0;
547 }
548
549/* Start checks. Only the first frozen stream with a check list is started;
550 the rest are unfrozen as checks succeed, or as streams reach a final
551 state. In the trickle case there may be nothing to start yet, in which
552 case this returns R_NOT_FOUND; streams are then started as their
553 candidates arrive. */
554int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx)
555 {
556 int r,_status;
557 nr_ice_media_stream *stream;
558 int started = 0;
559
560 /* Ensure that grace period timer is running. We might cancel this if we
561 * didn't actually start any pairs. */
562 nr_ice_peer_ctx_start_trickle_timer(pctx);
563
564 /* Might have added some streams */
565 pctx->reported_connected = 0;
566 NR_async_timer_cancel(pctx->connected_cb_timer);
567 pctx->connected_cb_timer = 0;
568 pctx->checks_started = 0;
569
570 if(nr_ice_peer_ctx_react_to_stream_change(pctx)){
571 ++started;
572 }
573 else if(pctx->reported_connected){
574 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) in %s all streams were done",pctx->ctx->label,pctx->label,__FUNCTION__);
575 return (0);
576 }
577 else{
578 /* Not all that unusual in the trickle case. */
579 r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) no streams with non-empty check lists",pctx->ctx->label,pctx->label);
580 }
581
582 if(STAILQ_EMPTY(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first == __null))
583 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
584
585 stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
586 while (stream) {
587 int serviced = 0;
588 if (r=nr_ice_media_stream_service_pre_answer_requests(pctx, stream->local_stream, stream, &serviced))
589 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
590
591 if (serviced) {
592 ++started;
593 }
594 else {
595 r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) no streams with pre-answer requests",pctx->ctx->label,pctx->label);
596 }
597
598
599 stream=STAILQ_NEXT(stream, entry)((stream)->entry.stqe_next);
600 }
601
602 if (!started && pctx->ctx->uninitialized_candidates) {
603 r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) no checks to start, but gathering is not done yet, cancelling grace period timer",pctx->ctx->label,pctx->label);
604 /* Never mind on the grace period timer */
605 NR_async_timer_cancel(pctx->trickle_grace_period_timer);
606 pctx->trickle_grace_period_timer=0;
607 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
608 }
609
610 _status=0;
611 abort:
612 return(_status);
613 }
614
615void nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
616 {
617 if (!pctx->checks_started) {
618 r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) is now checking",pctx->ctx->label,pctx->label);
619 pctx->checks_started = 1;
620 if (pctx->handler && pctx->handler->vtbl->ice_checking) {
621 pctx->handler->vtbl->ice_checking(pctx->handler->obj, pctx);
622 }
623 }
624 }
625
626void nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx *pctx)
627 {
628 nr_ice_media_stream *str;
629
630 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): refreshing consent on all streams",pctx->label);
631
632 str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
633 while(str) {
634 nr_ice_media_stream_refresh_consent_all(str);
635 str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next);
636 }
637 }
638
639void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx)
640 {
641 if (pctx->connected_cb_timer) {
642 /* Whoops, never mind */
643 NR_async_timer_cancel(pctx->connected_cb_timer);
644 pctx->connected_cb_timer = 0;
645 }
646
647 if (pctx->reported_connected &&
648 pctx->handler &&
649 pctx->handler->vtbl->ice_disconnected) {
650 pctx->handler->vtbl->ice_disconnected(pctx->handler->obj, pctx);
651
652 pctx->reported_connected = 0;
653 }
654 }
655
656void nr_ice_peer_ctx_disconnect_all_streams(nr_ice_peer_ctx *pctx)
657 {
658 nr_ice_media_stream *str;
659
660 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): disconnecting all streams",pctx->label);
661
662 str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
663 while(str) {
664 nr_ice_media_stream_disconnect_all_components(str);
665
666 /* The first stream to be disconnected will cause the peer ctx to signal
667 the disconnect up. */
668 nr_ice_media_stream_set_disconnected(str, NR_ICE_MEDIA_STREAM_DISCONNECTED1);
669
670 str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next);
671 }
672 }
673
674void nr_ice_peer_ctx_connected(nr_ice_peer_ctx *pctx)
675 {
676 /* Fire the handler callback to say we're done */
677 if (pctx->reported_connected &&
678 pctx->handler &&
679 pctx->handler->vtbl->ice_connected) {
680 pctx->handler->vtbl->ice_connected(pctx->handler->obj, pctx);
681 }
682 }
683
684static void nr_ice_peer_ctx_fire_connected(NR_SOCKET s, int how, void *cb_arg)
685 {
686 nr_ice_peer_ctx *pctx=(nr_ice_peer_ctx*)cb_arg;
687
688 pctx->connected_cb_timer=0;
689
690 nr_ice_peer_ctx_connected(pctx);
691 }
692
693/* A stream reached a final state (connected, failed, or removed), or a stream
694 * has been added and needs to start checks. If every stream is done, report
695 * it; otherwise make sure some stream is still checking. Returns 1 if it
696 * started checks on a stream. */
697int nr_ice_peer_ctx_react_to_stream_change(nr_ice_peer_ctx *pctx)
698 {
699 int r;
700 nr_ice_media_stream *str;
701 int failed=0;
702 int succeeded=0;
703
704 str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
705 while(str){
706 if (!str->local_stream->obsolete){
707 if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED4){
708 succeeded++;
709 }
710 else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED5){
711 failed++;
712 }
713 else{
714 break;
715 }
716 }
717 str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next);
718 }
719
720 if (!str) {
721 /* OK, we're finished, one way or another */
722 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): all checks completed success=%d fail=%d",pctx->label,succeeded,failed);
723
724 /* Make sure grace period timer is cancelled */
725 if(pctx->trickle_grace_period_timer) {
726 r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) cancelling grace period timer",pctx->ctx->label,pctx->label);
727 NR_async_timer_cancel(pctx->trickle_grace_period_timer);
728 pctx->trickle_grace_period_timer=0;
729 }
730
731 /* Schedule a connected notification for the first connected event.
732 IMPORTANT: This is done in a callback because we expect destructors
733 of various kinds to be fired from here */
734 if (!pctx->reported_connected && !failed) {
735 pctx->reported_connected = 1;
736 assert(!pctx->connected_cb_timer)(static_cast <bool> (!pctx->connected_cb_timer) ? void
(0) : __assert_fail ("!pctx->connected_cb_timer", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
737 NR_ASYNC_TIMER_SET(0,nr_ice_peer_ctx_fire_connected,pctx,&pctx->connected_cb_timer)NR_async_timer_set(0,nr_ice_peer_ctx_fire_connected,pctx,(char
*)__FUNCTION__,737,&pctx->connected_cb_timer)
;
738 }
739 } else {
740 /* Something isn't done. Whatever was checking may just have finished,
741 failed, or been removed; don't leave the rest frozen behind it.
742 (Before checks are first started nothing is FROZEN yet, so this is a
743 no-op then.) */
744 r=nr_ice_peer_ctx_start_next_stream(pctx);
745 if(!r)
746 return 1;
747 if(r!=R_NOT_FOUND2){
748 r_log(LOG_ICE,LOG_ERR3,"ICE-PEER(%s): couldn't start checks for next stream, error=%d",pctx->label,r);
749 }
750 }
751
752 return 0;
753 }
754
755
756/* Given a component in the main ICE ctx, find the relevant component in
757 the peer_ctx */
758int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp)
759 {
760 nr_ice_media_stream *pstr;
761 int r,_status;
762
763 pstr=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
764 while(pstr){
765 if(pstr->local_stream==str)
766 break;
767
768 pstr=STAILQ_NEXT(pstr,entry)((pstr)->entry.stqe_next);
769 }
770 if(!pstr)
771 ABORT(R_BAD_ARGS)do { int _r=6; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
772
773 if(r=nr_ice_media_stream_find_component(pstr,component_id,compp))
774 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
775
776 _status=0;
777 abort:
778 return(_status);
779 }
780
781/*
782 This packet may be for us.
783
784 1. Find the matching peer component
785 2. Examine the packet source address to see if it matches
786 one of the peer candidates.
787 3. Fire the relevant callback handler if there is a match
788
789 Return 0 if match, R_REJECTED if no match, other errors
790 if we can't even find the component or something like that.
791*/
792
793int 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)
794 {
795 nr_ice_component *peer_comp;
796 nr_ice_candidate *cand;
797 int r,_status;
798
799 if(r=nr_ice_peer_ctx_find_component(pctx, comp->stream, comp->component_id,
800 &peer_comp))
801 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
802
803 /* OK, we've found the component, now look for matches */
804 cand=TAILQ_FIRST(&peer_comp->candidates)((&peer_comp->candidates)->tqh_first);
805 while(cand){
806 if(!nr_transport_addr_cmp(source_addr,&cand->addr,
807 NR_TRANSPORT_ADDR_CMP_MODE_ALL4))
808 break;
809
810 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
811 }
812
813 if(!cand)
814 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
815
816 // accumulate the received bytes and packets for the active candidate pair
817 if (peer_comp->active) {
818 peer_comp->active->bytes_recvd += len;
819 peer_comp->active->packets_recvd += 1;
820 gettimeofday(&peer_comp->active->last_recvd, 0);
821 }
822
823 /* OK, there's a match. Call the handler */
824
825 if (pctx->handler) {
826 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s): Delivering data", pctx->label);
827
828 pctx->handler->vtbl->msg_recvd(pctx->handler->obj,
829 pctx,comp->stream,comp->component_id,data,len);
830 }
831
832 _status=0;
833 abort:
834 return(_status);
835 }
836
837void nr_ice_peer_ctx_switch_controlling_role(nr_ice_peer_ctx *pctx)
838 {
839 int controlling = !(pctx->controlling);
840 if(pctx->controlling_conflict_resolved) {
841 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) %s called more than once; "
842 "this probably means the peer is confused. Not switching roles.",
843 pctx->ctx->label,pctx->label,__FUNCTION__);
844 return;
845 }
846
847 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): detected "
848 "role conflict. Switching to %s",
849 pctx->label,
850 controlling ? "controlling" : "controlled");
851
852 pctx->controlling = controlling;
853 pctx->controlling_conflict_resolved = 1;
854
855 if(pctx->state == NR_ICE_PEER_STATE_PAIRED2) {
856 /* We have formed candidate pairs. We need to inform them. */
857 nr_ice_media_stream *pstream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
858 while(pstream) {
859 nr_ice_media_stream_role_change(pstream);
860 pstream = STAILQ_NEXT(pstream, entry)((pstream)->entry.stqe_next);
861 }
862 }
863 }
864