Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2022-09-01 10:29:38 +08:00
commit e235eb81c6
40 changed files with 516 additions and 78 deletions

View file

@ -588,7 +588,7 @@ RTCPeerConnection.prototype = {
throw new this._win.DOMException(msg + " - improper scheme: " + url.scheme, throw new this._win.DOMException(msg + " - improper scheme: " + url.scheme,
"SyntaxError"); "SyntaxError");
} }
if (url.scheme in { stuns:1, turns:1 }) { if (url.scheme in { stuns:1 }) {
this.logWarning(url.scheme.toUpperCase() + " is not yet supported."); this.logWarning(url.scheme.toUpperCase() + " is not yet supported.");
} }
}); });

View file

@ -0,0 +1,26 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
// This is only usable from the parent process, even for doing simple stuff like
// serializing a cert.
var gCertMaker = Cc["@mozilla.org/security/x509certdb;1"].
getService(Ci.nsIX509CertDB);
var gCertOverrides = Cc["@mozilla.org/security/certoverride;1"].
getService(Ci.nsICertOverrideService);
addMessageListener('add-turns-certs', certs => {
var port = 5349;
certs.forEach(certDescription => {
var cert = gCertMaker.constructX509FromBase64(certDescription.cert);
gCertOverrides.rememberValidityOverride(certDescription.hostname, port,
cert, Ci.nsICertOverrideService.ERROR_UNTRUSTED, false);
});
sendAsyncMessage('certs-added');
});

View file

@ -13,6 +13,7 @@ support-files =
blacksilence.js blacksilence.js
turnConfig.js turnConfig.js
sdpUtils.js sdpUtils.js
addTurnsSelfsignedCert.js
!/dom/canvas/test/captureStream_common.js !/dom/canvas/test/captureStream_common.js
!/dom/canvas/test/webgl-mochitest/webgl-util.js !/dom/canvas/test/webgl-mochitest/webgl-util.js
!/dom/media/test/manifest.js !/dom/media/test/manifest.js
@ -97,6 +98,8 @@ skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217) skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
[test_peerConnection_basicAudioNATRelayTCP.html] [test_peerConnection_basicAudioNATRelayTCP.html]
skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217) skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
[test_peerConnection_basicAudioNATRelayTLS.html]
skip-if = true # need pyopenssl on builders, see bug 1323439
[test_peerConnection_basicAudioRequireEOC.html] [test_peerConnection_basicAudioRequireEOC.html]
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator) skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_basicAudioPcmaPcmuOnly.html] [test_peerConnection_basicAudioPcmaPcmuOnly.html]

View file

@ -1869,6 +1869,33 @@ function createHTML(options) {
var iceServerWebsocket; var iceServerWebsocket;
var iceServersArray = []; var iceServersArray = [];
var addTurnsSelfsignedCerts = () => {
var gUrl = SimpleTest.getTestFileURL('addTurnsSelfsignedCert.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
var certs = [];
// If the ICE server is running TURNS, and includes a "cert" attribute in
// its JSON, we set up an override that will forgive things like
// self-signed for it.
iceServersArray.forEach(iceServer => {
if (iceServer.hasOwnProperty("cert")) {
iceServer.urls.forEach(url => {
if (url.startsWith("turns:")) {
// Assumes no port or params!
certs.push({"cert": iceServer.cert, "hostname": url.substr(6)});
}
});
}
});
return new Promise((resolve, reject) => {
gScript.addMessageListener('certs-added', () => {
resolve();
});
gScript.sendAsyncMessage('add-turns-certs', certs);
});
};
var setupIceServerConfig = useIceServer => { var setupIceServerConfig = useIceServer => {
// We disable ICE support for HTTP proxy when using a TURN server, because // We disable ICE support for HTTP proxy when using a TURN server, because
// mochitest uses a fake HTTP proxy to serve content, which will eat our STUN // mochitest uses a fake HTTP proxy to serve content, which will eat our STUN
@ -1910,7 +1937,8 @@ var setupIceServerConfig = useIceServer => {
return enableHttpProxy(false) return enableHttpProxy(false)
.then(spawnIceServer) .then(spawnIceServer)
.then(iceServersStr => { iceServersArray = JSON.parse(iceServersStr); }); .then(iceServersStr => { iceServersArray = JSON.parse(iceServersStr); })
.then(addTurnsSelfsignedCerts);
}; };
function runNetworkTest(testFunction, fixtureOptions) { function runNetworkTest(testFunction, fixtureOptions) {

View file

@ -0,0 +1,38 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "1231975",
title: "Basic audio-only peer connection with port dependent NAT that blocks STUN"
});
var test;
runNetworkTest(options => {
SpecialPowers.pushPrefEnv(
{
'set': [
['media.peerconnection.nat_simulator.filtering_type', 'PORT_DEPENDENT'],
['media.peerconnection.nat_simulator.mapping_type', 'PORT_DEPENDENT'],
['media.peerconnection.nat_simulator.block_udp', true],
['media.peerconnection.nat_simulator.block_tcp', true]
]
}, function (options) {
options = options || {};
options.expectedLocalCandidateType = "relayed-tcp";
options.expectedRemoteCandidateType = "relayed-tcp";
// No reason to wait for gathering to complete like the other NAT tests,
// since relayed-tcp is the only thing that can work.
test = new PeerConnectionTest(options);
test.setMediaConstraints([{audio: true}], [{audio: true}]);
test.run();
})
}, { useIceServer: true });
</script>
</pre>
</body>
</html>

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2011 Google Inc. All rights reserved. * Copyright (C) 2011 Google Inc.
* Copyright (C) 2022 Moonchild Productions.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -104,7 +105,7 @@ protected:
float m_lastAnchor; float m_lastAnchor;
float m_lastFilterStageGain; float m_lastFilterStageGain;
typedef struct { typedef struct ZeroPoleFilterPack4 {
ZeroPole filters[4]; ZeroPole filters[4];
size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{ {

View file

@ -44,7 +44,8 @@ parent:
// address specified in |localAddr| and |localPort|. // address specified in |localAddr| and |localPort|.
async OpenBind(nsCString host, uint16_t port, async OpenBind(nsCString host, uint16_t port,
nsCString localAddr, uint16_t localPort, nsCString localAddr, uint16_t localPort,
bool useSSL, bool aUseArrayBuffers, nsCString aFilter); bool useSSL, bool reuseAddrPort,
bool aUseArrayBuffers, nsCString aFilter);
// When child's send() is called, this message requrests parent to send // When child's send() is called, this message requrests parent to send
// data and update it's trackingNumber. // data and update it's trackingNumber.

View file

@ -108,7 +108,7 @@ void
TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketCallback* aSocket, TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketCallback* aSocket,
const nsACString& aRemoteHost, uint16_t aRemotePort, const nsACString& aRemoteHost, uint16_t aRemotePort,
const nsACString& aLocalHost, uint16_t aLocalPort, const nsACString& aLocalHost, uint16_t aLocalPort,
bool aUseSSL) bool aUseSSL, bool aReuseAddrPort)
{ {
mSocket = aSocket; mSocket = aSocket;
AddIPDLReference(); AddIPDLReference();
@ -117,7 +117,8 @@ TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketCallback* aSocket,
aRemotePort); aRemotePort);
PTCPSocketChild::SendOpenBind(nsCString(aRemoteHost), aRemotePort, PTCPSocketChild::SendOpenBind(nsCString(aRemoteHost), aRemotePort,
nsCString(aLocalHost), aLocalPort, nsCString(aLocalHost), aLocalPort,
aUseSSL, true, mFilterName); aUseSSL, aReuseAddrPort,
true, mFilterName);
} }
void void

View file

@ -55,7 +55,7 @@ public:
void SendWindowlessOpenBind(nsITCPSocketCallback* aSocket, void SendWindowlessOpenBind(nsITCPSocketCallback* aSocket,
const nsACString& aRemoteHost, uint16_t aRemotePort, const nsACString& aRemoteHost, uint16_t aRemotePort,
const nsACString& aLocalHost, uint16_t aLocalPort, const nsACString& aLocalHost, uint16_t aLocalPort,
bool aUseSSL); bool aUseSSL, bool aUseRealtimeOptions);
NS_IMETHOD SendSendArray(nsTArray<uint8_t>& aArray, NS_IMETHOD SendSendArray(nsTArray<uint8_t>& aArray,
uint32_t aTrackingNumber); uint32_t aTrackingNumber);
void SendSend(const nsACString& aData, uint32_t aTrackingNumber); void SendSend(const nsACString& aData, uint32_t aTrackingNumber);

View file

@ -149,6 +149,7 @@ TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost,
const nsCString& aLocalAddr, const nsCString& aLocalAddr,
const uint16_t& aLocalPort, const uint16_t& aLocalPort,
const bool& aUseSSL, const bool& aUseSSL,
const bool& aReuseAddrPort,
const bool& aUseArrayBuffers, const bool& aUseArrayBuffers,
const nsCString& aFilter) const nsCString& aFilter)
{ {
@ -167,14 +168,27 @@ TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost,
} }
nsCOMPtr<nsISocketTransport> socketTransport; nsCOMPtr<nsISocketTransport> socketTransport;
rv = sts->CreateTransport(nullptr, 0, if (aUseSSL) {
aRemoteHost, aRemotePort, const char* socketTypes[1];
nullptr, getter_AddRefs(socketTransport)); socketTypes[0] = "ssl";
rv = sts->CreateTransport(socketTypes, 1,
aRemoteHost, aRemotePort,
nullptr, getter_AddRefs(socketTransport));
} else {
rv = sts->CreateTransport(nullptr, 0,
aRemoteHost, aRemotePort,
nullptr, getter_AddRefs(socketTransport));
}
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
FireInteralError(this, __LINE__); FireInteralError(this, __LINE__);
return true; return true;
} }
// in most cases aReuseAddrPort is false, but ICE TCP needs
// sockets options set that allow addr/port reuse
socketTransport->SetReuseAddrPort(aReuseAddrPort);
PRNetAddr prAddr; PRNetAddr prAddr;
if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr)) { if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr)) {
FireInteralError(this, __LINE__); FireInteralError(this, __LINE__);

View file

@ -54,6 +54,7 @@ public:
const nsCString& aLocalAddr, const nsCString& aLocalAddr,
const uint16_t& aLocalPort, const uint16_t& aLocalPort,
const bool& aUseSSL, const bool& aUseSSL,
const bool& aReuseAddrPort,
const bool& aUseArrayBuffers, const bool& aUseArrayBuffers,
const nsCString& aFilter) override; const nsCString& aFilter) override;

View file

@ -25,8 +25,7 @@ public:
Display* display, Display* display,
GLXDrawable drawable, GLXDrawable drawable,
GLXFBConfig cfg, GLXFBConfig cfg,
bool deleteDrawable, Drawable ownedPixmap = X11None,
gfxXlibSurface* pixmap = nullptr,
ContextProfile profile = ContextProfile::OpenGLCompatibility); ContextProfile profile = ContextProfile::OpenGLCompatibility);
// Finds a GLXFBConfig compatible with the provided window. // Finds a GLXFBConfig compatible with the provided window.
@ -77,25 +76,26 @@ private:
Display* aDisplay, Display* aDisplay,
GLXDrawable aDrawable, GLXDrawable aDrawable,
GLXContext aContext, GLXContext aContext,
bool aDeleteDrawable,
bool aDoubleBuffered, bool aDoubleBuffered,
gfxXlibSurface* aPixmap, ContextProfile profile,
ContextProfile profile); Drawable aOwnedPixmap = X11None);
GLXContext mContext; GLXContext mContext;
Display* mDisplay; Display* mDisplay;
GLXDrawable mDrawable; GLXDrawable mDrawable;
Maybe<GLXDrawable> mOverrideDrawable; Maybe<GLXDrawable> mOverrideDrawable;
bool mDeleteDrawable; // The X pixmap associated with the GLX pixmap. If this is provided, then
// this class assumes responsibility for freeing both. Otherwise, the
// user of this class is responsibile for freeing the drawables.
const Drawable mOwnedPixmap;
bool mDoubleBuffered; bool mDoubleBuffered;
GLXLibrary* mGLX; GLXLibrary* mGLX;
RefPtr<gfxXlibSurface> mPixmap;
bool mOwnsContext; bool mOwnsContext;
}; };
} } // namespace gl
} } // namespace mozilla
#endif // GLCONTEXTGLX_H_ #endif // GLCONTEXTGLX_H_

View file

@ -327,7 +327,7 @@ GLXLibrary::CreatePixmap(gfxASurface* aSurface)
X11None }; X11None };
int numConfigs = 0; int numConfigs = 0;
Display* display = xs->XDisplay(); Display *display = xs->XDisplay();
int xscreen = DefaultScreen(display); int xscreen = DefaultScreen(display);
ScopedXFree<GLXFBConfig> cfgs(xChooseFBConfig(display, ScopedXFree<GLXFBConfig> cfgs(xChooseFBConfig(display,
@ -800,7 +800,7 @@ already_AddRefed<GLContextGLX>
GLContextGLX::CreateGLContext(CreateContextFlags flags, const SurfaceCaps& caps, GLContextGLX::CreateGLContext(CreateContextFlags flags, const SurfaceCaps& caps,
GLContextGLX* shareContext, bool isOffscreen, GLContextGLX* shareContext, bool isOffscreen,
Display* display, GLXDrawable drawable, GLXFBConfig cfg, Display* display, GLXDrawable drawable, GLXFBConfig cfg,
bool deleteDrawable, gfxXlibSurface* pixmap, Drawable ownedPixmap,
ContextProfile profile) ContextProfile profile)
{ {
GLXLibrary& glx = sGLXLibrary; GLXLibrary& glx = sGLXLibrary;
@ -860,8 +860,7 @@ GLContextGLX::CreateGLContext(CreateContextFlags flags, const SurfaceCaps& caps,
if (context) { if (context) {
glContext = new GLContextGLX(flags, caps, shareContext, isOffscreen, display, glContext = new GLContextGLX(flags, caps, shareContext, isOffscreen, display,
drawable, context, deleteDrawable, db, pixmap, drawable, context, db, profile, ownedPixmap);
profile);
if (!glContext->Init()) if (!glContext->Init())
error = true; error = true;
} else { } else {
@ -896,8 +895,9 @@ GLContextGLX::~GLContextGLX()
mGLX->xDestroyContext(mDisplay, mContext); mGLX->xDestroyContext(mDisplay, mContext);
if (mDeleteDrawable) { if (mOwnedPixmap) {
mGLX->xDestroyPixmap(mDisplay, mDrawable); mGLX->xDestroyPixmap(mDisplay, mDrawable);
XFreePixmap(mDisplay, mOwnedPixmap);
} }
MOZ_ASSERT(!mOverrideDrawable); MOZ_ASSERT(!mOverrideDrawable);
} }
@ -1035,18 +1035,16 @@ GLContextGLX::GLContextGLX(
Display* aDisplay, Display* aDisplay,
GLXDrawable aDrawable, GLXDrawable aDrawable,
GLXContext aContext, GLXContext aContext,
bool aDeleteDrawable,
bool aDoubleBuffered, bool aDoubleBuffered,
gfxXlibSurface* aPixmap, ContextProfile profile,
ContextProfile profile) Drawable aOwnedPixmap)
: GLContext(flags, caps, shareContext, isOffscreen), : GLContext(flags, caps, shareContext, isOffscreen),
mContext(aContext), mContext(aContext),
mDisplay(aDisplay), mDisplay(aDisplay),
mDrawable(aDrawable), mDrawable(aDrawable),
mDeleteDrawable(aDeleteDrawable), mOwnedPixmap(aOwnedPixmap),
mDoubleBuffered(aDoubleBuffered), mDoubleBuffered(aDoubleBuffered),
mGLX(&sGLXLibrary), mGLX(&sGLXLibrary),
mPixmap(aPixmap),
mOwnsContext(true) mOwnsContext(true)
{ {
MOZ_ASSERT(mGLX); MOZ_ASSERT(mGLX);
@ -1098,10 +1096,9 @@ GLContextProviderGLX::CreateWrappingExisting(void* aContext, void* aSurface)
false, // Offscreen false, // Offscreen
(Display*)DefaultXDisplay(), // Display (Display*)DefaultXDisplay(), // Display
(GLXDrawable)aSurface, (GLXContext)aContext, (GLXDrawable)aSurface, (GLXContext)aContext,
false, // aDeleteDrawable,
true, true,
(gfxXlibSurface*)nullptr, ContextProfile::OpenGLCompatibility,
ContextProfile::OpenGLCompatibility); (Drawable)nullptr);
glContext->mOwnsContext = false; glContext->mOwnsContext = false;
gGlobalContext = glContext; gGlobalContext = glContext;
@ -1146,8 +1143,7 @@ CreateForWidget(Display* aXDisplay, Window aXWindow, bool aForceAccelerated)
GLContextGLX* shareContext = GetGlobalContextGLX(); GLContextGLX* shareContext = GetGlobalContextGLX();
RefPtr<GLContextGLX> gl = GLContextGLX::CreateGLContext(CreateContextFlags::NONE, RefPtr<GLContextGLX> gl = GLContextGLX::CreateGLContext(CreateContextFlags::NONE,
caps, shareContext, false, caps, shareContext, false,
aXDisplay, aXWindow, config, aXDisplay, aXWindow, config);
false);
return gl.forget(); return gl.forget();
} }
@ -1326,24 +1322,20 @@ CreateOffscreenPixmapContext(CreateContextFlags flags, const IntSize& size,
FindVisualAndDepth(display, visid, &visual, &depth); FindVisualAndDepth(display, visid, &visual, &depth);
OffMainThreadScopedXErrorHandler xErrorHandler; OffMainThreadScopedXErrorHandler xErrorHandler;
bool error = false;
Drawable drawable;
GLXPixmap pixmap = 0; GLXPixmap pixmap = 0;
gfx::IntSize dummySize(16, 16); gfx::IntSize dummySize(16, 16);
RefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display), const auto drawable =
visual, XCreatePixmap(display, DefaultRootWindow(display),
dummySize); dummySize.width, dummySize.height, depth);
if (surface->CairoStatus() != 0) { if (!drawable) {
mozilla::Unused << xErrorHandler.SyncAndGetError(display); mozilla::Unused << xErrorHandler.SyncAndGetError(display);
return nullptr; return nullptr;
} }
// Handle slightly different signature between glXCreatePixmap and // Handle slightly different signature between glXCreatePixmap and
// its pre-GLX-1.3 extension equivalent (though given the ABI, we // its pre-GLX-1.3 extension equivalent (though given the ABI, we
// might not need to). // might not need to).
drawable = surface->XDrawable();
if (glx->GLXVersionCheck(1, 3)) { if (glx->GLXVersionCheck(1, 3)) {
pixmap = glx->xCreatePixmap(display, config, drawable, nullptr); pixmap = glx->xCreatePixmap(display, config, drawable, nullptr);
} else { } else {
@ -1351,16 +1343,17 @@ CreateOffscreenPixmapContext(CreateContextFlags flags, const IntSize& size,
} }
if (pixmap == 0) { if (pixmap == 0) {
error = true; XFreePixmap(display, drawable);
return nullptr;
} }
bool serverError = xErrorHandler.SyncAndGetError(display); bool serverError = xErrorHandler.SyncAndGetError(display);
if (error || serverError) if (serverError)
return nullptr; return nullptr;
GLContextGLX* shareContext = GetGlobalContextGLX(); GLContextGLX* shareContext = GetGlobalContextGLX();
return GLContextGLX::CreateGLContext(flags, minCaps, shareContext, true, display, return GLContextGLX::CreateGLContext(flags, minCaps, shareContext, true, display,
pixmap, config, true, surface, profile); pixmap, config, drawable, profile);
} }
/*static*/ already_AddRefed<GLContext> /*static*/ already_AddRefed<GLContext>

View file

@ -731,8 +731,7 @@ public:
false, false,
mXDisplay, mXDisplay,
root, root,
config, config);
false);
if (!mGLContext) { if (!mGLContext) {
lock.NotifyAll(); lock.NotifyAll();

View file

@ -833,7 +833,7 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) {
} }
// Step 7. // Step 7.
assert(usingIterator === undefined, "`items` can't be an Iterable after step 6.g.iv"); assert(usingIterator === undefined, "`items` cannot be an Iterable after step 6.g.iv");
// Steps 8-9. // Steps 8-9.
var arrayLike = ToObject(items); var arrayLike = ToObject(items);
@ -1181,6 +1181,35 @@ function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunctio
return targetIndex; return targetIndex;
} }
// ES2022 at() method on the built-in indexables
// Array.prototype.at(index)
function ArrayAt(index) {
// Step 1.
var O = ToObject(this);
// Step 2.
var len = ToLength(O.length);
// Step 3.
var relativeIndex = ToInteger(index);
// Steps 4-5.
var k;
if (relativeIndex >= 0) {
k = relativeIndex;
} else {
k = len + relativeIndex;
}
// Step 6.
if (k < 0 || k >= len) {
return undefined;
}
// Step 7.
return O[k];
}
function ArrayStaticConcat(arr, arg1) { function ArrayStaticConcat(arr, arg1) {
if (arguments.length < 1) if (arguments.length < 1)
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.concat'); ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.concat');

View file

@ -784,6 +784,39 @@ function String_static_raw(callSite, ...substitutions) {
} }
} }
// ES2022 at() method on the built-in indexables
// String.prototype.at(index)
function String_at(index) {
// Step 1.
if (this === undefined || this === null)
ThrowIncompatibleMethod("at", this);
// Step 2.
var string = ToString(this);
// Step 3.
var len = string.length;
// Step 4.
var relativeIndex = ToInteger(index);
// Steps 5-6.
var k;
if (relativeIndex >= 0) {
k = relativeIndex;
} else {
k = len + relativeIndex;
}
// Step 7.
if (k < 0 || k >= len) {
return undefined;
}
// Step 8.
return string[k];
}
/** /**
* Compare String str1 against String str2, using the locale and collation * Compare String str1 against String str2, using the locale and collation
* options provided. * options provided.

View file

@ -1308,6 +1308,45 @@ function TypedArraySubarray(begin, end) {
return TypedArraySpeciesCreateWithBuffer(obj, buffer, beginByteOffset, newLength); return TypedArraySpeciesCreateWithBuffer(obj, buffer, beginByteOffset, newLength);
} }
// ES2022 at() method on the built-in indexables
// %TypedArray%.prototype.at(index)
function TypedArrayAt(index) {
// Step 1.
var obj = this;
// Step 2.
// This function is not generic.
if (!IsObject(obj) || !IsTypedArray(obj)) {
return callFunction(CallTypedArrayMethodIfWrapped, obj, index,
"TypedArrayAt");
}
GetAttachedArrayBuffer(obj);
// If we got here, `this` is either a typed array or a wrapper for one.
// Step 3.
var len = TypedArrayLength(obj);
// Step 4.
var relativeIndex = ToInteger(index);
// Steps 5-6.
var k;
if (relativeIndex >= 0) {
k = relativeIndex;
} else {
k = len + relativeIndex;
}
// Step 7.
if (k < 0 || k >= len) {
return undefined;
}
// Step 8.
return obj[k];
}
// ES6 draft rev30 (2014/12/24) 22.2.3.30 %TypedArray%.prototype.values() // ES6 draft rev30 (2014/12/24) 22.2.3.30 %TypedArray%.prototype.values()
function TypedArrayValues() { function TypedArrayValues() {
// Step 1. // Step 1.

View file

@ -332,7 +332,7 @@ class StoreBuffer
explicit operator bool() const { return objectAndKind_ != 0; } explicit operator bool() const { return objectAndKind_ != 0; }
typedef struct { typedef struct Hasher {
typedef SlotsEdge Lookup; typedef SlotsEdge Lookup;
static HashNumber hash(const Lookup& l) { return l.objectAndKind_ ^ l.start_ ^ l.count_; } static HashNumber hash(const Lookup& l) { return l.objectAndKind_ ^ l.start_ ^ l.count_; }
static bool match(const SlotsEdge& k, const Lookup& l) { return k == l; } static bool match(const SlotsEdge& k, const Lookup& l) { return k == l; }

View file

@ -3189,6 +3189,9 @@ static const JSFunctionSpec array_methods[] = {
JS_SELF_HOSTED_FN("flat", "ArrayFlat", 0,0), JS_SELF_HOSTED_FN("flat", "ArrayFlat", 0,0),
JS_SELF_HOSTED_FN("flatMap", "ArrayFlatMap", 1,0), JS_SELF_HOSTED_FN("flatMap", "ArrayFlatMap", 1,0),
/* ES2022 additions */
JS_SELF_HOSTED_FN("at", "ArrayAt", 1,0),
JS_FS_END JS_FS_END
}; };

View file

@ -2847,6 +2847,9 @@ static const JSFunctionSpec string_methods[] = {
/* Python-esque sequence methods. */ /* Python-esque sequence methods. */
JS_FN("concat", str_concat, 1,0), JS_FN("concat", str_concat, 1,0),
JS_SELF_HOSTED_FN("slice", "String_slice", 2,0), JS_SELF_HOSTED_FN("slice", "String_slice", 2,0),
/* ES2022 additions */
JS_SELF_HOSTED_FN("at", "String_at", 1,0),
/* HTML string methods. */ /* HTML string methods. */
JS_SELF_HOSTED_FN("bold", "String_bold", 0,0), JS_SELF_HOSTED_FN("bold", "String_bold", 0,0),

View file

@ -1538,6 +1538,10 @@ TypedArrayObject::protoFunctions[] = {
JS_SELF_HOSTED_FN("includes", "TypedArrayIncludes", 2, 0), JS_SELF_HOSTED_FN("includes", "TypedArrayIncludes", 2, 0),
JS_SELF_HOSTED_FN("toString", "ArrayToString", 0, 0), JS_SELF_HOSTED_FN("toString", "ArrayToString", 0, 0),
JS_SELF_HOSTED_FN("toLocaleString", "TypedArrayToLocaleString", 2, 0), JS_SELF_HOSTED_FN("toLocaleString", "TypedArrayToLocaleString", 2, 0),
/* ES2022 additions */
JS_SELF_HOSTED_FN("at", "TypedArrayAt", 1, 0),
JS_FS_END JS_FS_END
}; };

View file

@ -858,6 +858,10 @@ int NrSocket::connect(nr_transport_addr *addr) {
PRNetAddr naddr; PRNetAddr naddr;
int32_t connect_status, getsockname_status; int32_t connect_status, getsockname_status;
// TODO: Add TLS layer with nsISocketProviderService?
if (addr->tls_host[0] != '\0')
ABORT(R_INTERNAL);
if ((r=nr_transport_addr_to_praddr(addr, &naddr))) if ((r=nr_transport_addr_to_praddr(addr, &naddr)))
ABORT(r); ABORT(r);
@ -1840,7 +1844,7 @@ void NrTcpSocketIpc::close() {
} }
int NrTcpSocketIpc::connect(nr_transport_addr *addr) { int NrTcpSocketIpc::connect(nr_transport_addr *addr) {
nsCString remote_addr, local_addr; nsCString remote_addr, local_addr, tls_host;
int32_t remote_port, local_port; int32_t remote_port, local_port;
int r, _status; int r, _status;
if ((r=nr_transport_addr_get_addrstring_and_port(addr, if ((r=nr_transport_addr_get_addrstring_and_port(addr,
@ -1856,6 +1860,8 @@ int NrTcpSocketIpc::connect(nr_transport_addr *addr) {
ABORT(r); ABORT(r);
} }
tls_host = addr->tls_host;
state_ = mirror_state_ = NR_CONNECTING; state_ = mirror_state_ = NR_CONNECTING;
RUN_ON_THREAD(io_thread_, RUN_ON_THREAD(io_thread_,
mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this), mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
@ -1863,7 +1869,8 @@ int NrTcpSocketIpc::connect(nr_transport_addr *addr) {
remote_addr, remote_addr,
static_cast<uint16_t>(remote_port), static_cast<uint16_t>(remote_port),
local_addr, local_addr,
static_cast<uint16_t>(local_port)), static_cast<uint16_t>(local_port),
tls_host),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
// Make caller wait for ready to write. // Make caller wait for ready to write.
@ -1939,7 +1946,8 @@ int NrTcpSocketIpc::accept(nr_transport_addr *addrp, nr_socket **sockp) {
void NrTcpSocketIpc::connect_i(const nsACString &remote_addr, void NrTcpSocketIpc::connect_i(const nsACString &remote_addr,
uint16_t remote_port, uint16_t remote_port,
const nsACString &local_addr, const nsACString &local_addr,
uint16_t local_port) { uint16_t local_port,
const nsACString &tls_host) {
ASSERT_ON_THREAD(io_thread_); ASSERT_ON_THREAD(io_thread_);
mirror_state_ = NR_CONNECTING; mirror_state_ = NR_CONNECTING;
@ -1948,11 +1956,21 @@ void NrTcpSocketIpc::connect_i(const nsACString &remote_addr,
// Bug 1285330: put filtering back in here // Bug 1285330: put filtering back in here
// XXX remove remote! if (tls_host.IsEmpty()) {
socket_child_->SendWindowlessOpenBind(this, // XXX remove remote!
remote_addr, remote_port, socket_child_->SendWindowlessOpenBind(this,
local_addr, local_port, remote_addr, remote_port,
/* use ssl */ false); local_addr, local_port,
/* use ssl */ false,
/* reuse addr port */ true);
} else {
// XXX remove remote!
socket_child_->SendWindowlessOpenBind(this,
tls_host, remote_port,
local_addr, local_port,
/* use ssl */ true,
/* reuse addr port */ true);
}
} }
void NrTcpSocketIpc::write_i(nsAutoPtr<InfallibleTArray<uint8_t>> arr, void NrTcpSocketIpc::write_i(nsAutoPtr<InfallibleTArray<uint8_t>> arr,

View file

@ -369,7 +369,8 @@ private:
void connect_i(const nsACString &remote_addr, void connect_i(const nsACString &remote_addr,
uint16_t remote_port, uint16_t remote_port,
const nsACString &local_addr, const nsACString &local_addr,
uint16_t local_port); uint16_t local_port,
const nsACString &tls_host);
void write_i(nsAutoPtr<InfallibleTArray<uint8_t>> buf, void write_i(nsAutoPtr<InfallibleTArray<uint8_t>> buf,
uint32_t tracking_number); uint32_t tracking_number);
void close_i(); void close_i();

View file

@ -108,6 +108,7 @@ MOZ_MTLOG_MODULE("mtransport")
const char kNrIceTransportUdp[] = "udp"; const char kNrIceTransportUdp[] = "udp";
const char kNrIceTransportTcp[] = "tcp"; const char kNrIceTransportTcp[] = "tcp";
const char kNrIceTransportTls[] = "tls";
static bool initialized = false; static bool initialized = false;
@ -210,6 +211,9 @@ nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server) const {
server->transport = IPPROTO_UDP; server->transport = IPPROTO_UDP;
} else if (transport_ == kNrIceTransportTcp) { } else if (transport_ == kNrIceTransportTcp) {
server->transport = IPPROTO_TCP; server->transport = IPPROTO_TCP;
} else if (transport_ == kNrIceTransportTls) {
server->transport = IPPROTO_TCP;
server->tls = 1;
} else { } else {
MOZ_MTLOG(ML_ERROR, "Unsupported STUN server transport: " << transport_); MOZ_MTLOG(ML_ERROR, "Unsupported STUN server transport: " << transport_);
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -586,6 +590,7 @@ NrIceCtx::Initialize(const std::string& ufrag,
nsCString mapping_type; nsCString mapping_type;
nsCString filtering_type; nsCString filtering_type;
bool block_udp = false; bool block_udp = false;
bool block_tcp = false;
nsresult rv; nsresult rv;
nsCOMPtr<nsIPrefService> pref_service = nsCOMPtr<nsIPrefService> pref_service =
@ -604,6 +609,9 @@ NrIceCtx::Initialize(const std::string& ufrag,
rv = pref_branch->GetBoolPref( rv = pref_branch->GetBoolPref(
"media.peerconnection.nat_simulator.block_udp", "media.peerconnection.nat_simulator.block_udp",
&block_udp); &block_udp);
rv = pref_branch->GetBoolPref(
"media.peerconnection.nat_simulator.block_tcp",
&block_tcp);
} }
} }
@ -614,6 +622,7 @@ NrIceCtx::Initialize(const std::string& ufrag,
test_nat->filtering_type_ = TestNat::ToNatBehavior(filtering_type.get()); test_nat->filtering_type_ = TestNat::ToNatBehavior(filtering_type.get());
test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type.get()); test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type.get());
test_nat->block_udp_ = block_udp; test_nat->block_udp_ = block_udp;
test_nat->block_tcp_ = block_tcp;
test_nat->enabled_ = true; test_nat->enabled_ = true;
SetNat(test_nat); SetNat(test_nat);
} }

View file

@ -90,6 +90,7 @@ class NrIceMediaStream;
extern const char kNrIceTransportUdp[]; extern const char kNrIceTransportUdp[];
extern const char kNrIceTransportTcp[]; extern const char kNrIceTransportTcp[];
extern const char kNrIceTransportTls[];
class NrIceStunServer { class NrIceStunServer {
public: public:

View file

@ -200,6 +200,7 @@ int TestNat::create_socket_factory(nr_socket_factory **factorypp) {
TestNrSocket::TestNrSocket(TestNat *nat) TestNrSocket::TestNrSocket(TestNat *nat)
: nat_(nat), : nat_(nat),
tls_(false),
timer_handle_(nullptr) { timer_handle_(nullptr) {
nat_->insert_socket(this); nat_->insert_socket(this);
} }
@ -473,6 +474,10 @@ int TestNrSocket::connect(nr_transport_addr *addr) {
return R_INTERNAL; return R_INTERNAL;
} }
if (addr->tls_host[0] != '\0') {
tls_ = true;
}
if (!nat_->enabled_ if (!nat_->enabled_
|| addr->protocol==IPPROTO_UDP // Horrible hack to allow default address || addr->protocol==IPPROTO_UDP // Horrible hack to allow default address
// discovery to work. Only works because // discovery to work. Only works because
@ -508,6 +513,24 @@ int TestNrSocket::connect(nr_transport_addr *addr) {
} }
int TestNrSocket::write(const void *msg, size_t len, size_t *written) { int TestNrSocket::write(const void *msg, size_t len, size_t *written) {
UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg));
if (nat_->block_stun_ && nr_is_stun_message(buf, len)) {
// Should cause this socket to be abandoned
r_log(LOG_GENERIC, LOG_DEBUG,
"TestNrSocket %s dropping outgoing TCP "
"because it is configured to drop STUN",
my_addr().as_string);
return R_INTERNAL;
}
if (nat_->block_tcp_ && !tls_) {
// Should cause this socket to be abandoned
r_log(LOG_GENERIC, LOG_DEBUG,
"TestNrSocket %s dropping outgoing TCP "
"because it is configured to drop TCP",
my_addr().as_string);
return R_INTERNAL;
}
if (port_mappings_.empty()) { if (port_mappings_.empty()) {
// The no-nat case, just pass call through. // The no-nat case, just pass call through.
@ -518,7 +541,11 @@ int TestNrSocket::write(const void *msg, size_t len, size_t *written) {
} else { } else {
destroy_stale_port_mappings(); destroy_stale_port_mappings();
if (port_mappings_.empty()) { if (port_mappings_.empty()) {
return -1; r_log(LOG_GENERIC, LOG_DEBUG,
"TestNrSocket %s dropping outgoing TCP "
"because the port mapping was stale",
my_addr().as_string);
return R_INTERNAL;
} }
// This is TCP only // This is TCP only
MOZ_ASSERT(port_mappings_.size() == 1); MOZ_ASSERT(port_mappings_.size() == 1);
@ -533,18 +560,34 @@ int TestNrSocket::write(const void *msg, size_t len, size_t *written) {
} }
int TestNrSocket::read(void *buf, size_t maxlen, size_t *len) { int TestNrSocket::read(void *buf, size_t maxlen, size_t *len) {
int r;
if (port_mappings_.empty()) { if (port_mappings_.empty()) {
return internal_socket_->read(buf, maxlen, len); r = internal_socket_->read(buf, maxlen, len);
} else { } else {
MOZ_ASSERT(port_mappings_.size() == 1); MOZ_ASSERT(port_mappings_.size() == 1);
int bytesRead = r = port_mappings_.front()->external_socket_->read(buf, maxlen, len);
port_mappings_.front()->external_socket_->read(buf, maxlen, len); if (!r && nat_->refresh_on_ingress_) {
if (bytesRead > 0 && nat_->refresh_on_ingress_) {
port_mappings_.front()->last_used_ = PR_IntervalNow(); port_mappings_.front()->last_used_ = PR_IntervalNow();
} }
return bytesRead;
} }
if (r) {
return r;
}
if (nat_->block_tcp_ && !tls_) {
// Should cause this socket to be abandoned
return R_INTERNAL;
}
UCHAR *cbuf = static_cast<UCHAR*>(const_cast<void*>(buf));
if (nat_->block_stun_ && nr_is_stun_message(cbuf, *len)) {
// Should cause this socket to be abandoned
return R_INTERNAL;
}
return r;
} }
int TestNrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg, int TestNrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg,

View file

@ -137,6 +137,7 @@ class TestNat {
refresh_on_ingress_(false), refresh_on_ingress_(false),
block_udp_(false), block_udp_(false),
block_stun_(false), block_stun_(false),
block_tcp_(false),
delay_stun_resp_ms_(0), delay_stun_resp_ms_(0),
sockets_() {} sockets_() {}
@ -168,6 +169,7 @@ class TestNat {
bool refresh_on_ingress_; bool refresh_on_ingress_;
bool block_udp_; bool block_udp_;
bool block_stun_; bool block_stun_;
bool block_tcp_;
/* Note: this can only delay a single response so far (bug 1253657) */ /* Note: this can only delay a single response so far (bug 1253657) */
uint32_t delay_stun_resp_ms_; uint32_t delay_stun_resp_ms_;
@ -319,6 +321,7 @@ class TestNrSocket : public NrSocketBase {
// same nat. // same nat.
RefPtr<NrSocketBase> internal_socket_; RefPtr<NrSocketBase> internal_socket_;
RefPtr<TestNat> nat_; RefPtr<TestNat> nat_;
bool tls_;
// Since our comparison logic is different depending on what kind of NAT // Since our comparison logic is different depending on what kind of NAT
// we simulate, and the STL does not make it very easy to switch out the // we simulate, and the STL does not make it very easy to switch out the
// comparison function at runtime, and these lists are going to be very // comparison function at runtime, and these lists are going to be very

View file

@ -666,6 +666,14 @@ static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr)
if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr)) if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr))
ABORT(r); ABORT(r);
if (cand->stun_server->tls) {
/* Copy over the DNS name; needed for TLS. There is already a null at the
* end of the buffer, leave it there. */
strncpy(cand->stun_server_addr.tls_host,
cand->stun_server->u.dnsname.host,
sizeof(cand->stun_server_addr.tls_host) - 1);
}
if (cand->tcp_type == TCP_TYPE_PASSIVE || cand->tcp_type == TCP_TYPE_SO){ if (cand->tcp_type == TCP_TYPE_PASSIVE || cand->tcp_type == TCP_TYPE_SO){
if (r=nr_socket_multi_tcp_stun_server_connect(cand->osock, addr)) if (r=nr_socket_multi_tcp_stun_server_connect(cand->osock, addr))
ABORT(r); ABORT(r);

View file

@ -63,6 +63,7 @@ typedef struct nr_ice_stun_server_ {
} u; } u;
int id; int id;
int transport; int transport;
int tls; /* Whether to use TLS or not */
} nr_ice_stun_server; } nr_ice_stun_server;
typedef struct nr_ice_turn_server_ { typedef struct nr_ice_turn_server_ {

View file

@ -66,6 +66,7 @@ typedef struct nr_transport_addr_ {
/* A string version. /* A string version.
56 = 5 ("IP6:[") + 39 (ipv6 address) + 2 ("]:") + 5 (port) + 4 (/UDP) + 1 (null) */ 56 = 5 ("IP6:[") + 39 (ipv6 address) + 2 ("]:") + 5 (port) + 4 (/UDP) + 1 (null) */
char as_string[56]; char as_string[56];
char tls_host[256];
} nr_transport_addr; } nr_transport_addr;
typedef struct nr_transport_addr_mask_ { typedef struct nr_transport_addr_mask_ {

View file

@ -335,6 +335,7 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
, mSTSThread(nullptr) , mSTSThread(nullptr)
, mAllowIceLoopback(false) , mAllowIceLoopback(false)
, mAllowIceLinkLocal(false) , mAllowIceLinkLocal(false)
, mForceIceTcp(false)
, mMedia(nullptr) , mMedia(nullptr)
, mUuidGen(MakeUnique<PCUuidGenerator>()) , mUuidGen(MakeUnique<PCUuidGenerator>())
, mNumAudioStreams(0) , mNumAudioStreams(0)
@ -365,6 +366,8 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
"media.peerconnection.ice.loopback", false); "media.peerconnection.ice.loopback", false);
mAllowIceLinkLocal = Preferences::GetBool( mAllowIceLinkLocal = Preferences::GetBool(
"media.peerconnection.ice.link_local", false); "media.peerconnection.ice.link_local", false);
mForceIceTcp = Preferences::GetBool(
"media.peerconnection.ice.force_ice_tcp", false);
#endif #endif
memset(mMaxReceiving, 0, sizeof(mMaxReceiving)); memset(mMaxReceiving, 0, sizeof(mMaxReceiving));
memset(mMaxSending, 0, sizeof(mMaxSending)); memset(mMaxSending, 0, sizeof(mMaxSending));
@ -527,8 +530,8 @@ PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer)
if (!(isStun || isStuns || isTurn || isTurns)) { if (!(isStun || isStuns || isTurn || isTurns)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if (isTurns || isStuns) { if (isStuns) {
continue; // TODO: Support TURNS and STUNS (Bug 1056934) continue; // TODO: Support STUNS (Bug 1056934)
} }
nsAutoCString spec; nsAutoCString spec;
rv = url->GetSpec(spec); rv = url->GetSpec(spec);
@ -577,6 +580,11 @@ PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer)
if (port == -1) if (port == -1)
port = (isStuns || isTurns)? 5349 : 3478; port = (isStuns || isTurns)? 5349 : 3478;
if (isStuns || isTurns) {
// Should we barf if transport is set to udp or something?
transport = "tls";
}
// First check the known good ports for webrtc // First check the known good ports for webrtc
bool knownGoodPort = false; bool knownGoodPort = false;
for (int i = 0; !knownGoodPort && gGoodWebrtcPortList[i]; i++) { for (int i = 0; !knownGoodPort && gGoodWebrtcPortList[i]; i++) {
@ -2256,6 +2264,11 @@ NS_IMETHODIMP
PeerConnectionImpl::AddIceCandidate(const char* aCandidate, const char* aMid, unsigned short aLevel) { PeerConnectionImpl::AddIceCandidate(const char* aCandidate, const char* aMid, unsigned short aLevel) {
PC_AUTO_ENTER_API_CALL(true); PC_AUTO_ENTER_API_CALL(true);
if (mForceIceTcp && std::string::npos != std::string(aCandidate).find(" UDP ")) {
CSFLogError(logTag, "Blocking remote UDP candidate: %s", aCandidate);
return NS_OK;
}
JSErrorResult rv; JSErrorResult rv;
RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver); RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) { if (!pco) {
@ -3111,7 +3124,7 @@ PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState,
mNegotiationNeeded = false; mNegotiationNeeded = false;
// If we're rolling back a local offer, we might need to remove some // If we're rolling back a local offer, we might need to remove some
// transports, but nothing further needs to be done. // transports, but nothing further needs to be done.
mMedia->ActivateOrRemoveTransports(*mJsepSession); mMedia->ActivateOrRemoveTransports(*mJsepSession, mForceIceTcp);
if (!rollback) { if (!rollback) {
if (NS_FAILED(mMedia->UpdateMediaPipelines(*mJsepSession))) { if (NS_FAILED(mMedia->UpdateMediaPipelines(*mJsepSession))) {
CSFLogError(logTag, "Error Updating MediaPipelines"); CSFLogError(logTag, "Error Updating MediaPipelines");
@ -3277,6 +3290,11 @@ PeerConnectionImpl::CandidateReady(const std::string& candidate,
uint16_t level) { uint16_t level) {
PC_AUTO_ENTER_API_CALL_VOID_RETURN(false); PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
if (mForceIceTcp && std::string::npos != candidate.find(" UDP ")) {
CSFLogError(logTag, "Blocking local UDP candidate: %s", candidate.c_str());
return;
}
std::string mid; std::string mid;
bool skipped = false; bool skipped = false;
nsresult res = mJsepSession->AddLocalIceCandidate(candidate, nsresult res = mJsepSession->AddLocalIceCandidate(candidate,

View file

@ -803,6 +803,7 @@ private:
bool mAllowIceLoopback; bool mAllowIceLoopback;
bool mAllowIceLinkLocal; bool mAllowIceLinkLocal;
bool mForceIceTcp;
RefPtr<PeerConnectionMedia> mMedia; RefPtr<PeerConnectionMedia> mMedia;
// The JSEP negotiation session. // The JSEP negotiation session.

View file

@ -468,7 +468,8 @@ PeerConnectionMedia::EnsureTransport_s(size_t aLevel, size_t aComponentCount)
} }
void void
PeerConnectionMedia::ActivateOrRemoveTransports(const JsepSession& aSession) PeerConnectionMedia::ActivateOrRemoveTransports(const JsepSession& aSession,
const bool forceIceTcp)
{ {
auto transports = aSession.GetTransports(); auto transports = aSession.GetTransports();
for (size_t i = 0; i < transports.size(); ++i) { for (size_t i = 0; i < transports.size(); ++i) {
@ -491,6 +492,14 @@ PeerConnectionMedia::ActivateOrRemoveTransports(const JsepSession& aSession)
RemoveTransportFlow(i, true); RemoveTransportFlow(i, true);
} }
if (forceIceTcp) {
candidates.erase(std::remove_if(candidates.begin(),
candidates.end(),
[](const std::string & s) {
return s.find(" UDP "); }),
candidates.end());
}
RUN_ON_THREAD( RUN_ON_THREAD(
GetSTSThread(), GetSTSThread(),
WrapRunnable(RefPtr<PeerConnectionMedia>(this), WrapRunnable(RefPtr<PeerConnectionMedia>(this),

View file

@ -270,7 +270,8 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// Activate or remove ICE transports at the conclusion of offer/answer, // Activate or remove ICE transports at the conclusion of offer/answer,
// or when rollback occurs. // or when rollback occurs.
void ActivateOrRemoveTransports(const JsepSession& aSession); void ActivateOrRemoveTransports(const JsepSession& aSession,
const bool forceIceTcp);
// Start ICE checks. // Start ICE checks.
void StartIceChecks(const JsepSession& session); void StartIceChecks(const JsepSession& session);

View file

@ -129,6 +129,11 @@ interface nsISocketTransport : nsITransport
unsigned long getTimeout(in unsigned long aType); unsigned long getTimeout(in unsigned long aType);
void setTimeout(in unsigned long aType, in unsigned long aValue); void setTimeout(in unsigned long aType, in unsigned long aValue);
/**
* True to set addr and port reuse socket options.
*/
void setReuseAddrPort(in bool reuseAddrPort);
/** /**
* Values for the aType parameter passed to get/setTimeout. * Values for the aType parameter passed to get/setTimeout.
*/ */

View file

@ -738,6 +738,7 @@ nsSocketTransport::nsSocketTransport()
, mProxyTransparentResolvesHost(false) , mProxyTransparentResolvesHost(false)
, mHttpsProxy(false) , mHttpsProxy(false)
, mConnectionFlags(0) , mConnectionFlags(0)
, mReuseAddrPort(false)
, mState(STATE_CLOSED) , mState(STATE_CLOSED)
, mAttached(false) , mAttached(false)
, mInputClosed(true) , mInputClosed(true)
@ -1355,6 +1356,32 @@ nsSocketTransport::InitiateSocket()
status = PR_SetSocketOption(fd, &opt); status = PR_SetSocketOption(fd, &opt);
NS_ASSERTION(status == PR_SUCCESS, "unable to make socket non-blocking"); NS_ASSERTION(status == PR_SUCCESS, "unable to make socket non-blocking");
if (mReuseAddrPort) {
SOCKET_LOG((" Setting port/addr reuse socket options\n"));
// Set ReuseAddr for TCP sockets to enable having several
// sockets bound to same local IP and port
PRSocketOptionData opt_reuseaddr;
opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
opt_reuseaddr.value.reuse_addr = PR_TRUE;
status = PR_SetSocketOption(fd, &opt_reuseaddr);
if (status != PR_SUCCESS) {
SOCKET_LOG((" Couldn't set reuse addr socket option: %d\n",
status));
}
// And also set ReusePort for platforms supporting this socket option
PRSocketOptionData opt_reuseport;
opt_reuseport.option = PR_SockOpt_Reuseport;
opt_reuseport.value.reuse_port = PR_TRUE;
status = PR_SetSocketOption(fd, &opt_reuseport);
if (status != PR_SUCCESS
&& PR_GetError() != PR_OPERATION_NOT_SUPPORTED_ERROR) {
SOCKET_LOG((" Couldn't set reuse port socket option: %d\n",
status));
}
}
// disable the nagle algorithm - if we rely on it to coalesce writes into // disable the nagle algorithm - if we rely on it to coalesce writes into
// full packets the final packet of a multi segment POST/PUT or pipeline // full packets the final packet of a multi segment POST/PUT or pipeline
// sequence is delayed a full rtt // sequence is delayed a full rtt
@ -2484,6 +2511,13 @@ nsSocketTransport::SetTimeout(uint32_t type, uint32_t value)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsSocketTransport::SetReuseAddrPort(bool reuseAddrPort)
{
mReuseAddrPort = reuseAddrPort;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsSocketTransport::SetQoSBits(uint8_t aQoSBits) nsSocketTransport::SetQoSBits(uint8_t aQoSBits)
{ {

View file

@ -295,6 +295,7 @@ private:
bool mProxyTransparentResolvesHost; bool mProxyTransparentResolvesHost;
bool mHttpsProxy; bool mHttpsProxy;
uint32_t mConnectionFlags; uint32_t mConnectionFlags;
bool mReuseAddrPort;
// The origin attributes are used to create sockets. The first party domain // The origin attributes are used to create sockets. The first party domain
// will eventually be used to isolate OCSP cache and is only non-empty when // will eventually be used to isolate OCSP cache and is only non-empty when

View file

@ -1685,6 +1685,12 @@ SocketTransportShim::SetTimeout(uint32_t aType, uint32_t aValue)
return mWrapped->SetTimeout(aType, aValue); return mWrapped->SetTimeout(aType, aValue);
} }
NS_IMETHODIMP
SocketTransportShim::SetReuseAddrPort(bool aReuseAddrPort)
{
return mWrapped->SetReuseAddrPort(aReuseAddrPort);
}
NS_IMETHODIMP NS_IMETHODIMP
SocketTransportShim::GetQoSBits(uint8_t *aQoSBits) SocketTransportShim::GetQoSBits(uint8_t *aQoSBits)
{ {

View file

@ -1346,7 +1346,7 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
raise raise
# Resign the executable, since install_name_tool invalidates the signature # Resign the executable, since install_name_tool invalidates the signature
call_subprocess(["codesign", "-s", "-", py_executable]) call_subprocess(["codesign", "-fs", "-", py_executable])
if not is_win: if not is_win:
# Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist

View file

@ -10,7 +10,9 @@ import passlib.utils # for saslprep
import copy import copy
import random import random
import operator import operator
import os
import platform import platform
import string
import time import time
from string import Template from string import Template
from twisted.internet import reactor, protocol from twisted.internet import reactor, protocol
@ -715,6 +717,38 @@ def prune_allocations():
del allocations[key] del allocations[key]
allocation.close() allocation.close()
CERT_FILE = "selfsigned.crt"
KEY_FILE = "private.key"
def create_self_signed_cert(name):
from OpenSSL import crypto
if os.path.isfile(CERT_FILE) and os.path.isfile(KEY_FILE):
return
# create a key pair
k = crypto.PKey()
k.generate_key(crypto.TYPE_RSA, 1024)
# create a self-signed cert
cert = crypto.X509()
cert.get_subject().C = "US"
cert.get_subject().ST = "TX"
cert.get_subject().L = "Dallas"
cert.get_subject().O = "Mozilla test iceserver"
cert.get_subject().OU = "Mozilla test iceserver"
cert.get_subject().CN = name
cert.set_serial_number(1000)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(10*365*24*60*60)
cert.set_issuer(cert.get_subject())
cert.set_pubkey(k)
cert.sign(k, 'sha1')
open(CERT_FILE, "wt").write(
crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
open(KEY_FILE, "wt").write(
crypto.dump_privatekey(crypto.FILETYPE_PEM, k))
if __name__ == "__main__": if __name__ == "__main__":
random.seed() random.seed()
@ -739,20 +773,48 @@ if __name__ == "__main__":
except: except:
pass pass
try:
from twisted.internet import ssl
from OpenSSL import SSL
create_self_signed_cert(hostname)
tls_context_factory = ssl.DefaultOpenSSLContextFactory(KEY_FILE, CERT_FILE, SSL.TLSv1_2_METHOD)
reactor.listenSSL(5349, TcpStunHandlerFactory(), tls_context_factory, interface=interface_4)
try:
reactor.listenSSL(5349, TcpStunHandlerFactory(), tls_context_factory, interface=interface_6)
except:
pass
f = open(CERT_FILE, 'r');
lines = f.readlines();
lines.pop(0); # Remove BEGIN CERTIFICATE
lines.pop(); # Remove END CERTIFICATE
lines = map(string.strip, lines);
certbase64 = string.join(lines, '');
turns_url = ', "turns:' + hostname + '"'
cert_prop = ', "cert":"' + certbase64 + '"'
except:
turns_url = ''
cert_prop = ''
pass
allocation_pruner = LoopingCall(prune_allocations) allocation_pruner = LoopingCall(prune_allocations)
allocation_pruner.start(1) allocation_pruner.start(1)
template = Template( template = Template(
'[\ '[\
{"url":"stun:$hostname"}, \ {"urls":["stun:$hostname", "stun:$hostname?transport=tcp"]}, \
{"url":"stun:$hostname?transport=tcp"}, \ {"username":"$user","credential":"$pwd","urls": \
{"username":"$user","credential":"$pwd","url":"turn:$hostname"}, \ ["turn:$hostname", "turn:$hostname?transport=tcp" $turns_url] \
{"username":"$user","credential":"$pwd","url":"turn:$hostname?transport=tcp"}]' $cert_prop}]' # Hack to make it easier to override cert checks
) )
print(template.substitute(user=turn_user, print(template.substitute(user=turn_user,
pwd=turn_pass, pwd=turn_pass,
hostname=hostname)) hostname=hostname,
turns_url=turns_url,
cert_prop=cert_prop))
reactor.run() reactor.run()