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 <guidou@webrtc.org>
Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21345}
diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn
index 8e61730..cd54b7d 100644
--- a/p2p/BUILD.gn
+++ b/p2p/BUILD.gn
@@ -81,8 +81,11 @@
     "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 66685ec..af96582 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -621,6 +621,10 @@
   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 2957fd8..e56afc4 100644
--- a/p2p/base/port.h
+++ b/p2p/base/port.h
@@ -254,6 +254,11 @@
                                     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 cad33af..6e8f098 100644
--- a/p2p/base/stun.cc
+++ b/p2p/base/stun.cc
@@ -92,6 +92,26 @@
   attrs_.push_back(std::move(attr));
 }
 
+std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
+  std::unique_ptr<StunAttribute> 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<uint16_t>(attr_length + 4);
+  }
+  return attribute;
+}
+
 const StunAddressAttribute* StunMessage::GetAddress(int type) const {
   switch (type) {
     case STUN_ATTR_MAPPED_ADDRESS: {
@@ -984,6 +1004,35 @@
   return true;
 }
 
+std::unique_ptr<StunAttribute> CopyStunAttribute(
+    const StunAttribute& attribute,
+    rtc::ByteBufferWriter* tmp_buffer_ptr) {
+  ByteBufferWriter tmpBuffer;
+  if (tmp_buffer_ptr == nullptr) {
+    tmp_buffer_ptr = &tmpBuffer;
+  }
+
+  std::unique_ptr<StunAttribute> copy(
+      StunAttribute::Create(attribute.value_type(),
+                            attribute.type(),
+                            static_cast<uint16_t>(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 b576d37..a1cce87 100644
--- a/p2p/base/stun.h
+++ b/p2p/base/stun.h
@@ -165,6 +165,9 @@
   // Takes ownership of the specified attribute and adds it to the message.
   void AddAttribute(std::unique_ptr<StunAttribute> attr);
 
+  // Remove the last occurrence of an attribute.
+  std::unique_ptr<StunAttribute> 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 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<StunAttribute> 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 9d418c4..5c805dc 100644
--- a/p2p/base/stun_unittest.cc
+++ b/p2p/base/stun_unittest.cc
@@ -1480,4 +1480,94 @@
   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<StunByteStringAttribute*>(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<StunByteStringAttribute*>(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<StunByteStringAttribute*>(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<StunByteStringAttribute*>(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<StunAddressAttribute*>(copy.get()),
+                                STUN_ADDRESS_IPV6, kTestMessagePort2, test_ip);
+    }
+  }
+}
+
 }  // namespace cricket
diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc
index e676824..285d41b 100644
--- a/p2p/base/turnport.cc
+++ b/p2p/base/turnport.cc
@@ -523,7 +523,11 @@
             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 @@
   return static_cast<int>(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 @@
   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 @@
       RTC_DCHECK(GetConnection(addr));
     }
   }
+  return false;
 }
 
 void TurnPort::DestroyEntry(TurnEntry* entry) {
diff --git a/p2p/base/turnport.h b/p2p/base/turnport.h
index 8246b43..4ee5f89 100644
--- a/p2p/base/turnport.h
+++ b/p2p/base/turnport.h
@@ -124,6 +124,8 @@
                             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 @@
   // 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 @@
            const std::vector<std::string>& 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 @@
   typedef std::set<rtc::SocketAddress> AttemptedServerSet;
 
   void OnMessage(rtc::Message* pmsg) override;
-  void HandleConnectionDestroyed(Connection* conn) override;
 
   bool CreateTurnClientSocket();
 
@@ -264,7 +272,6 @@
   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 b3b9e73..5f27a7d 100644
--- a/p2p/client/basicportallocator.cc
+++ b/p2p/client/basicportallocator.cc
@@ -100,8 +100,11 @@
 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<RelayServerConfig>(),
@@ -109,16 +112,22 @@
   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<RelayServerConfig>(), 0, false,
                    nullptr);
@@ -132,6 +141,9 @@
     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<RelayServerConfig> turn_servers;
   RelayServerConfig config(RELAY_GTURN);
   if (!relay_address_udp.IsNil()) {
@@ -204,6 +216,16 @@
                    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::Clear() {
   udp_port_ = NULL;
-  turn_ports_.clear();
+  relay_ports_.clear();
 }
 
 void AllocationSequence::OnNetworkFailed() {
@@ -1387,8 +1409,6 @@
   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 @@
       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<cricket::Port> 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 @@
   // 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 @@
     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 f5cc1d1..23faff1 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 @@
 
 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 @@
   // 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<RelayPortFactoryInterface> default_relay_port_factory_;
 };
 
 struct PortConfiguration;
@@ -369,7 +387,7 @@
   std::unique_ptr<rtc::AsyncPacketSocket> udp_socket_;
   // There will be only one udp port per AllocationSequence.
   UDPPort* udp_port_;
-  std::vector<TurnPort*> turn_ports_;
+  std::vector<Port*> relay_ports_;
   int phase_;
 };
 
diff --git a/p2p/client/relayportfactoryinterface.h b/p2p/client/relayportfactoryinterface.h
new file mode 100644
index 0000000..5890bcd
--- /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 <memory>
+#include <string>
+
+#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<Port> Create(
+      const CreateRelayPortArgs& args,
+      rtc::AsyncPacketSocket* udp_socket) = 0;
+
+  // This variant is used for the other cases.
+  virtual std::unique_ptr<Port> 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 0000000..9f24f5f
--- /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 <memory>
+
+#include "p2p/base/turnport.h"
+
+namespace cricket {
+
+TurnPortFactory::~TurnPortFactory() {
+}
+
+std::unique_ptr<Port> 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>(port);
+}
+
+std::unique_ptr<Port> 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>(port);
+}
+
+}  // namespace cricket
diff --git a/p2p/client/turnportfactory.h b/p2p/client/turnportfactory.h
new file mode 100644
index 0000000..d5c510b
--- /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 <memory>
+
+#include "p2p/client/relayportfactoryinterface.h"
+
+namespace cricket {
+
+// This is a RelayPortFactory that produces TurnPorts.
+class TurnPortFactory : public RelayPortFactoryInterface {
+ public:
+  ~TurnPortFactory() override;
+
+  std::unique_ptr<Port> Create(
+      const CreateRelayPortArgs& args,
+      rtc::AsyncPacketSocket* udp_socket) override;
+
+  std::unique_ptr<Port> Create(
+      const CreateRelayPortArgs& args,
+      int min_port,
+      int max_port) override;
+};
+
+}  // namespace cricket
+
+#endif  // P2P_CLIENT_TURNPORTFACTORY_H_