Adding OrtcFactory, and changing UdpTransport to match current plan.
The factory follows the same principles as PeerConnectionFactory;
various modules can be passed into its constructor but default
implementations are provided. Currently the only object the factory can
create is a UdpTransport (need to start somewhere).
UdpTransportChannel (renamed to UdpTransport)
will now accept a socket passed into its constructor,
relying on the factory to create the socket. This allows some
simplifications to be made, such as getting rid of "State" since the
only states are now "has destination set or doesn't".
BUG=webrtc:7013
Review-Url: https://codereview.webrtc.org/2632613002
Cr-Commit-Position: refs/heads/master@{#16154}
diff --git a/webrtc/api/BUILD.gn b/webrtc/api/BUILD.gn
index 149fd51..fa3c629 100644
--- a/webrtc/api/BUILD.gn
+++ b/webrtc/api/BUILD.gn
@@ -75,6 +75,9 @@
"mediastreamtrack.h",
"mediastreamtrackproxy.h",
"notifier.h",
+ "ortcfactory.cc",
+ "ortcfactory.h",
+ "ortcfactoryinterface.h",
"peerconnection.cc",
"peerconnection.h",
"peerconnectionfactory.cc",
@@ -103,6 +106,7 @@
"streamcollection.h",
"trackmediainfomap.cc",
"trackmediainfomap.h",
+ "udptransportinterface.h",
"videocapturertracksource.cc",
"videocapturertracksource.h",
"videosourceproxy.h",
@@ -236,6 +240,7 @@
"localaudiosource_unittest.cc",
"mediaconstraintsinterface_unittest.cc",
"mediastream_unittest.cc",
+ "ortcfactory_unittest.cc",
"peerconnection_unittest.cc",
"peerconnectionendtoend_unittest.cc",
"peerconnectionfactory_unittest.cc",
diff --git a/webrtc/api/ortcfactory.cc b/webrtc/api/ortcfactory.cc
new file mode 100644
index 0000000..ba41a03
--- /dev/null
+++ b/webrtc/api/ortcfactory.cc
@@ -0,0 +1,119 @@
+/*
+ * 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 "webrtc/api/ortcfactory.h"
+
+#include <string>
+#include <utility> // For std::move.
+
+#include "webrtc/base/bind.h"
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/udptransport.h"
+
+namespace webrtc {
+
+// static
+std::unique_ptr<OrtcFactoryInterface> OrtcFactoryInterface::Create(
+ rtc::Thread* network_thread,
+ rtc::Thread* signaling_thread,
+ rtc::NetworkManager* network_manager,
+ rtc::PacketSocketFactory* socket_factory) {
+ // Hop to signaling thread if needed.
+ if (signaling_thread && !signaling_thread->IsCurrent()) {
+ return signaling_thread->Invoke<std::unique_ptr<OrtcFactoryInterface>>(
+ RTC_FROM_HERE,
+ rtc::Bind(&OrtcFactoryInterface::Create, network_thread,
+ signaling_thread, network_manager, socket_factory));
+ }
+ OrtcFactory* new_factory =
+ new OrtcFactory(network_thread, signaling_thread,
+ network_manager, socket_factory);
+ // Return a proxy so that any calls on the returned object (including
+ // destructor) happen on the signaling thread.
+ return OrtcFactoryProxy::Create(new_factory->signaling_thread(),
+ new_factory->network_thread(), new_factory);
+}
+
+OrtcFactory::OrtcFactory(rtc::Thread* network_thread,
+ rtc::Thread* signaling_thread,
+ rtc::NetworkManager* network_manager,
+ rtc::PacketSocketFactory* socket_factory)
+ : network_thread_(network_thread),
+ signaling_thread_(signaling_thread),
+ network_manager_(network_manager),
+ socket_factory_(socket_factory) {
+ if (!network_thread_) {
+ owned_network_thread_ = rtc::Thread::CreateWithSocketServer();
+ owned_network_thread_->Start();
+ network_thread_ = owned_network_thread_.get();
+ }
+
+ // The worker thread is created internally because it's an implementation
+ // detail, and consumers of the API don't need to really know about it.
+ owned_worker_thread_ = rtc::Thread::Create();
+ owned_worker_thread_->Start();
+
+ if (signaling_thread_) {
+ RTC_DCHECK_RUN_ON(signaling_thread_);
+ } else {
+ signaling_thread_ = rtc::Thread::Current();
+ if (!signaling_thread_) {
+ // If this thread isn't already wrapped by an rtc::Thread, create a
+ // wrapper and own it in this class.
+ signaling_thread_ = rtc::ThreadManager::Instance()->WrapCurrentThread();
+ wraps_signaling_thread_ = true;
+ }
+ }
+ if (!network_manager_) {
+ owned_network_manager_.reset(new rtc::BasicNetworkManager());
+ network_manager_ = owned_network_manager_.get();
+ }
+ if (!socket_factory_) {
+ owned_socket_factory_.reset(
+ new rtc::BasicPacketSocketFactory(network_thread_));
+ socket_factory_ = owned_socket_factory_.get();
+ }
+}
+
+OrtcFactory::~OrtcFactory() {
+ RTC_DCHECK_RUN_ON(signaling_thread_);
+ if (wraps_signaling_thread_) {
+ rtc::ThreadManager::Instance()->UnwrapCurrentThread();
+ }
+}
+
+std::unique_ptr<UdpTransportInterface> OrtcFactory::CreateUdpTransport(
+ int family,
+ uint16_t min_port,
+ uint16_t max_port) {
+ if (!network_thread_->IsCurrent()) {
+ RTC_DCHECK_RUN_ON(signaling_thread_);
+ return network_thread_->Invoke<std::unique_ptr<UdpTransportInterface>>(
+ RTC_FROM_HERE, rtc::Bind(&OrtcFactory::CreateUdpTransport, this, family,
+ min_port, max_port));
+ }
+ std::unique_ptr<rtc::AsyncPacketSocket> socket(
+ socket_factory_->CreateUdpSocket(
+ rtc::SocketAddress(rtc::GetAnyIP(family), 0), min_port, max_port));
+ if (!socket) {
+ LOG(LS_WARNING) << "Local socket allocation failure.";
+ return nullptr;
+ }
+ LOG(LS_INFO) << "Created UDP socket with address "
+ << socket->GetLocalAddress().ToSensitiveString() << ".";
+ // Use proxy so that calls to the returned object are invoked on the network
+ // thread.
+ return UdpTransportProxy::Create(
+ signaling_thread_, network_thread_,
+ new cricket::UdpTransport(std::string(), std::move(socket)));
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/ortcfactory.h b/webrtc/api/ortcfactory.h
new file mode 100644
index 0000000..dc92774
--- /dev/null
+++ b/webrtc/api/ortcfactory.h
@@ -0,0 +1,64 @@
+/*
+ * 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 WEBRTC_API_ORTCFACTORY_H_
+#define WEBRTC_API_ORTCFACTORY_H_
+
+#include <memory>
+
+#include "webrtc/api/ortcfactoryinterface.h"
+#include "webrtc/base/constructormagic.h"
+
+namespace webrtc {
+
+// Implementation of OrtcFactoryInterface.
+//
+// See ortcfactoryinterface.h for documentation.
+class OrtcFactory : public OrtcFactoryInterface {
+ public:
+ OrtcFactory(rtc::Thread* network_thread,
+ rtc::Thread* signaling_thread,
+ rtc::NetworkManager* network_manager,
+ rtc::PacketSocketFactory* socket_factory);
+ ~OrtcFactory() override;
+ std::unique_ptr<UdpTransportInterface>
+ CreateUdpTransport(int family, uint16_t min_port, uint16_t max_port) override;
+
+ rtc::Thread* network_thread() { return network_thread_; }
+ rtc::Thread* worker_thread() { return owned_worker_thread_.get(); }
+ rtc::Thread* signaling_thread() { return signaling_thread_; }
+
+ private:
+ rtc::Thread* network_thread_;
+ rtc::Thread* signaling_thread_;
+ rtc::NetworkManager* network_manager_;
+ rtc::PacketSocketFactory* socket_factory_;
+ // If we created/own the objects above, these will be non-null and thus will
+ // be released automatically upon destruction.
+ std::unique_ptr<rtc::Thread> owned_network_thread_;
+ std::unique_ptr<rtc::Thread> owned_worker_thread_;
+ bool wraps_signaling_thread_ = false;
+ std::unique_ptr<rtc::NetworkManager> owned_network_manager_;
+ std::unique_ptr<rtc::PacketSocketFactory> owned_socket_factory_;
+ RTC_DISALLOW_COPY_AND_ASSIGN(OrtcFactory);
+};
+
+BEGIN_OWNED_PROXY_MAP(OrtcFactory)
+ PROXY_SIGNALING_THREAD_DESTRUCTOR()
+ PROXY_METHOD3(std::unique_ptr<UdpTransportInterface>,
+ CreateUdpTransport,
+ int,
+ uint16_t,
+ uint16_t)
+END_PROXY_MAP()
+
+} // namespace webrtc
+
+#endif // WEBRTC_API_ORTCFACTORY_H_
diff --git a/webrtc/api/ortcfactory_unittest.cc b/webrtc/api/ortcfactory_unittest.cc
new file mode 100644
index 0000000..21ad6f8
--- /dev/null
+++ b/webrtc/api/ortcfactory_unittest.cc
@@ -0,0 +1,122 @@
+/*
+ * 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 <memory>
+
+#include "webrtc/api/ortcfactoryinterface.h"
+#include "webrtc/base/fakenetwork.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/virtualsocketserver.h"
+#include "webrtc/p2p/base/udptransport.h"
+
+namespace {
+
+const int kDefaultTimeout = 10000; // 10 seconds.
+static const rtc::IPAddress kIPv4LocalHostAddress =
+ rtc::IPAddress(0x7F000001); // 127.0.0.1
+
+class PacketReceiver : public sigslot::has_slots<> {
+ public:
+ explicit PacketReceiver(rtc::PacketTransportInterface* transport) {
+ transport->SignalReadPacket.connect(this, &PacketReceiver::OnReadPacket);
+ }
+ int packets_read() const { return packets_read_; }
+
+ private:
+ void OnReadPacket(rtc::PacketTransportInterface*,
+ const char*,
+ size_t,
+ const rtc::PacketTime&,
+ int) {
+ ++packets_read_;
+ }
+
+ int packets_read_ = 0;
+};
+
+} // namespace
+
+namespace webrtc {
+
+// Used to test that things work end-to-end when using the default
+// implementations of threads/etc. provided by OrtcFactory, with the exception
+// of using a virtual network.
+//
+// By default, the virtual network manager doesn't enumerate any networks, but
+// sockets can still be created in this state.
+class OrtcFactoryTest : public testing::Test {
+ public:
+ OrtcFactoryTest()
+ : virtual_socket_server_(&physical_socket_server_),
+ network_thread_(&virtual_socket_server_),
+ ortc_factory_(OrtcFactoryInterface::Create(&network_thread_,
+ nullptr,
+ &fake_network_manager_,
+ nullptr)) {
+ // Sockets are bound to the ANY address, so this is needed to tell the
+ // virtual network which address to use in this case.
+ virtual_socket_server_.SetDefaultRoute(kIPv4LocalHostAddress);
+ network_thread_.Start();
+ }
+
+ protected:
+ rtc::PhysicalSocketServer physical_socket_server_;
+ rtc::VirtualSocketServer virtual_socket_server_;
+ rtc::Thread network_thread_;
+ rtc::FakeNetworkManager fake_network_manager_;
+ std::unique_ptr<OrtcFactoryInterface> ortc_factory_;
+};
+
+TEST_F(OrtcFactoryTest, EndToEndUdpTransport) {
+ std::unique_ptr<UdpTransportInterface> transport1 =
+ ortc_factory_->CreateUdpTransport(AF_INET);
+ std::unique_ptr<UdpTransportInterface> transport2 =
+ ortc_factory_->CreateUdpTransport(AF_INET);
+ ASSERT_NE(nullptr, transport1);
+ ASSERT_NE(nullptr, transport2);
+ // Sockets are bound to the ANY address, so we need to provide the IP address
+ // explicitly.
+ transport1->SetRemoteAddress(
+ rtc::SocketAddress(virtual_socket_server_.GetDefaultRoute(AF_INET),
+ transport2->GetLocalAddress().port()));
+ transport2->SetRemoteAddress(
+ rtc::SocketAddress(virtual_socket_server_.GetDefaultRoute(AF_INET),
+ transport1->GetLocalAddress().port()));
+
+ // TODO(deadbeef): Once there's something (RTP senders/receivers) that can
+ // use UdpTransport end-to-end, use that for this end-to-end test instead of
+ // making assumptions about the implementation.
+ //
+ // For now, this assumes the returned object is a UdpTransportProxy that wraps
+ // a UdpTransport.
+ cricket::UdpTransport* internal_transport1 =
+ static_cast<UdpTransportProxyWithInternal<cricket::UdpTransport>*>(
+ transport1.get())
+ ->internal();
+ cricket::UdpTransport* internal_transport2 =
+ static_cast<UdpTransportProxyWithInternal<cricket::UdpTransport>*>(
+ transport2.get())
+ ->internal();
+ // Need to call internal "SendPacket" method on network thread.
+ network_thread_.Invoke<void>(
+ RTC_FROM_HERE, [internal_transport1, internal_transport2]() {
+ PacketReceiver receiver1(internal_transport1);
+ PacketReceiver receiver2(internal_transport2);
+ internal_transport1->SendPacket("foo", sizeof("foo"),
+ rtc::PacketOptions(), 0);
+ internal_transport2->SendPacket("foo", sizeof("foo"),
+ rtc::PacketOptions(), 0);
+ EXPECT_EQ_WAIT(1, receiver1.packets_read(), kDefaultTimeout);
+ EXPECT_EQ_WAIT(1, receiver2.packets_read(), kDefaultTimeout);
+ });
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/ortcfactoryinterface.h b/webrtc/api/ortcfactoryinterface.h
new file mode 100644
index 0000000..8d46d68
--- /dev/null
+++ b/webrtc/api/ortcfactoryinterface.h
@@ -0,0 +1,81 @@
+/*
+ * 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 WEBRTC_API_ORTCFACTORYINTERFACE_H_
+#define WEBRTC_API_ORTCFACTORYINTERFACE_H_
+
+#include <memory>
+
+#include "webrtc/api/udptransportinterface.h"
+#include "webrtc/base/network.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/p2p/base/packetsocketfactory.h"
+
+namespace webrtc {
+
+// WARNING: This is experimental/under development, so use at your own risk; no
+// guarantee about API stability is guaranteed here yet.
+//
+// This class is the ORTC analog of PeerConnectionFactory. It acts as a factory
+// for ORTC objects that can be connected to each other.
+//
+// Some of these objects may not be represented by the ORTC specification, but
+// follow the same general principles.
+//
+// On object lifetimes: The factory must not be destroyed before destroying the
+// objects it created, and the objects passed into the factory must not be
+// destroyed before destroying the factory.
+class OrtcFactoryInterface {
+ public:
+ // |network_thread| is the thread on which packets are sent and received.
+ // If null, a new rtc::Thread with a default socket server is created.
+ //
+ // |signaling_thread| is used for callbacks to the consumer of the API. If
+ // null, the current thread will be used, which assumes that the API consumer
+ // is running a message loop on this thread (either using an existing
+ // rtc::Thread, or by calling rtc::Thread::Current()->ProcessMessages).
+ //
+ // |network_manager| is used to determine which network interfaces are
+ // available. This is used for ICE, for example. If null, a default
+ // implementation will be used. Only accessed on |network_thread|.
+ //
+ // |socket_factory| is used (on the network thread) for creating sockets. If
+ // it's null, a default implementation will be used, which assumes
+ // |network_thread| is a normal rtc::Thread.
+ //
+ // Note that the OrtcFactoryInterface does not take ownership of any of the
+ // objects
+ // passed in, and as previously stated, these objects can't be destroyed
+ // before the factory is.
+ static std::unique_ptr<OrtcFactoryInterface> Create(
+ rtc::Thread* network_thread,
+ rtc::Thread* signaling_thread,
+ rtc::NetworkManager* network_manager,
+ rtc::PacketSocketFactory* socket_factory);
+ // Constructor for convenience which uses default implementations of
+ // everything (though does still require that the current thread runs a
+ // message loop; see above).
+ static std::unique_ptr<OrtcFactoryInterface> Create() {
+ return Create(nullptr, nullptr, nullptr, nullptr);
+ }
+
+ virtual ~OrtcFactoryInterface() {}
+
+ virtual std::unique_ptr<UdpTransportInterface>
+ CreateUdpTransport(int family, uint16_t min_port, uint16_t max_port) = 0;
+ // Method for convenience that has no port range restrictions.
+ std::unique_ptr<UdpTransportInterface> CreateUdpTransport(int family) {
+ return CreateUdpTransport(family, 0, 0);
+ }
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_API_ORTCFACTORYINTERFACE_H_
diff --git a/webrtc/api/udptransportinterface.h b/webrtc/api/udptransportinterface.h
new file mode 100644
index 0000000..1a28531
--- /dev/null
+++ b/webrtc/api/udptransportinterface.h
@@ -0,0 +1,57 @@
+/*
+ * 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 WEBRTC_API_UDPTRANSPORTINTERFACE_H_
+#define WEBRTC_API_UDPTRANSPORTINTERFACE_H_
+
+#include "webrtc/api/proxy.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace webrtc {
+
+// Interface for a raw UDP transport (not using ICE), meaning a combination of
+// a local/remote IP address/port.
+//
+// An instance can be instantiated using OrtcFactory.
+//
+// Each instance reserves a UDP port, which will be freed when the
+// UdpTransportInterface destructor is called.
+//
+// Calling SetRemoteAddress sets the destination of outgoing packets; without a
+// destination, packets can't be sent, but they can be received.
+class UdpTransportInterface {
+ public:
+ virtual ~UdpTransportInterface() {}
+
+ // Get the address of the socket allocated for this transport.
+ virtual rtc::SocketAddress GetLocalAddress() const = 0;
+
+ // Sets the address to which packets will be delivered.
+ //
+ // Calling with a "nil" (default-constructed) address is legal, and unsets
+ // any previously set destination.
+ //
+ // However, calling with an incomplete address (port or IP not set) will
+ // fail.
+ virtual bool SetRemoteAddress(const rtc::SocketAddress& dest) = 0;
+ // Simple getter. If never set, returns nil address.
+ virtual rtc::SocketAddress GetRemoteAddress() const = 0;
+};
+
+BEGIN_OWNED_PROXY_MAP(UdpTransport)
+ PROXY_WORKER_THREAD_DESTRUCTOR()
+ PROXY_WORKER_CONSTMETHOD0(rtc::SocketAddress, GetLocalAddress)
+ PROXY_WORKER_METHOD1(bool, SetRemoteAddress, const rtc::SocketAddress&)
+ PROXY_WORKER_CONSTMETHOD0(rtc::SocketAddress, GetRemoteAddress)
+END_PROXY_MAP()
+
+} // namespace webrtc
+
+#endif // WEBRTC_API_UDPTRANSPORTINTERFACE_H_
diff --git a/webrtc/p2p/BUILD.gn b/webrtc/p2p/BUILD.gn
index 649e9cf..bc2306b 100644
--- a/webrtc/p2p/BUILD.gn
+++ b/webrtc/p2p/BUILD.gn
@@ -74,8 +74,8 @@
"base/turnport.cc",
"base/turnport.h",
"base/udpport.h",
- "base/udptransportchannel.cc",
- "base/udptransportchannel.h",
+ "base/udptransport.cc",
+ "base/udptransport.h",
"client/basicportallocator.cc",
"client/basicportallocator.h",
"client/socketmonitor.cc",
@@ -169,7 +169,7 @@
"base/transportdescriptionfactory_unittest.cc",
"base/turnport_unittest.cc",
"base/turnserver_unittest.cc",
- "base/udptransportchannel_unittest.cc",
+ "base/udptransport_unittest.cc",
"client/basicportallocator_unittest.cc",
]
if (rtc_use_quic) {
diff --git a/webrtc/p2p/base/udptransport.cc b/webrtc/p2p/base/udptransport.cc
new file mode 100644
index 0000000..976d5bb
--- /dev/null
+++ b/webrtc/p2p/base/udptransport.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 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 "webrtc/p2p/base/udptransport.h"
+
+#include <string>
+#include <utility> // For std::move.
+
+#include "webrtc/base/asyncudpsocket.h"
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/thread_checker.h"
+
+namespace cricket {
+
+UdpTransport::UdpTransport(const std::string& transport_name,
+ std::unique_ptr<rtc::AsyncPacketSocket> socket)
+ : transport_name_(transport_name), socket_(std::move(socket)) {
+ RTC_DCHECK(socket_);
+ socket_->SignalReadPacket.connect(this, &UdpTransport::OnSocketReadPacket);
+ socket_->SignalSentPacket.connect(this, &UdpTransport::OnSocketSentPacket);
+}
+
+UdpTransport::~UdpTransport() {
+ RTC_DCHECK_RUN_ON(&network_thread_checker_);
+}
+
+rtc::SocketAddress UdpTransport::GetLocalAddress() const {
+ RTC_DCHECK_RUN_ON(&network_thread_checker_);
+ return socket_->GetLocalAddress();
+}
+
+bool UdpTransport::SetRemoteAddress(const rtc::SocketAddress& addr) {
+ RTC_DCHECK_RUN_ON(&network_thread_checker_);
+ if (!addr.IsComplete()) {
+ LOG(LS_WARNING) << "Remote address not complete.";
+ return false;
+ }
+ // TODO(johan): check for ipv4, other settings.
+ bool prev_destination_nil = remote_address_.IsNil();
+ remote_address_ = addr;
+ // Going from "didn't have destination" to "have destination" or vice versa.
+ if (prev_destination_nil != remote_address_.IsNil()) {
+ SignalWritableState(this);
+ if (prev_destination_nil) {
+ SignalReadyToSend(this);
+ }
+ }
+ return true;
+}
+
+rtc::SocketAddress UdpTransport::GetRemoteAddress() const {
+ RTC_DCHECK_RUN_ON(&network_thread_checker_);
+ return remote_address_;
+}
+
+bool UdpTransport::writable() const {
+ RTC_DCHECK_RUN_ON(&network_thread_checker_);
+ return !remote_address_.IsNil();
+}
+
+int UdpTransport::SendPacket(const char* data,
+ size_t len,
+ const rtc::PacketOptions& options,
+ int flags) {
+ // No thread_checker in high frequency network function.
+ if (remote_address_.IsNil()) {
+ LOG(LS_WARNING) << "Remote address not set.";
+ send_error_ = ENOTCONN;
+ return -1;
+ }
+ int result =
+ socket_->SendTo((const void*)data, len, remote_address_, options);
+ if (result <= 0) {
+ LOG(LS_VERBOSE) << "SendPacket() " << result;
+ }
+ return result;
+}
+
+void UdpTransport::OnSocketReadPacket(rtc::AsyncPacketSocket* socket,
+ const char* data,
+ size_t len,
+ const rtc::SocketAddress& remote_addr,
+ const rtc::PacketTime& packet_time) {
+ // No thread_checker in high frequency network function.
+ SignalReadPacket(this, data, len, packet_time, 0);
+}
+
+void UdpTransport::OnSocketSentPacket(rtc::AsyncPacketSocket* socket,
+ const rtc::SentPacket& packet) {
+ RTC_DCHECK_EQ(socket_.get(), socket);
+ SignalSentPacket(this, packet);
+}
+
+} // namespace cricket
diff --git a/webrtc/p2p/base/udptransport.h b/webrtc/p2p/base/udptransport.h
new file mode 100644
index 0000000..802d892
--- /dev/null
+++ b/webrtc/p2p/base/udptransport.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 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 WEBRTC_P2P_BASE_UDPTRANSPORT_H_
+#define WEBRTC_P2P_BASE_UDPTRANSPORT_H_
+
+#include <memory>
+#include <string>
+
+#include "webrtc/api/udptransportinterface.h"
+#include "webrtc/base/asyncpacketsocket.h" // For PacketOptions.
+#include "webrtc/base/optional.h"
+#include "webrtc/base/thread_checker.h"
+#include "webrtc/p2p/base/packettransportinterface.h"
+
+namespace rtc {
+class AsyncPacketSocket;
+struct PacketTime;
+struct SentPacket;
+class SocketAddress;
+}
+
+namespace cricket {
+
+// Implementation of UdpTransportInterface.
+// Used by OrtcFactory.
+class UdpTransport : public webrtc::UdpTransportInterface,
+ public rtc::PacketTransportInterface {
+ public:
+ // |transport_name| is only used for identification/logging.
+ // |socket| must be non-null.
+ UdpTransport(const std::string& transport_name,
+ std::unique_ptr<rtc::AsyncPacketSocket> socket);
+ ~UdpTransport();
+
+ // Overrides of UdpTransportInterface, used by the API consumer.
+ rtc::SocketAddress GetLocalAddress() const override;
+ bool SetRemoteAddress(const rtc::SocketAddress& addr) override;
+ rtc::SocketAddress GetRemoteAddress() const override;
+
+ // Overrides of PacketTransportInterface, used by webrtc internally.
+ const std::string debug_name() const override { return transport_name_; }
+
+ bool receiving() const override {
+ // TODO(johan): Implement method and signal.
+ return true;
+ }
+
+ bool writable() const override;
+
+ int SendPacket(const char* data,
+ size_t len,
+ const rtc::PacketOptions& options,
+ int flags) override;
+
+ int SetOption(rtc::Socket::Option opt, int value) override { return 0; }
+
+ int GetError() override { return send_error_; }
+
+ private:
+ void OnSocketReadPacket(rtc::AsyncPacketSocket* socket,
+ const char* data,
+ size_t len,
+ const rtc::SocketAddress& remote_addr,
+ const rtc::PacketTime& packet_time);
+ void OnSocketSentPacket(rtc::AsyncPacketSocket* socket,
+ const rtc::SentPacket& packet);
+ bool IsLocalConsistent();
+ std::string transport_name_;
+ int send_error_ = 0;
+ std::unique_ptr<rtc::AsyncPacketSocket> socket_;
+ // If not set, will be an "nil" address ("IsNil" returns true).
+ rtc::SocketAddress remote_address_;
+ rtc::ThreadChecker network_thread_checker_;
+};
+} // namespace cricket
+
+#endif // WEBRTC_P2P_BASE_UDPTRANSPORT_H_
diff --git a/webrtc/p2p/base/udptransportchannel_unittest.cc b/webrtc/p2p/base/udptransport_unittest.cc
similarity index 66%
rename from webrtc/p2p/base/udptransportchannel_unittest.cc
rename to webrtc/p2p/base/udptransport_unittest.cc
index 1cedde6..0e67beb 100644
--- a/webrtc/p2p/base/udptransportchannel_unittest.cc
+++ b/webrtc/p2p/base/udptransport_unittest.cc
@@ -22,8 +22,9 @@
#include "webrtc/base/socketaddress.h"
#include "webrtc/base/socketserver.h"
#include "webrtc/base/virtualsocketserver.h"
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
#include "webrtc/p2p/base/packettransportinterface.h"
-#include "webrtc/p2p/base/udptransportchannel.h"
+#include "webrtc/p2p/base/udptransport.h"
namespace cricket {
@@ -31,28 +32,39 @@
static const rtc::IPAddress kIPv4LocalHostAddress =
rtc::IPAddress(0x7F000001); // 127.0.0.1
-class UdpTransportChannelTest : public testing::Test,
- public sigslot::has_slots<> {
+class UdpTransportTest : public testing::Test, public sigslot::has_slots<> {
public:
- UdpTransportChannelTest()
+ UdpTransportTest()
: network_thread_(rtc::Thread::Current()),
physical_socket_server_(new rtc::PhysicalSocketServer),
virtual_socket_server_(
new rtc::VirtualSocketServer(physical_socket_server_.get())),
ss_scope_(virtual_socket_server_.get()),
- ep1_("Name1"),
- ep2_("name2") {
- // Setup IP Address for outgoing packets from sockets bound to
- // IPV4 INADDR_ANY ("0.0.0.0."). Virtual socket server sends these packets
- // only if the default address is explicit set. With a physical socket, the
- // actual network stack / operating system would set the IP address for
- // outgoing packets.
+ ep1_("Name1",
+ std::unique_ptr<rtc::AsyncPacketSocket>(
+ socket_factory_.CreateUdpSocket(
+ rtc::SocketAddress(rtc::GetAnyIP(AF_INET), 0),
+ 0,
+ 0))),
+ ep2_("Name2",
+ std::unique_ptr<rtc::AsyncPacketSocket>(
+ socket_factory_.CreateUdpSocket(
+ rtc::SocketAddress(rtc::GetAnyIP(AF_INET), 0),
+ 0,
+ 0))) {
+ // Setup IP Address for outgoing packets from sockets bound to IPV4
+ // INADDR_ANY ("0.0.0.0."), as used above when creating the virtual
+ // sockets. The virtual socket server sends these packets only if the
+ // default address is explicit set. With a physical socket, the actual
+ // network stack / operating system would set the IP address for outgoing
+ // packets.
virtual_socket_server_->SetDefaultRoute(kIPv4LocalHostAddress);
}
struct Endpoint : public sigslot::has_slots<> {
- explicit Endpoint(std::string tch_name) {
- ch_.reset(new UdpTransportChannel(std::move(tch_name)));
+ explicit Endpoint(std::string tch_name,
+ std::unique_ptr<rtc::AsyncPacketSocket> socket) {
+ ch_.reset(new UdpTransport(std::move(tch_name), std::move(socket)));
ch_->SignalReadPacket.connect(this, &Endpoint::OnReadPacket);
ch_->SignalSentPacket.connect(this, &Endpoint::OnSentPacket);
ch_->SignalReadyToSend.connect(this, &Endpoint::OnReadyToSend);
@@ -98,16 +110,11 @@
}
void GetLocalPort(uint16_t* local_port) {
- rtc::Optional<rtc::SocketAddress> addr = ch_->local_parameters();
- if (!addr) {
- *local_port = 0;
- return;
- }
- *local_port = addr->port();
+ *local_port = ch_->GetLocalAddress().port();
}
std::list<std::string> ch_packets_;
- std::unique_ptr<UdpTransportChannel> ch_;
+ std::unique_ptr<UdpTransport> ch_;
uint32_t num_received_packets_ = 0; // Increases on SignalReadPacket.
uint32_t num_sig_sent_packets_ = 0; // Increases on SignalSentPacket.
uint32_t num_sig_writable_ = 0; // Increases on SignalWritable.
@@ -118,6 +125,8 @@
std::unique_ptr<rtc::PhysicalSocketServer> physical_socket_server_;
std::unique_ptr<rtc::VirtualSocketServer> virtual_socket_server_;
rtc::SocketServerScope ss_scope_;
+ // Uses current thread's socket server, which will be set by ss_scope_.
+ rtc::BasicPacketSocketFactory socket_factory_;
Endpoint ep1_;
Endpoint ep2_;
@@ -137,43 +146,43 @@
}
};
-TEST_F(UdpTransportChannelTest, SendRecvBasic) {
- ep1_.ch_->Start();
- ep2_.ch_->Start();
+TEST_F(UdpTransportTest, AddressGetters) {
+ // Initially, remote address should be nil but local address shouldn't be.
+ EXPECT_FALSE(ep1_.ch_->GetLocalAddress().IsNil());
+ EXPECT_TRUE(ep1_.ch_->GetRemoteAddress().IsNil());
+ rtc::SocketAddress destination("127.0.0.1", 1337);
+ ASSERT_TRUE(ep1_.ch_->SetRemoteAddress(destination));
+ EXPECT_EQ(destination, ep1_.ch_->GetRemoteAddress());
+}
+
+// Setting an invalid address should fail and have no effect.
+TEST_F(UdpTransportTest, SettingIncompleteRemoteAddressFails) {
+ EXPECT_FALSE(ep1_.ch_->SetRemoteAddress(rtc::SocketAddress("127.0.0.1", 0)));
+ EXPECT_TRUE(ep1_.ch_->GetRemoteAddress().IsNil());
+}
+
+TEST_F(UdpTransportTest, SendRecvBasic) {
uint16_t port;
ep2_.GetLocalPort(&port);
rtc::SocketAddress addr2 = rtc::SocketAddress("127.0.0.1", port);
- ep1_.ch_->SetRemoteParameters(addr2);
+ EXPECT_TRUE(ep1_.ch_->SetRemoteAddress(addr2));
ep1_.GetLocalPort(&port);
rtc::SocketAddress addr1 = rtc::SocketAddress("127.0.0.1", port);
- ep2_.ch_->SetRemoteParameters(addr1);
+ EXPECT_TRUE(ep2_.ch_->SetRemoteAddress(addr1));
TestSendRecv();
}
-TEST_F(UdpTransportChannelTest, DefaultLocalParameters) {
- EXPECT_FALSE(ep1_.ch_->local_parameters());
-}
-
-TEST_F(UdpTransportChannelTest, StartTwice) {
- ep1_.ch_->Start();
- EXPECT_EQ(UdpTransportChannel::State::CONNECTING, ep1_.ch_->state());
- ep1_.ch_->Start();
- EXPECT_EQ(UdpTransportChannel::State::CONNECTING, ep1_.ch_->state());
-}
-
-TEST_F(UdpTransportChannelTest, StatusAndSignals) {
- EXPECT_EQ(UdpTransportChannel::State::INIT, ep1_.ch_->state());
- ep1_.ch_->Start();
- EXPECT_EQ(UdpTransportChannel::State::CONNECTING, ep1_.ch_->state());
+// Test the signals and state methods used internally by causing a UdpTransport
+// to send a packet to itself.
+TEST_F(UdpTransportTest, StatusAndSignals) {
EXPECT_EQ(0u, ep1_.num_sig_writable_);
EXPECT_EQ(0u, ep1_.num_sig_ready_to_send_);
// Loopback
EXPECT_TRUE(!ep1_.ch_->writable());
- rtc::Optional<rtc::SocketAddress> addr = ep1_.ch_->local_parameters();
- ASSERT_TRUE(addr);
+ rtc::SocketAddress addr = ep1_.ch_->GetLocalAddress();
// Keep port, but explicitly set IP.
- addr->SetIP("127.0.0.1");
- ep1_.ch_->SetRemoteParameters(*addr);
+ addr.SetIP("127.0.0.1");
+ ep1_.ch_->SetRemoteAddress(addr);
EXPECT_TRUE(ep1_.ch_->writable());
EXPECT_EQ(1u, ep1_.num_sig_writable_);
EXPECT_EQ(1u, ep1_.num_sig_ready_to_send_);
@@ -182,4 +191,5 @@
EXPECT_EQ_WAIT(1u, ep1_.ch_packets_.size(), kTimeoutMs);
EXPECT_EQ_WAIT(1u, ep1_.num_sig_sent_packets_, kTimeoutMs);
}
+
} // namespace cricket
diff --git a/webrtc/p2p/base/udptransportchannel.cc b/webrtc/p2p/base/udptransportchannel.cc
deleted file mode 100644
index 7360217..0000000
--- a/webrtc/p2p/base/udptransportchannel.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2016 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 "webrtc/p2p/base/udptransportchannel.h"
-
-#include <string>
-
-#include "webrtc/base/asyncudpsocket.h"
-#include "webrtc/base/asyncpacketsocket.h"
-#include "webrtc/base/logging.h"
-#include "webrtc/base/physicalsocketserver.h"
-#include "webrtc/base/socketaddress.h"
-#include "webrtc/base/thread.h"
-#include "webrtc/base/thread_checker.h"
-#include "webrtc/p2p/base/basicpacketsocketfactory.h"
-#include "webrtc/p2p/base/packettransportinterface.h"
-
-namespace cricket {
-
-UdpTransportChannel::UdpTransportChannel(const std::string& transport_name)
- : UdpTransportChannel(transport_name,
- rtc::Thread::Current()->socketserver()) {}
-
-UdpTransportChannel::UdpTransportChannel(const std::string& transport_name,
- rtc::SocketServer* socket_server)
- : transport_name_(transport_name), socket_server_(socket_server) {}
-
-UdpTransportChannel::~UdpTransportChannel() {
- RTC_DCHECK_RUN_ON(&network_thread_checker_);
-}
-
-void UdpTransportChannel::OnSocketReadPacket(
- rtc::AsyncPacketSocket* socket,
- const char* data,
- size_t len,
- const rtc::SocketAddress& remote_addr,
- const rtc::PacketTime& packet_time) {
- // No thread_checker in high frequency network function.
- SignalReadPacket(this, data, len, packet_time, 0);
-}
-
-void UdpTransportChannel::OnSocketSentPacket(rtc::AsyncPacketSocket* socket,
- const rtc::SentPacket& packet) {
- RTC_DCHECK_EQ(socket_.get(), socket);
- SignalSentPacket(this, packet);
-}
-
-bool UdpTransportChannel::writable() const {
- return state_ == State::CONNECTED;
-}
-
-int UdpTransportChannel::SendPacket(const char* data,
- size_t len,
- const rtc::PacketOptions& options,
- int flags) {
- // No thread_checker in high frequency network function.
- if (!remote_parameters_) {
- LOG(LS_WARNING) << "Remote parameters not set.";
- send_error_ = ENOTCONN;
- return -1;
- }
- const rtc::SocketAddress& remote_addr_ = *remote_parameters_;
- int result = socket_->SendTo((const void*)data, len, remote_addr_, options);
- if (result <= 0) {
- LOG(LS_VERBOSE) << "SendPacket() " << result;
- }
- return result;
-}
-
-void UdpTransportChannel::Start() {
- RTC_DCHECK_RUN_ON(&network_thread_checker_);
- if (socket_) {
- LOG(LS_WARNING) << "Local socket already allocated.";
- return;
- }
- static constexpr uint16_t kMaxTries = 100;
- static constexpr uint16_t kMinPortNumber = 2000;
- // TODO(johan) provide configuration option for kMinPortNumber.
- rtc::SocketAddress socket_addr("0.0.0.0", 0);
- // TODO(johan): Replace BasicPacketSocketFactory by something that honors RFC
- // 3550 Section 11 port number requirements like
- // {port_{RTP} is even, port_{RTCP} := port{RTP} + 1}.
- rtc::BasicPacketSocketFactory socket_factory(socket_server_);
- socket_.reset(socket_factory.CreateUdpSocket(socket_addr, kMinPortNumber,
- kMinPortNumber + kMaxTries));
- if (socket_) {
- local_parameters_ =
- rtc::Optional<rtc::SocketAddress>(socket_->GetLocalAddress());
- LOG(INFO) << "Created UDP socket with addr " << local_parameters_->ipaddr()
- << " port " << local_parameters_->port() << ".";
- socket_->SignalReadPacket.connect(this,
- &UdpTransportChannel::OnSocketReadPacket);
- socket_->SignalSentPacket.connect(this,
- &UdpTransportChannel::OnSocketSentPacket);
- } else {
- LOG(INFO) << "Local socket allocation failure";
- }
- UpdateState();
- return;
-}
-
-void UdpTransportChannel::UpdateState() {
- RTC_DCHECK_RUN_ON(&network_thread_checker_);
- RTC_DCHECK(!(local_parameters_ && !socket_));
- RTC_DCHECK(!(!local_parameters_ && socket_));
- if (!local_parameters_) {
- SetState(State::INIT);
- } else if (!remote_parameters_) {
- SetState(State::CONNECTING);
- } else {
- SetState(State::CONNECTED);
- }
-}
-
-void UdpTransportChannel::SetRemoteParameters(const rtc::SocketAddress& addr) {
- RTC_DCHECK_RUN_ON(&network_thread_checker_);
- if (!addr.IsComplete()) {
- LOG(INFO) << "remote address not complete";
- return;
- }
- // TODO(johan) check for ipv4, other settings.
- remote_parameters_ = rtc::Optional<rtc::SocketAddress>(addr);
- UpdateState();
-}
-
-void UdpTransportChannel::SetState(State state) {
- RTC_DCHECK_RUN_ON(&network_thread_checker_);
- if (state_ == state) {
- return;
- }
- state_ = state;
- if (state == State::CONNECTED) {
- SignalWritableState(this);
- SignalReadyToSend(this);
- }
-}
-} // namespace cricket
diff --git a/webrtc/p2p/base/udptransportchannel.h b/webrtc/p2p/base/udptransportchannel.h
deleted file mode 100644
index 2152fb7..0000000
--- a/webrtc/p2p/base/udptransportchannel.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2016 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 WEBRTC_P2P_BASE_UDPTRANSPORTCHANNEL_H_
-#define WEBRTC_P2P_BASE_UDPTRANSPORTCHANNEL_H_
-
-#include <memory>
-#include <string>
-
-#include "webrtc/base/optional.h"
-#include "webrtc/base/thread_checker.h"
-#include "webrtc/p2p/base/packettransportinterface.h"
-
-namespace rtc {
-class AsyncPacketSocket;
-class PhysicalSocketServer;
-class SocketAddress;
-class SocketServer;
-class Thread;
-}
-
-namespace cricket {
-
-class UdpTransportChannel : public rtc::PacketTransportInterface {
- public:
- enum class State { INIT, CONNECTING, CONNECTED, FAILED };
- explicit UdpTransportChannel(const std::string& transport_name);
- UdpTransportChannel(const std::string& transport_name, rtc::SocketServer* ss);
- ~UdpTransportChannel();
-
- const std::string debug_name() const override { return transport_name_; }
-
- bool receiving() const override {
- // TODO(johan): Implement method and signal.
- return true;
- }
-
- bool writable() const override;
-
- int SendPacket(const char* data,
- size_t len,
- const rtc::PacketOptions& options,
- int flags) override;
-
- int SetOption(rtc::Socket::Option opt, int value) override { return 0; }
-
- int GetError() override { return send_error_; }
-
- State state() const {
- RTC_DCHECK_RUN_ON(&network_thread_checker_);
- return state_;
- }
-
- // Start() makes UdpTransportChannel transition from state INIT to CONNECTING.
- // It creates the local UDP socket and binds it to a port.
- // Consider checking state() after calling Start().
- void Start();
-
- void SetRemoteParameters(const rtc::SocketAddress& remote);
-
- // Returned optional does not have a value if in the INIT or FAILED state.
- // Consider checking state() before calling local_parameters().
- rtc::Optional<rtc::SocketAddress> local_parameters() const {
- return local_parameters_;
- }
-
- private:
- void OnSocketReadPacket(rtc::AsyncPacketSocket* socket,
- const char* data,
- size_t len,
- const rtc::SocketAddress& remote_addr,
- const rtc::PacketTime& packet_time);
- void OnSocketSentPacket(rtc::AsyncPacketSocket* socket,
- const rtc::SentPacket& packet);
- void SetState(State state); // Set State and Signal.
- bool IsLocalConsistent();
- void UpdateState();
- std::string transport_name_;
- rtc::SocketServer* socket_server_;
- State state_ = State::INIT;
- int send_error_ = 0;
- std::unique_ptr<rtc::AsyncPacketSocket> socket_;
- rtc::Optional<rtc::SocketAddress> local_parameters_;
- rtc::Optional<rtc::SocketAddress> remote_parameters_;
- rtc::ThreadChecker network_thread_checker_;
-};
-} // namespace cricket
-
-#endif // WEBRTC_P2P_BASE_UDPTRANSPORTCHANNEL_H_