Bug Summary

File:root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_component.cpp
Warning:line 583, column 13
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_component.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_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-11-12-001017-1011516-1 -x c++ /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_component.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 <nr_api.h>
36#include <registry.h>
37#include <async_timer.h>
38#include "ice_ctx.h"
39#include "ice_codeword.h"
40#include "stun.h"
41#include "nr_socket_local.h"
42#include "nr_socket_turn.h"
43#include "nr_socket_buffered_stun.h"
44#include "nr_socket_multi_tcp.h"
45#include "ice_reg.h"
46#include "nr_crypto.h"
47#include "r_time.h"
48
49static void nr_ice_component_refresh_consent_cb(NR_SOCKET s, int how, void *cb_arg);
50static int nr_ice_component_stun_server_default_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error);
51static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp);
52int nr_ice_component_can_candidate_addr_pair(nr_transport_addr *local, nr_transport_addr *remote);
53int nr_ice_component_can_candidate_tcptype_pair(nr_socket_tcp_type left, nr_socket_tcp_type right);
54void nr_ice_component_consent_calc_consent_timer(nr_ice_component *comp);
55void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp);
56int nr_ice_component_refresh_consent(nr_stun_client_ctx *ctx, NR_async_cb finished_cb, void *cb_arg);
57int nr_ice_component_setup_consent(nr_ice_component *comp);
58int nr_ice_pre_answer_enqueue(nr_ice_component *comp, nr_socket *sock, nr_stun_server_request *req, int *dont_free);
59
60/* This function takes ownership of the contents of req (but not req itself) */
61static int nr_ice_pre_answer_request_create(nr_transport_addr *dst, nr_stun_server_request *req, nr_ice_pre_answer_request **parp)
62 {
63 int r, _status;
64 nr_ice_pre_answer_request *par = 0;
65 nr_stun_message_attribute *attr;
66
67 if (!(par = R_NEW(nr_ice_pre_answer_request)(nr_ice_pre_answer_request*)calloc(1,sizeof(nr_ice_pre_answer_request
))
))
68 ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
69
70 par->req = *req; /* Struct assignment */
71 memset(req, 0, sizeof(*req)); /* Zero contents to avoid confusion */
72
73 if (r=nr_transport_addr_copy(&par->local_addr, dst))
74 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
75 if (!nr_stun_message_has_attribute(par->req.request, NR_STUN_ATTR_USERNAME0x0006, &attr))
76 ABORT(R_INTERNAL)do { int _r=3; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
77 if (!(par->username = strdup(attr->u.username)))
78 ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
79
80 *parp=par;
81 _status=0;
82 abort:
83 if (_status) {
84 /* Erase the request so we don't free it */
85 memset(&par->req, 0, sizeof(nr_stun_server_request));
86 nr_ice_pre_answer_request_destroy(&par);
87 }
88
89 return(_status);
90 }
91
92static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp)
93 {
94 nr_ice_pre_answer_request *par;
95
96 if (!parp || !*parp)
97 return(0);
98
99 par = *parp;
100 *parp = 0;
101
102 nr_stun_message_destroy(&par->req.request);
103 nr_stun_message_destroy(&par->req.response);
104
105 free(par->username);
106 free(par);
107
108 return(0);
109 }
110
111int nr_ice_component_create(nr_ice_media_stream *stream, int component_id, nr_ice_component **componentp)
112 {
113 int _status;
114 nr_ice_component *comp=0;
115
116 if(!(comp=R_NEW(nr_ice_component)(nr_ice_component*)calloc(1,sizeof(nr_ice_component))))
117 ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
118
119 comp->state=NR_ICE_COMPONENT_UNPAIRED0;
120 comp->component_id=component_id;
121 comp->stream=stream;
122 comp->ctx=stream->ctx;
123
124 STAILQ_INIT(&comp->sockets)do { (((&comp->sockets))->stqh_first) = __null; (&
comp->sockets)->stqh_last = &(((&comp->sockets
))->stqh_first); } while (0)
;
125 TAILQ_INIT(&comp->candidates)do { (((&comp->candidates))->tqh_first) = __null; (
&comp->candidates)->tqh_last = &(((&comp->
candidates))->tqh_first); ; } while (0)
;
126 STAILQ_INIT(&comp->pre_answer_reqs)do { (((&comp->pre_answer_reqs))->stqh_first) = __null
; (&comp->pre_answer_reqs)->stqh_last = &(((&
comp->pre_answer_reqs))->stqh_first); } while (0)
;
127
128 STAILQ_INSERT_TAIL(&stream->components,comp,entry)do { (((comp))->entry.stqe_next) = __null; *(&stream->
components)->stqh_last = (comp); (&stream->components
)->stqh_last = &(((comp))->entry.stqe_next); } while
(0)
;
129
130 _status=0;
131 abort:
132 return(_status);
133 }
134
135int nr_ice_component_destroy(nr_ice_component **componentp)
136 {
137 nr_ice_component *component;
138 nr_ice_socket *s1,*s2;
139 nr_ice_candidate *c1,*c2;
140 nr_ice_pre_answer_request *r1,*r2;
141
142 if(!componentp || !*componentp)
143 return(0);
144
145 component=*componentp;
146 *componentp=0;
147
148 nr_ice_component_consent_destroy(component);
149
150 /* Detach ourselves from the sockets */
151 if (component->local_component){
152 nr_ice_socket *isock=STAILQ_FIRST(&component->local_component->sockets)((&component->local_component->sockets)->stqh_first
)
;
153 while(isock){
154 nr_stun_server_remove_client(isock->stun_server, component);
155 isock=STAILQ_NEXT(isock, entry)((isock)->entry.stqe_next);
156 }
157 }
158
159 /* candidates MUST be destroyed before the sockets so that
160 they can deregister */
161 TAILQ_FOREACH_SAFE(c1, &component->candidates, entry_comp, c2)for ((c1) = (((&component->candidates))->tqh_first)
; (c1) && ((c2) = (((c1))->entry_comp.tqe_next), 1
); (c1) = (c2))
{
162 TAILQ_REMOVE(&component->candidates,c1,entry_comp)do { if (((((c1))->entry_comp.tqe_next)) != __null) (((c1)
)->entry_comp.tqe_next)->entry_comp.tqe_prev = (c1)->
entry_comp.tqe_prev; else { (&component->candidates)->
tqh_last = (c1)->entry_comp.tqe_prev; ; } *(c1)->entry_comp
.tqe_prev = (((c1))->entry_comp.tqe_next); ; ; ; } while (
0)
;
163 nr_ice_candidate_destroy(&c1);
164 }
165
166 STAILQ_FOREACH_SAFE(s1, &component->sockets, entry, s2)for ((s1) = (((&component->sockets))->stqh_first); (
s1) && ((s2) = (((s1))->entry.stqe_next), 1); (s1)
= (s2))
{
167 STAILQ_REMOVE(&component->sockets,s1,nr_ice_socket_,entry)do { if ((((&component->sockets))->stqh_first) == (
s1)) { do { if ((((((&component->sockets)))->stqh_first
) = ((((((&component->sockets)))->stqh_first))->
entry.stqe_next)) == __null) ((&component->sockets))->
stqh_last = &((((&component->sockets)))->stqh_first
); } while (0); } else { struct nr_ice_socket_ *curelm = (((&
component->sockets))->stqh_first); while (((curelm)->
entry.stqe_next) != (s1)) curelm = ((curelm)->entry.stqe_next
); if ((((curelm)->entry.stqe_next) = ((((curelm)->entry
.stqe_next))->entry.stqe_next)) == __null) (&component
->sockets)->stqh_last = &(((curelm))->entry.stqe_next
); } } while (0)
;
168 nr_ice_socket_destroy(&s1);
169 }
170
171 STAILQ_FOREACH_SAFE(r1, &component->pre_answer_reqs, entry, r2)for ((r1) = (((&component->pre_answer_reqs))->stqh_first
); (r1) && ((r2) = (((r1))->entry.stqe_next), 1); (
r1) = (r2))
{
172 STAILQ_REMOVE(&component->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry)do { if ((((&component->pre_answer_reqs))->stqh_first
) == (r1)) { do { if ((((((&component->pre_answer_reqs
)))->stqh_first) = ((((((&component->pre_answer_reqs
)))->stqh_first))->entry.stqe_next)) == __null) ((&
component->pre_answer_reqs))->stqh_last = &((((&
component->pre_answer_reqs)))->stqh_first); } while (0)
; } else { struct nr_ice_pre_answer_request_ *curelm = (((&
component->pre_answer_reqs))->stqh_first); while (((curelm
)->entry.stqe_next) != (r1)) curelm = ((curelm)->entry.
stqe_next); if ((((curelm)->entry.stqe_next) = ((((curelm)
->entry.stqe_next))->entry.stqe_next)) == __null) (&
component->pre_answer_reqs)->stqh_last = &(((curelm
))->entry.stqe_next); } } while (0)
;
173 nr_ice_pre_answer_request_destroy(&r1);
174 }
175
176 free(component);
177 return(0);
178 }
179
180static int nr_ice_component_create_stun_server_ctx(nr_ice_component *component, nr_ice_socket *isock, nr_transport_addr *addr, char *lufrag, Data *pwd)
181 {
182 char label[256];
183 int r,_status;
184
185 /* Create a STUN server context for this socket */
186 snprintf(label, sizeof(label), "server(%s)", addr->as_string);
187 if(r=nr_stun_server_ctx_create(label,&isock->stun_server))
188 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
189
190 /* Add the default STUN credentials so that we can respond before
191 we hear about the peer.*/
192 if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
193 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
194
195 /* Do this last; if this function fails, we should not be taking a reference to isock */
196 if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
197 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
198
199 _status = 0;
200 abort:
201 return(_status);
202 }
203
204static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_local_addr *addrs, int addr_ct, char *lufrag, Data *pwd)
205 {
206 nr_socket *sock;
207 nr_ice_socket *isock=0;
208 nr_ice_candidate *cand=0;
209 int i;
210 int j;
211 int r,_status;
212
213 if(ctx->flags & NR_ICE_CTX_FLAGS_ONLY_PROXY(1<<5)) {
214 /* No UDP support if we must use a proxy */
215 return 0;
216 }
217
218 /* Now one ice_socket for each address */
219 for(i=0;i<addr_ct;i++){
220 char suppress;
221
222 if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX"ice.suppress.interface",addrs[i].addr.ifname,&suppress)){
223 if(r!=R_NOT_FOUND2)
224 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
225 }
226 else{
227 if(suppress)
228 continue;
229 }
230 r_log(LOG_ICE,LOG_DEBUG7,"ICE-STREAM(%s): host address %s",component->stream->label,addrs[i].addr.as_string);
231 if((r=nr_socket_factory_create_socket(ctx->socket_factory,&addrs[i].addr,&sock))){
232 r_log(LOG_ICE,LOG_WARNING4,"ICE-STREAM(%s): couldn't create socket for address %s",component->stream->label,addrs[i].addr.as_string);
233 continue;
234 }
235
236 if(r=nr_ice_socket_create(ctx,component,sock,NR_ICE_SOCKET_TYPE_DGRAM1,&isock))
237 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
238
239 /* Make sure we don't leak this. Failures might result in it being
240 * unused, but we hand off references to this in enough places below
241 * that unwinding it all becomes impractical. */
242 STAILQ_INSERT_TAIL(&component->sockets,isock,entry)do { (((isock))->entry.stqe_next) = __null; *(&component
->sockets)->stqh_last = (isock); (&component->sockets
)->stqh_last = &(((isock))->entry.stqe_next); } while
(0)
;
243
244 /* Create a STUN server context for this socket */
245 if ((r=nr_ice_component_create_stun_server_ctx(component,isock,&addrs[i].addr,lufrag,pwd)))
246 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
247
248 if (!(component->stream->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY(1<<2))) {
249 /* Create one host candidate */
250 if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,TCP_TYPE_NONE,0,
251 component->component_id,&cand))
252 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
253
254 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
255 component->candidate_ct++;
256 cand=0;
257
258 /* And a srvrflx candidate for each STUN server */
259 for(j=0;j<component->stream->stun_server_ct;j++){
260 r_log(LOG_ICE,LOG_DEBUG7,"ICE-STREAM(%s): Checking STUN server %s %s", component->stream->label, component->stream->stun_servers[j].addr.fqdn, component->stream->stun_servers[j].addr.as_string);
261 /* Skip non-UDP */
262 if (component->stream->stun_servers[j].addr.protocol != IPPROTO_UDPIPPROTO_UDP) continue;
263
264 if (nr_transport_addr_check_compatibility(
265 &addrs[i].addr, &component->stream->stun_servers[j].addr)) {
266 r_log(LOG_ICE,LOG_INFO6,"ICE-STREAM(%s): Skipping STUN server because of address type mis-match",component->stream->label);
267 continue;
268 }
269
270 /* Ensure id is set (nr_ice_ctx_set_stun_servers does not) */
271 component->stream->stun_servers[j].id = j;
272 if(r=nr_ice_candidate_create(ctx,component,
273 isock,sock,SERVER_REFLEXIVE,TCP_TYPE_NONE,
274 &component->stream->stun_servers[j],component->component_id,&cand))
275 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
276 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
277 component->candidate_ct++;
278 cand=0;
279 }
280 }
281 else{
282 r_log(LOG_ICE,LOG_WARNING4,"ICE-STREAM(%s): relay only option results in no host candidate for %s",component->stream->label,addrs[i].addr.as_string);
283 }
284
285 if ((component->stream->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY(1<<2)) &&
286 (component->stream->turn_server_ct == 0)) {
287 r_log(LOG_ICE,LOG_ERR3,"ICE-STREAM(%s): relay only option is set without any TURN server configured",component->stream->label);
288 }
289 /* And both a srvrflx and relayed candidate for each TURN server (unless
290 we're in relay-only mode, in which case just the relayed one) */
291 for(j=0;j<component->stream->turn_server_ct;j++){
292 nr_socket *turn_sock;
293 nr_ice_candidate *srvflx_cand=0;
294
295 r_log(LOG_ICE,LOG_DEBUG7,"ICE-STREAM(%s): Checking TURN server %s %s", component->stream->label, component->stream->turn_servers[j].turn_server.addr.fqdn, component->stream->turn_servers[j].turn_server.addr.as_string);
296
297 /* Skip non-UDP */
298 if (component->stream->turn_servers[j].turn_server.addr.protocol != IPPROTO_UDPIPPROTO_UDP)
299 continue;
300
301 if (nr_transport_addr_check_compatibility(
302 &addrs[i].addr, &component->stream->turn_servers[j].turn_server.addr)) {
303 r_log(LOG_ICE,LOG_INFO6,"ICE-STREAM(%s): Skipping TURN server because of address type mis-match",component->stream->label);
304 continue;
305 }
306
307 if (!(component->stream->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY(1<<2))) {
308 /* Ensure id is set with a unique value */
309 component->stream->turn_servers[j].turn_server.id = j + component->stream->stun_server_ct;
310 /* srvrflx */
311 if(r=nr_ice_candidate_create(ctx,component,
312 isock,sock,SERVER_REFLEXIVE,TCP_TYPE_NONE,
313 &component->stream->turn_servers[j].turn_server,component->component_id,&cand))
314 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
315 cand->state=NR_ICE_CAND_STATE_INITIALIZING2; /* Don't start */
316 cand->done_cb=nr_ice_gather_finished_cb;
317 cand->cb_arg=cand;
318
319 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
320 component->candidate_ct++;
321 srvflx_cand=cand;
322 cand=0;
323 }
324 /* relayed*/
325 if(r=nr_socket_turn_create(&turn_sock))
326 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
327 if(r=nr_ice_candidate_create(ctx,component,
328 isock,turn_sock,RELAYED,TCP_TYPE_NONE,
329 &component->stream->turn_servers[j].turn_server,component->component_id,&cand))
330 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
331 if (srvflx_cand) {
332 cand->u.relayed.srvflx_candidate=srvflx_cand;
333 srvflx_cand->u.srvrflx.relay_candidate=cand;
334 }
335 cand->u.relayed.server=&component->stream->turn_servers[j];
336 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
337 component->candidate_ct++;
338
339 cand=0;
340 }
341 }
342
343 _status = 0;
344 abort:
345 return(_status);
346 }
347
348static int nr_ice_component_get_port_from_ephemeral_range(uint16_t *port)
349 {
350 int _status, r;
351 void *buf = port;
352 if(r=nr_crypto_random_bytes((UCHAR*)buf, 2)nr_crypto_vtbl->random_bytes((UCHAR*)buf,2))
353 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
354 *port|=49152; /* make it fit into IANA ephemeral port range >= 49152 */
355 _status=0;
356abort:
357 return(_status);
358 }
359
360static int nr_ice_component_create_tcp_host_candidate(struct nr_ice_ctx_ *ctx,
361 nr_ice_component *component, nr_transport_addr *interface_addr, nr_socket_tcp_type tcp_type,
362 int backlog, int so_sock_ct, char *lufrag, Data *pwd, nr_ice_socket **isock)
363 {
364 int r,_status;
365 nr_ice_candidate *cand=0;
366 int tries=3;
367 nr_ice_socket *isock_tmp=0;
368 nr_socket *nrsock=0;
369 nr_transport_addr addr;
370 uint16_t local_port;
371
372 if ((r=nr_transport_addr_copy(&addr,interface_addr)))
373 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
374 addr.protocol=IPPROTO_TCPIPPROTO_TCP;
375
376 do{
377 if (!tries--)
378 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
379
380 if((r=nr_ice_component_get_port_from_ephemeral_range(&local_port)))
381 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
382
383 if ((r=nr_transport_addr_set_port(&addr, local_port)))
384 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
385
386 if((r=nr_transport_addr_fmt_addr_string(&addr)))
387 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
388
389 /* It would be better to stop trying if there is error other than
390 port already used, but it'd require significant work to support this. */
391 r=nr_socket_multi_tcp_create(ctx,component,&addr,tcp_type,so_sock_ct,NR_STUN_MAX_MESSAGE_SIZE2048,&nrsock);
392
393 } while(r);
394
395 if((tcp_type == TCP_TYPE_PASSIVE) && (r=nr_socket_listen(nrsock,backlog)))
396 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
397
398 if((r=nr_ice_socket_create(ctx,component,nrsock,NR_ICE_SOCKET_TYPE_STREAM_TCP3,&isock_tmp)))
399 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
400
401 /* nr_ice_socket took ownership of nrsock */
402 nrsock=NULL__null;
403
404 /* Create a STUN server context for this socket */
405 if ((r=nr_ice_component_create_stun_server_ctx(component,isock_tmp,&addr,lufrag,pwd)))
406 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
407
408 if((r=nr_ice_candidate_create(ctx,component,isock_tmp,isock_tmp->sock,HOST,tcp_type,0,
409 component->component_id,&cand)))
410 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
411
412 if (isock)
413 *isock=isock_tmp;
414
415 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
416 component->candidate_ct++;
417
418 STAILQ_INSERT_TAIL(&component->sockets,isock_tmp,entry)do { (((isock_tmp))->entry.stqe_next) = __null; *(&component
->sockets)->stqh_last = (isock_tmp); (&component->
sockets)->stqh_last = &(((isock_tmp))->entry.stqe_next
); } while (0)
;
419
420 _status=0;
421abort:
422 if (_status) {
423 nr_ice_socket_destroy(&isock_tmp);
424 nr_socket_destroy(&nrsock);
425 }
426 return(_status);
427 }
428
429static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_local_addr *addrs, int addr_ct, char *lufrag, Data *pwd)
430 {
431 nr_ice_candidate *cand=0;
432 int i;
433 int j;
434 int r,_status;
435 int so_sock_ct=0;
436 int backlog=10;
437 char ice_tcp_disabled=1;
438
439 r_log(LOG_ICE,LOG_DEBUG7,"nr_ice_component_initialize_tcp");
440
441 if(r=NR_reg_get_int4(NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT"ice.tcp.so_sock_count",&so_sock_ct)){
442 if(r!=R_NOT_FOUND2)
443 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
444 }
445
446 if(r=NR_reg_get_int4(NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG"ice.tcp.listen_backlog",&backlog)){
447 if(r!=R_NOT_FOUND2)
448 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
449 }
450
451 if ((r=NR_reg_get_char(NR_ICE_REG_ICE_TCP_DISABLE"ice.tcp.disable", &ice_tcp_disabled))) {
452 if (r != R_NOT_FOUND2)
453 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
454 }
455 if ((component->stream->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY(1<<2)) ||
456 (component->stream->flags & NR_ICE_CTX_FLAGS_ONLY_PROXY(1<<5))) {
457 r_log(LOG_ICE,LOG_WARNING4,"ICE-STREAM(%s): relay/proxy only option results in ICE TCP being disabled",component->stream->label);
458 ice_tcp_disabled = 1;
459 }
460
461 for(i=0;i<addr_ct;i++){
462 char suppress;
463 nr_ice_socket *isock_psv=0;
464 nr_ice_socket *isock_so=0;
465
466 if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX"ice.suppress.interface",addrs[i].addr.ifname,&suppress)){
467 if(r!=R_NOT_FOUND2)
468 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
469 }
470 else if(suppress) {
471 continue;
472 }
473
474 if (!ice_tcp_disabled) {
475 /* passive host candidate */
476 if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
477 TCP_TYPE_PASSIVE, backlog, 0, lufrag, pwd, &isock_psv))) {
478 r_log(LOG_ICE,LOG_WARNING4,"ICE-STREAM(%s): failed to create passive TCP host candidate: %d",component->stream->label,r);
479 }
480
481 /* active host candidate */
482 if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
483 TCP_TYPE_ACTIVE, 0, 0, lufrag, pwd, NULL__null))) {
484 r_log(LOG_ICE,LOG_WARNING4,"ICE-STREAM(%s): failed to create active TCP host candidate: %d",component->stream->label,r);
485 }
486
487 /* simultaneous-open host candidate */
488 if (so_sock_ct) {
489 if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
490 TCP_TYPE_SO, 0, so_sock_ct, lufrag, pwd, &isock_so))) {
491 r_log(LOG_ICE,LOG_WARNING4,"ICE-STREAM(%s): failed to create simultanous open TCP host candidate: %d",component->stream->label,r);
492 }
493 }
494
495 /* And srvrflx candidates for each STUN server */
496 for(j=0;j<component->stream->stun_server_ct;j++){
497 if (component->stream->stun_servers[j].addr.protocol != IPPROTO_TCPIPPROTO_TCP) continue;
498
499 if (isock_psv) {
500 if(r=nr_ice_candidate_create(ctx,component,
501 isock_psv,isock_psv->sock,SERVER_REFLEXIVE,TCP_TYPE_PASSIVE,
502 &component->stream->stun_servers[j],component->component_id,&cand))
503 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
504 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
505 component->candidate_ct++;
506 cand=0;
507 }
508
509 if (isock_so) {
510 if(r=nr_ice_candidate_create(ctx,component,
511 isock_so,isock_so->sock,SERVER_REFLEXIVE,TCP_TYPE_SO,
512 &component->stream->stun_servers[j],component->component_id,&cand))
513 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
514 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
515 component->candidate_ct++;
516 cand=0;
517 }
518 }
519 }
520
521 /* Create a new relayed candidate for each addr/TURN server pair */
522 for(j=0;j<component->stream->turn_server_ct;j++){
523 nr_transport_addr addr;
524 nr_socket *local_sock;
525 nr_socket *buffered_sock;
526 nr_socket *turn_sock;
527 nr_ice_socket *turn_isock;
528
529 r_log(LOG_ICE,LOG_DEBUG7,"ICE-STREAM(%s): Checking TURN server %s %s", component->stream->label, component->stream->turn_servers[j].turn_server.addr.fqdn, component->stream->turn_servers[j].turn_server.addr.as_string);
530
531 /* Skip non-TCP */
532 if (component->stream->turn_servers[j].turn_server.addr.protocol != IPPROTO_TCPIPPROTO_TCP)
533 continue;
534
535 /* Create relay candidate */
536 if ((r=nr_transport_addr_copy(&addr, &addrs[i].addr)))
537 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
538 addr.protocol = IPPROTO_TCPIPPROTO_TCP;
539
540 if (nr_transport_addr_check_compatibility(
541 &addr, &component->stream->turn_servers[j].turn_server.addr)) {
542 r_log(LOG_ICE,LOG_INFO6,"ICE-STREAM(%s): Skipping TURN server because of address type mis-match",component->stream->label);
543 continue;
544 }
545
546 if (!ice_tcp_disabled) {
547 /* Use TURN server to get srflx candidates */
548 if (isock_psv) {
549 if(r=nr_ice_candidate_create(ctx,component,
550 isock_psv,isock_psv->sock,SERVER_REFLEXIVE,TCP_TYPE_PASSIVE,
551 &component->stream->turn_servers[j].turn_server,component->component_id,&cand))
552 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
553 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
554 component->candidate_ct++;
555 cand=0;
556 }
557
558 if (isock_so) {
559 if(r=nr_ice_candidate_create(ctx,component,
560 isock_so,isock_so->sock,SERVER_REFLEXIVE,TCP_TYPE_SO,
561 &component->stream->turn_servers[j].turn_server,component->component_id,&cand))
562 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
563 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
564 component->candidate_ct++;
565 cand=0;
566 }
567 }
568
569 if (component->stream->turn_servers[j].turn_server.addr.fqdn[0] != 0) {
570 /* If we're going to use TLS, make sure that's recorded */
571 addr.tls = component->stream->turn_servers[j].turn_server.addr.tls;
572 }
573
574 if ((r=nr_transport_addr_fmt_addr_string(&addr)))
575 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
576
577 r_log(LOG_ICE, LOG_DEBUG7,
578 "ICE-STREAM(%s): Creating socket for address %s (turn server %s)",
579 component->stream->label, addr.as_string,
580 component->stream->turn_servers[j].turn_server.addr.as_string);
581
582 /* Create a local socket */
583 if((r=nr_socket_factory_create_socket(ctx->socket_factory,&addr,&local_sock))){
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'
584 r_log(LOG_ICE,LOG_DEBUG7,"ICE-STREAM(%s): couldn't create socket for address %s",component->stream->label,addr.as_string);
585 continue;
586 }
587
588 r_log(LOG_ICE,LOG_DEBUG7,"nr_ice_component_initialize_tcp creating TURN TCP wrappers");
589
590 /* The TCP buffered socket */
591 if((r=nr_socket_buffered_stun_create(local_sock, NR_STUN_MAX_MESSAGE_SIZE2048, TURN_TCP_FRAMING, &buffered_sock)))
592 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
593
594 /* The TURN socket */
595 if(r=nr_socket_turn_create(&turn_sock))
596 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
597
598 /* Create an ICE socket */
599 if((r=nr_ice_socket_create(ctx, component, buffered_sock, NR_ICE_SOCKET_TYPE_STREAM_TURN2, &turn_isock)))
600 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
601
602 /* Make sure we don't leak this. Failures might result in it being
603 * unused, but we hand off references to this in enough places below
604 * that unwinding it all becomes impractical. */
605 STAILQ_INSERT_TAIL(&component->sockets,turn_isock,entry)do { (((turn_isock))->entry.stqe_next) = __null; *(&component
->sockets)->stqh_last = (turn_isock); (&component->
sockets)->stqh_last = &(((turn_isock))->entry.stqe_next
); } while (0)
;
606
607 /* Create a STUN server context for this socket */
608 if ((r=nr_ice_component_create_stun_server_ctx(component,turn_isock,&addr,lufrag,pwd)))
609 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
610
611 /* Attach ourselves to it */
612 if(r=nr_ice_candidate_create(ctx,component,
613 turn_isock,turn_sock,RELAYED,TCP_TYPE_NONE,
614 &component->stream->turn_servers[j].turn_server,component->component_id,&cand))
615 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
616 cand->u.relayed.srvflx_candidate=NULL__null;
617 cand->u.relayed.server=&component->stream->turn_servers[j];
618 TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)->
entry_comp.tqe_prev = (&component->candidates)->tqh_last
; *(&component->candidates)->tqh_last = (cand); (&
component->candidates)->tqh_last = &(((cand))->entry_comp
.tqe_next); ; ; } while (0)
;
619 component->candidate_ct++;
620 cand=0;
621 }
622 }
623
624 _status = 0;
625 abort:
626 return(_status);
627 }
628
629
630/* Make all the candidates we can make at the beginning */
631int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component)
632 {
633 int r,_status;
634 nr_local_addr *addrs=ctx->local_addrs;
635 int addr_ct=ctx->local_addr_ct;
636 char *lufrag;
637 char *lpwd;
638 Data pwd;
639 nr_ice_candidate *cand;
640
641 if (component->candidate_ct) {
642 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): component with id %d already has candidates, probably restarting gathering because of a new stream",ctx->label,component->component_id);
643 return(0);
644 }
645
646 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): initializing component with id %d",ctx->label,component->component_id);
647
648 if(addr_ct==0){
649 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): no local addresses available",ctx->label);
650 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
651 }
652
653 /* Note: we need to recompute these because
654 we have not yet computed the values in the peer media stream.*/
655 lufrag=component->stream->ufrag;
656 assert(lufrag)(static_cast <bool> (lufrag) ? void (0) : __assert_fail
("lufrag", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
657 if (!lufrag)
658 ABORT(R_INTERNAL)do { int _r=3; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
659 lpwd=component->stream->pwd;
660 assert(lpwd)(static_cast <bool> (lpwd) ? void (0) : __assert_fail (
"lpwd", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
661 if (!lpwd)
662 ABORT(R_INTERNAL)do { int _r=3; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
663 INIT_DATA(pwd, (UCHAR *)lpwd, strlen(lpwd))(pwd).data=(UCHAR *)lpwd; (pwd).len=strlen(lpwd);
664
665 /* Initialize the UDP candidates */
666 if (r=nr_ice_component_initialize_udp(ctx, component, addrs, addr_ct, lufrag, &pwd))
667 r_log(LOG_ICE,LOG_INFO6,"ICE(%s): failed to create UDP candidates with error %d",ctx->label,r);
668 /* And the TCP candidates */
669 if (r=nr_ice_component_initialize_tcp(ctx, component, addrs, addr_ct, lufrag, &pwd))
670 r_log(LOG_ICE,LOG_INFO6,"ICE(%s): failed to create TCP candidates with error %d",ctx->label,r);
671
672 /* count the candidates that will be initialized */
673 cand=TAILQ_FIRST(&component->candidates)((&component->candidates)->tqh_first);
674 if(!cand){
675 r_log(LOG_ICE,LOG_ERR3,"ICE(%s): couldn't create any valid candidates",ctx->label);
676 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
677 }
678
679 while(cand){
680 ctx->uninitialized_candidates++;
681 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
682 }
683
684 /* Now initialize all the candidates */
685 cand=TAILQ_FIRST(&component->candidates)((&component->candidates)->tqh_first);
686 while(cand){
687 if(cand->state!=NR_ICE_CAND_STATE_INITIALIZING2){
688 nr_ice_candidate_initialize(cand,nr_ice_gather_finished_cb,cand);
689 }
690 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
691 }
692 _status=0;
693 abort:
694 return(_status);
695 }
696
697void nr_ice_component_stop_gathering(nr_ice_component *component)
698 {
699 nr_ice_candidate *c1,*c2;
700 TAILQ_FOREACH_SAFE(c1, &component->candidates, entry_comp, c2)for ((c1) = (((&component->candidates))->tqh_first)
; (c1) && ((c2) = (((c1))->entry_comp.tqe_next), 1
); (c1) = (c2))
{
701 nr_ice_candidate_stop_gathering(c1);
702 }
703 }
704
705int nr_ice_component_is_done_gathering(nr_ice_component *comp)
706 {
707 nr_ice_candidate *cand=TAILQ_FIRST(&comp->candidates)((&comp->candidates)->tqh_first);
708 while(cand){
709 if(cand->state != NR_ICE_CAND_STATE_INITIALIZED3 &&
710 cand->state != NR_ICE_CAND_STATE_FAILED4){
711 return 0;
712 }
713 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
714 }
715 return 1;
716 }
717
718
719static int nr_ice_any_peer_paired(nr_ice_candidate* cand) {
720 nr_ice_peer_ctx* pctx=STAILQ_FIRST(&cand->ctx->peers)((&cand->ctx->peers)->stqh_first);
721 while(pctx && pctx->state == NR_ICE_PEER_STATE_UNPAIRED1){
722 /* Is it worth actually looking through the check lists? Probably not. */
723 pctx=STAILQ_NEXT(pctx,entry)((pctx)->entry.stqe_next);
724 }
725 return pctx != NULL__null;
726}
727
728/*
729 Compare this newly initialized candidate against the other initialized
730 candidates and discard the lower-priority one if they are redundant.
731
732 This algorithm combined with the other algorithms, favors
733 host > srflx > relay
734 */
735int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned)
736 {
737 nr_ice_candidate *c2, *tmp = NULL__null;
738
739 *was_pruned = 0;
740 c2 = TAILQ_FIRST(&comp->candidates)((&comp->candidates)->tqh_first);
741 while(c2){
742 if((c1 != c2) &&
743 (c2->state == NR_ICE_CAND_STATE_INITIALIZED3) &&
744 !nr_transport_addr_cmp(&c1->base,&c2->base,NR_TRANSPORT_ADDR_CMP_MODE_ALL4) &&
745 !nr_transport_addr_cmp(&c1->addr,&c2->addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL4)){
746
747 if((c1->type == c2->type) ||
748 (!(ctx->flags & NR_ICE_CTX_FLAGS_DISABLE_HOST_CANDIDATES(1<<3)) &&
749 !(ctx->flags & NR_ICE_CTX_FLAGS_OBFUSCATE_HOST_ADDRESSES(1<<6)) &&
750 ((c1->type==HOST && c2->type == SERVER_REFLEXIVE) ||
751 (c2->type==HOST && c1->type == SERVER_REFLEXIVE)))){
752
753 /*
754 These are redundant. Remove the lower pri one, or if pairing has
755 already occurred, remove the newest one.
756
757 Since this algorithmis run whenever a new candidate
758 is initialized, there should at most one duplicate.
759 */
760 if ((c1->priority <= c2->priority) || nr_ice_any_peer_paired(c2)) {
761 tmp = c1;
762 *was_pruned = 1;
763 }
764 else {
765 tmp = c2;
766 }
767 break;
768 }
769 }
770
771 c2=TAILQ_NEXT(c2,entry_comp)((c2)->entry_comp.tqe_next);
772 }
773
774 if (tmp) {
775 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s)/CAND(%s): Removing redundant candidate",
776 ctx->label,tmp->label);
777
778 TAILQ_REMOVE(&comp->candidates,tmp,entry_comp)do { if (((((tmp))->entry_comp.tqe_next)) != __null) (((tmp
))->entry_comp.tqe_next)->entry_comp.tqe_prev = (tmp)->
entry_comp.tqe_prev; else { (&comp->candidates)->tqh_last
= (tmp)->entry_comp.tqe_prev; ; } *(tmp)->entry_comp.tqe_prev
= (((tmp))->entry_comp.tqe_next); ; ; ; } while (0)
;
779 comp->candidate_ct--;
780 TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock)do { if (((((tmp))->entry_sock.tqe_next)) != __null) (((tmp
))->entry_sock.tqe_next)->entry_sock.tqe_prev = (tmp)->
entry_sock.tqe_prev; else { (&tmp->isock->candidates
)->tqh_last = (tmp)->entry_sock.tqe_prev; ; } *(tmp)->
entry_sock.tqe_prev = (((tmp))->entry_sock.tqe_next); ; ; ;
} while (0)
;
781
782 nr_ice_candidate_destroy(&tmp);
783 }
784
785 return 0;
786 }
787
788static int nr_ice_component_pair_matches_check(nr_ice_component *comp, nr_ice_cand_pair *pair, nr_transport_addr *local_addr, nr_stun_server_request *req)
789 {
790 if(pair->remote->component->component_id!=comp->component_id)
791 return(0);
792
793 if(nr_transport_addr_cmp(&pair->local->base,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL4))
794 return(0);
795
796 if(nr_transport_addr_cmp(&pair->remote->addr,&req->src_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL4))
797 return(0);
798
799 return(1);
800 }
801
802static int nr_ice_component_handle_use_candidate(nr_ice_component *comp, nr_ice_cand_pair *pair, int *error)
803 {
804 int r=0,_status;
805
806 if(comp->stream->pctx->controlling){
807 r_log(LOG_ICE,LOG_WARNING4,"ICE-PEER(%s)/CAND_PAIR(%s): Peer sent USE-CANDIDATE but is controlled",comp->stream->pctx->label, pair->codeword);
808 }
809 else{
810 /* If this is the first time we've noticed this is nominated...*/
811 pair->peer_nominated=1;
812
813 if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED5 && !pair->nominated){
814 pair->nominated=1;
815
816 if(r=nr_ice_component_nominated_pair(pair->remote->component, pair)) {
817 *error=(r==R_NO_MEMORY1)?500:400;
818 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
819 }
820 }
821 }
822
823 _status=0;
824 abort:
825 return(_status);
826 }
827
828/* Section 7.2.1 */
829static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_transport_addr *local_addr, nr_stun_server_request *req, int *error)
830 {
831 nr_ice_cand_pair *pair;
832 nr_ice_candidate *pcand=0;
833 nr_stun_message *sreq=req->request;
834 nr_stun_message_attribute *attr;
835 int r=0,_status;
836 int found_valid=0;
837
838 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): received request from %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,req->src_addr.as_string);
839
840 if (comp->state == NR_ICE_COMPONENT_DISABLED4)
841 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
842
843 /* Check for role conficts (7.2.1.1) */
844 if(comp->stream->pctx->controlling){
845 if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLING0x802A,&attr)){
846 /* OK, there is a conflict. Who's right? */
847 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): role conflict, both controlling",comp->stream->pctx->label);
848
849 if(attr->u.ice_controlling > comp->stream->pctx->tiebreaker){
850 /* Update the peer ctx. This will propagate to all candidate pairs
851 in the context. */
852 nr_ice_peer_ctx_switch_controlling_role(comp->stream->pctx);
853 }
854 else {
855 /* We are: throw an error */
856 r_log(LOG_ICE,LOG_WARNING4,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
857
858 *error=487;
859 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
860 }
861 }
862 }
863 else{
864 if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLED0x8029,&attr)){
865 /* OK, there is a conflict. Who's right? */
866 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): role conflict, both controlled",comp->stream->pctx->label);
867
868 if(attr->u.ice_controlled < comp->stream->pctx->tiebreaker){
869 /* Update the peer ctx. This will propagate to all candidate pairs
870 in the context. */
871 nr_ice_peer_ctx_switch_controlling_role(comp->stream->pctx);
872 }
873 else {
874 /* We are: throw an error */
875 r_log(LOG_ICE,LOG_WARNING4,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
876
877 *error=487;
878 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
879 }
880 }
881 }
882
883 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s): This STUN request appears to map to local addr %s",comp->stream->pctx->label,local_addr->as_string);
884
885 pair=TAILQ_FIRST(&comp->stream->check_list)((&comp->stream->check_list)->tqh_first);
886 while(pair){
887 /* Since triggered checks create duplicate pairs (in this implementation)
888 * we are willing to handle multiple matches here. */
889 if(nr_ice_component_pair_matches_check(comp, pair, local_addr, req)){
890 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/CAND_PAIR(%s): Found a matching pair for received check: %s",comp->stream->pctx->label,pair->codeword,pair->as_string);
891 int peer_nominated = pair->peer_nominated;
892 if(nr_stun_message_has_attribute(req->request,NR_STUN_ATTR_USE_CANDIDATE0x0025,0)){
893 if(r=nr_ice_component_handle_use_candidate(comp, pair, error)) {
894 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
895 }
896 }
897
898 int new_peer_nomination = !peer_nominated && pair->peer_nominated;
899 int might_select = !comp->nominated ||
900 (comp->nominated->priority < pair->priority);
901 int force = new_peer_nomination && might_select;
902
903 /* Note: the RFC says to trigger first and then nominate. But in that
904 * case the canceled trigger pair would get nominated and the cloned
905 * trigger pair would not get the nomination status cloned with it.*/
906 if(!found_valid && (r=nr_ice_candidate_pair_do_triggered_check(comp->stream->pctx, pair, force))) {
907 *error=(r==R_NO_MEMORY1)?500:400;
908 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
909 }
910 found_valid=1;
911 }
912 pair=TAILQ_NEXT(pair,check_queue_entry)((pair)->check_queue_entry.tqe_next);
913 }
914
915 if(!found_valid){
916 /* There were no matching pairs, so we need to create a new peer
917 * reflexive candidate pair. */
918
919 if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY0x0024,&attr)){
920 r_log(LOG_ICE,LOG_WARNING4,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label);
921 *error=400;
922 ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
923 }
924
925 /* Find our local component candidate */
926 nr_ice_candidate *cand;
927
928 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s): no matching pair",comp->stream->pctx->label);
929 cand=TAILQ_FIRST(&comp->local_component->candidates)((&comp->local_component->candidates)->tqh_first
)
;
930 while(cand){
931 if(!nr_transport_addr_cmp(&cand->addr,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL4))
932 break;
933
934 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
935 }
936
937 /* Well, this really shouldn't happen, but it's an error from the
938 other side, so we just throw an error and keep going */
939 if(!cand){
940 r_log(LOG_ICE,LOG_WARNING4,"ICE-PEER(%s): stun request to unknown local address %s, discarding",comp->stream->pctx->label,local_addr->as_string);
941
942 *error=400;
943 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
944 }
945
946 /* Now make a peer reflexive (remote) candidate */
947 if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) {
948 *error=(r==R_NO_MEMORY1)?500:400;
949 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
950 }
951 pcand->priority=attr->u.priority;
952 pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED10;
953
954 /* Finally, create the candidate pair, insert into the check list, and
955 * apply the incoming check to it. */
956 if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand,
957 &pair)) {
958 *error=(r==R_NO_MEMORY1)?500:400;
959 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
960 }
961
962 nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FROZEN1);
963 if(r=nr_ice_component_insert_pair(comp,pair)) {
964 *error=(r==R_NO_MEMORY1)?500:400;
965 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
966 }
967
968 /* Do this last, since any call to ABORT will destroy pcand */
969 TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp)do { (((pcand))->entry_comp.tqe_next) = __null; (pcand)->
entry_comp.tqe_prev = (&comp->candidates)->tqh_last
; *(&comp->candidates)->tqh_last = (pcand); (&comp
->candidates)->tqh_last = &(((pcand))->entry_comp
.tqe_next); ; ; } while (0)
;
970 pcand=0;
971
972 if(nr_stun_message_has_attribute(req->request,NR_STUN_ATTR_USE_CANDIDATE0x0025,0)){
973 if(r=nr_ice_component_handle_use_candidate(comp, pair, error)) {
974 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
975 }
976 }
977
978 /* Finally start the trigger check if needed */
979 if(r=nr_ice_candidate_pair_do_triggered_check(comp->stream->pctx, pair, 0)) {
980 *error=(r==R_NO_MEMORY1)?500:400;
981 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
982 }
983 }
984
985 _status=0;
986 abort:
987 if(_status){
988 nr_ice_candidate_destroy(&pcand);
989 assert(*error != 0)(static_cast <bool> (*error != 0) ? void (0) : __assert_fail
("*error != 0", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
990 if(r!=R_NO_MEMORY1) assert(*error != 500)(static_cast <bool> (*error != 500) ? void (0) : __assert_fail
("*error != 500", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
991 }
992 return(_status);
993 }
994
995static int nr_ice_component_stun_server_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error)
996 {
997 nr_ice_component *pcomp=(nr_ice_component*)cb_arg;
998 nr_transport_addr local_addr;
999 int r,_status;
1000
1001 if(pcomp->state==NR_ICE_COMPONENT_FAILED3) {
1002 *error=400;
1003 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1004 }
1005
1006 if (pcomp->local_component->stream->obsolete) {
1007 /* Don't do any triggered check stuff in thiis case. */
1008 return 0;
1009 }
1010
1011 /* Find the candidate pair that this maps to */
1012 if(r=nr_socket_getaddr(sock,&local_addr)) {
1013 *error=500;
1014 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1015 }
1016
1017 if (r=nr_ice_component_process_incoming_check(pcomp, &local_addr, req, error))
1018 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1019
1020 _status=0;
1021 abort:
1022 return(_status);
1023 }
1024
1025int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced)
1026 {
1027 nr_ice_pre_answer_request *r1,*r2;
1028 nr_ice_component *comp = pcomp->local_component;
1029 int r,_status;
1030
1031 if (serviced)
1032 *serviced = 0;
1033
1034 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): looking for pre-answer requests",pctx->label,comp->stream->label,comp->component_id);
1035
1036 STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2)for ((r1) = (((&comp->pre_answer_reqs))->stqh_first
); (r1) && ((r2) = (((r1))->entry.stqe_next), 1); (
r1) = (r2))
{
1037 if (!strcmp(r1->username, username)) {
1038 int error = 0;
1039
1040 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): found pre-answer request",pctx->label,comp->stream->label,comp->component_id);
1041 r = nr_ice_component_process_incoming_check(pcomp, &r1->local_addr, &r1->req, &error);
1042 if (r) {
1043 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): error processing pre-answer request. Would have returned %d",pctx->label,comp->stream->label,comp->component_id, error);
1044 }
1045 (*serviced)++;
1046 STAILQ_REMOVE(&comp->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry)do { if ((((&comp->pre_answer_reqs))->stqh_first) ==
(r1)) { do { if ((((((&comp->pre_answer_reqs)))->stqh_first
) = ((((((&comp->pre_answer_reqs)))->stqh_first))->
entry.stqe_next)) == __null) ((&comp->pre_answer_reqs)
)->stqh_last = &((((&comp->pre_answer_reqs)))->
stqh_first); } while (0); } else { struct nr_ice_pre_answer_request_
*curelm = (((&comp->pre_answer_reqs))->stqh_first)
; while (((curelm)->entry.stqe_next) != (r1)) curelm = ((curelm
)->entry.stqe_next); if ((((curelm)->entry.stqe_next) =
((((curelm)->entry.stqe_next))->entry.stqe_next)) == __null
) (&comp->pre_answer_reqs)->stqh_last = &(((curelm
))->entry.stqe_next); } } while (0)
;
1047 nr_ice_pre_answer_request_destroy(&r1);
1048 }
1049 }
1050
1051 _status=0;
1052 return(_status);
1053 }
1054
1055int nr_ice_component_can_candidate_tcptype_pair(nr_socket_tcp_type left, nr_socket_tcp_type right)
1056 {
1057 if (left && !right)
1058 return(0);
1059 if (!left && right)
1060 return(0);
1061 if (left == TCP_TYPE_ACTIVE && right != TCP_TYPE_PASSIVE)
1062 return(0);
1063 if (left == TCP_TYPE_SO && right != TCP_TYPE_SO)
1064 return(0);
1065 if (left == TCP_TYPE_PASSIVE)
1066 return(0);
1067
1068 return(1);
1069 }
1070
1071/* filter out pairings which won't work. */
1072int nr_ice_component_can_candidate_addr_pair(nr_transport_addr *local, nr_transport_addr *remote)
1073 {
1074 if(local->ip_version != remote->ip_version)
1075 return(0);
1076 if(local->protocol != remote->protocol)
1077 return(0);
1078 if(nr_transport_addr_is_link_local(local) !=
1079 nr_transport_addr_is_link_local(remote))
1080 return(0);
1081 /* This prevents our ice_unittest (or broken clients) from pairing a
1082 * loopback with a host candidate. */
1083 if(nr_transport_addr_is_loopback(local) !=
1084 nr_transport_addr_is_loopback(remote))
1085 return(0);
1086
1087 return(1);
1088 }
1089
1090int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote)
1091 {
1092 int r, _status;
1093 nr_ice_candidate *pcand;
1094 nr_ice_cand_pair *pair=0;
1095 char codeword[5];
1096
1097 nr_ice_compute_codeword(lcand->label,strlen(lcand->label),codeword);
1098 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/CAND(%s): Pairing local candidate %s",pctx->label,codeword,lcand->label);
1099
1100 switch(lcand->type){
1101 case HOST:
1102 break;
1103 case SERVER_REFLEXIVE:
1104 case PEER_REFLEXIVE:
1105 /* Don't actually pair these candidates */
1106 goto done;
1107 break;
1108 case RELAYED:
1109 break;
1110 default:
1111 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1112 ABORT(R_INTERNAL)do { int _r=3; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1113 break;
1114 }
1115
1116 TAILQ_FOREACH(pcand, &pcomp->candidates, entry_comp)for ((pcand) = (((&pcomp->candidates))->tqh_first);
(pcand); (pcand) = (((pcand))->entry_comp.tqe_next))
{
1117 if(!nr_ice_component_can_candidate_addr_pair(&lcand->addr, &pcand->addr))
1118 continue;
1119 if(!nr_ice_component_can_candidate_tcptype_pair(lcand->tcp_type, pcand->tcp_type))
1120 continue;
1121
1122 /* https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-mdns-ice-candidates#section-3.3.2-3 */
1123 // Note: This probably should not hold for FQDN (as opposed to mDNS), but
1124 // we don't really support that anyway for remote candidates.
1125 if(lcand->type == RELAYED && strlen(pcand->addr.fqdn)) {
1126 continue;
1127 }
1128
1129 /*
1130 Two modes, depending on |pair_all_remote|
1131
1132 1. Pair remote candidates which have not been paired
1133 (used in initial pairing or in processing the other side's
1134 trickle candidates).
1135 2. Pair any remote candidate (used when processing our own
1136 trickle candidates).
1137 */
1138 if (pair_all_remote || (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED9)) {
1139 if (pair_all_remote) {
1140 /* When a remote candidate arrives after the start of checking, but
1141 * before the gathering of local candidates, it can be in UNPAIRED */
1142 pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED10;
1143 }
1144
1145 nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
1146 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/CAND(%s): Pairing with peer candidate %s", pctx->label, codeword, pcand->label);
1147
1148 if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
1149 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1150
1151 if(r=nr_ice_component_insert_pair(pcomp, pair))
1152 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1153 }
1154 }
1155
1156 done:
1157 _status = 0;
1158 abort:
1159 return(_status);
1160 }
1161
1162int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp)
1163 {
1164 nr_ice_candidate *lcand, *pcand;
1165 nr_ice_socket *isock;
1166 int r,_status;
1167
1168 r_log(LOG_ICE,LOG_DEBUG7,"Pairing candidates======");
1169
1170 /* Create the candidate pairs */
1171 lcand=TAILQ_FIRST(&lcomp->candidates)((&lcomp->candidates)->tqh_first);
1172
1173 if (!lcand) {
1174 /* No local candidates, initialized or not! */
1175 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1176 }
1177
1178 while(lcand){
1179 if (lcand->state == NR_ICE_CAND_STATE_INITIALIZED3) {
1180 if ((r = nr_ice_component_pair_candidate(pctx, pcomp, lcand, 0)))
1181 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1182 }
1183
1184 lcand=TAILQ_NEXT(lcand,entry_comp)((lcand)->entry_comp.tqe_next);
1185 }
1186
1187 /* Mark all peer candidates as paired */
1188 pcand=TAILQ_FIRST(&pcomp->candidates)((&pcomp->candidates)->tqh_first);
1189 while(pcand){
1190 pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED10;
1191
1192 pcand=TAILQ_NEXT(pcand,entry_comp)((pcand)->entry_comp.tqe_next);
1193
1194 }
1195
1196 /* Now register the STUN server callback for this component.
1197 Note that this is a per-component CB so we only need to
1198 do this once.
1199 */
1200 if (pcomp->state != NR_ICE_COMPONENT_RUNNING1) {
1201 isock=STAILQ_FIRST(&lcomp->sockets)((&lcomp->sockets)->stqh_first);
1202 while(isock){
1203 if(r=nr_stun_server_add_client(isock->stun_server,pctx->label,
1204 pcomp->stream->r2l_user,&pcomp->stream->r2l_pass,nr_ice_component_stun_server_cb,pcomp)) {
1205 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1206 }
1207 isock=STAILQ_NEXT(isock,entry)((isock)->entry.stqe_next);
1208 }
1209 }
1210
1211 pcomp->state = NR_ICE_COMPONENT_RUNNING1;
1212
1213 _status=0;
1214 abort:
1215 return(_status);
1216 }
1217
1218int nr_ice_pre_answer_enqueue(nr_ice_component *comp, nr_socket *sock, nr_stun_server_request *req, int *dont_free)
1219 {
1220 int r = 0;
1221 int _status;
1222 nr_ice_pre_answer_request *r1, *r2;
1223 nr_transport_addr dst_addr;
1224 nr_ice_pre_answer_request *par = 0;
1225
1226 if (r=nr_socket_getaddr(sock, &dst_addr))
1227 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1228
1229 STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2)for ((r1) = (((&comp->pre_answer_reqs))->stqh_first
); (r1) && ((r2) = (((r1))->entry.stqe_next), 1); (
r1) = (r2))
{
1230 if (!nr_transport_addr_cmp(&r1->local_addr, &dst_addr,
1231 NR_TRANSPORT_ADDR_CMP_MODE_ALL4) &&
1232 !nr_transport_addr_cmp(&r1->req.src_addr, &req->src_addr,
1233 NR_TRANSPORT_ADDR_CMP_MODE_ALL4)) {
1234 return(0);
1235 }
1236 }
1237
1238 if (r=nr_ice_pre_answer_request_create(&dst_addr, req, &par))
1239 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1240
1241 r_log(LOG_ICE,LOG_DEBUG7, "ICE(%s)/STREAM(%s)/COMP(%d): Enqueuing STUN request pre-answer from %s",
1242 comp->ctx->label, comp->stream->label, comp->component_id,
1243 req->src_addr.as_string);
1244
1245 *dont_free = 1;
1246 STAILQ_INSERT_TAIL(&comp->pre_answer_reqs, par, entry)do { (((par))->entry.stqe_next) = __null; *(&comp->
pre_answer_reqs)->stqh_last = (par); (&comp->pre_answer_reqs
)->stqh_last = &(((par))->entry.stqe_next); } while
(0)
;
1247
1248 _status=0;
1249abort:
1250 return(_status);
1251 }
1252
1253/* Fires when we have an incoming candidate that doesn't correspond to an existing
1254 remote peer. This is either pre-answer or just spurious. Store it in the
1255 component for use when we see the actual answer, at which point we need
1256 to do the procedures from S 7.2.1 in nr_ice_component_stun_server_cb.
1257 */
1258static int nr_ice_component_stun_server_default_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error)
1259 {
1260 int r, _status;
1261 nr_ice_component *comp = (nr_ice_component *)cb_arg;
1262
1263 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s)/STREAM(%s)/COMP(%d): Received STUN request pre-answer from %s",
1264 comp->ctx->label, comp->stream->label, comp->component_id,
1265 req->src_addr.as_string);
1266
1267 if (r=nr_ice_pre_answer_enqueue(comp, sock, req, dont_free)) {
1268 r_log(LOG_ICE,LOG_ERR3,"ICE(%s)/STREAM(%s)/COMP(%d): Failed (%d) to enque pre-answer request from %s",
1269 comp->ctx->label, comp->stream->label, comp->component_id, r,
1270 req->src_addr.as_string);
1271 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1272 }
1273
1274 _status=0;
1275 abort:
1276 return(_status);
1277 }
1278
1279#define NR_ICE_CONSENT_TIMER_DEFAULT5000 5000
1280#define NR_ICE_CONSENT_TIMEOUT_DEFAULT30000 30000
1281
1282static void nr_ice_component_consent_failed(nr_ice_component *comp)
1283 {
1284 if (!comp->can_send) {
1285 return;
1286 }
1287
1288 r_log(LOG_ICE,LOG_INFO6,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh failed",
1289 comp->ctx->label, comp->stream->label, comp->component_id);
1290 comp->can_send = 0;
1291
1292 if (comp->consent_timeout) {
1293 NR_async_timer_cancel(comp->consent_timeout);
1294 comp->consent_timeout = 0;
1295 }
1296 if (comp->consent_timer) {
1297 NR_async_timer_cancel(comp->consent_timer);
1298 comp->consent_timer = 0;
1299 }
1300 /* We are turning the consent failure into a ICE component failure to
1301 * alert the browser via ICE connection state change about this event. */
1302 nr_ice_media_stream_component_failed(comp->stream, comp);
1303 }
1304
1305static void nr_ice_component_consent_timeout_cb(NR_SOCKET s, int how, void *cb_arg)
1306 {
1307 nr_ice_component *comp=(nr_ice_component*)cb_arg;
1308
1309 comp->consent_timeout = 0;
1310
1311 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh final time out",
1312 comp->ctx->label, comp->stream->label, comp->component_id);
1313 nr_ice_component_consent_failed(comp);
1314 }
1315
1316
1317void nr_ice_component_disconnected(nr_ice_component *comp)
1318 {
1319 if (!comp->can_send) {
1320 return;
1321 }
1322
1323 if (comp->disconnected) {
1324 return;
1325 }
1326
1327 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s)/STREAM(%s)/COMP(%d): component disconnected",
1328 comp->ctx->label, comp->stream->label, comp->component_id);
1329 comp->disconnected = 1;
1330
1331 /* a single disconnected component disconnects the stream */
1332 nr_ice_media_stream_set_disconnected(comp->stream, NR_ICE_MEDIA_STREAM_DISCONNECTED1);
1333 }
1334
1335static void nr_ice_component_consent_refreshed(nr_ice_component *comp)
1336 {
1337 uint16_t tval;
1338
1339 if (!comp->can_send) {
1340 return;
1341 }
1342
1343 gettimeofday(&comp->consent_last_seen, 0);
1344 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s)/STREAM(%s)/COMP(%d): consent_last_seen is now %lu",
1345 comp->ctx->label, comp->stream->label, comp->component_id,
1346 comp->consent_last_seen.tv_sec);
1347
1348 comp->disconnected = 0;
1349
1350 nr_ice_media_stream_check_if_connected(comp->stream);
1351
1352 if (comp->consent_timeout)
1353 NR_async_timer_cancel(comp->consent_timeout);
1354
1355 tval = NR_ICE_CONSENT_TIMEOUT_DEFAULT30000;
1356 if (comp->ctx->test_timer_divider)
1357 tval = tval / comp->ctx->test_timer_divider;
1358
1359 NR_ASYNC_TIMER_SET(tval, nr_ice_component_consent_timeout_cb, comp,NR_async_timer_set(tval,nr_ice_component_consent_timeout_cb,comp
,(char *)__FUNCTION__,1360,&comp->consent_timeout)
1360 &comp->consent_timeout)NR_async_timer_set(tval,nr_ice_component_consent_timeout_cb,comp
,(char *)__FUNCTION__,1360,&comp->consent_timeout)
;
1361 }
1362
1363static void nr_ice_component_refresh_consent_cb(NR_SOCKET s, int how, void *cb_arg)
1364 {
1365 nr_ice_cand_pair *pair=(nr_ice_cand_pair*)cb_arg;
1366 assert(pair && pair->remote && pair->remote->component)(static_cast <bool> (pair && pair->remote &&
pair->remote->component) ? void (0) : __assert_fail ("pair && pair->remote && pair->remote->component"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1367 nr_ice_component *comp=pair->remote->component;
1368
1369 switch (comp->consent_ctx->state) {
1370 case NR_STUN_CLIENT_STATE_FAILED3:
1371 if (comp->consent_ctx->error_code == 403) {
1372 r_log(LOG_ICE, LOG_INFO6, "ICE(%s)/STREAM(%s)/COMP(%d): Consent revoked by peer",
1373 comp->ctx->label, comp->stream->label, comp->component_id);
1374 nr_ice_component_consent_failed(comp);
1375 }
1376 break;
1377 case NR_STUN_CLIENT_STATE_DONE2:
1378 r_log(LOG_ICE, LOG_INFO6, "ICE(%s)/STREAM(%s)/COMP(%d): Consent refreshed",
1379 comp->ctx->label, comp->stream->label, comp->component_id);
1380 if (comp->consent_ctx->rtt_valid) {
1381 nr_ice_candidate_pair_update_rtt(pair, comp->consent_ctx->rtt_ms);
1382 // clear rtt_ms so we can't double process it.
1383 comp->consent_ctx->rtt_valid = 0;
1384 comp->consent_ctx->rtt_ms = 0;
1385 }
1386 nr_ice_component_consent_refreshed(comp);
1387 break;
1388 case NR_STUN_CLIENT_STATE_TIMED_OUT4:
1389 r_log(LOG_ICE, LOG_INFO6, "ICE(%s)/STREAM(%s)/COMP(%d): A single consent refresh request timed out",
1390 comp->ctx->label, comp->stream->label, comp->component_id);
1391 nr_ice_component_disconnected(comp);
1392 break;
1393 default:
1394 break;
1395 }
1396 }
1397
1398int nr_ice_component_refresh_consent(nr_stun_client_ctx *ctx, NR_async_cb finished_cb, void *cb_arg)
1399 {
1400 int r,_status;
1401
1402 nr_stun_client_reset(ctx);
1403
1404 if (r=nr_stun_client_start(ctx, NR_ICE_CLIENT_MODE_BINDING_REQUEST11, finished_cb, cb_arg))
1405 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1406
1407 _status=0;
1408 abort:
1409 return(_status);
1410 }
1411
1412void nr_ice_component_consent_calc_consent_timer(nr_ice_component *comp)
1413 {
1414 uint16_t trange, trand, tval;
1415
1416 trange = NR_ICE_CONSENT_TIMER_DEFAULT5000 * 20 / 100;
1417 tval = NR_ICE_CONSENT_TIMER_DEFAULT5000 - trange;
1418 if (!nr_crypto_random_bytes((UCHAR*)&trand, sizeof(trand))nr_crypto_vtbl->random_bytes((UCHAR*)&trand,sizeof(trand
))
)
1419 tval += (trand % (trange * 2));
1420
1421 if (comp->ctx->test_timer_divider)
1422 tval = tval / comp->ctx->test_timer_divider;
1423
1424 /* The timeout of the transaction is the maximum time until we send the
1425 * next consent request. */
1426 comp->consent_ctx->maximum_transmits_timeout_ms = tval;
1427 }
1428
1429static void nr_ice_component_consent_timer_cb(NR_SOCKET s, int how, void *cb_arg)
1430 {
1431 nr_ice_component *comp=(nr_ice_component*)cb_arg;
1432 int r;
1433
1434 if (!comp->consent_ctx) {
1435 return;
1436 }
1437
1438 if (comp->consent_timer) {
1439 NR_async_timer_cancel(comp->consent_timer);
1440 }
1441 comp->consent_timer = 0;
1442
1443 comp->consent_ctx->params.ice_binding_request.username =
1444 comp->stream->l2r_user;
1445 comp->consent_ctx->params.ice_binding_request.password =
1446 comp->stream->l2r_pass;
1447 comp->consent_ctx->params.ice_binding_request.control =
1448 comp->stream->pctx->controlling?
1449 NR_ICE_CONTROLLING1:NR_ICE_CONTROLLED2;
1450 comp->consent_ctx->params.ice_binding_request.tiebreaker =
1451 comp->stream->pctx->tiebreaker;
1452 comp->consent_ctx->params.ice_binding_request.priority =
1453 comp->active->local->priority;
1454
1455 nr_ice_component_consent_calc_consent_timer(comp);
1456
1457 if (r=nr_ice_component_refresh_consent(comp->consent_ctx,
1458 nr_ice_component_refresh_consent_cb,
1459 comp->active)) {
1460 r_log(LOG_ICE,LOG_ERR3,"ICE(%s)/STREAM(%s)/COMP(%d): Refresh consent failed with %d",
1461 comp->ctx->label, comp->stream->label, comp->component_id, r);
1462 }
1463
1464 nr_ice_component_consent_schedule_consent_timer(comp);
1465
1466 }
1467
1468void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp)
1469 {
1470 if (!comp->can_send) {
1471 return;
1472 }
1473
1474 NR_ASYNC_TIMER_SET(comp->consent_ctx->maximum_transmits_timeout_ms,NR_async_timer_set(comp->consent_ctx->maximum_transmits_timeout_ms
,nr_ice_component_consent_timer_cb,comp,(char *)__FUNCTION__,
1476,&comp->consent_timer)
1475 nr_ice_component_consent_timer_cb, comp,NR_async_timer_set(comp->consent_ctx->maximum_transmits_timeout_ms
,nr_ice_component_consent_timer_cb,comp,(char *)__FUNCTION__,
1476,&comp->consent_timer)
1476 &comp->consent_timer)NR_async_timer_set(comp->consent_ctx->maximum_transmits_timeout_ms
,nr_ice_component_consent_timer_cb,comp,(char *)__FUNCTION__,
1476,&comp->consent_timer)
;
1477 }
1478
1479void nr_ice_component_refresh_consent_now(nr_ice_component *comp)
1480 {
1481 nr_ice_component_consent_timer_cb(0, 0, comp);
1482 }
1483
1484void nr_ice_component_consent_destroy(nr_ice_component *comp)
1485 {
1486 if (comp->consent_timer) {
1487 NR_async_timer_cancel(comp->consent_timer);
1488 comp->consent_timer = 0;
1489 }
1490 if (comp->consent_timeout) {
1491 NR_async_timer_cancel(comp->consent_timeout);
1492 comp->consent_timeout = 0;
1493 }
1494 if (comp->consent_handle) {
1495 nr_ice_socket_deregister(comp->active->local->isock,
1496 comp->consent_handle);
1497 comp->consent_handle = 0;
1498 }
1499 if (comp->consent_ctx) {
1500 nr_stun_client_ctx_destroy(&comp->consent_ctx);
1501 comp->consent_ctx = 0;
1502 }
1503 }
1504
1505int nr_ice_component_setup_consent(nr_ice_component *comp)
1506 {
1507 int r,_status;
1508
1509 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s)/STREAM(%s)/COMP(%d): Setting up refresh consent",
1510 comp->ctx->label, comp->stream->label, comp->component_id);
1511
1512 nr_ice_component_consent_destroy(comp);
1513
1514 int flags = NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD1;
1515 if (!(comp->ctx->flags & NR_ICE_CTX_FLAGS_ALLOW_LOOPBACK(1 << 7))) {
1516 flags |= NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK2;
1517 }
1518 if (!(comp->ctx->flags & NR_ICE_CTX_FLAGS_ALLOW_LINK_LOCAL(1 << 8))) {
1519 flags |= NR_STUN_TRANSPORT_ADDR_CHECK_LINK_LOCAL4;
1520 }
1521
1522 if (r = nr_stun_client_ctx_create("consent", comp->active->local->osock,
1523 &comp->active->remote->addr, 0, flags,
1524 &comp->consent_ctx))
1525 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1526 /* Consent request get send only once. */
1527 comp->consent_ctx->maximum_transmits = 1;
1528
1529 if (r=nr_ice_socket_register_stun_client(comp->active->local->isock,
1530 comp->consent_ctx, &comp->consent_handle))
1531 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1532
1533 comp->can_send = 1;
1534 comp->disconnected = 0;
1535 nr_ice_component_consent_refreshed(comp);
1536
1537 nr_ice_component_consent_calc_consent_timer(comp);
1538 nr_ice_component_consent_schedule_consent_timer(comp);
1539
1540 _status=0;
1541 abort:
1542 return(_status);
1543 }
1544
1545int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
1546 {
1547 int r,_status;
1548 nr_ice_cand_pair *p2;
1549
1550 /* Are we changing what the nominated pair is? */
1551 if(comp->nominated){
1552 if(comp->nominated->priority >= pair->priority)
1553 return(0);
1554 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): replacing pair %s with CAND-PAIR(%s)",comp->stream->pctx->label,comp->stream->label,comp->component_id,comp->nominated->codeword,comp->nominated->as_string,pair->codeword);
1555 /* As consent doesn't hold a reference to its isock this needs to happen
1556 * before making the new pair the active one. */
1557 nr_ice_component_consent_destroy(comp);
1558 }
1559
1560 /* Set the new nominated pair */
1561 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): nominated pair is %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->codeword,pair->as_string);
1562 comp->state=NR_ICE_COMPONENT_NOMINATED2;
1563 comp->nominated=pair;
1564 comp->active=pair;
1565
1566 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling all pairs but %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->codeword,pair->as_string);
1567
1568 /* Cancel checks in WAITING and FROZEN per ICE S 8.1.2 */
1569 /* DO NOT CANCEL HIGHER PRIORITY PEER NOMINATED PAIRS!!! If a pair has been
1570 * peer nominated, we _must_ pursue it to completion, because if this is
1571 * the highest priority working pair from the peer's perspective, this is
1572 * the one it will use! This is a spec bug. */
1573 p2=TAILQ_FIRST(&comp->stream->trigger_check_queue)((&comp->stream->trigger_check_queue)->tqh_first
)
;
1574 while(p2){
1575 if((p2 != pair) &&
1576 (p2->remote->component->component_id == comp->component_id) &&
1577 !(p2->peer_nominated && (p2->priority > pair->priority))) {
1578 assert(p2->state == NR_ICE_PAIR_STATE_WAITING ||(static_cast <bool> (p2->state == 2 || p2->state ==
6) ? void (0) : __assert_fail ("p2->state == NR_ICE_PAIR_STATE_WAITING || p2->state == NR_ICE_PAIR_STATE_CANCELLED"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
1579 p2->state == NR_ICE_PAIR_STATE_CANCELLED)(static_cast <bool> (p2->state == 2 || p2->state ==
6) ? void (0) : __assert_fail ("p2->state == NR_ICE_PAIR_STATE_WAITING || p2->state == NR_ICE_PAIR_STATE_CANCELLED"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1580 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s in trigger check queue because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword);
1581
1582 nr_ice_candidate_pair_cancel(pair->pctx,p2,0);
1583 }
1584
1585 p2=TAILQ_NEXT(p2,triggered_check_queue_entry)((p2)->triggered_check_queue_entry.tqe_next);
1586 }
1587 p2=TAILQ_FIRST(&comp->stream->check_list)((&comp->stream->check_list)->tqh_first);
1588 while(p2){
1589 if((p2 != pair) &&
1590 (p2->remote->component->component_id == comp->component_id) &&
1591 ((p2->state == NR_ICE_PAIR_STATE_FROZEN1) ||
1592 (p2->state == NR_ICE_PAIR_STATE_WAITING2)) &&
1593 !(p2->peer_nominated && (p2->priority > pair->priority))) {
1594 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword);
1595
1596 nr_ice_candidate_pair_cancel(pair->pctx,p2,0);
1597 }
1598
1599 p2=TAILQ_NEXT(p2,check_queue_entry)((p2)->check_queue_entry.tqe_next);
1600 }
1601 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): cancelling done",comp->stream->pctx->label,comp->stream->label,comp->component_id);
1602
1603 if(r=nr_ice_component_setup_consent(comp))
1604 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1605
1606 nr_ice_media_stream_component_nominated(comp->stream,comp);
1607
1608 _status=0;
1609 abort:
1610 return(_status);
1611 }
1612
1613static int nr_ice_component_have_all_pairs_failed(nr_ice_component *comp)
1614 {
1615 nr_ice_cand_pair *p2;
1616
1617 p2=TAILQ_FIRST(&comp->stream->check_list)((&comp->stream->check_list)->tqh_first);
1618 while(p2){
1619 if(comp->component_id==p2->local->component_id){
1620 switch(p2->state){
1621 case NR_ICE_PAIR_STATE_FROZEN1:
1622 case NR_ICE_PAIR_STATE_WAITING2:
1623 case NR_ICE_PAIR_STATE_IN_PROGRESS3:
1624 case NR_ICE_PAIR_STATE_SUCCEEDED5:
1625 return(0);
1626 case NR_ICE_PAIR_STATE_FAILED4:
1627 case NR_ICE_PAIR_STATE_CANCELLED6:
1628 /* states that will never be recovered from */
1629 break;
1630 default:
1631 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1632 break;
1633 }
1634 }
1635
1636 p2=TAILQ_NEXT(p2,check_queue_entry)((p2)->check_queue_entry.tqe_next);
1637 }
1638
1639 return(1);
1640 }
1641
1642void nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
1643 {
1644 nr_ice_component_check_if_failed(comp);
1645 }
1646
1647void nr_ice_component_check_if_failed(nr_ice_component *comp)
1648 {
1649 if (comp->state == NR_ICE_COMPONENT_RUNNING1) {
1650 /* Don't do anything to streams that aren't currently running */
1651 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): Checking whether component needs to be marked failed.",comp->stream->pctx->label,comp->stream->label,comp->component_id);
1652
1653 if (!comp->stream->pctx->trickle_grace_period_timer &&
1654 nr_ice_component_have_all_pairs_failed(comp)) {
1655 r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): All pairs are failed, and grace period has elapsed. Marking component as failed.",comp->stream->pctx->label,comp->stream->label,comp->component_id);
1656 nr_ice_media_stream_component_failed(comp->stream,comp);
1657 }
1658 }
1659 }
1660
1661void nr_ice_component_maybe_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp)
1662 {
1663 nr_ice_cand_pair **pairs=0;
1664 int ct=0;
1665 nr_ice_cand_pair *pair;
1666 int r;
1667
1668 if(comp->nominated)
1669 return;
1670
1671 assert(pctx->controlling)(static_cast <bool> (pctx->controlling) ? void (0) :
__assert_fail ("pctx->controlling", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__))
;
1672 assert(!nr_ice_peer_ctx_aggressive_nomination(pctx))(static_cast <bool> (!nr_ice_peer_ctx_aggressive_nomination
(pctx)) ? void (0) : __assert_fail ("!nr_ice_peer_ctx_aggressive_nomination(pctx)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1673
1674 /* Size the array */
1675 pair=TAILQ_FIRST(&comp->stream->check_list)((&comp->stream->check_list)->tqh_first);
1676 while(pair){
1677 if (comp->component_id == pair->local->component_id){
1678 if(pair->nominated ||
1679 (pair->state == NR_ICE_PAIR_STATE_IN_PROGRESS3 &&
1680 pair->stun_client->mode == NR_ICE_CLIENT_MODE_USE_CANDIDATE10))
1681 return;
1682
1683 ct++;
1684 }
1685
1686 pair=TAILQ_NEXT(pair,check_queue_entry)((pair)->check_queue_entry.tqe_next);
1687 }
1688
1689 /* Make and fill the array */
1690 if(!(pairs=R_NEW_CNT(nr_ice_cand_pair*, ct)(nr_ice_cand_pair**)calloc(ct,sizeof(nr_ice_cand_pair*)))){
1691 r_log(LOG_ICE,LOG_ERR3,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): Failed to allocate candidate pairs",pctx->label,comp->stream->label,comp->component_id);
1692 return;
1693 }
1694
1695 ct=0;
1696 pair=TAILQ_FIRST(&comp->stream->check_list)((&comp->stream->check_list)->tqh_first);
1697 while(pair){
1698 if (comp->component_id == pair->local->component_id)
1699 pairs[ct++]=pair;
1700
1701 pair=TAILQ_NEXT(pair,check_queue_entry)((pair)->check_queue_entry.tqe_next);
1702 }
1703
1704 if (pctx->handler) {
1705 if(r=pctx->handler->vtbl->select_pair(pctx->handler->obj,
1706 comp->stream,comp->component_id,pairs,ct))
1707 r_log(LOG_ICE,LOG_ERR3,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): Pair selection callback failed with %d",pctx->label,comp->stream->label,comp->component_id,r);
1708 }
1709
1710 free(pairs);
1711 }
1712
1713
1714/* Close the underlying sockets for everything but the nominated candidate */
1715int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp)
1716 {
1717 nr_ice_socket *isock=0;
1718 nr_ice_socket *s1,*s2;
1719
1720 if(rcomp->state==NR_ICE_COMPONENT_NOMINATED2){
1721 assert(rcomp->active == rcomp->nominated)(static_cast <bool> (rcomp->active == rcomp->nominated
) ? void (0) : __assert_fail ("rcomp->active == rcomp->nominated"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1722 isock=rcomp->nominated->local->isock;
1723 }
1724
1725 STAILQ_FOREACH_SAFE(s1, &lcomp->sockets, entry, s2)for ((s1) = (((&lcomp->sockets))->stqh_first); (s1)
&& ((s2) = (((s1))->entry.stqe_next), 1); (s1) = (
s2))
{
1726 if(s1!=isock){
1727 STAILQ_REMOVE(&lcomp->sockets,s1,nr_ice_socket_,entry)do { if ((((&lcomp->sockets))->stqh_first) == (s1))
{ do { if ((((((&lcomp->sockets)))->stqh_first) = (
(((((&lcomp->sockets)))->stqh_first))->entry.stqe_next
)) == __null) ((&lcomp->sockets))->stqh_last = &
((((&lcomp->sockets)))->stqh_first); } while (0); }
else { struct nr_ice_socket_ *curelm = (((&lcomp->sockets
))->stqh_first); while (((curelm)->entry.stqe_next) != (
s1)) curelm = ((curelm)->entry.stqe_next); if ((((curelm)->
entry.stqe_next) = ((((curelm)->entry.stqe_next))->entry
.stqe_next)) == __null) (&lcomp->sockets)->stqh_last
= &(((curelm))->entry.stqe_next); } } while (0)
;
1728 nr_ice_socket_destroy(&s1);
1729 }
1730 }
1731
1732 return(0);
1733 }
1734
1735
1736int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair)
1737 {
1738 int _status;
1739
1740 /* Pairs for peer reflexive are marked SUCCEEDED immediately */
1741 if (pair->state != NR_ICE_PAIR_STATE_FROZEN1 &&
1742 pair->state != NR_ICE_PAIR_STATE_SUCCEEDED5){
1743 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1744 ABORT(R_BAD_ARGS)do { int _r=6; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1745 }
1746
1747 /* We do not throw an error after this, because we've inserted the pair. */
1748 nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,pair);
1749
1750 /* Make sure the check timer is running, if the stream was previously
1751 * started. We will not start streams just because a pair was created,
1752 * unless it is the first pair to be created across all streams. */
1753 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/CAND-PAIR(%s): Ensure that check timer is running for new pair %s.",pair->remote->stream->pctx->label, pair->codeword, pair->as_string);
1754
1755 if(pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3 ||
1756 (pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2 &&
1757 !pair->remote->stream->pctx->checks_started)){
1758 if(nr_ice_media_stream_start_checks(pair->remote->stream->pctx, pair->remote->stream)) {
1759 r_log(LOG_ICE,LOG_WARNING4,"ICE-PEER(%s)/CAND-PAIR(%s): Could not restart checks for new pair %s.",pair->remote->stream->pctx->label, pair->codeword, pair->as_string);
1760 }
1761 }
1762
1763 _status=0;
1764 abort:
1765 if (_status) {
1766 nr_ice_candidate_pair_destroy(&pair);
1767 }
1768 return(_status);
1769 }
1770
1771int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version)
1772 {
1773 int _status;
1774 nr_ice_candidate *cand;
1775 nr_ice_candidate *best_cand = NULL__null;
1776
1777 /* We have the component. Now find the "best" candidate, making
1778 use of the fact that more "reliable" candidate types have
1779 higher numbers. So, we sort by type and then priority within
1780 type
1781 */
1782 cand=TAILQ_FIRST(&comp->candidates)((&comp->candidates)->tqh_first);
1783 while(cand){
1784 if (!nr_ice_ctx_hide_candidate(comp->ctx, cand) &&
1785 cand->addr.ip_version == ip_version) {
1786 if (!best_cand) {
1787 best_cand = cand;
1788 }
1789 else if (best_cand->type < cand->type) {
1790 best_cand = cand;
1791 } else if (best_cand->type == cand->type &&
1792 best_cand->priority < cand->priority) {
1793 best_cand = cand;
1794 }
1795 }
1796
1797 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
1798 }
1799
1800 /* No candidates */
1801 if (!best_cand)
1802 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1803
1804 *candp = best_cand;
1805
1806 _status=0;
1807 abort:
1808 return(_status);
1809
1810 }
1811
1812
1813void nr_ice_component_dump_state(nr_ice_component *comp, int log_level)
1814 {
1815 nr_ice_candidate *cand;
1816
1817 if (comp->local_component) {
1818 r_log(LOG_ICE,log_level,"ICE(%s)/ICE-STREAM(%s): Remote component %d in state %d - dumping candidates",comp->ctx->label,comp->stream->label,comp->component_id,comp->state);
1819 } else {
1820 r_log(LOG_ICE,log_level,"ICE(%s)/ICE-STREAM(%s): Local component %d - dumping candidates",comp->ctx->label,comp->stream->label,comp->component_id);
1821 }
1822
1823 cand=TAILQ_FIRST(&comp->candidates)((&comp->candidates)->tqh_first);
1824 while(cand){
1825 r_log(LOG_ICE,log_level,"ICE(%s)/ICE-STREAM(%s)/CAND(%s): %s",comp->ctx->label,comp->stream->label,cand->codeword,cand->label);
1826 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
1827 }
1828 }
1829