From 0466eb531d7012f98a22648fb4de0aa0a1b7dcd8 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Fri, 29 Mar 2013 19:02:08 -0400 Subject: [PATCH] Bug 855769: Wire up TURN support in RTCPeerConnection config r=jesup --- .../test_peerConnection_bug825703.html | 72 +++++++++++-------- dom/webidl/RTCConfiguration.webidl | 1 + .../src/peerconnection/PeerConnectionImpl.cpp | 39 +++++----- .../src/peerconnection/PeerConnectionImpl.h | 28 ++++++-- .../peerconnection/PeerConnectionMedia.cpp | 7 +- .../src/peerconnection/PeerConnectionMedia.h | 3 +- .../signaling/test/signaling_unittests.cpp | 2 +- 7 files changed, 99 insertions(+), 53 deletions(-) diff --git a/dom/media/tests/mochitest/test_peerConnection_bug825703.html b/dom/media/tests/mochitest/test_peerConnection_bug825703.html index 1dcfda8dfe8e..6f4a4d00fef0 100644 --- a/dom/media/tests/mochitest/test_peerConnection_bug825703.html +++ b/dom/media/tests/mochitest/test_peerConnection_bug825703.html @@ -13,40 +13,56 @@ title: "RTCConfiguration valid/invalid permutations" }); + makePC = function (config, expect_success) { + var exception = null; + + try { + var pc = new mozRTCPeerConnection(config); + } catch (e) { + exception = e; + } + + if (expect_success) { + ok(!exception, "mozRTCPeerConnection(" + + JSON.stringify(config) + ") succeeds"); + } else { + ok(exception, "mozRTCPeerConnection(" + + JSON.stringify(config) + ") throws"); + } + } + runTest(function () { var pc; - var pcs; var exception = null; + var config; + try { pcs = new mozRTCPeerConnection(); } catch (e) { exception = e; } ok(!exception, "mozRTCPeerConnection() succeeds"); exception = null; - try { pc = new mozRTCPeerConnection(1); } catch (e) { exception = e; } - ok(exception, "mozRTCPeerConnection(1) throws"); - exception = null; - try { pc = new mozRTCPeerConnection({}); } catch (e) { exception = e; } - ok(exception, "mozRTCPeerConnection({}) throws"); - exception = null; - try { pcs = new mozRTCPeerConnection([]); } catch (e) { exception = e; } - ok(exception, "mozRTCPeerConnection([]) throws"); - exception = null; - try { pc = new mozRTCPeerConnection({ iceServers: {}}); } catch (e) { exception = e; } - ok(exception, "mozRTCPeerConnection({ iceServers: {}}) throws"); - exception = null; - try { pcs = new mozRTCPeerConnection({ iceServers: [] }); } catch (e) { exception = e; } - ok(!exception, "mozRTCPeerConnection({ iceServers: [] }) succeeds"); - exception = null; - try { pc = new mozRTCPeerConnection({ iceServers: [{ url:"" }] }); } catch (e) { exception = e; } - ok(exception, "mozRTCPeerConnection({ iceServers: [{ url:\"\" }] }) throws"); - exception = null; - try { pc = new mozRTCPeerConnection({ iceServers: [{ url:"http:0.0.0.0" }] }); } catch (e) { exception = e; } - ok(exception, "mozRTCPeerConnection({ iceServers: [{ url:\"http:0.0.0.0\" }] }) throws"); - exception = null; - try { pcs = new mozRTCPeerConnection({ iceServers: [{ url:"stun:0.0.0.0" }, { url:"stuns:x.net", foo:"" }, { url: "turn:[::192.9.5.5]:42" }, { url:"turns:user@x.org:42", credential:"p" }] }); } catch (e) { exception = e; } - ok(!exception, "mozRTCPeerConnection({ iceServers: [{ url:\"stun:0.0.0.0\" }, { url:\"stuns:x.net\", foo:\"\" }, { url: \"turn:[::192.9.5.5]:42\" }, { url:\"turns:user@x.org:42\", credential:\"p\" }] }) succeeds"); - exception = null; - try { pc = new mozRTCPeerConnection({ iceServers: [{ url:"stun:0.0.0.0", credential:{}}] }); } catch (e) { exception = e; } - ok(exception, "mozRTCPeerConnection({ iceServers: [{ url:\"stun:0.0.0.0\", credential:{}}] }) throws"); - pc = null; + + makePC(1, false); + + makePC({}, false); + + makePC([], false); + + makePC({ iceServers: {}}, false); + + makePC({ iceServers: [] }, true); + + makePC({ iceServers: [{ url:"" }] }, false); + + makePC({ iceServers: [{ url:"http:0.0.0.0" }] }, false); + + makePC({ iceServers: [ + { url:"stun:0.0.0.0" }, + { url:"stuns:x.net", foo:"" }, + { url:"turn:[::192.9.5.5]:42", username:"p", credential:"p" }, + { url:"turns:x.org:42", username:"p", credential:"p" } + ]}, true); + + makePC({ iceServers: [{ url:"stun:0.0.0.0", credential:{}}] }, false); + pcs = null; SimpleTest.finish(); }, true); diff --git a/dom/webidl/RTCConfiguration.webidl b/dom/webidl/RTCConfiguration.webidl index b53ef98938f2..a34359e892dc 100644 --- a/dom/webidl/RTCConfiguration.webidl +++ b/dom/webidl/RTCConfiguration.webidl @@ -7,6 +7,7 @@ dictionary RTCIceServer { DOMString url; DOMString? credential = null; + DOMString? username = null; }; dictionary RTCConfiguration { diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index ef1993cb671e..e7eaf7de0309 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -376,7 +376,7 @@ Warn(JSContext* aCx, const nsCString& aMsg) { * In JS, an RTCConfiguration looks like this: * * { "iceServers": [ { url:"stun:23.21.150.121" }, - * { url:"turn:user@turn.example.org", credential:"mypass"} ] } + * { url:"turn:turn.example.org", credential:"mypass", "username"} ] } * * This function converts an already-validated jsval that looks like the above * into an IceConfiguration object. @@ -416,17 +416,8 @@ PeerConnectionImpl::ConvertRTCConfiguration(const JS::Value& aSrc, nsAutoCString spec; rv = url->GetSpec(spec); NS_ENSURE_SUCCESS(rv, rv); - if (!server.mCredential.IsEmpty()) { - // TODO(jib@mozilla.com): Support username, credentials & TURN servers - Warn(aCx, nsPrintfCString(ICE_PARSING - ": Credentials not yet implemented. Omitting \"%s\"", spec.get())); - continue; - } - if (isTurn || isTurns) { - Warn(aCx, nsPrintfCString(ICE_PARSING - ": TURN servers not yet supported. Treating as STUN: \"%s\"", spec.get())); - } - // TODO(jib@mozilla.com): Revisit once nsURI supports host and port on STUN + + // TODO(jib@mozilla.com): Revisit once nsURI has STUN host+port (Bug 833509) int32_t port; nsAutoCString host; { @@ -443,13 +434,26 @@ PeerConnectionImpl::ConvertRTCConfiguration(const JS::Value& aSrc, if (!hostLen) { return NS_ERROR_FAILURE; } + if (hostPos > 1) /* The username was removed */ + return NS_ERROR_FAILURE; path.Mid(host, hostPos, hostLen); } if (port == -1) port = (isStuns || isTurns)? 5349 : 3478; - if (!aDst->addServer(host.get(), port)) { - Warn(aCx, nsPrintfCString(ICE_PARSING - ": FQDN not yet implemented (only IP-#s). Omitting \"%s\"", spec.get())); + + if (isTurn || isTurns) { + NS_ConvertUTF16toUTF8 credential(server.mCredential); + NS_ConvertUTF16toUTF8 username(server.mUsername); + + if (!aDst->addTurnServer(host.get(), port, + username.get(), + credential.get())) { + return NS_ERROR_FAILURE; + } + } else { + if (!aDst->addStunServer(host.get(), port)) { + return NS_ERROR_FAILURE; + } } } #endif @@ -523,9 +527,10 @@ PeerConnectionImpl::Initialize(IPeerConnectionObserver* aObserver, IceConfiguration ic; res = ConvertRTCConfiguration(*aRTCConfiguration, &ic, aCx); NS_ENSURE_SUCCESS(res, res); - res = mMedia->Init(ic.getServers()); + res = mMedia->Init(ic.getStunServers(), ic.getTurnServers()); } else { - res = mMedia->Init(aConfiguration->getServers()); + res = mMedia->Init(aConfiguration->getStunServers(), + aConfiguration->getTurnServers()); } if (NS_FAILED(res)) { CSFLogError(logTag, "%s: Couldn't initialize media object", __FUNCTION__); diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index af9349f5e442..904c31004700 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -68,19 +68,37 @@ private: class IceConfiguration { public: - bool addServer(const std::string& addr, uint16_t port) + bool addStunServer(const std::string& addr, uint16_t port) { NrIceStunServer* server(NrIceStunServer::Create(addr, port)); if (!server) { return false; } - addServer(*server); + addStunServer(*server); return true; } - void addServer(const NrIceStunServer& server) { mServers.push_back (server); } - const std::vector& getServers() const { return mServers; } + bool addTurnServer(const std::string& addr, uint16_t port, + const std::string& username, + const std::string& pwd) + { + // TODO(ekr@rtfm.com): Need support for SASLprep for + // username and password. Bug # ??? + std::vector password(pwd.begin(), pwd.end()); + + NrIceTurnServer* server(NrIceTurnServer::Create(addr, port, username, password)); + if (!server) { + return false; + } + addTurnServer(*server); + return true; + } + void addStunServer(const NrIceStunServer& server) { mStunServers.push_back (server); } + void addTurnServer(const NrIceTurnServer& server) { mTurnServers.push_back (server); } + const std::vector& getStunServers() const { return mStunServers; } + const std::vector& getTurnServers() const { return mTurnServers; } private: - std::vector mServers; + std::vector mStunServers; + std::vector mTurnServers; }; class PeerConnectionWrapper; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp index 972061396571..6bdb26a4dd44 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp @@ -119,7 +119,8 @@ PeerConnectionImpl* PeerConnectionImpl::CreatePeerConnection() } -nsresult PeerConnectionMedia::Init(const std::vector& stun_servers) +nsresult PeerConnectionMedia::Init(const std::vector& stun_servers, + const std::vector& turn_servers) { mMainThread = mParent->GetMainThread(); mSTSThread = mParent->GetSTSThread(); @@ -136,6 +137,10 @@ nsresult PeerConnectionMedia::Init(const std::vector& stun_serv CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__); return rv; } + if (NS_FAILED(rv = mIceCtx->SetTurnServers(turn_servers))) { + CSFLogError(logTag, "%s: Failed to set turn servers", __FUNCTION__); + return rv; + } if (NS_FAILED(rv = mDNSResolver->Init())) { CSFLogError(logTag, "%s: Failed to initialize dns resolver", __FUNCTION__); return rv; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h index 26d7006c9162..9ffc884573d0 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h @@ -238,7 +238,8 @@ class PeerConnectionMedia : public sigslot::has_slots<> { ~PeerConnectionMedia() {} - nsresult Init(const std::vector& stun_servers); + nsresult Init(const std::vector& stun_servers, + const std::vector& turn_servers); // WARNING: This destroys the object! void SelfDestruct(); diff --git a/media/webrtc/signaling/test/signaling_unittests.cpp b/media/webrtc/signaling/test/signaling_unittests.cpp index 6d8bb8cc174f..e28313d80f1d 100644 --- a/media/webrtc/signaling/test/signaling_unittests.cpp +++ b/media/webrtc/signaling/test/signaling_unittests.cpp @@ -544,7 +544,7 @@ class SignalingAgent { ASSERT_TRUE(pObserver); sipcc::IceConfiguration cfg; - cfg.addServer("23.21.150.121", 3478); + cfg.addStunServer("23.21.150.121", 3478); ASSERT_EQ(pc->Initialize(pObserver, nullptr, cfg, thread), NS_OK); }