Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 5 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | |
michael@0 | 8 | // Original author: ekr@rtfm.com |
michael@0 | 9 | |
michael@0 | 10 | // Some of this code is cut-and-pasted from nICEr. Copyright is: |
michael@0 | 11 | |
michael@0 | 12 | /* |
michael@0 | 13 | Copyright (c) 2007, Adobe Systems, Incorporated |
michael@0 | 14 | All rights reserved. |
michael@0 | 15 | |
michael@0 | 16 | Redistribution and use in source and binary forms, with or without |
michael@0 | 17 | modification, are permitted provided that the following conditions are |
michael@0 | 18 | met: |
michael@0 | 19 | |
michael@0 | 20 | * Redistributions of source code must retain the above copyright |
michael@0 | 21 | notice, this list of conditions and the following disclaimer. |
michael@0 | 22 | |
michael@0 | 23 | * Redistributions in binary form must reproduce the above copyright |
michael@0 | 24 | notice, this list of conditions and the following disclaimer in the |
michael@0 | 25 | documentation and/or other materials provided with the distribution. |
michael@0 | 26 | |
michael@0 | 27 | * Neither the name of Adobe Systems, Network Resonance nor the names of its |
michael@0 | 28 | contributors may be used to endorse or promote products derived from |
michael@0 | 29 | this software without specific prior written permission. |
michael@0 | 30 | |
michael@0 | 31 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 32 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 33 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 34 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 35 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 36 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 37 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 38 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 39 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 40 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 41 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 42 | */ |
michael@0 | 43 | |
michael@0 | 44 | #include <string> |
michael@0 | 45 | #include <vector> |
michael@0 | 46 | |
michael@0 | 47 | #include "logging.h" |
michael@0 | 48 | #include "nspr.h" |
michael@0 | 49 | #include "nss.h" |
michael@0 | 50 | #include "pk11pub.h" |
michael@0 | 51 | #include "plbase64.h" |
michael@0 | 52 | |
michael@0 | 53 | #include "nsCOMPtr.h" |
michael@0 | 54 | #include "nsComponentManagerUtils.h" |
michael@0 | 55 | #include "nsError.h" |
michael@0 | 56 | #include "nsIEventTarget.h" |
michael@0 | 57 | #include "nsNetCID.h" |
michael@0 | 58 | #include "nsComponentManagerUtils.h" |
michael@0 | 59 | #include "nsServiceManagerUtils.h" |
michael@0 | 60 | #include "ScopedNSSTypes.h" |
michael@0 | 61 | |
michael@0 | 62 | // nICEr includes |
michael@0 | 63 | extern "C" { |
michael@0 | 64 | #include "nr_api.h" |
michael@0 | 65 | #include "registry.h" |
michael@0 | 66 | #include "async_timer.h" |
michael@0 | 67 | #include "r_crc32.h" |
michael@0 | 68 | #include "r_memory.h" |
michael@0 | 69 | #include "ice_reg.h" |
michael@0 | 70 | #include "ice_util.h" |
michael@0 | 71 | #include "transport_addr.h" |
michael@0 | 72 | #include "nr_crypto.h" |
michael@0 | 73 | #include "nr_socket.h" |
michael@0 | 74 | #include "nr_socket_local.h" |
michael@0 | 75 | #include "stun_client_ctx.h" |
michael@0 | 76 | #include "stun_server_ctx.h" |
michael@0 | 77 | #include "ice_codeword.h" |
michael@0 | 78 | #include "ice_ctx.h" |
michael@0 | 79 | #include "ice_candidate.h" |
michael@0 | 80 | #include "ice_handler.h" |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | // Local includes |
michael@0 | 84 | #include "nricectx.h" |
michael@0 | 85 | #include "nricemediastream.h" |
michael@0 | 86 | #include "nr_socket_prsock.h" |
michael@0 | 87 | #include "nrinterfaceprioritizer.h" |
michael@0 | 88 | #include "rlogringbuffer.h" |
michael@0 | 89 | |
michael@0 | 90 | namespace mozilla { |
michael@0 | 91 | |
michael@0 | 92 | MOZ_MTLOG_MODULE("mtransport") |
michael@0 | 93 | |
michael@0 | 94 | const char kNrIceTransportUdp[] = "udp"; |
michael@0 | 95 | const char kNrIceTransportTcp[] = "tcp"; |
michael@0 | 96 | |
michael@0 | 97 | static bool initialized = false; |
michael@0 | 98 | |
michael@0 | 99 | // Implement NSPR-based crypto algorithms |
michael@0 | 100 | static int nr_crypto_nss_random_bytes(UCHAR *buf, int len) { |
michael@0 | 101 | ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); |
michael@0 | 102 | if (!slot) |
michael@0 | 103 | return R_INTERNAL; |
michael@0 | 104 | |
michael@0 | 105 | SECStatus rv = PK11_GenerateRandomOnSlot(slot, buf, len); |
michael@0 | 106 | if (rv != SECSuccess) |
michael@0 | 107 | return R_INTERNAL; |
michael@0 | 108 | |
michael@0 | 109 | return 0; |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | static int nr_crypto_nss_hmac(UCHAR *key, int keyl, UCHAR *buf, int bufl, |
michael@0 | 113 | UCHAR *result) { |
michael@0 | 114 | CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC; |
michael@0 | 115 | PK11SlotInfo *slot = 0; |
michael@0 | 116 | MOZ_ASSERT(keyl > 0); |
michael@0 | 117 | SECItem keyi = { siBuffer, key, static_cast<unsigned int>(keyl)}; |
michael@0 | 118 | PK11SymKey *skey = 0; |
michael@0 | 119 | PK11Context *hmac_ctx = 0; |
michael@0 | 120 | SECStatus status; |
michael@0 | 121 | unsigned int hmac_len; |
michael@0 | 122 | SECItem param = { siBuffer, nullptr, 0 }; |
michael@0 | 123 | int err = R_INTERNAL; |
michael@0 | 124 | |
michael@0 | 125 | slot = PK11_GetInternalKeySlot(); |
michael@0 | 126 | if (!slot) |
michael@0 | 127 | goto abort; |
michael@0 | 128 | |
michael@0 | 129 | skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, |
michael@0 | 130 | CKA_SIGN, &keyi, nullptr); |
michael@0 | 131 | if (!skey) |
michael@0 | 132 | goto abort; |
michael@0 | 133 | |
michael@0 | 134 | |
michael@0 | 135 | hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, |
michael@0 | 136 | skey, ¶m); |
michael@0 | 137 | if (!hmac_ctx) |
michael@0 | 138 | goto abort; |
michael@0 | 139 | |
michael@0 | 140 | status = PK11_DigestBegin(hmac_ctx); |
michael@0 | 141 | if (status != SECSuccess) |
michael@0 | 142 | goto abort; |
michael@0 | 143 | |
michael@0 | 144 | status = PK11_DigestOp(hmac_ctx, buf, bufl); |
michael@0 | 145 | if (status != SECSuccess) |
michael@0 | 146 | goto abort; |
michael@0 | 147 | |
michael@0 | 148 | status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20); |
michael@0 | 149 | if (status != SECSuccess) |
michael@0 | 150 | goto abort; |
michael@0 | 151 | |
michael@0 | 152 | MOZ_ASSERT(hmac_len == 20); |
michael@0 | 153 | |
michael@0 | 154 | err = 0; |
michael@0 | 155 | |
michael@0 | 156 | abort: |
michael@0 | 157 | if(hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE); |
michael@0 | 158 | if (skey) PK11_FreeSymKey(skey); |
michael@0 | 159 | if (slot) PK11_FreeSlot(slot); |
michael@0 | 160 | |
michael@0 | 161 | return err; |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | static int nr_crypto_nss_md5(UCHAR *buf, int bufl, UCHAR *result) { |
michael@0 | 165 | int err = R_INTERNAL; |
michael@0 | 166 | SECStatus rv; |
michael@0 | 167 | |
michael@0 | 168 | const SECHashObject *ho = HASH_GetHashObject(HASH_AlgMD5); |
michael@0 | 169 | MOZ_ASSERT(ho); |
michael@0 | 170 | if (!ho) |
michael@0 | 171 | goto abort; |
michael@0 | 172 | |
michael@0 | 173 | MOZ_ASSERT(ho->length == 16); |
michael@0 | 174 | |
michael@0 | 175 | rv = HASH_HashBuf(ho->type, result, buf, bufl); |
michael@0 | 176 | if (rv != SECSuccess) |
michael@0 | 177 | goto abort; |
michael@0 | 178 | |
michael@0 | 179 | err = 0; |
michael@0 | 180 | abort: |
michael@0 | 181 | return err; |
michael@0 | 182 | } |
michael@0 | 183 | |
michael@0 | 184 | static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl = { |
michael@0 | 185 | nr_crypto_nss_random_bytes, |
michael@0 | 186 | nr_crypto_nss_hmac, |
michael@0 | 187 | nr_crypto_nss_md5 |
michael@0 | 188 | }; |
michael@0 | 189 | |
michael@0 | 190 | |
michael@0 | 191 | |
michael@0 | 192 | |
michael@0 | 193 | nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server, |
michael@0 | 194 | const std::string &transport) const { |
michael@0 | 195 | int r; |
michael@0 | 196 | int transport_int; |
michael@0 | 197 | |
michael@0 | 198 | memset(server, 0, sizeof(nr_ice_stun_server)); |
michael@0 | 199 | if (transport == kNrIceTransportUdp) { |
michael@0 | 200 | transport_int = IPPROTO_UDP; |
michael@0 | 201 | } else if (transport == kNrIceTransportTcp) { |
michael@0 | 202 | transport_int = IPPROTO_TCP; |
michael@0 | 203 | } else { |
michael@0 | 204 | MOZ_ASSERT(false); |
michael@0 | 205 | return NS_ERROR_FAILURE; |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | if (has_addr_) { |
michael@0 | 209 | r = nr_praddr_to_transport_addr(&addr_, &server->u.addr, |
michael@0 | 210 | transport_int, 0); |
michael@0 | 211 | if (r) { |
michael@0 | 212 | return NS_ERROR_FAILURE; |
michael@0 | 213 | } |
michael@0 | 214 | server->type=NR_ICE_STUN_SERVER_TYPE_ADDR; |
michael@0 | 215 | } |
michael@0 | 216 | else { |
michael@0 | 217 | MOZ_ASSERT(sizeof(server->u.dnsname.host) > host_.size()); |
michael@0 | 218 | PL_strncpyz(server->u.dnsname.host, host_.c_str(), |
michael@0 | 219 | sizeof(server->u.dnsname.host)); |
michael@0 | 220 | server->u.dnsname.port = port_; |
michael@0 | 221 | server->type=NR_ICE_STUN_SERVER_TYPE_DNSNAME; |
michael@0 | 222 | } |
michael@0 | 223 | |
michael@0 | 224 | return NS_OK; |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | |
michael@0 | 228 | nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server *server) const { |
michael@0 | 229 | memset(server, 0, sizeof(nr_ice_turn_server)); |
michael@0 | 230 | |
michael@0 | 231 | nsresult rv = ToNicerStunStruct(&server->turn_server, transport_); |
michael@0 | 232 | if (NS_FAILED(rv)) |
michael@0 | 233 | return rv; |
michael@0 | 234 | |
michael@0 | 235 | if (transport_ == kNrIceTransportUdp) { |
michael@0 | 236 | server->transport = IPPROTO_UDP; |
michael@0 | 237 | } else if (transport_ == kNrIceTransportTcp) { |
michael@0 | 238 | server->transport = IPPROTO_TCP; |
michael@0 | 239 | } else { |
michael@0 | 240 | MOZ_ASSERT(false); |
michael@0 | 241 | return NS_ERROR_FAILURE; |
michael@0 | 242 | } |
michael@0 | 243 | |
michael@0 | 244 | if (username_.empty()) |
michael@0 | 245 | return NS_ERROR_INVALID_ARG; |
michael@0 | 246 | if (password_.empty()) |
michael@0 | 247 | return NS_ERROR_INVALID_ARG; |
michael@0 | 248 | |
michael@0 | 249 | if (!(server->username=r_strdup(username_.c_str()))) |
michael@0 | 250 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 251 | |
michael@0 | 252 | // TODO(ekr@rtfm.com): handle non-ASCII passwords somehow? |
michael@0 | 253 | // STUN requires they be SASLpreped, but we don't know if |
michael@0 | 254 | // they are at this point. |
michael@0 | 255 | |
michael@0 | 256 | // C++03 23.2.4, Paragraph 1 stipulates that the elements |
michael@0 | 257 | // in std::vector must be contiguous, and can therefore be |
michael@0 | 258 | // used as input to functions expecting C arrays. |
michael@0 | 259 | int r = r_data_create(&server->password, |
michael@0 | 260 | const_cast<UCHAR *>(&password_[0]), |
michael@0 | 261 | password_.size()); |
michael@0 | 262 | if (r) { |
michael@0 | 263 | RFREE(server->username); |
michael@0 | 264 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 265 | } |
michael@0 | 266 | |
michael@0 | 267 | return NS_OK; |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | // Handler callbacks |
michael@0 | 271 | int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream, |
michael@0 | 272 | int component_id, nr_ice_cand_pair **potentials, |
michael@0 | 273 | int potential_ct) { |
michael@0 | 274 | MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = " |
michael@0 | 275 | << potential_ct); |
michael@0 | 276 | |
michael@0 | 277 | return 0; |
michael@0 | 278 | } |
michael@0 | 279 | |
michael@0 | 280 | int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) { |
michael@0 | 281 | MOZ_MTLOG(ML_DEBUG, "stream_ready called"); |
michael@0 | 282 | |
michael@0 | 283 | // Get the ICE ctx. |
michael@0 | 284 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
michael@0 | 285 | |
michael@0 | 286 | RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); |
michael@0 | 287 | |
michael@0 | 288 | // Streams which do not exist should never be ready. |
michael@0 | 289 | MOZ_ASSERT(s); |
michael@0 | 290 | |
michael@0 | 291 | s->Ready(); |
michael@0 | 292 | |
michael@0 | 293 | return 0; |
michael@0 | 294 | } |
michael@0 | 295 | |
michael@0 | 296 | int NrIceCtx::stream_failed(void *obj, nr_ice_media_stream *stream) { |
michael@0 | 297 | MOZ_MTLOG(ML_DEBUG, "stream_failed called"); |
michael@0 | 298 | |
michael@0 | 299 | // Get the ICE ctx |
michael@0 | 300 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
michael@0 | 301 | RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); |
michael@0 | 302 | |
michael@0 | 303 | // Streams which do not exist should never fail. |
michael@0 | 304 | MOZ_ASSERT(s); |
michael@0 | 305 | |
michael@0 | 306 | ctx->SetConnectionState(ICE_CTX_FAILED); |
michael@0 | 307 | s -> SignalFailed(s); |
michael@0 | 308 | return 0; |
michael@0 | 309 | } |
michael@0 | 310 | |
michael@0 | 311 | int NrIceCtx::ice_completed(void *obj, nr_ice_peer_ctx *pctx) { |
michael@0 | 312 | MOZ_MTLOG(ML_DEBUG, "ice_completed called"); |
michael@0 | 313 | |
michael@0 | 314 | // Get the ICE ctx |
michael@0 | 315 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
michael@0 | 316 | |
michael@0 | 317 | // This is called even on failed contexts. |
michael@0 | 318 | if (ctx->connection_state() != ICE_CTX_FAILED) { |
michael@0 | 319 | ctx->SetConnectionState(ICE_CTX_OPEN); |
michael@0 | 320 | } |
michael@0 | 321 | |
michael@0 | 322 | return 0; |
michael@0 | 323 | } |
michael@0 | 324 | |
michael@0 | 325 | int NrIceCtx::msg_recvd(void *obj, nr_ice_peer_ctx *pctx, |
michael@0 | 326 | nr_ice_media_stream *stream, int component_id, |
michael@0 | 327 | UCHAR *msg, int len) { |
michael@0 | 328 | // Get the ICE ctx |
michael@0 | 329 | NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); |
michael@0 | 330 | RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); |
michael@0 | 331 | |
michael@0 | 332 | // Streams which do not exist should never have packets. |
michael@0 | 333 | MOZ_ASSERT(s); |
michael@0 | 334 | |
michael@0 | 335 | s->SignalPacketReceived(s, component_id, msg, len); |
michael@0 | 336 | |
michael@0 | 337 | return 0; |
michael@0 | 338 | } |
michael@0 | 339 | |
michael@0 | 340 | void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx, |
michael@0 | 341 | nr_ice_media_stream *stream, |
michael@0 | 342 | int component_id, |
michael@0 | 343 | nr_ice_candidate *candidate) { |
michael@0 | 344 | // Get the ICE ctx |
michael@0 | 345 | NrIceCtx *ctx = static_cast<NrIceCtx *>(arg); |
michael@0 | 346 | RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); |
michael@0 | 347 | |
michael@0 | 348 | // Streams which do not exist shouldn't have candidates. |
michael@0 | 349 | MOZ_ASSERT(s); |
michael@0 | 350 | |
michael@0 | 351 | // Format the candidate. |
michael@0 | 352 | char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE]; |
michael@0 | 353 | int r = nr_ice_format_candidate_attribute(candidate, candidate_str, |
michael@0 | 354 | sizeof(candidate_str)); |
michael@0 | 355 | MOZ_ASSERT(!r); |
michael@0 | 356 | if (r) |
michael@0 | 357 | return; |
michael@0 | 358 | |
michael@0 | 359 | MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate " |
michael@0 | 360 | << candidate_str); |
michael@0 | 361 | |
michael@0 | 362 | s->SignalCandidate(s, candidate_str); |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name, |
michael@0 | 366 | bool offerer, |
michael@0 | 367 | bool set_interface_priorities) { |
michael@0 | 368 | |
michael@0 | 369 | RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer); |
michael@0 | 370 | |
michael@0 | 371 | // Initialize the crypto callbacks and logging stuff |
michael@0 | 372 | if (!initialized) { |
michael@0 | 373 | NR_reg_init(NR_REG_MODE_LOCAL); |
michael@0 | 374 | RLogRingBuffer::CreateInstance(); |
michael@0 | 375 | nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl; |
michael@0 | 376 | initialized = true; |
michael@0 | 377 | |
michael@0 | 378 | // Set the priorites for candidate type preferences. |
michael@0 | 379 | // These numbers come from RFC 5245 S. 4.1.2.2 |
michael@0 | 380 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_SRV_RFLX, 100); |
michael@0 | 381 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX, 110); |
michael@0 | 382 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST, 126); |
michael@0 | 383 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED, 5); |
michael@0 | 384 | NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED_TCP, 0); |
michael@0 | 385 | |
michael@0 | 386 | if (set_interface_priorities) { |
michael@0 | 387 | NR_reg_set_uchar((char *)"ice.pref.interface.rl0", 255); |
michael@0 | 388 | NR_reg_set_uchar((char *)"ice.pref.interface.wi0", 254); |
michael@0 | 389 | NR_reg_set_uchar((char *)"ice.pref.interface.lo0", 253); |
michael@0 | 390 | NR_reg_set_uchar((char *)"ice.pref.interface.en1", 252); |
michael@0 | 391 | NR_reg_set_uchar((char *)"ice.pref.interface.en0", 251); |
michael@0 | 392 | NR_reg_set_uchar((char *)"ice.pref.interface.eth0", 252); |
michael@0 | 393 | NR_reg_set_uchar((char *)"ice.pref.interface.eth1", 251); |
michael@0 | 394 | NR_reg_set_uchar((char *)"ice.pref.interface.eth2", 249); |
michael@0 | 395 | NR_reg_set_uchar((char *)"ice.pref.interface.ppp", 250); |
michael@0 | 396 | NR_reg_set_uchar((char *)"ice.pref.interface.ppp0", 249); |
michael@0 | 397 | NR_reg_set_uchar((char *)"ice.pref.interface.en2", 248); |
michael@0 | 398 | NR_reg_set_uchar((char *)"ice.pref.interface.en3", 247); |
michael@0 | 399 | NR_reg_set_uchar((char *)"ice.pref.interface.em0", 251); |
michael@0 | 400 | NR_reg_set_uchar((char *)"ice.pref.interface.em1", 252); |
michael@0 | 401 | NR_reg_set_uchar((char *)"ice.pref.interface.vmnet0", 240); |
michael@0 | 402 | NR_reg_set_uchar((char *)"ice.pref.interface.vmnet1", 241); |
michael@0 | 403 | NR_reg_set_uchar((char *)"ice.pref.interface.vmnet3", 239); |
michael@0 | 404 | NR_reg_set_uchar((char *)"ice.pref.interface.vmnet4", 238); |
michael@0 | 405 | NR_reg_set_uchar((char *)"ice.pref.interface.vmnet5", 237); |
michael@0 | 406 | NR_reg_set_uchar((char *)"ice.pref.interface.vmnet6", 236); |
michael@0 | 407 | NR_reg_set_uchar((char *)"ice.pref.interface.vmnet7", 235); |
michael@0 | 408 | NR_reg_set_uchar((char *)"ice.pref.interface.vmnet8", 234); |
michael@0 | 409 | NR_reg_set_uchar((char *)"ice.pref.interface.virbr0", 233); |
michael@0 | 410 | NR_reg_set_uchar((char *)"ice.pref.interface.wlan0", 232); |
michael@0 | 411 | } |
michael@0 | 412 | |
michael@0 | 413 | NR_reg_set_uint4((char *)"stun.client.maximum_transmits",5); |
michael@0 | 414 | } |
michael@0 | 415 | |
michael@0 | 416 | // Create the ICE context |
michael@0 | 417 | int r; |
michael@0 | 418 | |
michael@0 | 419 | UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER: |
michael@0 | 420 | NR_ICE_CTX_FLAGS_ANSWERER; |
michael@0 | 421 | flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION; |
michael@0 | 422 | |
michael@0 | 423 | r = nr_ice_ctx_create(const_cast<char *>(name.c_str()), flags, |
michael@0 | 424 | &ctx->ctx_); |
michael@0 | 425 | if (r) { |
michael@0 | 426 | MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name << "'"); |
michael@0 | 427 | return nullptr; |
michael@0 | 428 | } |
michael@0 | 429 | |
michael@0 | 430 | #ifdef USE_INTERFACE_PRIORITIZER |
michael@0 | 431 | nr_interface_prioritizer *prioritizer = CreateInterfacePrioritizer(); |
michael@0 | 432 | if (!prioritizer) { |
michael@0 | 433 | MOZ_MTLOG(PR_LOG_ERROR, "Couldn't create interface prioritizer."); |
michael@0 | 434 | return nullptr; |
michael@0 | 435 | } |
michael@0 | 436 | |
michael@0 | 437 | r = nr_ice_ctx_set_interface_prioritizer(ctx->ctx_, prioritizer); |
michael@0 | 438 | if (r) { |
michael@0 | 439 | MOZ_MTLOG(PR_LOG_ERROR, "Couldn't set interface prioritizer."); |
michael@0 | 440 | return nullptr; |
michael@0 | 441 | } |
michael@0 | 442 | #endif // USE_INTERFACE_PRIORITIZER |
michael@0 | 443 | |
michael@0 | 444 | if (ctx->generating_trickle()) { |
michael@0 | 445 | r = nr_ice_ctx_set_trickle_cb(ctx->ctx_, &NrIceCtx::trickle_cb, ctx); |
michael@0 | 446 | if (r) { |
michael@0 | 447 | MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name << "'"); |
michael@0 | 448 | return nullptr; |
michael@0 | 449 | } |
michael@0 | 450 | } |
michael@0 | 451 | |
michael@0 | 452 | // Create the handler objects |
michael@0 | 453 | ctx->ice_handler_vtbl_ = new nr_ice_handler_vtbl(); |
michael@0 | 454 | ctx->ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair; |
michael@0 | 455 | ctx->ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready; |
michael@0 | 456 | ctx->ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed; |
michael@0 | 457 | ctx->ice_handler_vtbl_->ice_completed = &NrIceCtx::ice_completed; |
michael@0 | 458 | ctx->ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd; |
michael@0 | 459 | |
michael@0 | 460 | ctx->ice_handler_ = new nr_ice_handler(); |
michael@0 | 461 | ctx->ice_handler_->vtbl = ctx->ice_handler_vtbl_; |
michael@0 | 462 | ctx->ice_handler_->obj = ctx; |
michael@0 | 463 | |
michael@0 | 464 | // Create the peer ctx. Because we do not support parallel forking, we |
michael@0 | 465 | // only have one peer ctx. |
michael@0 | 466 | std::string peer_name = name + ":default"; |
michael@0 | 467 | r = nr_ice_peer_ctx_create(ctx->ctx_, ctx->ice_handler_, |
michael@0 | 468 | const_cast<char *>(peer_name.c_str()), |
michael@0 | 469 | &ctx->peer_); |
michael@0 | 470 | if (r) { |
michael@0 | 471 | MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name << "'"); |
michael@0 | 472 | return nullptr; |
michael@0 | 473 | } |
michael@0 | 474 | |
michael@0 | 475 | nsresult rv; |
michael@0 | 476 | ctx->sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); |
michael@0 | 477 | |
michael@0 | 478 | if (!NS_SUCCEEDED(rv)) |
michael@0 | 479 | return nullptr; |
michael@0 | 480 | |
michael@0 | 481 | return ctx; |
michael@0 | 482 | } |
michael@0 | 483 | |
michael@0 | 484 | |
michael@0 | 485 | NrIceCtx::~NrIceCtx() { |
michael@0 | 486 | MOZ_MTLOG(ML_DEBUG, "Destroying ICE ctx '" << name_ <<"'"); |
michael@0 | 487 | nr_ice_peer_ctx_destroy(&peer_); |
michael@0 | 488 | nr_ice_ctx_destroy(&ctx_); |
michael@0 | 489 | delete ice_handler_vtbl_; |
michael@0 | 490 | delete ice_handler_; |
michael@0 | 491 | } |
michael@0 | 492 | |
michael@0 | 493 | RefPtr<NrIceMediaStream> |
michael@0 | 494 | NrIceCtx::CreateStream(const std::string& name, int components) { |
michael@0 | 495 | RefPtr<NrIceMediaStream> stream = |
michael@0 | 496 | NrIceMediaStream::Create(this, name, components); |
michael@0 | 497 | |
michael@0 | 498 | streams_.push_back(stream); |
michael@0 | 499 | |
michael@0 | 500 | return stream; |
michael@0 | 501 | } |
michael@0 | 502 | |
michael@0 | 503 | void NrIceCtx::destroy_peer_ctx() { |
michael@0 | 504 | nr_ice_peer_ctx_destroy(&peer_); |
michael@0 | 505 | } |
michael@0 | 506 | |
michael@0 | 507 | nsresult NrIceCtx::SetControlling(Controlling controlling) { |
michael@0 | 508 | peer_->controlling = (controlling == ICE_CONTROLLING)? 1 : 0; |
michael@0 | 509 | |
michael@0 | 510 | MOZ_MTLOG(ML_DEBUG, "ICE ctx " << name_ << " setting controlling to" << |
michael@0 | 511 | controlling); |
michael@0 | 512 | return NS_OK; |
michael@0 | 513 | } |
michael@0 | 514 | |
michael@0 | 515 | nsresult NrIceCtx::SetStunServers(const std::vector<NrIceStunServer>& |
michael@0 | 516 | stun_servers) { |
michael@0 | 517 | if (stun_servers.empty()) |
michael@0 | 518 | return NS_OK; |
michael@0 | 519 | |
michael@0 | 520 | ScopedDeleteArray<nr_ice_stun_server> servers( |
michael@0 | 521 | new nr_ice_stun_server[stun_servers.size()]); |
michael@0 | 522 | |
michael@0 | 523 | for (size_t i=0; i < stun_servers.size(); ++i) { |
michael@0 | 524 | nsresult rv = stun_servers[i].ToNicerStunStruct(&servers[i]); |
michael@0 | 525 | if (NS_FAILED(rv)) { |
michael@0 | 526 | MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'"); |
michael@0 | 527 | return NS_ERROR_FAILURE; |
michael@0 | 528 | } |
michael@0 | 529 | } |
michael@0 | 530 | |
michael@0 | 531 | int r = nr_ice_ctx_set_stun_servers(ctx_, servers, stun_servers.size()); |
michael@0 | 532 | if (r) { |
michael@0 | 533 | MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'"); |
michael@0 | 534 | return NS_ERROR_FAILURE; |
michael@0 | 535 | } |
michael@0 | 536 | |
michael@0 | 537 | return NS_OK; |
michael@0 | 538 | } |
michael@0 | 539 | |
michael@0 | 540 | // TODO(ekr@rtfm.com): This is just SetStunServers with s/Stun/Turn |
michael@0 | 541 | // Could we do a template or something? |
michael@0 | 542 | nsresult NrIceCtx::SetTurnServers(const std::vector<NrIceTurnServer>& |
michael@0 | 543 | turn_servers) { |
michael@0 | 544 | if (turn_servers.empty()) |
michael@0 | 545 | return NS_OK; |
michael@0 | 546 | |
michael@0 | 547 | ScopedDeleteArray<nr_ice_turn_server> servers( |
michael@0 | 548 | new nr_ice_turn_server[turn_servers.size()]); |
michael@0 | 549 | |
michael@0 | 550 | for (size_t i=0; i < turn_servers.size(); ++i) { |
michael@0 | 551 | nsresult rv = turn_servers[i].ToNicerTurnStruct(&servers[i]); |
michael@0 | 552 | if (NS_FAILED(rv)) { |
michael@0 | 553 | MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'"); |
michael@0 | 554 | return NS_ERROR_FAILURE; |
michael@0 | 555 | } |
michael@0 | 556 | } |
michael@0 | 557 | |
michael@0 | 558 | int r = nr_ice_ctx_set_turn_servers(ctx_, servers, turn_servers.size()); |
michael@0 | 559 | if (r) { |
michael@0 | 560 | MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'"); |
michael@0 | 561 | return NS_ERROR_FAILURE; |
michael@0 | 562 | } |
michael@0 | 563 | |
michael@0 | 564 | // TODO(ekr@rtfm.com): This leaks the username/password. Need to free that. |
michael@0 | 565 | |
michael@0 | 566 | return NS_OK; |
michael@0 | 567 | } |
michael@0 | 568 | |
michael@0 | 569 | nsresult NrIceCtx::SetResolver(nr_resolver *resolver) { |
michael@0 | 570 | int r = nr_ice_ctx_set_resolver(ctx_, resolver); |
michael@0 | 571 | |
michael@0 | 572 | if (r) { |
michael@0 | 573 | MOZ_MTLOG(ML_ERROR, "Couldn't set resolver for '" << name_ << "'"); |
michael@0 | 574 | return NS_ERROR_FAILURE; |
michael@0 | 575 | } |
michael@0 | 576 | |
michael@0 | 577 | return NS_OK; |
michael@0 | 578 | } |
michael@0 | 579 | |
michael@0 | 580 | nsresult NrIceCtx::StartGathering() { |
michael@0 | 581 | MOZ_ASSERT(ctx_->state == ICE_CTX_INIT); |
michael@0 | 582 | if (ctx_->state != ICE_CTX_INIT) { |
michael@0 | 583 | MOZ_MTLOG(ML_ERROR, "ICE ctx in the wrong state for gathering: '" |
michael@0 | 584 | << name_ << "'"); |
michael@0 | 585 | SetConnectionState(ICE_CTX_FAILED); |
michael@0 | 586 | return NS_ERROR_FAILURE; |
michael@0 | 587 | } |
michael@0 | 588 | |
michael@0 | 589 | int r = nr_ice_initialize(ctx_, &NrIceCtx::initialized_cb, |
michael@0 | 590 | this); |
michael@0 | 591 | |
michael@0 | 592 | if (r && r != R_WOULDBLOCK) { |
michael@0 | 593 | MOZ_MTLOG(ML_ERROR, "Couldn't gather ICE candidates for '" |
michael@0 | 594 | << name_ << "'"); |
michael@0 | 595 | SetConnectionState(ICE_CTX_FAILED); |
michael@0 | 596 | return NS_ERROR_FAILURE; |
michael@0 | 597 | } |
michael@0 | 598 | |
michael@0 | 599 | SetGatheringState(ICE_CTX_GATHER_STARTED); |
michael@0 | 600 | |
michael@0 | 601 | return NS_OK; |
michael@0 | 602 | } |
michael@0 | 603 | |
michael@0 | 604 | RefPtr<NrIceMediaStream> NrIceCtx::FindStream( |
michael@0 | 605 | nr_ice_media_stream *stream) { |
michael@0 | 606 | for (size_t i=0; i<streams_.size(); ++i) { |
michael@0 | 607 | if (streams_[i]->stream() == stream) { |
michael@0 | 608 | return streams_[i]; |
michael@0 | 609 | } |
michael@0 | 610 | } |
michael@0 | 611 | |
michael@0 | 612 | return nullptr; |
michael@0 | 613 | } |
michael@0 | 614 | |
michael@0 | 615 | std::vector<std::string> NrIceCtx::GetGlobalAttributes() { |
michael@0 | 616 | char **attrs = 0; |
michael@0 | 617 | int attrct; |
michael@0 | 618 | int r; |
michael@0 | 619 | std::vector<std::string> ret; |
michael@0 | 620 | |
michael@0 | 621 | r = nr_ice_get_global_attributes(ctx_, &attrs, &attrct); |
michael@0 | 622 | if (r) { |
michael@0 | 623 | MOZ_MTLOG(ML_ERROR, "Couldn't get ufrag and password for '" |
michael@0 | 624 | << name_ << "'"); |
michael@0 | 625 | return ret; |
michael@0 | 626 | } |
michael@0 | 627 | |
michael@0 | 628 | for (int i=0; i<attrct; i++) { |
michael@0 | 629 | ret.push_back(std::string(attrs[i])); |
michael@0 | 630 | RFREE(attrs[i]); |
michael@0 | 631 | } |
michael@0 | 632 | RFREE(attrs); |
michael@0 | 633 | |
michael@0 | 634 | return ret; |
michael@0 | 635 | } |
michael@0 | 636 | |
michael@0 | 637 | nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) { |
michael@0 | 638 | std::vector<char *> attrs_in; |
michael@0 | 639 | |
michael@0 | 640 | for (size_t i=0; i<attrs.size(); ++i) { |
michael@0 | 641 | attrs_in.push_back(const_cast<char *>(attrs[i].c_str())); |
michael@0 | 642 | } |
michael@0 | 643 | |
michael@0 | 644 | int r = nr_ice_peer_ctx_parse_global_attributes(peer_, |
michael@0 | 645 | attrs_in.size() ? |
michael@0 | 646 | &attrs_in[0] : nullptr, |
michael@0 | 647 | attrs_in.size()); |
michael@0 | 648 | if (r) { |
michael@0 | 649 | MOZ_MTLOG(ML_ERROR, "Couldn't parse global attributes for " |
michael@0 | 650 | << name_ << "'"); |
michael@0 | 651 | return NS_ERROR_FAILURE; |
michael@0 | 652 | } |
michael@0 | 653 | |
michael@0 | 654 | return NS_OK; |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | nsresult NrIceCtx::StartChecks() { |
michael@0 | 658 | int r; |
michael@0 | 659 | |
michael@0 | 660 | r=nr_ice_peer_ctx_pair_candidates(peer_); |
michael@0 | 661 | if (r) { |
michael@0 | 662 | MOZ_MTLOG(ML_ERROR, "Couldn't pair candidates on " |
michael@0 | 663 | << name_ << "'"); |
michael@0 | 664 | SetConnectionState(ICE_CTX_FAILED); |
michael@0 | 665 | return NS_ERROR_FAILURE; |
michael@0 | 666 | } |
michael@0 | 667 | |
michael@0 | 668 | r = nr_ice_peer_ctx_start_checks2(peer_,1); |
michael@0 | 669 | if (r) { |
michael@0 | 670 | if (r == R_NOT_FOUND) { |
michael@0 | 671 | MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on " |
michael@0 | 672 | << name_ << "' assuming trickle ICE"); |
michael@0 | 673 | } else { |
michael@0 | 674 | MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on " |
michael@0 | 675 | << name_ << "'"); |
michael@0 | 676 | SetConnectionState(ICE_CTX_FAILED); |
michael@0 | 677 | return NS_ERROR_FAILURE; |
michael@0 | 678 | } |
michael@0 | 679 | } else { |
michael@0 | 680 | SetConnectionState(ICE_CTX_CHECKING); |
michael@0 | 681 | } |
michael@0 | 682 | |
michael@0 | 683 | return NS_OK; |
michael@0 | 684 | } |
michael@0 | 685 | |
michael@0 | 686 | |
michael@0 | 687 | void NrIceCtx::initialized_cb(NR_SOCKET s, int h, void *arg) { |
michael@0 | 688 | NrIceCtx *ctx = static_cast<NrIceCtx *>(arg); |
michael@0 | 689 | |
michael@0 | 690 | ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE); |
michael@0 | 691 | } |
michael@0 | 692 | |
michael@0 | 693 | nsresult NrIceCtx::Finalize() { |
michael@0 | 694 | int r = nr_ice_ctx_finalize(ctx_, peer_); |
michael@0 | 695 | |
michael@0 | 696 | if (r) { |
michael@0 | 697 | MOZ_MTLOG(ML_ERROR, "Couldn't finalize " |
michael@0 | 698 | << name_ << "'"); |
michael@0 | 699 | return NS_ERROR_FAILURE; |
michael@0 | 700 | } |
michael@0 | 701 | |
michael@0 | 702 | return NS_OK; |
michael@0 | 703 | } |
michael@0 | 704 | |
michael@0 | 705 | void NrIceCtx::SetConnectionState(ConnectionState state) { |
michael@0 | 706 | if (state == connection_state_) |
michael@0 | 707 | return; |
michael@0 | 708 | |
michael@0 | 709 | MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " << |
michael@0 | 710 | connection_state_ << "->" << state); |
michael@0 | 711 | connection_state_ = state; |
michael@0 | 712 | |
michael@0 | 713 | SignalConnectionStateChange(this, state); |
michael@0 | 714 | } |
michael@0 | 715 | |
michael@0 | 716 | void NrIceCtx::SetGatheringState(GatheringState state) { |
michael@0 | 717 | if (state == gathering_state_) |
michael@0 | 718 | return; |
michael@0 | 719 | |
michael@0 | 720 | MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state " << |
michael@0 | 721 | gathering_state_ << "->" << state); |
michael@0 | 722 | gathering_state_ = state; |
michael@0 | 723 | |
michael@0 | 724 | SignalGatheringStateChange(this, state); |
michael@0 | 725 | } |
michael@0 | 726 | |
michael@0 | 727 | } // close namespace |
michael@0 | 728 | |
michael@0 | 729 | // Reimplement nr_ice_compute_codeword to avoid copyright issues |
michael@0 | 730 | void nr_ice_compute_codeword(char *buf, int len,char *codeword) { |
michael@0 | 731 | UINT4 c; |
michael@0 | 732 | |
michael@0 | 733 | r_crc32(buf,len,&c); |
michael@0 | 734 | |
michael@0 | 735 | PL_Base64Encode(reinterpret_cast<char*>(&c), 3, codeword); |
michael@0 | 736 | codeword[4] = 0; |
michael@0 | 737 | |
michael@0 | 738 | return; |
michael@0 | 739 | } |
michael@0 | 740 |