Bug Summary

File:root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_component.cpp
Warning:line 231, column 11
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_STUND_0_96 -D USE_STUN_PEDANTIC -D NR_SOCKET_IS_VOID_PTR -D restrict= -D R_PLATFORM_INT_TYPES=<stdint.h> -D R_DEFINED_INT2=int16_t -D R_DEFINED_UINT2=uint16_t -D R_DEFINED_INT4=int32_t -D R_DEFINED_UINT4=uint32_t -D R_DEFINED_INT8=int64_t -D R_DEFINED_UINT8=uint64_t -D LINUX -D HAVE_LIBM=1 -D HAVE_STRDUP=1 -D HAVE_STRLCPY=1 -D HAVE_SYS_TIME_H=1 -D HAVE_VFPRINTF=1 -D NEW_STDIORETSIGTYPE=void -D TIME_WITH_SYS_TIME_H=1 -D __UNUSED__=__attribute__((unused)) -D DYNAMIC_ANNOTATIONS_ENABLED=1 -D WTF_USE_DYNAMIC_ANNOTATIONS=1 -D _DEBUG -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media/webrtc/transport/third_party/nICEr/nicer_nicer -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/event -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/log -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/registry -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/share -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/util -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/util/libekr -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/port/generic/include -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/crypto -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/net -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/stun -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/util -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/port/linux/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-parentheses -Wno-format -Wno-format-security -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_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))){
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'
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))){
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://tools.ietf.org/html/draft-ietf-rtcweb-mdns-ice-candidates-03#section-3.3.2 */
1128 if(lcand->type == RELAYED && pcand->mdns_addr && strlen(pcand->mdns_addr)) {
1129 continue;
1130 }
1131
1132 /*
1133 Two modes, depending on |pair_all_remote|
1134
1135 1. Pair remote candidates which have not been paired
1136 (used in initial pairing or in processing the other side's
1137 trickle candidates).
1138 2. Pair any remote candidate (used when processing our own
1139 trickle candidates).
1140 */
1141 if (pair_all_remote || (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED9)) {
1142 if (pair_all_remote) {
1143 /* When a remote candidate arrives after the start of checking, but
1144 * before the gathering of local candidates, it can be in UNPAIRED */
1145 pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED10;
1146 }
1147
1148 nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
1149 r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/CAND(%s): Pairing with peer candidate %s", pctx->label, codeword, pcand->label);
1150
1151 if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
1152 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1153
1154 if(r=nr_ice_component_insert_pair(pcomp, pair))
1155 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1156 }
1157 }
1158
1159 done:
1160 _status = 0;
1161 abort:
1162 return(_status);
1163 }
1164
1165int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp)
1166 {
1167 nr_ice_candidate *lcand, *pcand;
1168 nr_ice_socket *isock;
1169 int r,_status;
1170
1171 r_log(LOG_ICE,LOG_DEBUG7,"Pairing candidates======");
1172
1173 /* Create the candidate pairs */
1174 lcand=TAILQ_FIRST(&lcomp->candidates)((&lcomp->candidates)->tqh_first);
1175
1176 if (!lcand) {
1177 /* No local candidates, initialized or not! */
1178 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1179 }
1180
1181 while(lcand){
1182 if (lcand->state == NR_ICE_CAND_STATE_INITIALIZED3) {
1183 if ((r = nr_ice_component_pair_candidate(pctx, pcomp, lcand, 0)))
1184 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1185 }
1186
1187 lcand=TAILQ_NEXT(lcand,entry_comp)((lcand)->entry_comp.tqe_next);
1188 }
1189
1190 /* Mark all peer candidates as paired */
1191 pcand=TAILQ_FIRST(&pcomp->candidates)((&pcomp->candidates)->tqh_first);
1192 while(pcand){
1193 pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED10;
1194
1195 pcand=TAILQ_NEXT(pcand,entry_comp)((pcand)->entry_comp.tqe_next);
1196
1197 }
1198
1199 /* Now register the STUN server callback for this component.
1200 Note that this is a per-component CB so we only need to
1201 do this once.
1202 */
1203 if (pcomp->state != NR_ICE_COMPONENT_RUNNING1) {
1204 isock=STAILQ_FIRST(&lcomp->sockets)((&lcomp->sockets)->stqh_first);
1205 while(isock){
1206 if(r=nr_stun_server_add_client(isock->stun_server,pctx->label,
1207 pcomp->stream->r2l_user,&pcomp->stream->r2l_pass,nr_ice_component_stun_server_cb,pcomp)) {
1208 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1209 }
1210 isock=STAILQ_NEXT(isock,entry)((isock)->entry.stqe_next);
1211 }
1212 }
1213
1214 pcomp->state = NR_ICE_COMPONENT_RUNNING1;
1215
1216 _status=0;
1217 abort:
1218 return(_status);
1219 }
1220
1221int nr_ice_pre_answer_enqueue(nr_ice_component *comp, nr_socket *sock, nr_stun_server_request *req, int *dont_free)
1222 {
1223 int r = 0;
1224 int _status;
1225 nr_ice_pre_answer_request *r1, *r2;
1226 nr_transport_addr dst_addr;
1227 nr_ice_pre_answer_request *par = 0;
1228
1229 if (r=nr_socket_getaddr(sock, &dst_addr))
1230 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1231
1232 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))
{
1233 if (!nr_transport_addr_cmp(&r1->local_addr, &dst_addr,
1234 NR_TRANSPORT_ADDR_CMP_MODE_ALL4) &&
1235 !nr_transport_addr_cmp(&r1->req.src_addr, &req->src_addr,
1236 NR_TRANSPORT_ADDR_CMP_MODE_ALL4)) {
1237 return(0);
1238 }
1239 }
1240
1241 if (r=nr_ice_pre_answer_request_create(&dst_addr, req, &par))
1242 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1243
1244 r_log(LOG_ICE,LOG_DEBUG7, "ICE(%s)/STREAM(%s)/COMP(%d): Enqueuing STUN request pre-answer from %s",
1245 comp->ctx->label, comp->stream->label, comp->component_id,
1246 req->src_addr.as_string);
1247
1248 *dont_free = 1;
1249 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)
;
1250
1251 _status=0;
1252abort:
1253 return(_status);
1254 }
1255
1256/* Fires when we have an incoming candidate that doesn't correspond to an existing
1257 remote peer. This is either pre-answer or just spurious. Store it in the
1258 component for use when we see the actual answer, at which point we need
1259 to do the procedures from S 7.2.1 in nr_ice_component_stun_server_cb.
1260 */
1261static 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)
1262 {
1263 int r, _status;
1264 nr_ice_component *comp = (nr_ice_component *)cb_arg;
1265
1266 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s)/STREAM(%s)/COMP(%d): Received STUN request pre-answer from %s",
1267 comp->ctx->label, comp->stream->label, comp->component_id,
1268 req->src_addr.as_string);
1269
1270 if (r=nr_ice_pre_answer_enqueue(comp, sock, req, dont_free)) {
1271 r_log(LOG_ICE,LOG_ERR3,"ICE(%s)/STREAM(%s)/COMP(%d): Failed (%d) to enque pre-answer request from %s",
1272 comp->ctx->label, comp->stream->label, comp->component_id, r,
1273 req->src_addr.as_string);
1274 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1275 }
1276
1277 _status=0;
1278 abort:
1279 return(_status);
1280 }
1281
1282#define NR_ICE_CONSENT_TIMER_DEFAULT5000 5000
1283#define NR_ICE_CONSENT_TIMEOUT_DEFAULT30000 30000
1284
1285static void nr_ice_component_consent_failed(nr_ice_component *comp)
1286 {
1287 if (!comp->can_send) {
1288 return;
1289 }
1290
1291 r_log(LOG_ICE,LOG_INFO6,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh failed",
1292 comp->ctx->label, comp->stream->label, comp->component_id);
1293 comp->can_send = 0;
1294
1295 if (comp->consent_timeout) {
1296 NR_async_timer_cancel(comp->consent_timeout);
1297 comp->consent_timeout = 0;
1298 }
1299 if (comp->consent_timer) {
1300 NR_async_timer_cancel(comp->consent_timer);
1301 comp->consent_timer = 0;
1302 }
1303 /* We are turning the consent failure into a ICE component failure to
1304 * alert the browser via ICE connection state change about this event. */
1305 nr_ice_media_stream_component_failed(comp->stream, comp);
1306 }
1307
1308static void nr_ice_component_consent_timeout_cb(NR_SOCKET s, int how, void *cb_arg)
1309 {
1310 nr_ice_component *comp=(nr_ice_component*)cb_arg;
1311
1312 comp->consent_timeout = 0;
1313
1314 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh final time out",
1315 comp->ctx->label, comp->stream->label, comp->component_id);
1316 nr_ice_component_consent_failed(comp);
1317 }
1318
1319
1320void nr_ice_component_disconnected(nr_ice_component *comp)
1321 {
1322 if (!comp->can_send) {
1323 return;
1324 }
1325
1326 if (comp->disconnected) {
1327 return;
1328 }
1329
1330 r_log(LOG_ICE,LOG_WARNING4,"ICE(%s)/STREAM(%s)/COMP(%d): component disconnected",
1331 comp->ctx->label, comp->stream->label, comp->component_id);
1332 comp->disconnected = 1;
1333
1334 /* a single disconnected component disconnects the stream */
1335 nr_ice_media_stream_set_disconnected(comp->stream, NR_ICE_MEDIA_STREAM_DISCONNECTED1);
1336 }
1337
1338static void nr_ice_component_consent_refreshed(nr_ice_component *comp)
1339 {
1340 uint16_t tval;
1341
1342 if (!comp->can_send) {
1343 return;
1344 }
1345
1346 gettimeofday(&comp->consent_last_seen, 0);
1347 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s)/STREAM(%s)/COMP(%d): consent_last_seen is now %lu",
1348 comp->ctx->label, comp->stream->label, comp->component_id,
1349 comp->consent_last_seen.tv_sec);
1350
1351 comp->disconnected = 0;
1352
1353 nr_ice_media_stream_check_if_connected(comp->stream);
1354
1355 if (comp->consent_timeout)
1356 NR_async_timer_cancel(comp->consent_timeout);
1357
1358 tval = NR_ICE_CONSENT_TIMEOUT_DEFAULT30000;
1359 if (comp->ctx->test_timer_divider)
1360 tval = tval / comp->ctx->test_timer_divider;
1361
1362 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__,1363,&comp->consent_timeout)
1363 &comp->consent_timeout)NR_async_timer_set(tval,nr_ice_component_consent_timeout_cb,comp
,(char *)__FUNCTION__,1363,&comp->consent_timeout)
;
1364 }
1365
1366static void nr_ice_component_refresh_consent_cb(NR_SOCKET s, int how, void *cb_arg)
1367 {
1368 nr_ice_cand_pair *pair=(nr_ice_cand_pair*)cb_arg;
1369 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__
))
;
1370 nr_ice_component *comp=pair->remote->component;
1371
1372 switch (comp->consent_ctx->state) {
1373 case NR_STUN_CLIENT_STATE_FAILED3:
1374 if (comp->consent_ctx->error_code == 403) {
1375 r_log(LOG_ICE, LOG_INFO6, "ICE(%s)/STREAM(%s)/COMP(%d): Consent revoked by peer",
1376 comp->ctx->label, comp->stream->label, comp->component_id);
1377 nr_ice_component_consent_failed(comp);
1378 }
1379 break;
1380 case NR_STUN_CLIENT_STATE_DONE2:
1381 r_log(LOG_ICE, LOG_INFO6, "ICE(%s)/STREAM(%s)/COMP(%d): Consent refreshed",
1382 comp->ctx->label, comp->stream->label, comp->component_id);
1383 if (comp->consent_ctx->rtt_valid) {
1384 nr_ice_candidate_pair_update_rtt(pair, comp->consent_ctx->rtt_ms);
1385 // clear rtt_ms so we can't double process it.
1386 comp->consent_ctx->rtt_valid = 0;
1387 comp->consent_ctx->rtt_ms = 0;
1388 }
1389 nr_ice_component_consent_refreshed(comp);
1390 break;
1391 case NR_STUN_CLIENT_STATE_TIMED_OUT4:
1392 r_log(LOG_ICE, LOG_INFO6, "ICE(%s)/STREAM(%s)/COMP(%d): A single consent refresh request timed out",
1393 comp->ctx->label, comp->stream->label, comp->component_id);
1394 nr_ice_component_disconnected(comp);
1395 break;
1396 default:
1397 break;
1398 }
1399 }
1400
1401int nr_ice_component_refresh_consent(nr_stun_client_ctx *ctx, NR_async_cb finished_cb, void *cb_arg)
1402 {
1403 int r,_status;
1404
1405 nr_stun_client_reset(ctx);
1406
1407 if (r=nr_stun_client_start(ctx, NR_ICE_CLIENT_MODE_BINDING_REQUEST11, finished_cb, cb_arg))
1408 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1409
1410 _status=0;
1411 abort:
1412 return(_status);
1413 }
1414
1415void nr_ice_component_consent_calc_consent_timer(nr_ice_component *comp)
1416 {
1417 uint16_t trange, trand, tval;
1418
1419 trange = NR_ICE_CONSENT_TIMER_DEFAULT5000 * 20 / 100;
1420 tval = NR_ICE_CONSENT_TIMER_DEFAULT5000 - trange;
1421 if (!nr_crypto_random_bytes((UCHAR*)&trand, sizeof(trand))nr_crypto_vtbl->random_bytes((UCHAR*)&trand,sizeof(trand
))
)
1422 tval += (trand % (trange * 2));
1423
1424 if (comp->ctx->test_timer_divider)
1425 tval = tval / comp->ctx->test_timer_divider;
1426
1427 /* The timeout of the transaction is the maximum time until we send the
1428 * next consent request. */
1429 comp->consent_ctx->maximum_transmits_timeout_ms = tval;
1430 }
1431
1432static void nr_ice_component_consent_timer_cb(NR_SOCKET s, int how, void *cb_arg)
1433 {
1434 nr_ice_component *comp=(nr_ice_component*)cb_arg;
1435 int r;
1436
1437 if (!comp->consent_ctx) {
1438 return;
1439 }
1440
1441 if (comp->consent_timer) {
1442 NR_async_timer_cancel(comp->consent_timer);
1443 }
1444 comp->consent_timer = 0;
1445
1446 comp->consent_ctx->params.ice_binding_request.username =
1447 comp->stream->l2r_user;
1448 comp->consent_ctx->params.ice_binding_request.password =
1449 comp->stream->l2r_pass;
1450 comp->consent_ctx->params.ice_binding_request.control =
1451 comp->stream->pctx->controlling?
1452 NR_ICE_CONTROLLING1:NR_ICE_CONTROLLED2;
1453 comp->consent_ctx->params.ice_binding_request.tiebreaker =
1454 comp->stream->pctx->tiebreaker;
1455 comp->consent_ctx->params.ice_binding_request.priority =
1456 comp->active->local->priority;
1457
1458 nr_ice_component_consent_calc_consent_timer(comp);
1459
1460 if (r=nr_ice_component_refresh_consent(comp->consent_ctx,
1461 nr_ice_component_refresh_consent_cb,
1462 comp->active)) {
1463 r_log(LOG_ICE,LOG_ERR3,"ICE(%s)/STREAM(%s)/COMP(%d): Refresh consent failed with %d",
1464 comp->ctx->label, comp->stream->label, comp->component_id, r);
1465 }
1466
1467 nr_ice_component_consent_schedule_consent_timer(comp);
1468
1469 }
1470
1471void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp)
1472 {
1473 if (!comp->can_send) {
1474 return;
1475 }
1476
1477 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__,
1479,&comp->consent_timer)
1478 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__,
1479,&comp->consent_timer)
1479 &comp->consent_timer)NR_async_timer_set(comp->consent_ctx->maximum_transmits_timeout_ms
,nr_ice_component_consent_timer_cb,comp,(char *)__FUNCTION__,
1479,&comp->consent_timer)
;
1480 }
1481
1482void nr_ice_component_refresh_consent_now(nr_ice_component *comp)
1483 {
1484 nr_ice_component_consent_timer_cb(0, 0, comp);
1485 }
1486
1487void nr_ice_component_consent_destroy(nr_ice_component *comp)
1488 {
1489 if (comp->consent_timer) {
1490 NR_async_timer_cancel(comp->consent_timer);
1491 comp->consent_timer = 0;
1492 }
1493 if (comp->consent_timeout) {
1494 NR_async_timer_cancel(comp->consent_timeout);
1495 comp->consent_timeout = 0;
1496 }
1497 if (comp->consent_handle) {
1498 nr_ice_socket_deregister(comp->active->local->isock,
1499 comp->consent_handle);
1500 comp->consent_handle = 0;
1501 }
1502 if (comp->consent_ctx) {
1503 nr_stun_client_ctx_destroy(&comp->consent_ctx);
1504 comp->consent_ctx = 0;
1505 }
1506 }
1507
1508int nr_ice_component_setup_consent(nr_ice_component *comp)
1509 {
1510 int r,_status;
1511
1512 r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s)/STREAM(%s)/COMP(%d): Setting up refresh consent",
1513 comp->ctx->label, comp->stream->label, comp->component_id);
1514
1515 nr_ice_component_consent_destroy(comp);
1516
1517 int flags = NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD1;
1518 if (!(comp->ctx->flags & NR_ICE_CTX_FLAGS_ALLOW_LOOPBACK(1 << 7))) {
1519 flags |= NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK2;
1520 }
1521 if (!(comp->ctx->flags & NR_ICE_CTX_FLAGS_ALLOW_LINK_LOCAL(1 << 8))) {
1522 flags |= NR_STUN_TRANSPORT_ADDR_CHECK_LINK_LOCAL4;
1523 }
1524
1525 if (r = nr_stun_client_ctx_create("consent", comp->active->local->osock,
1526 &comp->active->remote->addr, 0, flags,
1527 &comp->consent_ctx))
1528 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1529 /* Consent request get send only once. */
1530 comp->consent_ctx->maximum_transmits = 1;
1531
1532 if (r=nr_ice_socket_register_stun_client(comp->active->local->isock,
1533 comp->consent_ctx, &comp->consent_handle))
1534 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1535
1536 comp->can_send = 1;
1537 comp->disconnected = 0;
1538 nr_ice_component_consent_refreshed(comp);
1539
1540 nr_ice_component_consent_calc_consent_timer(comp);
1541 nr_ice_component_consent_schedule_consent_timer(comp);
1542
1543 _status=0;
1544 abort:
1545 return(_status);
1546 }
1547
1548int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
1549 {
1550 int r,_status;
1551 nr_ice_cand_pair *p2;
1552
1553 /* Are we changing what the nominated pair is? */
1554 if(comp->nominated){
1555 if(comp->nominated->priority >= pair->priority)
1556 return(0);
1557 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);
1558 /* As consent doesn't hold a reference to its isock this needs to happen
1559 * before making the new pair the active one. */
1560 nr_ice_component_consent_destroy(comp);
1561 }
1562
1563 /* Set the new nominated pair */
1564 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);
1565 comp->state=NR_ICE_COMPONENT_NOMINATED2;
1566 comp->nominated=pair;
1567 comp->active=pair;
1568
1569 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);
1570
1571 /* Cancel checks in WAITING and FROZEN per ICE S 8.1.2 */
1572 /* DO NOT CANCEL HIGHER PRIORITY PEER NOMINATED PAIRS!!! If a pair has been
1573 * peer nominated, we _must_ pursue it to completion, because if this is
1574 * the highest priority working pair from the peer's perspective, this is
1575 * the one it will use! This is a spec bug. */
1576 p2=TAILQ_FIRST(&comp->stream->trigger_check_queue)((&comp->stream->trigger_check_queue)->tqh_first
)
;
1577 while(p2){
1578 if((p2 != pair) &&
1579 (p2->remote->component->component_id == comp->component_id) &&
1580 !(p2->peer_nominated && (p2->priority > pair->priority))) {
1581 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__
))
1582 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__
))
;
1583 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);
1584
1585 nr_ice_candidate_pair_cancel(pair->pctx,p2,0);
1586 }
1587
1588 p2=TAILQ_NEXT(p2,triggered_check_queue_entry)((p2)->triggered_check_queue_entry.tqe_next);
1589 }
1590 p2=TAILQ_FIRST(&comp->stream->check_list)((&comp->stream->check_list)->tqh_first);
1591 while(p2){
1592 if((p2 != pair) &&
1593 (p2->remote->component->component_id == comp->component_id) &&
1594 ((p2->state == NR_ICE_PAIR_STATE_FROZEN1) ||
1595 (p2->state == NR_ICE_PAIR_STATE_WAITING2)) &&
1596 !(p2->peer_nominated && (p2->priority > pair->priority))) {
1597 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);
1598
1599 nr_ice_candidate_pair_cancel(pair->pctx,p2,0);
1600 }
1601
1602 p2=TAILQ_NEXT(p2,check_queue_entry)((p2)->check_queue_entry.tqe_next);
1603 }
1604 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);
1605
1606 if(r=nr_ice_component_setup_consent(comp))
1607 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1608
1609 nr_ice_media_stream_component_nominated(comp->stream,comp);
1610
1611 _status=0;
1612 abort:
1613 return(_status);
1614 }
1615
1616static int nr_ice_component_have_all_pairs_failed(nr_ice_component *comp)
1617 {
1618 nr_ice_cand_pair *p2;
1619
1620 p2=TAILQ_FIRST(&comp->stream->check_list)((&comp->stream->check_list)->tqh_first);
1621 while(p2){
1622 if(comp->component_id==p2->local->component_id){
1623 switch(p2->state){
1624 case NR_ICE_PAIR_STATE_FROZEN1:
1625 case NR_ICE_PAIR_STATE_WAITING2:
1626 case NR_ICE_PAIR_STATE_IN_PROGRESS3:
1627 case NR_ICE_PAIR_STATE_SUCCEEDED5:
1628 return(0);
1629 case NR_ICE_PAIR_STATE_FAILED4:
1630 case NR_ICE_PAIR_STATE_CANCELLED6:
1631 /* states that will never be recovered from */
1632 break;
1633 default:
1634 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1635 break;
1636 }
1637 }
1638
1639 p2=TAILQ_NEXT(p2,check_queue_entry)((p2)->check_queue_entry.tqe_next);
1640 }
1641
1642 return(1);
1643 }
1644
1645void nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
1646 {
1647 nr_ice_component_check_if_failed(comp);
1648 }
1649
1650void nr_ice_component_check_if_failed(nr_ice_component *comp)
1651 {
1652 if (comp->state == NR_ICE_COMPONENT_RUNNING1) {
1653 /* Don't do anything to streams that aren't currently running */
1654 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);
1655
1656 if (!comp->stream->pctx->trickle_grace_period_timer &&
1657 nr_ice_component_have_all_pairs_failed(comp)) {
1658 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);
1659 nr_ice_media_stream_component_failed(comp->stream,comp);
1660 }
1661 }
1662 }
1663
1664void nr_ice_component_maybe_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp)
1665 {
1666 nr_ice_cand_pair **pairs=0;
1667 int ct=0;
1668 nr_ice_cand_pair *pair;
1669 int r;
1670
1671 if(comp->nominated)
1672 return;
1673
1674 assert(pctx->controlling)(static_cast <bool> (pctx->controlling) ? void (0) :
__assert_fail ("pctx->controlling", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__))
;
1675 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__
))
;
1676
1677 /* Size the array */
1678 pair=TAILQ_FIRST(&comp->stream->check_list)((&comp->stream->check_list)->tqh_first);
1679 while(pair){
1680 if (comp->component_id == pair->local->component_id){
1681 if(pair->nominated ||
1682 (pair->state == NR_ICE_PAIR_STATE_IN_PROGRESS3 &&
1683 pair->stun_client->mode == NR_ICE_CLIENT_MODE_USE_CANDIDATE10))
1684 return;
1685
1686 ct++;
1687 }
1688
1689 pair=TAILQ_NEXT(pair,check_queue_entry)((pair)->check_queue_entry.tqe_next);
1690 }
1691
1692 /* Make and fill the array */
1693 if(!(pairs=R_NEW_CNT(nr_ice_cand_pair*, ct)(nr_ice_cand_pair**)calloc(ct,sizeof(nr_ice_cand_pair*)))){
1694 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);
1695 return;
1696 }
1697
1698 ct=0;
1699 pair=TAILQ_FIRST(&comp->stream->check_list)((&comp->stream->check_list)->tqh_first);
1700 while(pair){
1701 if (comp->component_id == pair->local->component_id)
1702 pairs[ct++]=pair;
1703
1704 pair=TAILQ_NEXT(pair,check_queue_entry)((pair)->check_queue_entry.tqe_next);
1705 }
1706
1707 if (pctx->handler) {
1708 if(r=pctx->handler->vtbl->select_pair(pctx->handler->obj,
1709 comp->stream,comp->component_id,pairs,ct))
1710 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);
1711 }
1712
1713 free(pairs);
1714 }
1715
1716
1717/* Close the underlying sockets for everything but the nominated candidate */
1718int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp)
1719 {
1720 nr_ice_socket *isock=0;
1721 nr_ice_socket *s1,*s2;
1722
1723 if(rcomp->state==NR_ICE_COMPONENT_NOMINATED2){
1724 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__
))
;
1725 isock=rcomp->nominated->local->isock;
1726 }
1727
1728 STAILQ_FOREACH_SAFE(s1, &lcomp->sockets, entry, s2)for ((s1) = (((&lcomp->sockets))->stqh_first); (s1)
&& ((s2) = (((s1))->entry.stqe_next), 1); (s1) = (
s2))
{
1729 if(s1!=isock){
1730 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)
;
1731 nr_ice_socket_destroy(&s1);
1732 }
1733 }
1734
1735 return(0);
1736 }
1737
1738
1739int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair)
1740 {
1741 int _status;
1742
1743 /* Pairs for peer reflexive are marked SUCCEEDED immediately */
1744 if (pair->state != NR_ICE_PAIR_STATE_FROZEN1 &&
1745 pair->state != NR_ICE_PAIR_STATE_SUCCEEDED5){
1746 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1747 ABORT(R_BAD_ARGS)do { int _r=6; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1748 }
1749
1750 /* We do not throw an error after this, because we've inserted the pair. */
1751 nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,pair);
1752
1753 /* Make sure the check timer is running, if the stream was previously
1754 * started. We will not start streams just because a pair was created,
1755 * unless it is the first pair to be created across all streams. */
1756 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);
1757
1758 if(pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3 ||
1759 (pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2 &&
1760 !pair->remote->stream->pctx->checks_started)){
1761 if(nr_ice_media_stream_start_checks(pair->remote->stream->pctx, pair->remote->stream)) {
1762 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);
1763 }
1764 }
1765
1766 _status=0;
1767 abort:
1768 if (_status) {
1769 nr_ice_candidate_pair_destroy(&pair);
1770 }
1771 return(_status);
1772 }
1773
1774int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version)
1775 {
1776 int _status;
1777 nr_ice_candidate *cand;
1778 nr_ice_candidate *best_cand = NULL__null;
1779
1780 /* We have the component. Now find the "best" candidate, making
1781 use of the fact that more "reliable" candidate types have
1782 higher numbers. So, we sort by type and then priority within
1783 type
1784 */
1785 cand=TAILQ_FIRST(&comp->candidates)((&comp->candidates)->tqh_first);
1786 while(cand){
1787 if (!nr_ice_ctx_hide_candidate(comp->ctx, cand) &&
1788 cand->addr.ip_version == ip_version) {
1789 if (!best_cand) {
1790 best_cand = cand;
1791 }
1792 else if (best_cand->type < cand->type) {
1793 best_cand = cand;
1794 } else if (best_cand->type == cand->type &&
1795 best_cand->priority < cand->priority) {
1796 best_cand = cand;
1797 }
1798 }
1799
1800 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
1801 }
1802
1803 /* No candidates */
1804 if (!best_cand)
1805 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1806
1807 *candp = best_cand;
1808
1809 _status=0;
1810 abort:
1811 return(_status);
1812
1813 }
1814
1815
1816void nr_ice_component_dump_state(nr_ice_component *comp, int log_level)
1817 {
1818 nr_ice_candidate *cand;
1819
1820 if (comp->local_component) {
1821 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);
1822 } else {
1823 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);
1824 }
1825
1826 cand=TAILQ_FIRST(&comp->candidates)((&comp->candidates)->tqh_first);
1827 while(cand){
1828 r_log(LOG_ICE,log_level,"ICE(%s)/ICE-STREAM(%s)/CAND(%s): %s",comp->ctx->label,comp->stream->label,cand->codeword,cand->label);
1829 cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next);
1830 }
1831 }
1832