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_STUND_0_96 -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-09-01-224014-2642839-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 *mdns_addr);
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 *mdns_addr)
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,&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 if (mdns_addr) {
196 cand->mdns_addr = strdup(mdns_addr);
197 if (!cand->mdns_addr) {
198 ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
199 }
200 }
201
202 /* Not the fastest way to find a component, but it's what we got */
203 j=1;
204 for(comp=STAILQ_FIRST(&pstream->components)((&pstream->components)->stqh_first);comp;comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next)){
205 if(j==cand->component_id)
206 break;
207
208 j++;
209 }
210
211 if(!comp){
212 /* Very common for the answerer when it uses rtcp-mux */
213 r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) no such component for candidate %s",pctx->ctx->label,pctx->label, candidate);
214 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
215 }
216
217 if (comp->state == NR_ICE_COMPONENT_DISABLED4) {
218 r_log(LOG_ICE,LOG_WARNING4,"Peer offered candidate for disabled remote component: %s", candidate);
219 ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
220 }
221 if (comp->local_component->state == NR_ICE_COMPONENT_DISABLED4) {
222 r_log(LOG_ICE,LOG_WARNING4,"Peer offered candidate for disabled local component: %s", candidate);
223 ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
224 }
225
226 cand->component=comp;
227
228 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)
;
229
230 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/CAND(%s): creating peer candidate",
231 pctx->label,cand->label);
232
233 _status=0;
234 abort:
235 if (_status) {
236 nr_ice_candidate_destroy(&cand);
237 }
238 return(_status);
239 }
240
241int nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream **pstreamp)
242 {
243 int _status;
244 nr_ice_media_stream *pstream;
245
246 /* Because we don't have forward pointers, iterate through all the
247 peer streams to find one that matches us */
248 pstream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
249
250 if(!pstream) {
251 /* No peer streams at all, presumably because they do not exist yet.
252 * Don't log a warning here. */
253 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
254 }
255
256 while(pstream) {
257 if (pstream->local_stream == stream)
258 break;
259
260 pstream = STAILQ_NEXT(pstream, entry)((pstream)->entry.stqe_next);
261 }
262
263 if (!pstream) {
264 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label);
265 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
266 }
267
268 *pstreamp = pstream;
269
270 _status=0;
271 abort:
272 return(_status);
273 }
274
275int nr_ice_peer_ctx_remove_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream **pstreamp)
276 {
277 int r,_status;
278
279 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)
;
280
281 if(r=nr_ice_media_stream_destroy(pstreamp)) {
282 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
283 }
284
285 _status=0;
286 abort:
287 return(_status);
288 }
289
290int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate, const char *mdns_addr)
291 {
292 nr_ice_media_stream *pstream;
293 int r,_status;
294 int needs_pairing = 0;
295
296 if (stream->obsolete) {
297 return 0;
298 }
299
300 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): peer (%s) parsing trickle ICE candidate %s",pctx->ctx->label,pctx->label,candidate);
301 r = nr_ice_peer_ctx_find_pstream(pctx, stream, &pstream);
302 if (r)
303 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
304
305 switch(pstream->ice_state) {
306 case NR_ICE_MEDIA_STREAM_UNPAIRED1:
307 break;
308 case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2:
309 case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3:
310 needs_pairing = 1;
311 break;
312 default:
313 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);
314 ABORT(R_ALREADY)do { int _r=4; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
315 break;
316 }
317
318 if(r=nr_ice_ctx_parse_candidate(pctx,pstream,candidate,1,mdns_addr)){
319 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
320 }
321
322 /* If ICE is running (i.e., we are in FROZEN or ACTIVE states)
323 then we need to pair this new candidate. For now we
324 just re-pair the stream which is inefficient but still
325 fine because we suppress duplicate pairing */
326 if (needs_pairing) {
327 /* Start the remote trickle grace timeout if it hasn't been started by
328 another trickled candidate or from the SDP. */
329 if (!pctx->trickle_grace_period_timer) {
330 nr_ice_peer_ctx_start_trickle_timer(pctx);
331 }
332
333 if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) {
334 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);
335 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
336 }
337
338 /* Start checks if this stream is not checking yet or if it has checked
339 all the available candidates but not had a completed check for all
340 components.
341
342 Note that this is not compliant with RFC 5245, but consistent with
343 the libjingle trickle ICE behavior. Note that we will not restart
344 checks if either (a) the stream has failed or (b) all components
345 have a successful pair because the switch statement above jumps
346 will in both states.
347
348 TODO(ekr@rtfm.com): restart checks.
349 TODO(ekr@rtfm.com): update when the trickle ICE RFC is published
350 */
351 if (!pstream->timer) {
352 if(r=nr_ice_media_stream_start_checks(pctx, pstream)) {
353 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s), stream(%s) failed to start checks",pctx->ctx->label,pctx->label,stream->label);
354 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
355 }
356 }
357 }
358
359 _status=0;
360 abort:
361 return(_status);
362
363 }
364
365
366static void nr_ice_peer_ctx_trickle_wait_cb(NR_SOCKET s, int how, void *cb_arg)
367 {
368 nr_ice_peer_ctx *pctx=(nr_ice_peer_ctx*)cb_arg;
369 nr_ice_media_stream *stream;
370 nr_ice_component *comp;
371
372 pctx->trickle_grace_period_timer=0;
373
374 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);
375
376 stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
377 while(stream){
378 comp=STAILQ_FIRST(&stream->components)((&stream->components)->stqh_first);
379 while(comp){
380 nr_ice_component_check_if_failed(comp);
381 comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next);
382 }
383 stream=STAILQ_NEXT(stream,entry)((stream)->entry.stqe_next);
384 }
385 }
386
387static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx)
388 {
389 UINT4 grace_period_timeout=0;
390
391 if(pctx->trickle_grace_period_timer) {
392 NR_async_timer_cancel(pctx->trickle_grace_period_timer);
393 pctx->trickle_grace_period_timer=0;
394 }
395
396 NR_reg_get_uint4(NR_ICE_REG_TRICKLE_GRACE_PERIOD"ice.trickle_grace_period",&grace_period_timeout);
397
398 if (grace_period_timeout) {
399 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);
400 /* If we're doing trickle, we need to allow a grace period for new
401 * trickle candidates to arrive in case the pairs we have fail quickly. */
402 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__,402,&pctx->trickle_grace_period_timer
)
;
403 }
404 }
405
406int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
407 {
408 nr_ice_media_stream *stream;
409 int r,_status;
410
411 if(pctx->peer_lite && !pctx->controlling) {
412 if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_LITE(1<<1)){
413 r_log(LOG_ICE,LOG_ERR3,"Both sides are ICE-Lite");
414 ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
415 }
416 nr_ice_peer_ctx_switch_controlling_role(pctx);
417 }
418
419 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): peer (%s) pairing candidates",pctx->ctx->label,pctx->label);
420
421 if(STAILQ_EMPTY(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first == __null)) {
422 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) received no media stream attributes",pctx->ctx->label,pctx->label);
423 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
424 }
425
426 /* Set this first; if we fail partway through, we do not want to end
427 * up in UNPAIRED after creating some pairs. */
428 pctx->state = NR_ICE_PEER_STATE_PAIRED2;
429
430 stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
431 while(stream){
432 if(!stream->local_stream->obsolete) {
433 if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream,
434 stream))
435 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
436 }
437
438 stream=STAILQ_NEXT(stream,entry)((stream)->entry.stqe_next);
439 }
440
441
442 _status=0;
443 abort:
444 return(_status);
445 }
446
447
448int nr_ice_peer_ctx_pair_new_trickle_candidate(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx, nr_ice_candidate *cand)
449 {
450 int r, _status;
451 nr_ice_media_stream *pstream;
452
453 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) pairing local trickle ICE candidate %s",pctx->ctx->label,pctx->label,cand->label);
454 if ((r = nr_ice_peer_ctx_find_pstream(pctx, cand->stream, &pstream)))
455 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
456
457 /* Start the remote trickle grace timeout if it hasn't been started
458 already. */
459 if (!pctx->trickle_grace_period_timer) {
460 nr_ice_peer_ctx_start_trickle_timer(pctx);
461 }
462
463 if ((r = nr_ice_media_stream_pair_new_trickle_candidate(pctx, pstream, cand)))
464 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
465
466 _status=0;
467 abort:
468 return _status;
469 }
470
471 void nr_ice_peer_ctx_destroy(nr_ice_peer_ctx** pctxp) {
472 if (!pctxp || !*pctxp) return;
473
474 nr_ice_peer_ctx* pctx = *pctxp;
475 nr_ice_media_stream *str1,*str2;
476
477 /* Stop calling the handler */
478 pctx->handler = 0;
479
480 NR_async_timer_cancel(pctx->connected_cb_timer);
481 free(pctx->label);
482
483 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))
{
484 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)
;
485 nr_ice_media_stream_destroy(&str1);
486 }
487 assert(pctx->ctx)(static_cast <bool> (pctx->ctx) ? void (0) : __assert_fail
("pctx->ctx", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
488 if (pctx->ctx)
489 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)
;
490
491 if(pctx->trickle_grace_period_timer) {
492 NR_async_timer_cancel(pctx->trickle_grace_period_timer);
493 pctx->trickle_grace_period_timer=0;
494 }
495
496 free(pctx);
497
498 *pctxp=0;
499 }
500
501/* Start the checks for the first media stream (S 5.7)
502 The rest remain FROZEN */
503int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx)
504 {
505 return nr_ice_peer_ctx_start_checks2(pctx, 0);
506 }
507
508/* Start checks for some media stream.
509
510 If allow_non_first == 0, then we only look at the first stream,
511 which is 5245-complaint.
512
513 If allow_non_first == 1 then we find the first non-empty stream
514 This is not compliant with RFC 5245 but is necessary to make trickle ICE
515 work plausibly
516*/
517int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first)
518 {
519 int r,_status;
520 nr_ice_media_stream *stream;
521 int started = 0;
522
523 /* Ensure that grace period timer is running. We might cancel this if we
524 * didn't actually start any pairs. */
525 nr_ice_peer_ctx_start_trickle_timer(pctx);
526
527 /* Might have added some streams */
528 pctx->reported_connected = 0;
529 NR_async_timer_cancel(pctx->connected_cb_timer);
530 pctx->connected_cb_timer = 0;
531 pctx->checks_started = 0;
532
533 nr_ice_peer_ctx_check_if_connected(pctx);
534
535 if (pctx->reported_connected) {
536 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) in %s all streams were done",pctx->ctx->label,pctx->label,__FUNCTION__);
537 return (0);
538 }
539
540 stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
541 if(!stream)
542 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
543
544 while (stream) {
545 if(!stream->local_stream->obsolete) {
546 assert(stream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED)(static_cast <bool> (stream->ice_state != 1) ? void (
0) : __assert_fail ("stream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
547
548 if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2) {
549 if(!TAILQ_EMPTY(&stream->check_list)((&stream->check_list)->tqh_first == __null))
550 break;
551
552 if(!allow_non_first){
553 /* This test applies if:
554
555 1. allow_non_first is 0 (i.e., non-trickle ICE)
556 2. the first stream has an empty check list.
557
558 But in the non-trickle ICE case, the other side should have provided
559 some candidates or ICE is pretty much not going to work and we're
560 just going to fail. Hence R_FAILED as opposed to R_NOT_FOUND and
561 immediate termination here.
562 */
563 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) first stream has empty check list",pctx->ctx->label,pctx->label);
564 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
565 }
566 }
567 }
568
569 stream=STAILQ_NEXT(stream, entry)((stream)->entry.stqe_next);
570 }
571
572 if (!stream) {
573 /*
574 We fail above if we aren't doing trickle, and this is not all that
575 unusual in the trickle case.
576 */
577 r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) no streams with non-empty check lists",pctx->ctx->label,pctx->label);
578 }
579 else if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2) {
580 if(r=nr_ice_media_stream_unfreeze_pairs(pctx,stream))
581 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
582 if(r=nr_ice_media_stream_start_checks(pctx,stream))
583 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
584 ++started;
585 }
586
587 stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
588 while (stream) {
589 int serviced = 0;
590 if (r=nr_ice_media_stream_service_pre_answer_requests(pctx, stream->local_stream, stream, &serviced))
591 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
592
593 if (serviced) {
594 ++started;
595 }
596 else {
597 r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) no streams with pre-answer requests",pctx->ctx->label,pctx->label);
598 }
599
600
601 stream=STAILQ_NEXT(stream, entry)((stream)->entry.stqe_next);
602 }
603
604 if (!started && pctx->ctx->uninitialized_candidates) {
605 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);
606 /* Never mind on the grace period timer */
607 NR_async_timer_cancel(pctx->trickle_grace_period_timer);
608 pctx->trickle_grace_period_timer=0;
609 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
610 }
611
612 _status=0;
613 abort:
614 return(_status);
615 }
616
617void nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
618 {
619 if (!pctx->checks_started) {
620 r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) is now checking",pctx->ctx->label,pctx->label);
621 pctx->checks_started = 1;
622 if (pctx->handler && pctx->handler->vtbl->ice_checking) {
623 pctx->handler->vtbl->ice_checking(pctx->handler->obj, pctx);
624 }
625 }
626 }
627
628void nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx *pctx)
629 {
630 nr_ice_media_stream *str;
631
632 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): refreshing consent on all streams",pctx->label);
633
634 str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
635 while(str) {
636 nr_ice_media_stream_refresh_consent_all(str);
637 str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next);
638 }
639 }
640
641void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx)
642 {
643 if (pctx->connected_cb_timer) {
644 /* Whoops, never mind */
645 NR_async_timer_cancel(pctx->connected_cb_timer);
646 pctx->connected_cb_timer = 0;
647 }
648
649 if (pctx->reported_connected &&
650 pctx->handler &&
651 pctx->handler->vtbl->ice_disconnected) {
652 pctx->handler->vtbl->ice_disconnected(pctx->handler->obj, pctx);
653
654 pctx->reported_connected = 0;
655 }
656 }
657
658void nr_ice_peer_ctx_disconnect_all_streams(nr_ice_peer_ctx *pctx)
659 {
660 nr_ice_media_stream *str;
661
662 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): disconnecting all streams",pctx->label);
663
664 str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
665 while(str) {
666 nr_ice_media_stream_disconnect_all_components(str);
667
668 /* The first stream to be disconnected will cause the peer ctx to signal
669 the disconnect up. */
670 nr_ice_media_stream_set_disconnected(str, NR_ICE_MEDIA_STREAM_DISCONNECTED1);
671
672 str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next);
673 }
674 }
675
676void nr_ice_peer_ctx_connected(nr_ice_peer_ctx *pctx)
677 {
678 /* Fire the handler callback to say we're done */
679 if (pctx->reported_connected &&
680 pctx->handler &&
681 pctx->handler->vtbl->ice_connected) {
682 pctx->handler->vtbl->ice_connected(pctx->handler->obj, pctx);
683 }
684 }
685
686static void nr_ice_peer_ctx_fire_connected(NR_SOCKET s, int how, void *cb_arg)
687 {
688 nr_ice_peer_ctx *pctx=(nr_ice_peer_ctx*)cb_arg;
689
690 pctx->connected_cb_timer=0;
691
692 nr_ice_peer_ctx_connected(pctx);
693 }
694
695/* Examine all the streams to see if we're
696 maybe miraculously connected */
697void nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx)
698 {
699 nr_ice_media_stream *str;
700 int failed=0;
701 int succeeded=0;
702
703 str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
704 while(str){
705 if (!str->local_stream->obsolete){
706 if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED4){
707 succeeded++;
708 }
709 else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED5){
710 failed++;
711 }
712 else{
713 break;
714 }
715 }
716 str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next);
717 }
718
719 if(str)
720 return; /* Something isn't done */
721
722 /* OK, we're finished, one way or another */
723 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): all checks completed success=%d fail=%d",pctx->label,succeeded,failed);
724
725 /* Make sure grace period timer is cancelled */
726 if(pctx->trickle_grace_period_timer) {
727 r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) cancelling grace period timer",pctx->ctx->label,pctx->label);
728 NR_async_timer_cancel(pctx->trickle_grace_period_timer);
729 pctx->trickle_grace_period_timer=0;
730 }
731
732 /* Schedule a connected notification for the first connected event.
733 IMPORTANT: This is done in a callback because we expect destructors
734 of various kinds to be fired from here */
735 if (!pctx->reported_connected) {
736 pctx->reported_connected = 1;
737 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__))
;
738 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__,738,&pctx->connected_cb_timer)
;
739 }
740 }
741
742
743/* Given a component in the main ICE ctx, find the relevant component in
744 the peer_ctx */
745int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp)
746 {
747 nr_ice_media_stream *pstr;
748 int r,_status;
749
750 pstr=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
751 while(pstr){
752 if(pstr->local_stream==str)
753 break;
754
755 pstr=STAILQ_NEXT(pstr,entry)((pstr)->entry.stqe_next);
756 }
757 if(!pstr)
758 ABORT(R_BAD_ARGS)do { int _r=6; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
759
760 if(r=nr_ice_media_stream_find_component(pstr,component_id,compp))
761 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
762
763 _status=0;
764 abort:
765 return(_status);
766 }
767
768/*
769 This packet may be for us.
770
771 1. Find the matching peer component
772 2. Examine the packet source address to see if it matches
773 one of the peer candidates.
774 3. Fire the relevant callback handler if there is a match
775
776 Return 0 if match, R_REJECTED if no match, other errors
777 if we can't even find the component or something like that.
778*/
779
780int 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)
781 {
782 nr_ice_component *peer_comp;
783 nr_ice_candidate *cand;
784 int r,_status;
785
786 if(r=nr_ice_peer_ctx_find_component(pctx, comp->stream, comp->component_id,
787 &peer_comp))
788 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
789
790 /* OK, we've found the component, now look for matches */
791 cand=TAILQ_FIRST(&peer_comp->candidates)((&peer_comp->candidates)->tqh_first);
792 while(cand){
793 if(!nr_transport_addr_cmp(source_addr,&cand->addr,
794 NR_TRANSPORT_ADDR_CMP_MODE_ALL4))
795 break;
796
797 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
798 }
799
800 if(!cand)
801 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
802
803 // accumulate the received bytes and packets for the active candidate pair
804 if (peer_comp->active) {
805 peer_comp->active->bytes_recvd += len;
806 peer_comp->active->packets_recvd += 1;
807 gettimeofday(&peer_comp->active->last_recvd, 0);
808 }
809
810 /* OK, there's a match. Call the handler */
811
812 if (pctx->handler) {
813 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s): Delivering data", pctx->label);
814
815 pctx->handler->vtbl->msg_recvd(pctx->handler->obj,
816 pctx,comp->stream,comp->component_id,data,len);
817 }
818
819 _status=0;
820 abort:
821 return(_status);
822 }
823
824void nr_ice_peer_ctx_switch_controlling_role(nr_ice_peer_ctx *pctx)
825 {
826 int controlling = !(pctx->controlling);
827 if(pctx->controlling_conflict_resolved) {
828 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) %s called more than once; "
829 "this probably means the peer is confused. Not switching roles.",
830 pctx->ctx->label,pctx->label,__FUNCTION__);
831 return;
832 }
833
834 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): detected "
835 "role conflict. Switching to %s",
836 pctx->label,
837 controlling ? "controlling" : "controlled");
838
839 pctx->controlling = controlling;
840 pctx->controlling_conflict_resolved = 1;
841
842 if(pctx->state == NR_ICE_PEER_STATE_PAIRED2) {
843 /* We have formed candidate pairs. We need to inform them. */
844 nr_ice_media_stream *pstream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first);
845 while(pstream) {
846 nr_ice_media_stream_role_change(pstream);
847 pstream = STAILQ_NEXT(pstream, entry)((pstream)->entry.stqe_next);
848 }
849 }
850 }
851