Sending WebRTC network packets should not go through the main thread
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 May 2020 09:23:43 +0000 (09:23 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 May 2020 09:23:43 +0000 (09:23 +0000)
https://bugs.webkit.org/show_bug.cgi?id=211291

Reviewed by Eric Carlson.

Source/WebCore:

Covered by existing tests.

* Modules/mediastream/PeerConnectionBackend.cpp:
(WebCore::PeerConnectionBackend::filterSDP const):
Fix a case where the SDP would be badly formatted if we do not have yet a MDNS name for the corresponding IP address.
Small refactoring to use early returns.
* platform/mediastream/libwebrtc/LibWebRTCProvider.cpp:
(WebCore::LibWebRTCProvider::getStaticFactoryAndThreads):
* platform/mediastream/libwebrtc/LibWebRTCProvider.h:
Add the ability for WebKit LibWebRTCProvider to do some processing on creation of the RTC threads.

Source/WebKit:

Following on receiving RTC packets from a background thread, we also send RTC packets from a background thread.
Creation of the sockets also happens in a background thread.
LibWebRTCNetwork is getting the connection whenever a new connection to network process is created.
It will then hop to the RTC network thread to set the IPC connection to the libwebrtc socket factory.

At creation of the socket, we get the IPC connection to the network process and keep a ref in the RTC socket.
In case network process crashed and the IPC connection of the RTC network is null, we hop to the main thread to create a new IPC connection.
This will fail the creation of the socket (as well as new ones as well) as long as the IPC connection to network process is not valid again.

Covered by existing tests.

* WebProcess/Network/webrtc/LibWebRTCNetwork.cpp:
(WebKit::LibWebRTCNetwork::setAsActive):
(WebKit::LibWebRTCNetwork::setConnection):
(WebKit::LibWebRTCNetwork::dispatchToThread):
* WebProcess/Network/webrtc/LibWebRTCNetwork.h:
(WebKit::LibWebRTCNetwork::connection):
(WebKit::LibWebRTCNetwork::isActive const):
* WebProcess/Network/webrtc/LibWebRTCProvider.cpp:
(WebKit::LibWebRTCProvider::startedNetworkThread):
* WebProcess/Network/webrtc/LibWebRTCProvider.h:
* WebProcess/Network/webrtc/LibWebRTCSocket.cpp:
(WebKit::LibWebRTCSocket::SendTo):
(WebKit::LibWebRTCSocket::Close):
(WebKit::LibWebRTCSocket::SetOption):
(WebKit::LibWebRTCSocket::suspend):
* WebProcess/Network/webrtc/LibWebRTCSocket.h:
* WebProcess/Network/webrtc/LibWebRTCSocketFactory.cpp:
(WebKit::LibWebRTCSocketFactory::setConnection):
(WebKit::LibWebRTCSocketFactory::connection):
(WebKit::LibWebRTCSocketFactory::createServerTcpSocket):
(WebKit::LibWebRTCSocketFactory::createUdpSocket):
(WebKit::LibWebRTCSocketFactory::createClientTcpSocket):
(WebKit::LibWebRTCSocketFactory::createNewConnectionSocket):
(WebKit::LibWebRTCSocketFactory::addSocket):
(WebKit::LibWebRTCSocketFactory::removeSocket):
(WebKit::LibWebRTCSocketFactory::forSocketInGroup):
* WebProcess/Network/webrtc/LibWebRTCSocketFactory.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261277 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp
Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCProvider.cpp
Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCProvider.h
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/Network/webrtc/LibWebRTCNetwork.cpp
Source/WebKit/WebProcess/Network/webrtc/LibWebRTCNetwork.h
Source/WebKit/WebProcess/Network/webrtc/LibWebRTCProvider.cpp
Source/WebKit/WebProcess/Network/webrtc/LibWebRTCProvider.h
Source/WebKit/WebProcess/Network/webrtc/LibWebRTCSocket.cpp
Source/WebKit/WebProcess/Network/webrtc/LibWebRTCSocket.h
Source/WebKit/WebProcess/Network/webrtc/LibWebRTCSocketFactory.cpp
Source/WebKit/WebProcess/Network/webrtc/LibWebRTCSocketFactory.h

index 757bef6..8d7c25e 100644 (file)
@@ -1,3 +1,21 @@
+2020-05-07  Youenn Fablet  <youenn@apple.com>
+
+        Sending WebRTC network packets should not go through the main thread
+        https://bugs.webkit.org/show_bug.cgi?id=211291
+
+        Reviewed by Eric Carlson.
+
+        Covered by existing tests.
+
+        * Modules/mediastream/PeerConnectionBackend.cpp:
+        (WebCore::PeerConnectionBackend::filterSDP const):
+        Fix a case where the SDP would be badly formatted if we do not have yet a MDNS name for the corresponding IP address.
+        Small refactoring to use early returns.
+        * platform/mediastream/libwebrtc/LibWebRTCProvider.cpp:
+        (WebCore::LibWebRTCProvider::getStaticFactoryAndThreads):
+        * platform/mediastream/libwebrtc/LibWebRTCProvider.h:
+        Add the ability for WebKit LibWebRTCProvider to do some processing on creation of the RTC threads.
+
 2020-05-06  Sergio Villar Senin  <svillar@igalia.com>
 
         [WebXR] Implement simulateUserActivation()
index 0fb76fd..c149d21 100644 (file)
@@ -439,23 +439,32 @@ String PeerConnectionBackend::filterSDP(String&& sdp) const
 
     StringBuilder filteredSDP;
     sdp.split('\n', [this, &filteredSDP](StringView line) {
-        if (line.startsWith("c=IN IP4"))
-            filteredSDP.append("c=IN IP4 0.0.0.0\r");
-        else if (line.startsWith("c=IN IP6"))
-            filteredSDP.append("c=IN IP6 ::\r");
-        else if (!line.startsWith("a=candidate"))
+        if (line.startsWith("c=IN IP4")) {
+            filteredSDP.append("c=IN IP4 0.0.0.0\r\n");
+            return;
+        }
+        if (line.startsWith("c=IN IP6")) {
+            filteredSDP.append("c=IN IP6 ::\r\n");
+            return;
+        }
+        if (!line.startsWith("a=candidate")) {
             filteredSDP.append(line);
-        else if (line.find(" host ", 11) == notFound)
+            filteredSDP.append('\n');
+            return;
+        }
+        if (line.find(" host ", 11) == notFound) {
             filteredSDP.append(filterICECandidate(line.toString()));
-        else {
-            auto ipAddress = extractIPAddress(line);
-            auto mdnsName = m_ipAddressToMDNSNameMap.get(ipAddress);
-            if (!mdnsName.isEmpty()) {
-                auto sdp = line.toString();
-                sdp.replace(ipAddress, mdnsName);
-                filteredSDP.append(sdp);
-            }
+            filteredSDP.append('\n');
+            return;
         }
+
+        auto ipAddress = extractIPAddress(line);
+        auto mdnsName = m_ipAddressToMDNSNameMap.get(ipAddress);
+        if (mdnsName.isEmpty())
+            return;
+        auto sdp = line.toString();
+        sdp.replace(ipAddress, mdnsName);
+        filteredSDP.append(sdp);
         filteredSDP.append('\n');
     });
     return filteredSDP.toString();
index 64db2b4..df2fd7c 100644 (file)
@@ -191,7 +191,7 @@ static inline PeerConnectionFactoryAndThreads& staticFactoryAndThreads()
     return factoryAndThreads.get();
 }
 
-static inline PeerConnectionFactoryAndThreads& getStaticFactoryAndThreads(bool useNetworkThreadWithSocketServer)
+PeerConnectionFactoryAndThreads& LibWebRTCProvider::getStaticFactoryAndThreads(bool useNetworkThreadWithSocketServer)
 {
     auto& factoryAndThreads = staticFactoryAndThreads();
 
@@ -200,6 +200,7 @@ static inline PeerConnectionFactoryAndThreads& getStaticFactoryAndThreads(bool u
     if (!factoryAndThreads.networkThread) {
         factoryAndThreads.networkThreadWithSocketServer = useNetworkThreadWithSocketServer;
         initializePeerConnectionFactoryAndThreads(factoryAndThreads);
+        startedNetworkThread();
     }
     return factoryAndThreads;
 }
index 22b10dd..2e96e66 100644 (file)
@@ -59,6 +59,7 @@ class PeerConnectionFactoryInterface;
 namespace WebCore {
 
 class LibWebRTCAudioModule;
+struct PeerConnectionFactoryAndThreads;
 struct RTCRtpCapabilities;
 
 enum class MDNSRegisterError { NotImplemented, BadParameter, DNSSD, Internal, Timeout };
@@ -134,6 +135,10 @@ protected:
     virtual std::unique_ptr<webrtc::VideoDecoderFactory> createDecoderFactory();
     virtual std::unique_ptr<webrtc::VideoEncoderFactory> createEncoderFactory();
 
+    virtual void startedNetworkThread() { };
+
+    PeerConnectionFactoryAndThreads& getStaticFactoryAndThreads(bool useNetworkThreadWithSocketServer);
+
     bool m_enableEnumeratingAllNetworkInterfaces { false };
     // FIXME: Remove m_useNetworkThreadWithSocketServer member variable and make it a global.
     bool m_useNetworkThreadWithSocketServer { true };
index d33b1f1..7315136 100644 (file)
@@ -1,3 +1,49 @@
+2020-05-07  Youenn Fablet  <youenn@apple.com>
+
+        Sending WebRTC network packets should not go through the main thread
+        https://bugs.webkit.org/show_bug.cgi?id=211291
+
+        Reviewed by Eric Carlson.
+
+        Following on receiving RTC packets from a background thread, we also send RTC packets from a background thread.
+        Creation of the sockets also happens in a background thread.
+        LibWebRTCNetwork is getting the connection whenever a new connection to network process is created.
+        It will then hop to the RTC network thread to set the IPC connection to the libwebrtc socket factory.
+
+        At creation of the socket, we get the IPC connection to the network process and keep a ref in the RTC socket.
+        In case network process crashed and the IPC connection of the RTC network is null, we hop to the main thread to create a new IPC connection.
+        This will fail the creation of the socket (as well as new ones as well) as long as the IPC connection to network process is not valid again.
+
+        Covered by existing tests.
+
+        * WebProcess/Network/webrtc/LibWebRTCNetwork.cpp:
+        (WebKit::LibWebRTCNetwork::setAsActive):
+        (WebKit::LibWebRTCNetwork::setConnection):
+        (WebKit::LibWebRTCNetwork::dispatchToThread):
+        * WebProcess/Network/webrtc/LibWebRTCNetwork.h:
+        (WebKit::LibWebRTCNetwork::connection):
+        (WebKit::LibWebRTCNetwork::isActive const):
+        * WebProcess/Network/webrtc/LibWebRTCProvider.cpp:
+        (WebKit::LibWebRTCProvider::startedNetworkThread):
+        * WebProcess/Network/webrtc/LibWebRTCProvider.h:
+        * WebProcess/Network/webrtc/LibWebRTCSocket.cpp:
+        (WebKit::LibWebRTCSocket::SendTo):
+        (WebKit::LibWebRTCSocket::Close):
+        (WebKit::LibWebRTCSocket::SetOption):
+        (WebKit::LibWebRTCSocket::suspend):
+        * WebProcess/Network/webrtc/LibWebRTCSocket.h:
+        * WebProcess/Network/webrtc/LibWebRTCSocketFactory.cpp:
+        (WebKit::LibWebRTCSocketFactory::setConnection):
+        (WebKit::LibWebRTCSocketFactory::connection):
+        (WebKit::LibWebRTCSocketFactory::createServerTcpSocket):
+        (WebKit::LibWebRTCSocketFactory::createUdpSocket):
+        (WebKit::LibWebRTCSocketFactory::createClientTcpSocket):
+        (WebKit::LibWebRTCSocketFactory::createNewConnectionSocket):
+        (WebKit::LibWebRTCSocketFactory::addSocket):
+        (WebKit::LibWebRTCSocketFactory::removeSocket):
+        (WebKit::LibWebRTCSocketFactory::forSocketInGroup):
+        * WebProcess/Network/webrtc/LibWebRTCSocketFactory.h:
+
 2020-05-07  Adrian Perez de Castro  <aperez@igalia.com>
 
         [GTK4] Stop using the GtkWidget.destroy vfunc
index 54b2bd0..d78d759 100644 (file)
@@ -39,6 +39,19 @@ LibWebRTCNetwork::~LibWebRTCNetwork()
     setConnection(nullptr);
 }
 
+void LibWebRTCNetwork::setAsActive()
+{
+    ASSERT(!m_isActive);
+    m_isActive = true;
+#if USE(LIBWEBRTC)
+    if (m_connection) {
+        WebCore::LibWebRTCProvider::callOnWebRTCNetworkThread([this, connection = m_connection]() mutable {
+            m_socketFactory.setConnection(WTFMove(connection));
+        });
+    }
+#endif
+}
+
 void LibWebRTCNetwork::networkProcessCrashed()
 {
     setConnection(nullptr);
@@ -53,6 +66,11 @@ void LibWebRTCNetwork::setConnection(RefPtr<IPC::Connection>&& connection)
 #if USE(LIBWEBRTC)
     if (m_connection)
         m_connection->removeThreadMessageReceiver(Messages::LibWebRTCNetwork::messageReceiverName());
+    if (m_isActive) {
+        WebCore::LibWebRTCProvider::callOnWebRTCNetworkThread([this, connection]() mutable {
+            m_socketFactory.setConnection(WTFMove(connection));
+        });
+    }
 #endif
     m_connection = WTFMove(connection);
 #if USE(LIBWEBRTC)
@@ -61,18 +79,9 @@ void LibWebRTCNetwork::setConnection(RefPtr<IPC::Connection>&& connection)
 #endif
 }
 
-bool LibWebRTCNetwork::isActive() const
-{
-#if USE(LIBWEBRTC)
-    return WebCore::LibWebRTCProvider::hasWebRTCThreads();
-#else
-    return false;
-#endif
-}
-
 void LibWebRTCNetwork::dispatchToThread(Function<void()>&& callback)
 {
-    if (!isActive()) {
+    if (!m_isActive) {
         RELEASE_LOG_ERROR(WebRTC, "Received WebRTCSocket message while libWebRTCNetwork is not active");
         return;
     }
index 5cdf4f7..15bb16e 100644 (file)
@@ -41,10 +41,12 @@ public:
     LibWebRTCNetwork() = default;
     ~LibWebRTCNetwork();
 
+    IPC::Connection* connection() { return m_connection.get(); }
     void setConnection(RefPtr<IPC::Connection>&&);
+
     void networkProcessCrashed();
 
-    bool isActive() const;
+    bool isActive() const { return m_isActive; }
 
 #if USE(LIBWEBRTC)
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&);
@@ -61,6 +63,8 @@ public:
     WebMDNSRegister& mdnsRegister() { return m_mdnsRegister; }
 #endif
 
+    void setAsActive();
+
 private:
 #if USE(LIBWEBRTC)
     void signalReadPacket(WebCore::LibWebRTCSocketIdentifier, const IPC::DataReference&, const RTCNetwork::IPAddress&, uint16_t port, int64_t);
@@ -81,6 +85,7 @@ private:
 #if ENABLE(WEB_RTC)
     WebMDNSRegister m_mdnsRegister;
 #endif
+    bool m_isActive { false };
     RefPtr<IPC::Connection> m_connection;
 };
 
index 67ab559..3410a99 100644 (file)
@@ -131,6 +131,11 @@ void RTCSocketFactory::resume()
     });
 }
 
+void LibWebRTCProvider::startedNetworkThread()
+{
+    WebProcess::singleton().libWebRTCNetwork().setAsActive();
+}
+
 std::unique_ptr<LibWebRTCProvider::SuspendableSocketFactory> LibWebRTCProvider::createSocketFactory(String&& userAgent)
 {
     return makeUnique<RTCSocketFactory>(WTFMove(userAgent));
index 755d6c6..c6b3e0a 100644 (file)
@@ -57,6 +57,7 @@ private:
     void unregisterMDNSNames(WebCore::DocumentIdentifier) final;
     void registerMDNSName(WebCore::DocumentIdentifier, const String& ipAddress, CompletionHandler<void(MDNSNameOrError&&)>&&) final;
     void disableNonLocalhostConnections() final;
+    void startedNetworkThread() final;
 
 #if PLATFORM(COCOA)
     std::unique_ptr<webrtc::VideoDecoderFactory> createDecoderFactory() final;
index 7aed645..e8ee734 100644 (file)
@@ -57,13 +57,6 @@ LibWebRTCSocket::~LibWebRTCSocket()
     m_factory.removeSocket(*this);
 }
 
-void LibWebRTCSocket::sendOnMainThread(Function<void(IPC::Connection&)>&& callback)
-{
-    callOnMainThread([callback = WTFMove(callback)]() {
-        callback(WebProcess::singleton().ensureNetworkProcessConnection().connection());
-    });
-}
-
 rtc::SocketAddress LibWebRTCSocket::GetLocalAddress() const
 {
     return m_localAddress;
@@ -135,32 +128,29 @@ bool LibWebRTCSocket::willSend(size_t size)
 
 int LibWebRTCSocket::SendTo(const void *value, size_t size, const rtc::SocketAddress& address, const rtc::PacketOptions& options)
 {
-    if (!willSend(size))
+    auto* connection = m_factory.connection();
+    if (!connection || !willSend(size))
         return -1;
 
     if (m_isSuspended)
         return size;
 
-    auto buffer = WebCore::SharedBuffer::create(static_cast<const uint8_t*>(value), size);
-    auto identifier = this->identifier();
+    IPC::DataReference data(static_cast<const uint8_t*>(value), size);
+    connection->send(Messages::NetworkRTCSocket::SendTo { data, RTCNetwork::SocketAddress { address }, RTCPacketOptions { options } }, m_identifier);
 
-    sendOnMainThread([identifier, buffer = WTFMove(buffer), address, options](auto& connection) {
-        IPC::DataReference data(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size());
-        connection.send(Messages::NetworkRTCSocket::SendTo { data, RTCNetwork::SocketAddress { address }, RTCPacketOptions { options } }, identifier);
-    });
     return size;
 }
 
 int LibWebRTCSocket::Close()
 {
-    if (m_state == STATE_CLOSED)
+    auto* connection = m_factory.connection();
+    if (!connection || m_state == STATE_CLOSED)
         return 0;
 
     m_state = STATE_CLOSED;
 
-    sendOnMainThread([identifier = identifier()](auto& connection) {
-        connection.send(Messages::NetworkRTCSocket::Close(), identifier);
-    });
+    connection->send(Messages::NetworkRTCSocket::Close(), m_identifier);
+
     return 0;
 }
 
@@ -180,9 +170,9 @@ int LibWebRTCSocket::SetOption(rtc::Socket::Option option, int value)
 
     m_options[option] = value;
 
-    sendOnMainThread([identifier = identifier(), option, value](auto& connection) {
-        connection.send(Messages::NetworkRTCSocket::SetOption(option, value), identifier);
-    });
+    if (auto* connection = m_factory.connection())
+        connection->send(Messages::NetworkRTCSocket::SetOption(option, value), m_identifier);
+
     return 0;
 }
 
@@ -207,11 +197,11 @@ void LibWebRTCSocket::suspend()
     m_isSuspended = true;
 
     // On suspend, we close TCP sockets as we cannot make sure packets are delivered reliably.
-    if (m_type != Type::UDP) {
-        sendOnMainThread([identifier = identifier()](auto& connection) {
-            connection.send(Messages::NetworkRTCSocket::Close { }, identifier);
-        });
-    }
+    if (m_type == Type::UDP)
+        return;
+
+    if (auto* connection = m_factory.connection())
+        connection->send(Messages::NetworkRTCSocket::Close { }, m_identifier);
 }
 
 } // namespace WebKit
index b2e8ecc..cb48e05 100644 (file)
@@ -85,8 +85,6 @@ private:
     int GetOption(rtc::Socket::Option, int*) final;
     int SetOption(rtc::Socket::Option, int) final;
 
-    static void sendOnMainThread(Function<void(IPC::Connection&)>&&);
-
     LibWebRTCSocketFactory& m_factory;
     WebCore::LibWebRTCSocketIdentifier m_identifier;
     Type m_type;
index a8da7cc..a687944 100644 (file)
@@ -28,6 +28,8 @@
 
 #if USE(LIBWEBRTC)
 
+#include "LibWebRTCNetwork.h"
+#include "Logging.h"
 #include "NetworkProcessConnection.h"
 #include "NetworkRTCMonitorMessages.h"
 #include "NetworkRTCProviderMessages.h"
@@ -45,76 +47,110 @@ static inline rtc::SocketAddress prepareSocketAddress(const rtc::SocketAddress&
     return result;
 }
 
+void LibWebRTCSocketFactory::setConnection(RefPtr<IPC::Connection>&& connection)
+{
+    ASSERT(!WTF::isMainRunLoop());
+    m_connection = WTFMove(connection);
+}
+
+IPC::Connection* LibWebRTCSocketFactory::connection()
+{
+    ASSERT(!WTF::isMainRunLoop());
+    return m_connection.get();
+}
+
 rtc::AsyncPacketSocket* LibWebRTCSocketFactory::createServerTcpSocket(const void* socketGroup, const rtc::SocketAddress& address, uint16_t minPort, uint16_t maxPort, int options)
 {
+    ASSERT(!WTF::isMainRunLoop());
+    if (!m_connection) {
+        RELEASE_LOG(WebRTC, "No connection to create server TCP socket");
+        callOnMainThread([] {
+            WebProcess::singleton().ensureNetworkProcessConnection();
+        });
+        return nullptr;
+    }
+
     auto socket = makeUnique<LibWebRTCSocket>(*this, socketGroup, LibWebRTCSocket::Type::ServerTCP, address, rtc::SocketAddress());
 
-    callOnMainThread([identifier = socket->identifier(), address = prepareSocketAddress(address, m_disableNonLocalhostConnections), minPort, maxPort, options]() {
-        if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkRTCProvider::CreateServerTCPSocket(identifier, RTCNetwork::SocketAddress(address), minPort, maxPort, options), 0)) {
-            // FIXME: Set error back to socket
-            return;
-        }
+    m_connection->send(Messages::NetworkRTCProvider::CreateServerTCPSocket(socket->identifier(), RTCNetwork::SocketAddress(address), minPort, maxPort, options), 0);
 
-    });
     return socket.release();
 }
 
 rtc::AsyncPacketSocket* LibWebRTCSocketFactory::createUdpSocket(const void* socketGroup, const rtc::SocketAddress& address, uint16_t minPort, uint16_t maxPort)
 {
+    ASSERT(!WTF::isMainRunLoop());
+    if (!m_connection) {
+        RELEASE_LOG(WebRTC, "No connection to create UDP socket");
+        callOnMainThread([] {
+            WebProcess::singleton().ensureNetworkProcessConnection();
+        });
+        return nullptr;
+    }
+
     auto socket = makeUnique<LibWebRTCSocket>(*this, socketGroup, LibWebRTCSocket::Type::UDP, address, rtc::SocketAddress());
 
-    callOnMainThread([identifier = socket->identifier(), address = prepareSocketAddress(address, m_disableNonLocalhostConnections), minPort, maxPort]() {
-        if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkRTCProvider::CreateUDPSocket(identifier, RTCNetwork::SocketAddress(address), minPort, maxPort), 0)) {
-            // FIXME: Set error back to socket
-            return;
-        }
-    });
+    m_connection->send(Messages::NetworkRTCProvider::CreateUDPSocket(socket->identifier(), RTCNetwork::SocketAddress(address), minPort, maxPort), 0);
+
     return socket.release();
 }
 
 rtc::AsyncPacketSocket* LibWebRTCSocketFactory::createClientTcpSocket(const void* socketGroup, const rtc::SocketAddress& localAddress, const rtc::SocketAddress& remoteAddress, String&& userAgent, const rtc::PacketSocketTcpOptions& options)
 {
+    ASSERT(!WTF::isMainRunLoop());
+    if (!m_connection) {
+        RELEASE_LOG(WebRTC, "No connection to create client TCP socket");
+        callOnMainThread([] {
+            WebProcess::singleton().ensureNetworkProcessConnection();
+        });
+        return nullptr;
+    }
+
     auto socket = makeUnique<LibWebRTCSocket>(*this, socketGroup, LibWebRTCSocket::Type::ClientTCP, localAddress, remoteAddress);
     socket->setState(LibWebRTCSocket::STATE_CONNECTING);
 
     // FIXME: We only transfer options.opts but should also handle other members.
-    callOnMainThread([identifier = socket->identifier(), localAddress = prepareSocketAddress(localAddress, m_disableNonLocalhostConnections), remoteAddress = prepareSocketAddress(remoteAddress, m_disableNonLocalhostConnections), userAgent = WTFMove(userAgent).isolatedCopy(), options = options.opts]() {
-        if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkRTCProvider::CreateClientTCPSocket(identifier, RTCNetwork::SocketAddress(localAddress), RTCNetwork::SocketAddress(remoteAddress), userAgent, options), 0)) {
-            // FIXME: Set error back to socket
-            return;
-        }
-    });
+    m_connection->send(Messages::NetworkRTCProvider::CreateClientTCPSocket(socket->identifier(), RTCNetwork::SocketAddress(prepareSocketAddress(localAddress, m_disableNonLocalhostConnections)), RTCNetwork::SocketAddress(prepareSocketAddress(remoteAddress, m_disableNonLocalhostConnections)), userAgent, options.opts), 0);
+
     return socket.release();
 }
 
 rtc::AsyncPacketSocket* LibWebRTCSocketFactory::createNewConnectionSocket(LibWebRTCSocket& serverSocket, LibWebRTCSocketIdentifier newConnectionSocketIdentifier, const rtc::SocketAddress& remoteAddress)
 {
+    ASSERT(!WTF::isMainRunLoop());
+    if (!m_connection) {
+        RELEASE_LOG(WebRTC, "No connection to create incoming TCP socket");
+        callOnMainThread([] {
+            WebProcess::singleton().ensureNetworkProcessConnection();
+        });
+        return nullptr;
+    }
+
     auto socket = makeUnique<LibWebRTCSocket>(*this, serverSocket.socketGroup(), LibWebRTCSocket::Type::ServerConnectionTCP, serverSocket.localAddress(), remoteAddress);
     socket->setState(LibWebRTCSocket::STATE_CONNECTED);
 
-    callOnMainThread([identifier = socket->identifier(), newConnectionSocketIdentifier]() {
-        if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkRTCProvider::WrapNewTCPConnection(identifier, newConnectionSocketIdentifier), 0)) {
-            // FIXME: Set error back to socket
-            return;
-        }
-    });
+    m_connection->send(Messages::NetworkRTCProvider::WrapNewTCPConnection(socket->identifier(), newConnectionSocketIdentifier), 0);
+
     return socket.release();
 }
 
 void LibWebRTCSocketFactory::addSocket(LibWebRTCSocket& socket)
 {
+    ASSERT(!WTF::isMainRunLoop());
     ASSERT(!m_sockets.contains(socket.identifier()));
     m_sockets.add(socket.identifier(), &socket);
 }
 
 void LibWebRTCSocketFactory::removeSocket(LibWebRTCSocket& socket)
 {
+    ASSERT(!WTF::isMainRunLoop());
     ASSERT(m_sockets.contains(socket.identifier()));
     m_sockets.remove(socket.identifier());
 }
 
 void LibWebRTCSocketFactory::forSocketInGroup(const void* socketGroup, const Function<void(LibWebRTCSocket&)>& callback)
 {
+    ASSERT(!WTF::isMainRunLoop());
     for (auto* socket : m_sockets.values()) {
         if (socket->socketGroup() == socketGroup)
             callback(*socket);
index d0a627b..dbbaafc 100644 (file)
 
 namespace WebKit {
 
+class LibWebRTCNetwork;
 class LibWebRTCSocket;
 
 class LibWebRTCSocketFactory {
 public:
-    LibWebRTCSocketFactory() { }
+    LibWebRTCSocketFactory() = default;
 
     void addSocket(LibWebRTCSocket&);
     void removeSocket(LibWebRTCSocket&);
@@ -59,6 +60,9 @@ public:
     
     void disableNonLocalhostConnections() { m_disableNonLocalhostConnections = true; }
 
+    void setConnection(RefPtr<IPC::Connection>&&);
+    IPC::Connection* connection();
+
 private:
     // We cannot own sockets, clients of the factory are responsible to free them.
     HashMap<WebCore::LibWebRTCSocketIdentifier, LibWebRTCSocket*> m_sockets;
@@ -66,6 +70,8 @@ private:
     // We can own resolvers as we control their Destroy method.
     HashMap<LibWebRTCResolverIdentifier, std::unique_ptr<LibWebRTCResolver>> m_resolvers;
     bool m_disableNonLocalhostConnections { false };
+
+    RefPtr<IPC::Connection> m_connection;
 };
 
 } // namespace WebKit