Bug Summary

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