From 202994ca64d692870b53e4ddc5de2c6e6d5f16a1 Mon Sep 17 00:00:00 2001 From: Jonas Oreland Date: Mon, 18 Dec 2017 12:10:43 +0100 Subject: [PATCH] This is a recommit of https://webrtc.googlesource.com/src.git/+/26246cac660a95f439b7d1c593edec2929806d3f that was reverted due to compile error on windows. Changes since last is an addition of a cast to uint16_t in stun.cc:1018. --- Add RelayPortFactoryInterface that allows for custom relay (e.g turn) ports This patch adds a RelayPortFactoryInterface that allows for custom relay ports. The factor is added as optional argument to BasicPortAlloctor. If none is provided a default implementation that mimics existing behavior is created. The patch also adds 2 stun functions, namely to copy a StunAttribute and to remove StunAttribute's from a StunMessage. Bug: webrtc:8640 Change-Id: If23638317130060286f576c94401de55c60a1821 Reviewed-on: https://webrtc-review.googlesource.com/34181 Reviewed-by: Guido Urdaneta Reviewed-by: Peter Thatcher Commit-Queue: Jonas Oreland Cr-Commit-Position: refs/heads/master@{#21345} --- p2p/BUILD.gn | 3 + p2p/base/port.cc | 4 ++ p2p/base/port.h | 5 ++ p2p/base/stun.cc | 49 +++++++++++++ p2p/base/stun.h | 15 ++++ p2p/base/stun_unittest.cc | 90 +++++++++++++++++++++++ p2p/base/turnport.cc | 18 ++++- p2p/base/turnport.h | 11 ++- p2p/client/basicportallocator.cc | 98 ++++++++++++++++++-------- p2p/client/basicportallocator.h | 28 ++++++-- p2p/client/relayportfactoryinterface.h | 72 +++++++++++++++++++ p2p/client/turnportfactory.cc | 66 +++++++++++++++++ p2p/client/turnportfactory.h | 37 ++++++++++ 13 files changed, 456 insertions(+), 40 deletions(-) create mode 100644 p2p/client/relayportfactoryinterface.h create mode 100644 p2p/client/turnportfactory.cc create mode 100644 p2p/client/turnportfactory.h diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn index 8e61730a02..cd54b7d5cc 100644 --- a/p2p/BUILD.gn +++ b/p2p/BUILD.gn @@ -81,8 +81,11 @@ rtc_static_library("rtc_p2p") { "base/udptransport.h", "client/basicportallocator.cc", "client/basicportallocator.h", + "client/relayportfactoryinterface.h", "client/socketmonitor.cc", "client/socketmonitor.h", + "client/turnportfactory.cc", + "client/turnportfactory.h", ] defines = [] diff --git a/p2p/base/port.cc b/p2p/base/port.cc index 66685ecca6..af96582fbc 100644 --- a/p2p/base/port.cc +++ b/p2p/base/port.cc @@ -621,6 +621,10 @@ bool Port::HandleIncomingPacket(rtc::AsyncPacketSocket* socket, return false; } +bool Port::CanHandleIncomingPacketsFrom(const rtc::SocketAddress&) const { + return false; +} + void Port::SendBindingResponse(StunMessage* request, const rtc::SocketAddress& addr) { RTC_DCHECK(request->type() == STUN_BINDING_REQUEST); diff --git a/p2p/base/port.h b/p2p/base/port.h index 2957fd8b74..e56afc4d7e 100644 --- a/p2p/base/port.h +++ b/p2p/base/port.h @@ -254,6 +254,11 @@ class Port : public PortInterface, public rtc::MessageHandler, const rtc::SocketAddress& remote_addr, const rtc::PacketTime& packet_time); + // Shall the port handle packet from this |remote_addr|. + // This method is overridden by TurnPort. + virtual bool CanHandleIncomingPacketsFrom( + const rtc::SocketAddress& remote_addr) const; + // Sends a response message (normal or error) to the given request. One of // these methods should be called as a response to SignalUnknownAddress. // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse. diff --git a/p2p/base/stun.cc b/p2p/base/stun.cc index cad33af264..6e8f098268 100644 --- a/p2p/base/stun.cc +++ b/p2p/base/stun.cc @@ -92,6 +92,26 @@ void StunMessage::AddAttribute(std::unique_ptr attr) { attrs_.push_back(std::move(attr)); } +std::unique_ptr StunMessage::RemoveAttribute(int type) { + std::unique_ptr attribute; + for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) { + if ((* it)->type() == type) { + attribute = std::move(* it); + attrs_.erase(std::next(it).base()); + break; + } + } + if (attribute) { + attribute->SetOwner(nullptr); + size_t attr_length = attribute->length(); + if (attr_length % 4 != 0) { + attr_length += (4 - (attr_length % 4)); + } + length_ -= static_cast(attr_length + 4); + } + return attribute; +} + const StunAddressAttribute* StunMessage::GetAddress(int type) const { switch (type) { case STUN_ATTR_MAPPED_ADDRESS: { @@ -984,6 +1004,35 @@ bool ComputeStunCredentialHash(const std::string& username, return true; } +std::unique_ptr CopyStunAttribute( + const StunAttribute& attribute, + rtc::ByteBufferWriter* tmp_buffer_ptr) { + ByteBufferWriter tmpBuffer; + if (tmp_buffer_ptr == nullptr) { + tmp_buffer_ptr = &tmpBuffer; + } + + std::unique_ptr copy( + StunAttribute::Create(attribute.value_type(), + attribute.type(), + static_cast(attribute.length()), + nullptr)); + + if (!copy) { + return nullptr; + } + tmp_buffer_ptr->Clear(); + if (!attribute.Write(tmp_buffer_ptr)) { + return nullptr; + } + rtc::ByteBufferReader reader(*tmp_buffer_ptr); + if (!copy->Read(&reader)) { + return nullptr; + } + + return copy; +} + StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const { switch (type) { case STUN_ATTR_LIFETIME: diff --git a/p2p/base/stun.h b/p2p/base/stun.h index b576d3767d..a1cce87769 100644 --- a/p2p/base/stun.h +++ b/p2p/base/stun.h @@ -165,6 +165,9 @@ class StunMessage { // Takes ownership of the specified attribute and adds it to the message. void AddAttribute(std::unique_ptr attr); + // Remove the last occurrence of an attribute. + std::unique_ptr RemoveAttribute(int type); + // Validates that a raw STUN message has a correct MESSAGE-INTEGRITY value. // This can't currently be done on a StunMessage, since it is affected by // padding data (which we discard when reading a StunMessage). @@ -477,6 +480,18 @@ bool IsStunErrorResponseType(int msg_type); bool ComputeStunCredentialHash(const std::string& username, const std::string& realm, const std::string& password, std::string* hash); +// Make a copy af |attribute| and return a new StunAttribute. +// This is useful if you don't care about what kind of attribute you +// are handling. +// +// The implementation copies by calling Write() followed by Read(). +// +// If |tmp_buffer| is supplied this buffer will be used, otherwise +// a buffer will created in the method. +std::unique_ptr CopyStunAttribute( + const StunAttribute& attribute, + rtc::ByteBufferWriter* tmp_buffer_ptr = 0); + // TODO(?): Move the TURN/ICE stuff below out to separate files. extern const char TURN_MAGIC_COOKIE_VALUE[4]; diff --git a/p2p/base/stun_unittest.cc b/p2p/base/stun_unittest.cc index 9d418c4a00..5c805dc770 100644 --- a/p2p/base/stun_unittest.cc +++ b/p2p/base/stun_unittest.cc @@ -1480,4 +1480,94 @@ TEST_F(StunTest, ReadRelayMessage) { EXPECT_EQ(0, memcmp(outstring2.c_str(), input, len2)); } +// Test that we can remove attribute from a message. +TEST_F(StunTest, RemoveAttribute) { + StunMessage msg; + + // Removing something that does exist should return nullptr. + EXPECT_EQ(msg.RemoveAttribute(STUN_ATTR_USERNAME), nullptr); + + { + auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME); + attr->CopyBytes("kes", sizeof("kes")); + msg.AddAttribute(std::move(attr)); + } + + size_t len = msg.length(); + { + auto attr = msg.RemoveAttribute(STUN_ATTR_USERNAME); + ASSERT_NE(attr, nullptr); + EXPECT_EQ(attr->type(), STUN_ATTR_USERNAME); + EXPECT_STREQ("kes", + static_cast(attr.get())->bytes()); + EXPECT_LT(msg.length(), len); + } + + // Now add same attribute type twice. + { + auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME); + attr->CopyBytes("kes", sizeof("kes")); + msg.AddAttribute(std::move(attr)); + } + + { + auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME); + attr->CopyBytes("kenta", sizeof("kenta")); + msg.AddAttribute(std::move(attr)); + } + + // Remove should remove the last added occurrence. + { + auto attr = msg.RemoveAttribute(STUN_ATTR_USERNAME); + ASSERT_NE(attr, nullptr); + EXPECT_EQ(attr->type(), STUN_ATTR_USERNAME); + EXPECT_STREQ("kenta", + static_cast(attr.get())->bytes()); + } + + // Remove should remove the last added occurrence. + { + auto attr = msg.RemoveAttribute(STUN_ATTR_USERNAME); + ASSERT_NE(attr, nullptr); + EXPECT_EQ(attr->type(), STUN_ATTR_USERNAME); + EXPECT_STREQ("kes", + static_cast(attr.get())->bytes()); + } + + // Removing something that does exist should return nullptr. + EXPECT_EQ(msg.RemoveAttribute(STUN_ATTR_USERNAME), nullptr); +} + +// Test CopyStunAttribute +TEST_F(StunTest, CopyAttribute) { + rtc::ByteBufferWriter buf; + rtc::ByteBufferWriter* buffer_ptrs[] = { &buf, nullptr }; + // Test both with and without supplied ByteBufferWriter. + for (auto buffer_ptr : buffer_ptrs) { + { // Test StunByteStringAttribute. + auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME); + attr->CopyBytes("kes", sizeof("kes")); + + auto copy = CopyStunAttribute(*attr.get(), buffer_ptr); + ASSERT_EQ(copy->value_type(), STUN_VALUE_BYTE_STRING); + EXPECT_STREQ("kes", + static_cast(copy.get())->bytes()); + } + + { // Test StunAddressAttribute. + rtc::IPAddress test_ip(kIPv6TestAddress2); + auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); + rtc::SocketAddress test_addr(test_ip, kTestMessagePort2); + addr->SetAddress(test_addr); + CheckStunAddressAttribute(addr.get(), + STUN_ADDRESS_IPV6, kTestMessagePort2, test_ip); + + auto copy = CopyStunAttribute(*addr.get(), buffer_ptr); + ASSERT_EQ(copy->value_type(), STUN_VALUE_ADDRESS); + CheckStunAddressAttribute(static_cast(copy.get()), + STUN_ADDRESS_IPV6, kTestMessagePort2, test_ip); + } + } +} + } // namespace cricket diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc index e67682430a..285d41bf39 100644 --- a/p2p/base/turnport.cc +++ b/p2p/base/turnport.cc @@ -523,7 +523,11 @@ Connection* TurnPort::CreateConnection(const Candidate& remote_candidate, remote_candidate.address().family()) { // Create an entry, if needed, so we can get our permissions set up // correctly. - CreateOrRefreshEntry(remote_candidate.address()); + if (CreateOrRefreshEntry(remote_candidate.address(), + next_channel_number_)) { + // An entry was created. + next_channel_number_++; + } ProxyConnection* conn = new ProxyConnection(this, index, remote_candidate); AddOrReplaceConnection(conn); @@ -596,6 +600,11 @@ int TurnPort::SendTo(const void* data, size_t size, return static_cast(size); } +bool TurnPort::CanHandleIncomingPacketsFrom( + const rtc::SocketAddress& addr) const { + return server_address_.address == addr; +} + bool TurnPort::HandleIncomingPacket(rtc::AsyncPacketSocket* socket, const char* data, size_t size, const rtc::SocketAddress& remote_addr, @@ -1070,11 +1079,13 @@ bool TurnPort::EntryExists(TurnEntry* e) { return it != entries_.end(); } -void TurnPort::CreateOrRefreshEntry(const rtc::SocketAddress& addr) { +bool TurnPort::CreateOrRefreshEntry(const rtc::SocketAddress& addr, + int channel_number) { TurnEntry* entry = FindEntry(addr); if (entry == nullptr) { - entry = new TurnEntry(this, next_channel_number_++, addr); + entry = new TurnEntry(this, channel_number, addr); entries_.push_back(entry); + return true; } else { if (entry->destruction_timestamp()) { // Destruction should have only been scheduled (indicated by @@ -1092,6 +1103,7 @@ void TurnPort::CreateOrRefreshEntry(const rtc::SocketAddress& addr) { RTC_DCHECK(GetConnection(addr)); } } + return false; } void TurnPort::DestroyEntry(TurnEntry* entry) { diff --git a/p2p/base/turnport.h b/p2p/base/turnport.h index 8246b43df6..4ee5f891fa 100644 --- a/p2p/base/turnport.h +++ b/p2p/base/turnport.h @@ -124,6 +124,8 @@ class TurnPort : public Port { size_t size, const rtc::SocketAddress& remote_addr, const rtc::PacketTime& packet_time) override; + bool CanHandleIncomingPacketsFrom( + const rtc::SocketAddress& addr) const override; virtual void OnReadPacket(rtc::AsyncPacketSocket* socket, const char* data, size_t size, const rtc::SocketAddress& remote_addr, @@ -175,6 +177,8 @@ class TurnPort : public Port { // Shuts down the turn port, usually because of some fatal errors. void Close(); + void HandleConnectionDestroyed(Connection* conn) override; + protected: TurnPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, @@ -203,6 +207,11 @@ class TurnPort : public Port { const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer); + // NOTE: This method needs to be accessible for StacPort + // return true if entry was created (i.e channel_number consumed). + bool CreateOrRefreshEntry(const rtc::SocketAddress& addr, + int channel_number); + private: enum { MSG_ALLOCATE_ERROR = MSG_FIRST_AVAILABLE, @@ -216,7 +225,6 @@ class TurnPort : public Port { typedef std::set AttemptedServerSet; void OnMessage(rtc::Message* pmsg) override; - void HandleConnectionDestroyed(Connection* conn) override; bool CreateTurnClientSocket(); @@ -264,7 +272,6 @@ class TurnPort : public Port { TurnEntry* FindEntry(const rtc::SocketAddress& address) const; TurnEntry* FindEntry(int channel_id) const; bool EntryExists(TurnEntry* e); - void CreateOrRefreshEntry(const rtc::SocketAddress& address); void DestroyEntry(TurnEntry* entry); // Destroys the entry only if |timestamp| matches the destruction timestamp // in |entry|. diff --git a/p2p/client/basicportallocator.cc b/p2p/client/basicportallocator.cc index b3b9e7347a..5f27a7db99 100644 --- a/p2p/client/basicportallocator.cc +++ b/p2p/client/basicportallocator.cc @@ -100,8 +100,11 @@ const uint32_t DISABLE_ALL_PHASES = BasicPortAllocator::BasicPortAllocator( rtc::NetworkManager* network_manager, rtc::PacketSocketFactory* socket_factory, - webrtc::TurnCustomizer* customizer) + webrtc::TurnCustomizer* customizer, + RelayPortFactoryInterface* relay_port_factory) : network_manager_(network_manager), socket_factory_(socket_factory) { + InitRelayPortFactory(relay_port_factory); + RTC_DCHECK(relay_port_factory_ != nullptr); RTC_DCHECK(network_manager_ != nullptr); RTC_DCHECK(socket_factory_ != nullptr); SetConfiguration(ServerAddresses(), std::vector(), @@ -109,16 +112,22 @@ BasicPortAllocator::BasicPortAllocator( Construct(); } -BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager) +BasicPortAllocator::BasicPortAllocator( + rtc::NetworkManager* network_manager) : network_manager_(network_manager), socket_factory_(nullptr) { + InitRelayPortFactory(nullptr); + RTC_DCHECK(relay_port_factory_ != nullptr); RTC_DCHECK(network_manager_ != nullptr); Construct(); } -BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager, - rtc::PacketSocketFactory* socket_factory, - const ServerAddresses& stun_servers) +BasicPortAllocator::BasicPortAllocator( + rtc::NetworkManager* network_manager, + rtc::PacketSocketFactory* socket_factory, + const ServerAddresses& stun_servers) : network_manager_(network_manager), socket_factory_(socket_factory) { + InitRelayPortFactory(nullptr); + RTC_DCHECK(relay_port_factory_ != nullptr); RTC_DCHECK(socket_factory_ != NULL); SetConfiguration(stun_servers, std::vector(), 0, false, nullptr); @@ -132,6 +141,9 @@ BasicPortAllocator::BasicPortAllocator( const rtc::SocketAddress& relay_address_tcp, const rtc::SocketAddress& relay_address_ssl) : network_manager_(network_manager), socket_factory_(NULL) { + InitRelayPortFactory(nullptr); + RTC_DCHECK(relay_port_factory_ != nullptr); + RTC_DCHECK(network_manager_ != nullptr); std::vector turn_servers; RelayServerConfig config(RELAY_GTURN); if (!relay_address_udp.IsNil()) { @@ -204,6 +216,16 @@ void BasicPortAllocator::AddTurnServer(const RelayServerConfig& turn_server) { prune_turn_ports(), turn_customizer()); } +void BasicPortAllocator::InitRelayPortFactory( + RelayPortFactoryInterface* relay_port_factory) { + if (relay_port_factory != nullptr) { + relay_port_factory_ = relay_port_factory; + } else { + default_relay_port_factory_.reset(new TurnPortFactory()); + relay_port_factory_ = default_relay_port_factory_.get(); + } +} + // BasicPortAllocatorSession BasicPortAllocatorSession::BasicPortAllocatorSession( BasicPortAllocator* allocator, @@ -1107,7 +1129,7 @@ void AllocationSequence::Init() { void AllocationSequence::Clear() { udp_port_ = NULL; - turn_ports_.clear(); + relay_ports_.clear(); } void AllocationSequence::OnNetworkFailed() { @@ -1387,8 +1409,6 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) { PortList::const_iterator relay_port; for (relay_port = config.ports.begin(); relay_port != config.ports.end(); ++relay_port) { - TurnPort* port = NULL; - // Skip UDP connections to relay servers if it's disallowed. if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP_RELAY) && relay_port->proto == PROTO_UDP) { @@ -1407,35 +1427,53 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) { continue; } + CreateRelayPortArgs args; + args.network_thread = session_->network_thread(); + args.socket_factory = session_->socket_factory(); + args.network = network_; + args.username = session_->username(); + args.password = session_->password(); + args.server_address = &(*relay_port); + args.config = &config; + args.origin = session_->allocator()->origin(); + args.turn_customizer = session_->allocator()->turn_customizer(); + + std::unique_ptr port; // Shared socket mode must be enabled only for UDP based ports. Hence // don't pass shared socket for ports which will create TCP sockets. // TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled // due to webrtc bug https://code.google.com/p/webrtc/issues/detail?id=3537 if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && relay_port->proto == PROTO_UDP && udp_socket_) { - port = TurnPort::Create(session_->network_thread(), - session_->socket_factory(), - network_, udp_socket_.get(), - session_->username(), session_->password(), - *relay_port, config.credentials, config.priority, - session_->allocator()->origin(), - session_->allocator()->turn_customizer()); - turn_ports_.push_back(port); + port = session_->allocator()->relay_port_factory()->Create( + args, udp_socket_.get()); + + if (!port) { + RTC_LOG(LS_WARNING) + << "Failed to create relay port with " + << args.server_address->address.ToString(); + continue; + } + + relay_ports_.push_back(port.get()); // Listen to the port destroyed signal, to allow AllocationSequence to // remove entrt from it's map. port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed); } else { - port = TurnPort::Create( - session_->network_thread(), session_->socket_factory(), network_, - session_->allocator()->min_port(), session_->allocator()->max_port(), - session_->username(), session_->password(), *relay_port, - config.credentials, config.priority, session_->allocator()->origin(), - config.tls_alpn_protocols, config.tls_elliptic_curves, - session_->allocator()->turn_customizer()); + port = session_->allocator()->relay_port_factory()->Create( + args, + session_->allocator()->min_port(), + session_->allocator()->max_port()); + + if (!port) { + RTC_LOG(LS_WARNING) + << "Failed to create relay port with " + << args.server_address->address.ToString(); + continue; + } } RTC_DCHECK(port != NULL); - port->SetTlsCertPolicy(config.tls_cert_policy); - session_->AddAllocatedPort(port, this, true); + session_->AddAllocatedPort(port.release(), this, true); } } @@ -1453,8 +1491,8 @@ void AllocationSequence::OnReadPacket( // a STUN binding response, so we pass the message to TurnPort regardless of // the message type. The TurnPort will just ignore the message since it will // not find any request by transaction ID. - for (TurnPort* port : turn_ports_) { - if (port->server_address().address == remote_addr) { + for (auto* port : relay_ports_) { + if (port->CanHandleIncomingPacketsFrom(remote_addr)) { if (port->HandleIncomingPacket(socket, data, size, remote_addr, packet_time)) { return; @@ -1483,9 +1521,9 @@ void AllocationSequence::OnPortDestroyed(PortInterface* port) { return; } - auto it = std::find(turn_ports_.begin(), turn_ports_.end(), port); - if (it != turn_ports_.end()) { - turn_ports_.erase(it); + auto it = std::find(relay_ports_.begin(), relay_ports_.end(), port); + if (it != relay_ports_.end()) { + relay_ports_.erase(it); } else { RTC_LOG(LS_ERROR) << "Unexpected OnPortDestroyed for nonexistent port."; RTC_NOTREACHED(); diff --git a/p2p/client/basicportallocator.h b/p2p/client/basicportallocator.h index f5cc1d16a6..23faff1cba 100644 --- a/p2p/client/basicportallocator.h +++ b/p2p/client/basicportallocator.h @@ -17,6 +17,8 @@ #include "api/turncustomizer.h" #include "p2p/base/portallocator.h" +#include "p2p/client/turnportfactory.h" +#include "p2p/client/relayportfactoryinterface.h" #include "rtc_base/checks.h" #include "rtc_base/messagequeue.h" #include "rtc_base/network.h" @@ -26,18 +28,21 @@ namespace cricket { class BasicPortAllocator : public PortAllocator { public: + // note: The (optional) relay_port_factory is owned by caller + // and must have a life time that exceeds that of BasicPortAllocator. BasicPortAllocator(rtc::NetworkManager* network_manager, rtc::PacketSocketFactory* socket_factory, - webrtc::TurnCustomizer* customizer = nullptr); + webrtc::TurnCustomizer* customizer = nullptr, + RelayPortFactoryInterface* relay_port_factory = nullptr); explicit BasicPortAllocator(rtc::NetworkManager* network_manager); BasicPortAllocator(rtc::NetworkManager* network_manager, rtc::PacketSocketFactory* socket_factory, const ServerAddresses& stun_servers); BasicPortAllocator(rtc::NetworkManager* network_manager, const ServerAddresses& stun_servers, - const rtc::SocketAddress& relay_server_udp, - const rtc::SocketAddress& relay_server_tcp, - const rtc::SocketAddress& relay_server_ssl); + const rtc::SocketAddress& relay_address_udp, + const rtc::SocketAddress& relay_address_tcp, + const rtc::SocketAddress& relay_address_ssl); ~BasicPortAllocator() override; // Set to kDefaultNetworkIgnoreMask by default. @@ -59,16 +64,29 @@ class BasicPortAllocator : public PortAllocator { // Convenience method that adds a TURN server to the configuration. void AddTurnServer(const RelayServerConfig& turn_server); + RelayPortFactoryInterface* relay_port_factory() { + return relay_port_factory_; + } + private: void Construct(); void OnIceRegathering(PortAllocatorSession* session, IceRegatheringReason reason); + // This function makes sure that relay_port_factory_ is set properly. + void InitRelayPortFactory(RelayPortFactoryInterface* relay_port_factory); + rtc::NetworkManager* network_manager_; rtc::PacketSocketFactory* socket_factory_; bool allow_tcp_listen_; int network_ignore_mask_ = rtc::kDefaultNetworkIgnoreMask; + + // This is the factory being used. + RelayPortFactoryInterface* relay_port_factory_; + + // This instance is created if caller does pass a factory. + std::unique_ptr default_relay_port_factory_; }; struct PortConfiguration; @@ -369,7 +387,7 @@ class AllocationSequence : public rtc::MessageHandler, std::unique_ptr udp_socket_; // There will be only one udp port per AllocationSequence. UDPPort* udp_port_; - std::vector turn_ports_; + std::vector relay_ports_; int phase_; }; diff --git a/p2p/client/relayportfactoryinterface.h b/p2p/client/relayportfactoryinterface.h new file mode 100644 index 0000000000..5890bcd9bd --- /dev/null +++ b/p2p/client/relayportfactoryinterface.h @@ -0,0 +1,72 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef P2P_CLIENT_RELAYPORTFACTORYINTERFACE_H_ +#define P2P_CLIENT_RELAYPORTFACTORYINTERFACE_H_ + +#include +#include + +#include "p2p/base/portinterface.h" +#include "rtc_base/refcount.h" + +namespace rtc { +class AsyncPacketSocket; +class Network; +class PacketSocketFactory; +class Thread; +} // namespace rtc + +namespace webrtc { +class TurnCustomizer; +} // namespace webrtc + +namespace cricket { +class Port; +struct ProtocolAddress; +struct RelayServerConfig; + +// A struct containing arguments to RelayPortFactory::Create() +struct CreateRelayPortArgs { + CreateRelayPortArgs(); + rtc::Thread* network_thread; + rtc::PacketSocketFactory* socket_factory; + rtc::Network* network; + const ProtocolAddress* server_address; + const RelayServerConfig* config; + std::string username; + std::string password; + std::string origin; + webrtc::TurnCustomizer* turn_customizer; +}; + +inline CreateRelayPortArgs::CreateRelayPortArgs() {} + +// A factory for creating RelayPort's. +class RelayPortFactoryInterface { + public: + virtual ~RelayPortFactoryInterface() {} + + // This variant is used for UDP connection to the relay server + // using a already existing shared socket. + virtual std::unique_ptr Create( + const CreateRelayPortArgs& args, + rtc::AsyncPacketSocket* udp_socket) = 0; + + // This variant is used for the other cases. + virtual std::unique_ptr Create( + const CreateRelayPortArgs& args, + int min_port, + int max_port) = 0; +}; + +} // namespace cricket + +#endif // P2P_CLIENT_RELAYPORTFACTORYINTERFACE_H_ diff --git a/p2p/client/turnportfactory.cc b/p2p/client/turnportfactory.cc new file mode 100644 index 0000000000..9f24f5f4b6 --- /dev/null +++ b/p2p/client/turnportfactory.cc @@ -0,0 +1,66 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "p2p/client/turnportfactory.h" + +#include + +#include "p2p/base/turnport.h" + +namespace cricket { + +TurnPortFactory::~TurnPortFactory() { +} + +std::unique_ptr TurnPortFactory::Create( + const CreateRelayPortArgs& args, + rtc::AsyncPacketSocket* udp_socket) { + + TurnPort* port = TurnPort::Create( + args.network_thread, + args.socket_factory, + args.network, + udp_socket, + args.username, + args.password, + *args.server_address, + args.config->credentials, + args.config->priority, + args.origin, + args.turn_customizer); + port->SetTlsCertPolicy(args.config->tls_cert_policy); + return std::unique_ptr(port); +} + +std::unique_ptr TurnPortFactory::Create( + const CreateRelayPortArgs& args, + int min_port, + int max_port) { + + TurnPort* port = TurnPort::Create( + args.network_thread, + args.socket_factory, + args.network, + min_port, + max_port, + args.username, + args.password, + *args.server_address, + args.config->credentials, + args.config->priority, + args.origin, + args.config->tls_alpn_protocols, + args.config->tls_elliptic_curves, + args.turn_customizer); + port->SetTlsCertPolicy(args.config->tls_cert_policy); + return std::unique_ptr(port); +} + +} // namespace cricket diff --git a/p2p/client/turnportfactory.h b/p2p/client/turnportfactory.h new file mode 100644 index 0000000000..d5c510b83f --- /dev/null +++ b/p2p/client/turnportfactory.h @@ -0,0 +1,37 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef P2P_CLIENT_TURNPORTFACTORY_H_ +#define P2P_CLIENT_TURNPORTFACTORY_H_ + +#include + +#include "p2p/client/relayportfactoryinterface.h" + +namespace cricket { + +// This is a RelayPortFactory that produces TurnPorts. +class TurnPortFactory : public RelayPortFactoryInterface { + public: + ~TurnPortFactory() override; + + std::unique_ptr Create( + const CreateRelayPortArgs& args, + rtc::AsyncPacketSocket* udp_socket) override; + + std::unique_ptr Create( + const CreateRelayPortArgs& args, + int min_port, + int max_port) override; +}; + +} // namespace cricket + +#endif // P2P_CLIENT_TURNPORTFACTORY_H_