/src/mozilla-central/media/mtransport/nricectx.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- mode: c++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
5 | | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | |
8 | | // Original author: ekr@rtfm.com |
9 | | |
10 | | // Some of this code is cut-and-pasted from nICEr. Copyright is: |
11 | | |
12 | | /* |
13 | | Copyright (c) 2007, Adobe Systems, Incorporated |
14 | | All rights reserved. |
15 | | |
16 | | Redistribution and use in source and binary forms, with or without |
17 | | modification, are permitted provided that the following conditions are |
18 | | met: |
19 | | |
20 | | * Redistributions of source code must retain the above copyright |
21 | | notice, this list of conditions and the following disclaimer. |
22 | | |
23 | | * Redistributions in binary form must reproduce the above copyright |
24 | | notice, this list of conditions and the following disclaimer in the |
25 | | documentation and/or other materials provided with the distribution. |
26 | | |
27 | | * Neither the name of Adobe Systems, Network Resonance nor the names of its |
28 | | contributors may be used to endorse or promote products derived from |
29 | | this software without specific prior written permission. |
30 | | |
31 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
32 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
33 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
34 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
35 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
36 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
37 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
38 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
39 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
40 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
41 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
42 | | */ |
43 | | |
44 | | #include <string> |
45 | | #include <vector> |
46 | | |
47 | | #include "mozilla/Telemetry.h" |
48 | | #include "mozilla/UniquePtr.h" |
49 | | #include "mozilla/Unused.h" |
50 | | |
51 | | #include "logging.h" |
52 | | #include "nspr.h" |
53 | | #include "nss.h" |
54 | | #include "pk11pub.h" |
55 | | #include "plbase64.h" |
56 | | |
57 | | #include "nsCOMPtr.h" |
58 | | #include "nsComponentManagerUtils.h" |
59 | | #include "nsError.h" |
60 | | #include "nsIEventTarget.h" |
61 | | #include "nsNetCID.h" |
62 | | #include "nsComponentManagerUtils.h" |
63 | | #include "nsServiceManagerUtils.h" |
64 | | #include "ScopedNSSTypes.h" |
65 | | #include "runnable_utils.h" |
66 | | #include "nsIPrefService.h" |
67 | | #include "nsIPrefBranch.h" |
68 | | |
69 | | // nICEr includes |
70 | | extern "C" { |
71 | | #include "nr_api.h" |
72 | | #include "registry.h" |
73 | | #include "async_timer.h" |
74 | | #include "r_crc32.h" |
75 | | #include "r_memory.h" |
76 | | #include "ice_reg.h" |
77 | | #include "ice_util.h" |
78 | | #include "transport_addr.h" |
79 | | #include "nr_crypto.h" |
80 | | #include "nr_socket.h" |
81 | | #include "nr_socket_local.h" |
82 | | #include "nr_proxy_tunnel.h" |
83 | | #include "stun_client_ctx.h" |
84 | | #include "stun_reg.h" |
85 | | #include "stun_server_ctx.h" |
86 | | #include "stun_util.h" |
87 | | #include "ice_codeword.h" |
88 | | #include "ice_ctx.h" |
89 | | #include "ice_candidate.h" |
90 | | #include "ice_handler.h" |
91 | | } |
92 | | |
93 | | // Local includes |
94 | | #include "nricectx.h" |
95 | | #include "nricemediastream.h" |
96 | | #include "nr_socket_prsock.h" |
97 | | #include "nrinterfaceprioritizer.h" |
98 | | #include "rlogconnector.h" |
99 | | #include "test_nr_socket.h" |
100 | | |
101 | | namespace mozilla { |
102 | | |
103 | 0 | TimeStamp nr_socket_short_term_violation_time() { |
104 | 0 | return NrSocketBase::short_term_violation_time(); |
105 | 0 | } |
106 | | |
107 | 0 | TimeStamp nr_socket_long_term_violation_time() { |
108 | 0 | return NrSocketBase::long_term_violation_time(); |
109 | 0 | } |
110 | | |
111 | | MOZ_MTLOG_MODULE("mtransport") |
112 | | |
113 | | const char kNrIceTransportUdp[] = "udp"; |
114 | | const char kNrIceTransportTcp[] = "tcp"; |
115 | | const char kNrIceTransportTls[] = "tls"; |
116 | | |
117 | | static bool initialized = false; |
118 | | |
119 | | // Implement NSPR-based crypto algorithms |
120 | 0 | static int nr_crypto_nss_random_bytes(UCHAR *buf, size_t len) { |
121 | 0 | UniquePK11SlotInfo slot(PK11_GetInternalSlot()); |
122 | 0 | if (!slot) |
123 | 0 | return R_INTERNAL; |
124 | 0 | |
125 | 0 | SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), buf, len); |
126 | 0 | if (rv != SECSuccess) |
127 | 0 | return R_INTERNAL; |
128 | 0 | |
129 | 0 | return 0; |
130 | 0 | } |
131 | | |
132 | | static int nr_crypto_nss_hmac(UCHAR *key, size_t keyl, UCHAR *buf, size_t bufl, |
133 | 0 | UCHAR *result) { |
134 | 0 | CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC; |
135 | 0 | PK11SlotInfo *slot = nullptr; |
136 | 0 | MOZ_ASSERT(keyl > 0); |
137 | 0 | SECItem keyi = { siBuffer, key, static_cast<unsigned int>(keyl)}; |
138 | 0 | PK11SymKey *skey = nullptr; |
139 | 0 | PK11Context *hmac_ctx = nullptr; |
140 | 0 | SECStatus status; |
141 | 0 | unsigned int hmac_len; |
142 | 0 | SECItem param = { siBuffer, nullptr, 0 }; |
143 | 0 | int err = R_INTERNAL; |
144 | 0 |
|
145 | 0 | slot = PK11_GetInternalKeySlot(); |
146 | 0 | if (!slot) |
147 | 0 | goto abort; |
148 | 0 | |
149 | 0 | skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, |
150 | 0 | CKA_SIGN, &keyi, nullptr); |
151 | 0 | if (!skey) |
152 | 0 | goto abort; |
153 | 0 | |
154 | 0 | |
155 | 0 | hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, |
156 | 0 | skey, ¶m); |
157 | 0 | if (!hmac_ctx) |
158 | 0 | goto abort; |
159 | 0 | |
160 | 0 | status = PK11_DigestBegin(hmac_ctx); |
161 | 0 | if (status != SECSuccess) |
162 | 0 | goto abort; |
163 | 0 | |
164 | 0 | status = PK11_DigestOp(hmac_ctx, buf, bufl); |
165 | 0 | if (status != SECSuccess) |
166 | 0 | goto abort; |
167 | 0 | |
168 | 0 | status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20); |
169 | 0 | if (status != SECSuccess) |
170 | 0 | goto abort; |
171 | 0 | |
172 | 0 | MOZ_ASSERT(hmac_len == 20); |
173 | 0 |
|
174 | 0 | err = 0; |
175 | 0 |
|
176 | 0 | abort: |
177 | 0 | if(hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE); |
178 | 0 | if (skey) PK11_FreeSymKey(skey); |
179 | 0 | if (slot) PK11_FreeSlot(slot); |
180 | 0 |
|
181 | 0 | return err; |
182 | 0 | } |
183 | | |
184 | 0 | static int nr_crypto_nss_md5(UCHAR *buf, size_t bufl, UCHAR *result) { |
185 | 0 | int err = R_INTERNAL; |
186 | 0 | SECStatus rv; |
187 | 0 |
|
188 | 0 | const SECHashObject *ho = HASH_GetHashObject(HASH_AlgMD5); |
189 | 0 | MOZ_ASSERT(ho); |
190 | 0 | if (!ho) |
191 | 0 | goto abort; |
192 | 0 | |
193 | 0 | MOZ_ASSERT(ho->length == 16); |
194 | 0 |
|
195 | 0 | rv = HASH_HashBuf(ho->type, result, buf, bufl); |
196 | 0 | if (rv != SECSuccess) |
197 | 0 | goto abort; |
198 | 0 | |
199 | 0 | err = 0; |
200 | 0 | abort: |
201 | 0 | return err; |
202 | 0 | } |
203 | | |
204 | | static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl = { |
205 | | nr_crypto_nss_random_bytes, |
206 | | nr_crypto_nss_hmac, |
207 | | nr_crypto_nss_md5 |
208 | | }; |
209 | | |
210 | 0 | nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server) const { |
211 | 0 | int r; |
212 | 0 |
|
213 | 0 | memset(server, 0, sizeof(nr_ice_stun_server)); |
214 | 0 | if (transport_ == kNrIceTransportUdp) { |
215 | 0 | server->transport = IPPROTO_UDP; |
216 | 0 | } else if (transport_ == kNrIceTransportTcp) { |
217 | 0 | server->transport = IPPROTO_TCP; |
218 | 0 | } else if (transport_ == kNrIceTransportTls) { |
219 | 0 | server->transport = IPPROTO_TCP; |
220 | 0 | if (has_addr_) { |
221 | 0 | // Refuse to try TLS without an FQDN |
222 | 0 | return NS_ERROR_INVALID_ARG; |
223 | 0 | } |
224 | 0 | server->tls = 1; |
225 | 0 | } else { |
226 | 0 | MOZ_MTLOG(ML_ERROR, "Unsupported STUN server transport: " << transport_); |
227 | 0 | return NS_ERROR_FAILURE; |
228 | 0 | } |
229 | 0 |
|
230 | 0 | if (has_addr_) { |
231 | 0 | r = nr_praddr_to_transport_addr(&addr_, &server->u.addr, |
232 | 0 | server->transport, 0); |
233 | 0 | if (r) { |
234 | 0 | return NS_ERROR_FAILURE; |
235 | 0 | } |
236 | 0 | server->type=NR_ICE_STUN_SERVER_TYPE_ADDR; |
237 | 0 | } |
238 | 0 | else { |
239 | 0 | MOZ_ASSERT(sizeof(server->u.dnsname.host) > host_.size()); |
240 | 0 | PL_strncpyz(server->u.dnsname.host, host_.c_str(), |
241 | 0 | sizeof(server->u.dnsname.host)); |
242 | 0 | server->u.dnsname.port = port_; |
243 | 0 | server->type=NR_ICE_STUN_SERVER_TYPE_DNSNAME; |
244 | 0 | } |
245 | 0 |
|
246 | 0 | return NS_OK; |
247 | 0 | } |
248 | | |
249 | | |
250 | 0 | nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server *server) const { |
251 | 0 | memset(server, 0, sizeof(nr_ice_turn_server)); |
252 | 0 |
|
253 | 0 | nsresult rv = ToNicerStunStruct(&server->turn_server); |
254 | 0 | if (NS_FAILED(rv)) |
255 | 0 | return rv; |
256 | 0 | |
257 | 0 | if (!(server->username=r_strdup(username_.c_str()))) |
258 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
259 | 0 | |
260 | 0 | // TODO(ekr@rtfm.com): handle non-ASCII passwords somehow? |
261 | 0 | // STUN requires they be SASLpreped, but we don't know if |
262 | 0 | // they are at this point. |
263 | 0 | |
264 | 0 | // C++03 23.2.4, Paragraph 1 stipulates that the elements |
265 | 0 | // in std::vector must be contiguous, and can therefore be |
266 | 0 | // used as input to functions expecting C arrays. |
267 | 0 | int r = r_data_create(&server->password, |
268 | 0 | const_cast<UCHAR *>(&password_[0]), |
269 | 0 | password_.size()); |
270 | 0 | if (r) { |
271 | 0 | RFREE(server->username); |
272 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
273 | 0 | } |
274 | 0 |
|
275 | 0 | return NS_OK; |
276 | 0 | } |
277 | | |
278 | | NrIceCtx::NrIceCtx(const std::string& name, Policy policy) |
279 | | : connection_state_(ICE_CTX_INIT), |
280 | | gathering_state_(ICE_CTX_GATHER_INIT), |
281 | | name_(name), |
282 | | offerer_(false), |
283 | | ice_controlling_set_(false), |
284 | | streams_(), |
285 | | ctx_(nullptr), |
286 | | peer_(nullptr), |
287 | | ice_handler_vtbl_(nullptr), |
288 | | ice_handler_(nullptr), |
289 | | trickle_(true), |
290 | | policy_(policy), |
291 | 0 | nat_ (nullptr) { |
292 | 0 | } |
293 | | |
294 | | /* static */ |
295 | | RefPtr<NrIceCtx> |
296 | | NrIceCtx::Create(const std::string& name, |
297 | | bool allow_loopback, |
298 | | bool tcp_enabled, |
299 | | bool allow_link_local, |
300 | | Policy policy) |
301 | 0 | { |
302 | 0 | // InitializeGlobals only executes once |
303 | 0 | NrIceCtx::InitializeGlobals(allow_loopback, tcp_enabled, allow_link_local); |
304 | 0 |
|
305 | 0 | RefPtr<NrIceCtx> ctx = new NrIceCtx(name, policy); |
306 | 0 |
|
307 | 0 | if (!ctx->Initialize()) { |
308 | 0 | return nullptr; |
309 | 0 | } |
310 | 0 | |
311 | 0 | return ctx; |
312 | 0 | } |
313 | | |
314 | | RefPtr<NrIceMediaStream> |
315 | | NrIceCtx::CreateStream(const std::string& id, |
316 | | const std::string& name, |
317 | | int components) |
318 | 0 | { |
319 | 0 | if (streams_.count(id)) { |
320 | 0 | MOZ_ASSERT(false); |
321 | 0 | return nullptr; |
322 | 0 | } |
323 | 0 |
|
324 | 0 | RefPtr<NrIceMediaStream> stream = |
325 | 0 | new NrIceMediaStream(this, id, name, components); |
326 | 0 | streams_[id] = stream; |
327 | 0 | return stream; |
328 | 0 | } |
329 | | |
330 | | void |
331 | 0 | NrIceCtx::DestroyStream(const std::string& id) { |
332 | 0 | auto it = streams_.find(id); |
333 | 0 | if (it != streams_.end()) { |
334 | 0 | auto preexisting_stream = it->second; |
335 | 0 | streams_.erase(it); |
336 | 0 | preexisting_stream->Close(); |
337 | 0 | } |
338 | 0 | } |
339 | | |
340 | | // Handler callbacks |
341 | | int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream, |
342 | | int component_id, nr_ice_cand_pair **potentials, |
343 | 0 | int potential_ct) { |
344 | 0 | MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = " |
345 | 0 | << potential_ct); |
346 | 0 | MOZ_ASSERT(stream->local_stream); |
347 | 0 | MOZ_ASSERT(!stream->local_stream->obsolete); |
348 | 0 |
|
349 | 0 | return 0; |
350 | 0 | } |
351 | | |
352 | 0 | int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) { |
353 | 0 | MOZ_MTLOG(ML_DEBUG, "stream_ready called"); |
354 | 0 | MOZ_ASSERT(!stream->local_stream); |
355 | 0 | MOZ_ASSERT(!stream->obsolete); |
356 | 0 |
|
357 | 0 | // Get the ICE ctx. |
358 | 0 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
359 | 0 |
|
360 | 0 | RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); |
361 | 0 |
|
362 | 0 | // Streams which do not exist should never be ready. |
363 | 0 | MOZ_ASSERT(s); |
364 | 0 |
|
365 | 0 | s->Ready(); |
366 | 0 |
|
367 | 0 | return 0; |
368 | 0 | } |
369 | | |
370 | 0 | int NrIceCtx::stream_failed(void *obj, nr_ice_media_stream *stream) { |
371 | 0 | MOZ_MTLOG(ML_DEBUG, "stream_failed called"); |
372 | 0 | MOZ_ASSERT(!stream->local_stream); |
373 | 0 | MOZ_ASSERT(!stream->obsolete); |
374 | 0 |
|
375 | 0 | // Get the ICE ctx |
376 | 0 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
377 | 0 | RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); |
378 | 0 |
|
379 | 0 | // Streams which do not exist should never fail. |
380 | 0 | MOZ_ASSERT(s); |
381 | 0 |
|
382 | 0 | ctx->SetConnectionState(ICE_CTX_FAILED); |
383 | 0 | s -> Failed(); |
384 | 0 | return 0; |
385 | 0 | } |
386 | | |
387 | 0 | int NrIceCtx::ice_checking(void *obj, nr_ice_peer_ctx *pctx) { |
388 | 0 | MOZ_MTLOG(ML_DEBUG, "ice_checking called"); |
389 | 0 |
|
390 | 0 | // Get the ICE ctx |
391 | 0 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
392 | 0 |
|
393 | 0 | ctx->SetConnectionState(ICE_CTX_CHECKING); |
394 | 0 |
|
395 | 0 | return 0; |
396 | 0 | } |
397 | | |
398 | 0 | int NrIceCtx::ice_connected(void *obj, nr_ice_peer_ctx *pctx) { |
399 | 0 | MOZ_MTLOG(ML_DEBUG, "ice_connected called"); |
400 | 0 |
|
401 | 0 | // Get the ICE ctx |
402 | 0 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
403 | 0 |
|
404 | 0 | // This is called even on failed contexts. |
405 | 0 | if (ctx->connection_state() != ICE_CTX_FAILED) { |
406 | 0 | ctx->SetConnectionState(ICE_CTX_CONNECTED); |
407 | 0 | } |
408 | 0 |
|
409 | 0 | return 0; |
410 | 0 | } |
411 | | |
412 | 0 | int NrIceCtx::ice_disconnected(void *obj, nr_ice_peer_ctx *pctx) { |
413 | 0 | MOZ_MTLOG(ML_DEBUG, "ice_disconnected called"); |
414 | 0 |
|
415 | 0 | // Get the ICE ctx |
416 | 0 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
417 | 0 |
|
418 | 0 | ctx->SetConnectionState(ICE_CTX_DISCONNECTED); |
419 | 0 |
|
420 | 0 | return 0; |
421 | 0 | } |
422 | | |
423 | | int NrIceCtx::msg_recvd(void *obj, nr_ice_peer_ctx *pctx, |
424 | | nr_ice_media_stream *stream, int component_id, |
425 | 0 | UCHAR *msg, int len) { |
426 | 0 | // Get the ICE ctx |
427 | 0 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
428 | 0 | RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); |
429 | 0 |
|
430 | 0 | // Streams which do not exist should never have packets. |
431 | 0 | MOZ_ASSERT(s); |
432 | 0 |
|
433 | 0 | s->SignalPacketReceived(s, component_id, msg, len); |
434 | 0 |
|
435 | 0 | return 0; |
436 | 0 | } |
437 | | |
438 | | void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx, |
439 | | nr_ice_media_stream *stream, |
440 | | int component_id, |
441 | 0 | nr_ice_candidate *candidate) { |
442 | 0 | MOZ_ASSERT(!stream->obsolete); |
443 | 0 | // Get the ICE ctx |
444 | 0 | NrIceCtx *ctx = static_cast<NrIceCtx *>(arg); |
445 | 0 | RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); |
446 | 0 |
|
447 | 0 | if (!s) { |
448 | 0 | // This stream has been removed because it is inactive |
449 | 0 | return; |
450 | 0 | } |
451 | 0 | |
452 | 0 | // Format the candidate. |
453 | 0 | char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE]; |
454 | 0 | int r = nr_ice_format_candidate_attribute(candidate, candidate_str, |
455 | 0 | sizeof(candidate_str)); |
456 | 0 | MOZ_ASSERT(!r); |
457 | 0 | if (r) |
458 | 0 | return; |
459 | 0 | |
460 | 0 | MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate " |
461 | 0 | << candidate_str); |
462 | 0 |
|
463 | 0 | s->SignalCandidate(s, candidate_str); |
464 | 0 | } |
465 | | |
466 | | |
467 | | void |
468 | | NrIceCtx::InitializeGlobals(bool allow_loopback, |
469 | | bool tcp_enabled, |
470 | 0 | bool allow_link_local) { |
471 | 0 | // Initialize the crypto callbacks and logging stuff |
472 | 0 | if (!initialized) { |
473 | 0 | NR_reg_init(NR_REG_MODE_LOCAL); |
474 | 0 | nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl; |
475 | 0 | initialized = true; |
476 | 0 |
|
477 | 0 | // Set the priorites for candidate type preferences. |
478 | 0 | // These numbers come from RFC 5245 S. 4.1.2.2 |
479 | 0 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_SRV_RFLX, 100); |
480 | 0 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX, 110); |
481 | 0 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST, 126); |
482 | 0 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED, 5); |
483 | 0 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP, 99); |
484 | 0 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP, 109); |
485 | 0 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST_TCP, 125); |
486 | 0 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED_TCP, 0); |
487 | 0 |
|
488 | 0 | int32_t stun_client_maximum_transmits = 7; |
489 | 0 | int32_t ice_trickle_grace_period = 5000; |
490 | 0 | int32_t ice_tcp_so_sock_count = 3; |
491 | 0 | int32_t ice_tcp_listen_backlog = 10; |
492 | 0 | nsAutoCString force_net_interface; |
493 | 0 | nsresult res; |
494 | 0 | nsCOMPtr<nsIPrefService> prefs = |
495 | 0 | do_GetService("@mozilla.org/preferences-service;1", &res); |
496 | 0 |
|
497 | 0 | if (NS_SUCCEEDED(res)) { |
498 | 0 | nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs); |
499 | 0 | if (branch) { |
500 | 0 | branch->GetIntPref( |
501 | 0 | "media.peerconnection.ice.stun_client_maximum_transmits", |
502 | 0 | &stun_client_maximum_transmits); |
503 | 0 | branch->GetIntPref( |
504 | 0 | "media.peerconnection.ice.trickle_grace_period", |
505 | 0 | &ice_trickle_grace_period); |
506 | 0 | branch->GetIntPref( |
507 | 0 | "media.peerconnection.ice.tcp_so_sock_count", |
508 | 0 | &ice_tcp_so_sock_count); |
509 | 0 | branch->GetIntPref( |
510 | 0 | "media.peerconnection.ice.tcp_listen_backlog", |
511 | 0 | &ice_tcp_listen_backlog); |
512 | 0 | branch->GetCharPref( |
513 | 0 | "media.peerconnection.ice.force_interface", |
514 | 0 | force_net_interface); |
515 | 0 | } |
516 | 0 | } |
517 | 0 |
|
518 | 0 | NR_reg_set_uint4((char *)"stun.client.maximum_transmits", |
519 | 0 | stun_client_maximum_transmits); |
520 | 0 | NR_reg_set_uint4((char *)NR_ICE_REG_TRICKLE_GRACE_PERIOD, |
521 | 0 | ice_trickle_grace_period); |
522 | 0 | NR_reg_set_int4((char *)NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT, |
523 | 0 | ice_tcp_so_sock_count); |
524 | 0 | NR_reg_set_int4((char *)NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG, |
525 | 0 | ice_tcp_listen_backlog); |
526 | 0 |
|
527 | 0 | NR_reg_set_char((char *)NR_ICE_REG_ICE_TCP_DISABLE, !tcp_enabled); |
528 | 0 |
|
529 | 0 | if (allow_loopback) { |
530 | 0 | NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1); |
531 | 0 | } |
532 | 0 |
|
533 | 0 | if (allow_link_local) { |
534 | 0 | NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, 1); |
535 | 0 | } |
536 | 0 | if (force_net_interface.Length() > 0) { |
537 | 0 | // Stupid cast.... but needed |
538 | 0 | const nsCString& flat = PromiseFlatCString(static_cast<nsACString&>(force_net_interface)); |
539 | 0 | NR_reg_set_string((char *)NR_ICE_REG_PREF_FORCE_INTERFACE_NAME, const_cast<char*>(flat.get())); |
540 | 0 | } |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | 0 | #define MAXADDRS 100 // mirrors setting in ice_ctx.c |
545 | | |
546 | | /* static */ |
547 | | nsTArray<NrIceStunAddr> |
548 | | NrIceCtx::GetStunAddrs() |
549 | 0 | { |
550 | 0 | nsTArray<NrIceStunAddr> addrs; |
551 | 0 |
|
552 | 0 | nr_local_addr local_addrs[MAXADDRS]; |
553 | 0 | int addr_ct=0; |
554 | 0 |
|
555 | 0 | // most likely running on parent process and need crypto vtbl |
556 | 0 | // initialized on Windows (Linux and OSX don't seem to care) |
557 | 0 | if (!initialized) { |
558 | 0 | nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl; |
559 | 0 | } |
560 | 0 |
|
561 | 0 | MOZ_MTLOG(ML_INFO, "NrIceCtx static call to find local stun addresses"); |
562 | 0 | if (nr_stun_find_local_addresses(local_addrs, MAXADDRS, &addr_ct)) { |
563 | 0 | MOZ_MTLOG(ML_INFO, "Error finding local stun addresses"); |
564 | 0 | } else { |
565 | 0 | for(int i=0; i<addr_ct; ++i) { |
566 | 0 | NrIceStunAddr addr(&local_addrs[i]); |
567 | 0 | addrs.AppendElement(addr); |
568 | 0 | } |
569 | 0 | } |
570 | 0 |
|
571 | 0 | return addrs; |
572 | 0 | } |
573 | | |
574 | | void |
575 | | NrIceCtx::SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs) |
576 | 0 | { |
577 | 0 | nr_local_addr* local_addrs; |
578 | 0 | local_addrs = new nr_local_addr[addrs.Length()]; |
579 | 0 |
|
580 | 0 | for(size_t i=0; i<addrs.Length(); ++i) { |
581 | 0 | nr_local_addr_copy(&local_addrs[i], |
582 | 0 | const_cast<nr_local_addr*>(&addrs[i].localAddr())); |
583 | 0 | } |
584 | 0 | nr_ice_set_local_addresses(ctx_, local_addrs, addrs.Length()); |
585 | 0 |
|
586 | 0 | delete[] local_addrs; |
587 | 0 | } |
588 | | |
589 | | bool |
590 | | NrIceCtx::Initialize() |
591 | 0 | { |
592 | 0 | // Create the ICE context |
593 | 0 | int r; |
594 | 0 |
|
595 | 0 | UINT4 flags = NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION; |
596 | 0 | switch (policy_) { |
597 | 0 | case ICE_POLICY_RELAY: |
598 | 0 | flags |= NR_ICE_CTX_FLAGS_RELAY_ONLY; |
599 | 0 | break; |
600 | 0 | case ICE_POLICY_NO_HOST: |
601 | 0 | flags |= NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES; |
602 | 0 | break; |
603 | 0 | case ICE_POLICY_ALL: |
604 | 0 | break; |
605 | 0 | } |
606 | 0 | |
607 | 0 | r = nr_ice_ctx_create(const_cast<char *>(name_.c_str()), flags, &ctx_); |
608 | 0 |
|
609 | 0 | if (r) { |
610 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name_ << "'"); |
611 | 0 | return false; |
612 | 0 | } |
613 | 0 |
|
614 | 0 | nr_interface_prioritizer *prioritizer = CreateInterfacePrioritizer(); |
615 | 0 | if (!prioritizer) { |
616 | 0 | MOZ_MTLOG(LogLevel::Error, "Couldn't create interface prioritizer."); |
617 | 0 | return false; |
618 | 0 | } |
619 | 0 |
|
620 | 0 | r = nr_ice_ctx_set_interface_prioritizer(ctx_, prioritizer); |
621 | 0 | if (r) { |
622 | 0 | MOZ_MTLOG(LogLevel::Error, "Couldn't set interface prioritizer."); |
623 | 0 | return false; |
624 | 0 | } |
625 | 0 |
|
626 | 0 | if (generating_trickle()) { |
627 | 0 | r = nr_ice_ctx_set_trickle_cb(ctx_, &NrIceCtx::trickle_cb, this); |
628 | 0 | if (r) { |
629 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name_ << "'"); |
630 | 0 | return false; |
631 | 0 | } |
632 | 0 | } |
633 | 0 |
|
634 | 0 | nsAutoCString mapping_type; |
635 | 0 | nsAutoCString filtering_type; |
636 | 0 | bool block_udp = false; |
637 | 0 | bool block_tcp = false; |
638 | 0 |
|
639 | 0 | nsresult rv; |
640 | 0 | nsCOMPtr<nsIPrefService> pref_service = |
641 | 0 | do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); |
642 | 0 |
|
643 | 0 | if (NS_SUCCEEDED(rv)) { |
644 | 0 | nsCOMPtr<nsIPrefBranch> pref_branch; |
645 | 0 | rv = pref_service->GetBranch(nullptr, getter_AddRefs(pref_branch)); |
646 | 0 | if (NS_SUCCEEDED(rv)) { |
647 | 0 | Unused << pref_branch->GetCharPref( |
648 | 0 | "media.peerconnection.nat_simulator.mapping_type", |
649 | 0 | mapping_type); |
650 | 0 | Unused << pref_branch->GetCharPref( |
651 | 0 | "media.peerconnection.nat_simulator.filtering_type", |
652 | 0 | filtering_type); |
653 | 0 | Unused << pref_branch->GetBoolPref( |
654 | 0 | "media.peerconnection.nat_simulator.block_udp", |
655 | 0 | &block_udp); |
656 | 0 | Unused << pref_branch->GetBoolPref( |
657 | 0 | "media.peerconnection.nat_simulator.block_tcp", |
658 | 0 | &block_tcp); |
659 | 0 | } |
660 | 0 | } |
661 | 0 |
|
662 | 0 | if (!mapping_type.IsEmpty() && !filtering_type.IsEmpty()) { |
663 | 0 | MOZ_MTLOG(ML_DEBUG, "NAT filtering type: " << filtering_type.get()); |
664 | 0 | MOZ_MTLOG(ML_DEBUG, "NAT mapping type: " << mapping_type.get()); |
665 | 0 | TestNat* test_nat = new TestNat; |
666 | 0 | test_nat->filtering_type_ = TestNat::ToNatBehavior(filtering_type.get()); |
667 | 0 | test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type.get()); |
668 | 0 | test_nat->block_udp_ = block_udp; |
669 | 0 | test_nat->block_tcp_ = block_tcp; |
670 | 0 | test_nat->enabled_ = true; |
671 | 0 | SetNat(test_nat); |
672 | 0 | } |
673 | 0 |
|
674 | 0 | // Create the handler objects |
675 | 0 | ice_handler_vtbl_ = new nr_ice_handler_vtbl(); |
676 | 0 | ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair; |
677 | 0 | ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready; |
678 | 0 | ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed; |
679 | 0 | ice_handler_vtbl_->ice_connected = &NrIceCtx::ice_connected; |
680 | 0 | ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd; |
681 | 0 | ice_handler_vtbl_->ice_checking = &NrIceCtx::ice_checking; |
682 | 0 | ice_handler_vtbl_->ice_disconnected = &NrIceCtx::ice_disconnected; |
683 | 0 |
|
684 | 0 | ice_handler_ = new nr_ice_handler(); |
685 | 0 | ice_handler_->vtbl = ice_handler_vtbl_; |
686 | 0 | ice_handler_->obj = this; |
687 | 0 |
|
688 | 0 | // Create the peer ctx. Because we do not support parallel forking, we |
689 | 0 | // only have one peer ctx. |
690 | 0 | std::string peer_name = name_ + ":default"; |
691 | 0 | r = nr_ice_peer_ctx_create(ctx_, ice_handler_, |
692 | 0 | const_cast<char *>(peer_name.c_str()), |
693 | 0 | &peer_); |
694 | 0 | if (r) { |
695 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name_ << "'"); |
696 | 0 | return false; |
697 | 0 | } |
698 | 0 |
|
699 | 0 | sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); |
700 | 0 |
|
701 | 0 | if (!NS_SUCCEEDED(rv)) |
702 | 0 | return false; |
703 | 0 | |
704 | 0 | return true; |
705 | 0 | } |
706 | | |
707 | 0 | int NrIceCtx::SetNat(const RefPtr<TestNat>& aNat) { |
708 | 0 | nat_ = aNat; |
709 | 0 | nr_socket_factory *fac; |
710 | 0 | int r = nat_->create_socket_factory(&fac); |
711 | 0 | if (r) { |
712 | 0 | return r; |
713 | 0 | } |
714 | 0 | nr_ice_ctx_set_socket_factory(ctx_, fac); |
715 | 0 | return 0; |
716 | 0 | } |
717 | | |
718 | | // ONLY USE THIS FOR TESTING. Will cause totally unpredictable and possibly very |
719 | | // bad effects if ICE is still live. |
720 | 0 | void NrIceCtx::internal_DeinitializeGlobal() { |
721 | 0 | NR_reg_del((char *)"stun"); |
722 | 0 | NR_reg_del((char *)"ice"); |
723 | 0 | RLogConnector::DestroyInstance(); |
724 | 0 | nr_crypto_vtbl = nullptr; |
725 | 0 | initialized = false; |
726 | 0 | } |
727 | | |
728 | 0 | void NrIceCtx::internal_SetTimerAccelarator(int divider) { |
729 | 0 | ctx_->test_timer_divider = divider; |
730 | 0 | } |
731 | | |
732 | 0 | void NrIceCtx::AccumulateStats(const NrIceStats& stats) { |
733 | 0 | nr_accumulate_count(&(ctx_->stats.stun_retransmits), |
734 | 0 | stats.stun_retransmits); |
735 | 0 | nr_accumulate_count(&(ctx_->stats.turn_401s), stats.turn_401s); |
736 | 0 | nr_accumulate_count(&(ctx_->stats.turn_403s), stats.turn_403s); |
737 | 0 | nr_accumulate_count(&(ctx_->stats.turn_438s), stats.turn_438s); |
738 | 0 | } |
739 | | |
740 | 0 | NrIceStats NrIceCtx::Destroy() { |
741 | 0 | // designed to be called more than once so if stats are desired, this can be |
742 | 0 | // called just prior to the destructor |
743 | 0 | MOZ_MTLOG(ML_DEBUG, "Destroying ICE ctx '" << name_ <<"'"); |
744 | 0 | for (auto& idAndStream : streams_) { |
745 | 0 | idAndStream.second->Close(); |
746 | 0 | } |
747 | 0 |
|
748 | 0 | NrIceStats stats; |
749 | 0 | if (ctx_) { |
750 | 0 | stats.stun_retransmits = ctx_->stats.stun_retransmits; |
751 | 0 | stats.turn_401s = ctx_->stats.turn_401s; |
752 | 0 | stats.turn_403s = ctx_->stats.turn_403s; |
753 | 0 | stats.turn_438s = ctx_->stats.turn_438s; |
754 | 0 | } |
755 | 0 |
|
756 | 0 | if (!ice_start_time_.IsNull()) { |
757 | 0 | TimeDuration time_delta = TimeStamp::Now() - ice_start_time_; |
758 | 0 | ice_start_time_ = TimeStamp(); // null out |
759 | 0 |
|
760 | 0 | if (offerer_) { |
761 | 0 | Telemetry::Accumulate( |
762 | 0 | Telemetry::WEBRTC_ICE_OFFERER_ABORT_TIME, |
763 | 0 | time_delta.ToMilliseconds()); |
764 | 0 | } else { |
765 | 0 | Telemetry::Accumulate( |
766 | 0 | Telemetry::WEBRTC_ICE_ANSWERER_ABORT_TIME, |
767 | 0 | time_delta.ToMilliseconds()); |
768 | 0 | } |
769 | 0 | } |
770 | 0 |
|
771 | 0 | if (peer_) { |
772 | 0 | nr_ice_peer_ctx_destroy(&peer_); |
773 | 0 | } |
774 | 0 | if (ctx_) { |
775 | 0 | nr_ice_ctx_destroy(&ctx_); |
776 | 0 | } |
777 | 0 |
|
778 | 0 | delete ice_handler_vtbl_; |
779 | 0 | delete ice_handler_; |
780 | 0 |
|
781 | 0 | ice_handler_vtbl_ = nullptr; |
782 | 0 | ice_handler_ = nullptr; |
783 | 0 | streams_.clear(); |
784 | 0 |
|
785 | 0 | return stats; |
786 | 0 | } |
787 | | |
788 | 0 | NrIceCtx::~NrIceCtx() { |
789 | 0 | Destroy(); |
790 | 0 | } |
791 | | |
792 | 0 | void NrIceCtx::destroy_peer_ctx() { |
793 | 0 | nr_ice_peer_ctx_destroy(&peer_); |
794 | 0 | } |
795 | | |
796 | 0 | nsresult NrIceCtx::SetControlling(Controlling controlling) { |
797 | 0 | if (!ice_controlling_set_) { |
798 | 0 | peer_->controlling = (controlling == ICE_CONTROLLING)? 1 : 0; |
799 | 0 | ice_controlling_set_ = true; |
800 | 0 |
|
801 | 0 | MOZ_MTLOG(ML_DEBUG, "ICE ctx " << name_ << " setting controlling to" << |
802 | 0 | controlling); |
803 | 0 | } |
804 | 0 | return NS_OK; |
805 | 0 | } |
806 | | |
807 | 0 | NrIceCtx::Controlling NrIceCtx::GetControlling() { |
808 | 0 | return (peer_->controlling) ? ICE_CONTROLLING : ICE_CONTROLLED; |
809 | 0 | } |
810 | | |
811 | 0 | nsresult NrIceCtx::SetPolicy(Policy policy) { |
812 | 0 | policy_ = policy; |
813 | 0 | return NS_OK; |
814 | 0 | } |
815 | | |
816 | | nsresult NrIceCtx::SetStunServers(const std::vector<NrIceStunServer>& |
817 | 0 | stun_servers) { |
818 | 0 | if (stun_servers.empty()) |
819 | 0 | return NS_OK; |
820 | 0 | |
821 | 0 | auto servers = MakeUnique<nr_ice_stun_server[]>(stun_servers.size()); |
822 | 0 |
|
823 | 0 | for (size_t i=0; i < stun_servers.size(); ++i) { |
824 | 0 | nsresult rv = stun_servers[i].ToNicerStunStruct(&servers[i]); |
825 | 0 | if (NS_FAILED(rv)) { |
826 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'"); |
827 | 0 | return NS_ERROR_FAILURE; |
828 | 0 | } |
829 | 0 | } |
830 | 0 |
|
831 | 0 | int r = nr_ice_ctx_set_stun_servers(ctx_, servers.get(), stun_servers.size()); |
832 | 0 | if (r) { |
833 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'"); |
834 | 0 | return NS_ERROR_FAILURE; |
835 | 0 | } |
836 | 0 |
|
837 | 0 | return NS_OK; |
838 | 0 | } |
839 | | |
840 | | // TODO(ekr@rtfm.com): This is just SetStunServers with s/Stun/Turn |
841 | | // Could we do a template or something? |
842 | | nsresult NrIceCtx::SetTurnServers(const std::vector<NrIceTurnServer>& |
843 | 0 | turn_servers) { |
844 | 0 | if (turn_servers.empty()) |
845 | 0 | return NS_OK; |
846 | 0 | |
847 | 0 | auto servers = MakeUnique<nr_ice_turn_server[]>(turn_servers.size()); |
848 | 0 |
|
849 | 0 | for (size_t i=0; i < turn_servers.size(); ++i) { |
850 | 0 | nsresult rv = turn_servers[i].ToNicerTurnStruct(&servers[i]); |
851 | 0 | if (NS_FAILED(rv)) { |
852 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'"); |
853 | 0 | return NS_ERROR_FAILURE; |
854 | 0 | } |
855 | 0 | } |
856 | 0 |
|
857 | 0 | int r = nr_ice_ctx_set_turn_servers(ctx_, servers.get(), turn_servers.size()); |
858 | 0 | if (r) { |
859 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'"); |
860 | 0 | return NS_ERROR_FAILURE; |
861 | 0 | } |
862 | 0 |
|
863 | 0 | // TODO(ekr@rtfm.com): This leaks the username/password. Need to free that. |
864 | 0 |
|
865 | 0 | return NS_OK; |
866 | 0 | } |
867 | | |
868 | 0 | nsresult NrIceCtx::SetResolver(nr_resolver *resolver) { |
869 | 0 | int r = nr_ice_ctx_set_resolver(ctx_, resolver); |
870 | 0 |
|
871 | 0 | if (r) { |
872 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set resolver for '" << name_ << "'"); |
873 | 0 | return NS_ERROR_FAILURE; |
874 | 0 | } |
875 | 0 |
|
876 | 0 | return NS_OK; |
877 | 0 | } |
878 | | |
879 | 0 | nsresult NrIceCtx::SetProxyServer(const NrIceProxyServer& proxy_server) { |
880 | 0 | int r,_status; |
881 | 0 | nr_proxy_tunnel_config *config = nullptr; |
882 | 0 | nr_socket_wrapper_factory *wrapper = nullptr; |
883 | 0 |
|
884 | 0 | if ((r = nr_proxy_tunnel_config_create(&config))) { |
885 | 0 | ABORT(r); |
886 | 0 | } |
887 | 0 |
|
888 | 0 | if ((r = nr_proxy_tunnel_config_set_proxy(config, |
889 | 0 | proxy_server.host().c_str(), |
890 | 0 | proxy_server.port()))) { |
891 | 0 | ABORT(r); |
892 | 0 | } |
893 | 0 |
|
894 | 0 | if ((r = nr_proxy_tunnel_config_set_resolver(config, ctx_->resolver))) { |
895 | 0 | ABORT(r); |
896 | 0 | } |
897 | 0 |
|
898 | 0 | if ((r = nr_socket_wrapper_factory_proxy_tunnel_create(config, &wrapper))) { |
899 | 0 | MOZ_MTLOG(LogLevel::Error, "Couldn't create proxy tunnel wrapper."); |
900 | 0 | ABORT(r); |
901 | 0 | } |
902 | 0 |
|
903 | 0 | // nr_ice_ctx will own the wrapper after this call |
904 | 0 | if ((r = nr_ice_ctx_set_turn_tcp_socket_wrapper(ctx_, wrapper))) { |
905 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set proxy for '" << name_ << "': " << r); |
906 | 0 | ABORT(r); |
907 | 0 | } |
908 | 0 |
|
909 | 0 | _status = 0; |
910 | 0 | abort: |
911 | 0 | nr_proxy_tunnel_config_destroy(&config); |
912 | 0 | if (_status) { |
913 | 0 | nr_socket_wrapper_factory_destroy(&wrapper); |
914 | 0 | return NS_ERROR_FAILURE; |
915 | 0 | } |
916 | 0 | return NS_OK; |
917 | 0 | } |
918 | | |
919 | 0 | void NrIceCtx::SetCtxFlags(bool default_route_only, bool proxy_only) { |
920 | 0 | ASSERT_ON_THREAD(sts_target_); |
921 | 0 |
|
922 | 0 | if (default_route_only) { |
923 | 0 | nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_DEFAULT_ADDRS); |
924 | 0 | } else { |
925 | 0 | nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_DEFAULT_ADDRS); |
926 | 0 | } |
927 | 0 |
|
928 | 0 | if (proxy_only) { |
929 | 0 | nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_PROXY); |
930 | 0 | } else { |
931 | 0 | nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_PROXY); |
932 | 0 | } |
933 | 0 | } |
934 | | |
935 | 0 | nsresult NrIceCtx::StartGathering(bool default_route_only, bool proxy_only) { |
936 | 0 | ASSERT_ON_THREAD(sts_target_); |
937 | 0 | SetGatheringState(ICE_CTX_GATHER_STARTED); |
938 | 0 |
|
939 | 0 | SetCtxFlags(default_route_only, proxy_only); |
940 | 0 |
|
941 | 0 | TimeStamp start = TimeStamp::Now(); |
942 | 0 | // This might start gathering for the first time, or again after |
943 | 0 | // renegotiation, or might do nothing at all if gathering has already |
944 | 0 | // finished. |
945 | 0 | int r = nr_ice_gather(ctx_, &NrIceCtx::gather_cb, this); |
946 | 0 |
|
947 | 0 |
|
948 | 0 | if (!r) { |
949 | 0 | SetGatheringState(ICE_CTX_GATHER_COMPLETE); |
950 | 0 | Telemetry::AccumulateTimeDelta( |
951 | 0 | Telemetry::WEBRTC_ICE_NR_ICE_GATHER_TIME_IMMEDIATE_SUCCESS, start); |
952 | 0 | } else if (r != R_WOULDBLOCK) { |
953 | 0 | MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't gather ICE candidates for '" |
954 | 0 | << name_ << "', error=" << r); |
955 | 0 | SetConnectionState(ICE_CTX_FAILED); |
956 | 0 | Telemetry::AccumulateTimeDelta( |
957 | 0 | Telemetry::WEBRTC_ICE_NR_ICE_GATHER_TIME_IMMEDIATE_FAILURE, start); |
958 | 0 | return NS_ERROR_FAILURE; |
959 | 0 | } else { |
960 | 0 | Telemetry::AccumulateTimeDelta( |
961 | 0 | Telemetry::WEBRTC_ICE_NR_ICE_GATHER_TIME, start); |
962 | 0 | } |
963 | 0 |
|
964 | 0 | return NS_OK; |
965 | 0 | } |
966 | | |
967 | 0 | RefPtr<NrIceMediaStream> NrIceCtx::FindStream(nr_ice_media_stream *stream) { |
968 | 0 | for (auto& idAndStream : streams_) { |
969 | 0 | if (idAndStream.second->HasStream(stream)) { |
970 | 0 | return idAndStream.second; |
971 | 0 | } |
972 | 0 | } |
973 | 0 |
|
974 | 0 | return nullptr; |
975 | 0 | } |
976 | | |
977 | 0 | std::vector<std::string> NrIceCtx::GetGlobalAttributes() { |
978 | 0 | char **attrs = nullptr; |
979 | 0 | int attrct; |
980 | 0 | int r; |
981 | 0 | std::vector<std::string> ret; |
982 | 0 |
|
983 | 0 | r = nr_ice_get_global_attributes(ctx_, &attrs, &attrct); |
984 | 0 | if (r) { |
985 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't get ufrag and password for '" |
986 | 0 | << name_ << "'"); |
987 | 0 | return ret; |
988 | 0 | } |
989 | 0 |
|
990 | 0 | for (int i=0; i<attrct; i++) { |
991 | 0 | ret.push_back(std::string(attrs[i])); |
992 | 0 | RFREE(attrs[i]); |
993 | 0 | } |
994 | 0 | RFREE(attrs); |
995 | 0 |
|
996 | 0 | return ret; |
997 | 0 | } |
998 | | |
999 | 0 | nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) { |
1000 | 0 | std::vector<char *> attrs_in; |
1001 | 0 | attrs_in.reserve(attrs.size()); |
1002 | 0 | for (auto& attr : attrs) { |
1003 | 0 | attrs_in.push_back(const_cast<char *>(attr.c_str())); |
1004 | 0 | } |
1005 | 0 |
|
1006 | 0 | int r = nr_ice_peer_ctx_parse_global_attributes(peer_, |
1007 | 0 | attrs_in.empty() ? |
1008 | 0 | nullptr : &attrs_in[0], |
1009 | 0 | attrs_in.size()); |
1010 | 0 | if (r) { |
1011 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't parse global attributes for " |
1012 | 0 | << name_ << "'"); |
1013 | 0 | return NS_ERROR_FAILURE; |
1014 | 0 | } |
1015 | 0 |
|
1016 | 0 | return NS_OK; |
1017 | 0 | } |
1018 | | |
1019 | 0 | bool NrIceCtx::HasStreamsToConnect() const { |
1020 | 0 | for (auto& idAndStream : streams_) { |
1021 | 0 | if (idAndStream.second->state() != NrIceMediaStream::ICE_CLOSED) { |
1022 | 0 | return true; |
1023 | 0 | } |
1024 | 0 | } |
1025 | 0 | return false; |
1026 | 0 | } |
1027 | | |
1028 | 0 | nsresult NrIceCtx::StartChecks(bool offerer) { |
1029 | 0 | int r; |
1030 | 0 | if (!HasStreamsToConnect()) { |
1031 | 0 | // Nothing to do |
1032 | 0 | return NS_OK; |
1033 | 0 | } |
1034 | 0 | |
1035 | 0 | offerer_ = offerer; |
1036 | 0 | ice_start_time_ = TimeStamp::Now(); |
1037 | 0 |
|
1038 | 0 | r=nr_ice_peer_ctx_pair_candidates(peer_); |
1039 | 0 | if (r) { |
1040 | 0 | MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't pair candidates on " << name_); |
1041 | 0 | SetConnectionState(ICE_CTX_FAILED); |
1042 | 0 | return NS_ERROR_FAILURE; |
1043 | 0 | } |
1044 | 0 |
|
1045 | 0 | r = nr_ice_peer_ctx_start_checks2(peer_,1); |
1046 | 0 | if (r) { |
1047 | 0 | if (r == R_NOT_FOUND) { |
1048 | 0 | MOZ_MTLOG(ML_INFO, "Couldn't start peer checks on " |
1049 | 0 | << name_ << ", assuming trickle ICE"); |
1050 | 0 | } else { |
1051 | 0 | MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't start peer checks on " |
1052 | 0 | << name_); |
1053 | 0 | SetConnectionState(ICE_CTX_FAILED); |
1054 | 0 | return NS_ERROR_FAILURE; |
1055 | 0 | } |
1056 | 0 | } |
1057 | 0 |
|
1058 | 0 | return NS_OK; |
1059 | 0 | } |
1060 | | |
1061 | | |
1062 | 0 | void NrIceCtx::gather_cb(NR_SOCKET s, int h, void *arg) { |
1063 | 0 | NrIceCtx *ctx = static_cast<NrIceCtx *>(arg); |
1064 | 0 |
|
1065 | 0 | ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE); |
1066 | 0 | } |
1067 | | |
1068 | 0 | nsresult NrIceCtx::Finalize() { |
1069 | 0 | int r = nr_ice_ctx_finalize(ctx_, peer_); |
1070 | 0 |
|
1071 | 0 | if (r) { |
1072 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't finalize " |
1073 | 0 | << name_ << "'"); |
1074 | 0 | return NS_ERROR_FAILURE; |
1075 | 0 | } |
1076 | 0 |
|
1077 | 0 | return NS_OK; |
1078 | 0 | } |
1079 | | |
1080 | 0 | void NrIceCtx::UpdateNetworkState(bool online) { |
1081 | 0 | MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): updating network state to " << |
1082 | 0 | (online ? "online" : "offline")); |
1083 | 0 | if (online) { |
1084 | 0 | nr_ice_peer_ctx_refresh_consent_all_streams(peer_); |
1085 | 0 | } else { |
1086 | 0 | nr_ice_peer_ctx_disconnect_all_streams(peer_); |
1087 | 0 | } |
1088 | 0 | } |
1089 | | |
1090 | 0 | void NrIceCtx::SetConnectionState(ConnectionState state) { |
1091 | 0 | if (state == connection_state_) |
1092 | 0 | return; |
1093 | 0 | |
1094 | 0 | if (!ice_start_time_.IsNull() && (state > ICE_CTX_CHECKING)) { |
1095 | 0 | TimeDuration time_delta = TimeStamp::Now() - ice_start_time_; |
1096 | 0 | ice_start_time_ = TimeStamp(); |
1097 | 0 |
|
1098 | 0 | switch (state) { |
1099 | 0 | case ICE_CTX_INIT: |
1100 | 0 | case ICE_CTX_CHECKING: |
1101 | 0 | MOZ_CRASH(); |
1102 | 0 | break; |
1103 | 0 | case ICE_CTX_CONNECTED: |
1104 | 0 | case ICE_CTX_COMPLETED: |
1105 | 0 | if (offerer_) { |
1106 | 0 | Telemetry::Accumulate( |
1107 | 0 | Telemetry::WEBRTC_ICE_OFFERER_SUCCESS_TIME, |
1108 | 0 | time_delta.ToMilliseconds()); |
1109 | 0 | } else { |
1110 | 0 | Telemetry::Accumulate( |
1111 | 0 | Telemetry::WEBRTC_ICE_ANSWERER_SUCCESS_TIME, |
1112 | 0 | time_delta.ToMilliseconds()); |
1113 | 0 | } |
1114 | 0 | break; |
1115 | 0 | case ICE_CTX_FAILED: |
1116 | 0 | if (offerer_) { |
1117 | 0 | Telemetry::Accumulate( |
1118 | 0 | Telemetry::WEBRTC_ICE_OFFERER_FAILURE_TIME, |
1119 | 0 | time_delta.ToMilliseconds()); |
1120 | 0 | } else { |
1121 | 0 | Telemetry::Accumulate( |
1122 | 0 | Telemetry::WEBRTC_ICE_ANSWERER_FAILURE_TIME, |
1123 | 0 | time_delta.ToMilliseconds()); |
1124 | 0 | } |
1125 | 0 | break; |
1126 | 0 | case ICE_CTX_DISCONNECTED: |
1127 | 0 | // We get this every time an ICE disconnect gets reported. |
1128 | 0 | // Do we want a Telemetry probe counting how often this happens? |
1129 | 0 | break; |
1130 | 0 | case ICE_CTX_CLOSED: |
1131 | 0 | // This doesn't seem to be used... |
1132 | 0 | break; |
1133 | 0 | } |
1134 | 0 | } |
1135 | 0 | |
1136 | 0 | MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " << |
1137 | 0 | connection_state_ << "->" << state); |
1138 | 0 | connection_state_ = state; |
1139 | 0 |
|
1140 | 0 | if (connection_state_ == ICE_CTX_FAILED) { |
1141 | 0 | MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): dumping r_log ringbuffer... "); |
1142 | 0 | std::deque<std::string> logs; |
1143 | 0 | RLogConnector::GetInstance()->GetAny(0, &logs); |
1144 | 0 | for (auto& log : logs) { |
1145 | 0 | MOZ_MTLOG(ML_INFO, log); |
1146 | 0 | } |
1147 | 0 | } |
1148 | 0 |
|
1149 | 0 | SignalConnectionStateChange(this, state); |
1150 | 0 | } |
1151 | | |
1152 | 0 | void NrIceCtx::SetGatheringState(GatheringState state) { |
1153 | 0 | if (state == gathering_state_) |
1154 | 0 | return; |
1155 | 0 | |
1156 | 0 | MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state " << |
1157 | 0 | gathering_state_ << "->" << state); |
1158 | 0 | gathering_state_ = state; |
1159 | 0 |
|
1160 | 0 | SignalGatheringStateChange(this, state); |
1161 | 0 | } |
1162 | | |
1163 | | } // close namespace |
1164 | | |
1165 | | // Reimplement nr_ice_compute_codeword to avoid copyright issues |
1166 | 0 | void nr_ice_compute_codeword(char *buf, int len,char *codeword) { |
1167 | 0 | UINT4 c; |
1168 | 0 |
|
1169 | 0 | r_crc32(buf,len,&c); |
1170 | 0 |
|
1171 | 0 | PL_Base64Encode(reinterpret_cast<char*>(&c), 3, codeword); |
1172 | 0 | codeword[4] = 0; |
1173 | 0 | } |