Title: [269128] trunk/Source
Revision
269128
Author
[email protected]
Date
2020-10-28 16:51:45 -0700 (Wed, 28 Oct 2020)

Log Message

[WinCairo][PlayStation] Add handling for accept failure case
https://bugs.webkit.org/show_bug.cgi?id=217353

Reviewed by Alex Christensen.

Source/_javascript_Core:

It is rare to happen, but listening socket can be invalid state (i.e. cable disconnection, interface error),
and accept() will be called because of the poll's false report. In that situation, it is required to rebuild
the listening socket from the scratch. The failure of accept is the good place to capture this situation.

This patch moves listening duty into Listener internal calss and it is possible to make the invalid state
while maintained by SocketEndpoint. Also in case of failure continues, the retry will be gradually increasing
the intervals.

* inspector/remote/socket/RemoteInspectorServer.h:
* inspector/remote/socket/RemoteInspectorSocketEndpoint.cpp:
(Inspector::RemoteInspectorSocketEndpoint::listenInet):
(Inspector::RemoteInspectorSocketEndpoint::pollingTimeout):
(Inspector::RemoteInspectorSocketEndpoint::workerThread):
(Inspector::RemoteInspectorSocketEndpoint::createClient):
(Inspector::RemoteInspectorSocketEndpoint::disconnect):
(Inspector::RemoteInspectorSocketEndpoint::acceptInetSocketIfEnabled):
* inspector/remote/socket/RemoteInspectorSocketEndpoint.h:

Source/WebDriver:

Following the interface change.

* HTTPServer.h:
* socket/HTTPServerSocket.cpp:
(WebDriver::HTTPServer::didStatusChanged):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (269127 => 269128)


--- trunk/Source/_javascript_Core/ChangeLog	2020-10-28 21:34:04 UTC (rev 269127)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-10-28 23:51:45 UTC (rev 269128)
@@ -1,3 +1,28 @@
+2020-10-28  Basuke Suzuki  <[email protected]>
+
+        [WinCairo][PlayStation] Add handling for accept failure case
+        https://bugs.webkit.org/show_bug.cgi?id=217353
+
+        Reviewed by Alex Christensen.
+
+        It is rare to happen, but listening socket can be invalid state (i.e. cable disconnection, interface error),
+        and accept() will be called because of the poll's false report. In that situation, it is required to rebuild
+        the listening socket from the scratch. The failure of accept is the good place to capture this situation.
+
+        This patch moves listening duty into Listener internal calss and it is possible to make the invalid state
+        while maintained by SocketEndpoint. Also in case of failure continues, the retry will be gradually increasing
+        the intervals.
+
+        * inspector/remote/socket/RemoteInspectorServer.h:
+        * inspector/remote/socket/RemoteInspectorSocketEndpoint.cpp:
+        (Inspector::RemoteInspectorSocketEndpoint::listenInet):
+        (Inspector::RemoteInspectorSocketEndpoint::pollingTimeout):
+        (Inspector::RemoteInspectorSocketEndpoint::workerThread):
+        (Inspector::RemoteInspectorSocketEndpoint::createClient):
+        (Inspector::RemoteInspectorSocketEndpoint::disconnect):
+        (Inspector::RemoteInspectorSocketEndpoint::acceptInetSocketIfEnabled):
+        * inspector/remote/socket/RemoteInspectorSocketEndpoint.h:
+
 2020-10-28  Saam Barati  <[email protected]>
 
         Better cache our serialization of the outer TDZ environment when creating FunctionExecutables during bytecode generation

Modified: trunk/Source/_javascript_Core/inspector/remote/socket/RemoteInspectorServer.h (269127 => 269128)


--- trunk/Source/_javascript_Core/inspector/remote/socket/RemoteInspectorServer.h	2020-10-28 21:34:04 UTC (rev 269127)
+++ trunk/Source/_javascript_Core/inspector/remote/socket/RemoteInspectorServer.h	2020-10-28 23:51:45 UTC (rev 269128)
@@ -47,7 +47,7 @@
     RemoteInspectorServer() { Socket::init(); }
 
     Optional<ConnectionID> doAccept(RemoteInspectorSocketEndpoint&, PlatformSocketType) final;
-    void didClose(RemoteInspectorSocketEndpoint&, ConnectionID) final { };
+    void didChangeStatus(RemoteInspectorSocketEndpoint&, ConnectionID, RemoteInspectorSocketEndpoint::Listener::Status) final { };
 
     Optional<ConnectionID> m_server;
 };

Modified: trunk/Source/_javascript_Core/inspector/remote/socket/RemoteInspectorSocketEndpoint.cpp (269127 => 269128)


--- trunk/Source/_javascript_Core/inspector/remote/socket/RemoteInspectorSocketEndpoint.cpp	2020-10-28 21:34:04 UTC (rev 269127)
+++ trunk/Source/_javascript_Core/inspector/remote/socket/RemoteInspectorSocketEndpoint.cpp	2020-10-28 23:51:45 UTC (rev 269128)
@@ -31,7 +31,6 @@
 #include <wtf/CryptographicallyRandomNumber.h>
 #include <wtf/MainThread.h>
 #include <wtf/RunLoop.h>
-#include <wtf/text/WTFString.h>
 
 namespace Inspector {
 
@@ -90,10 +89,15 @@
 
 Optional<ConnectionID> RemoteInspectorSocketEndpoint::listenInet(const char* address, uint16_t port, Listener& listener)
 {
-    if (auto socket = Socket::listen(address, port))
-        return createListener(*socket, listener);
+    LockHolder lock(m_connectionsLock);
+    auto id = generateConnectionID();
+    auto connection = makeUnique<ListenerConnection>(id, listener, address, port);
+    if (!connection->isListening())
+        return WTF::nullopt;
 
-    return WTF::nullopt;
+    m_listeners.add(id, WTFMove(connection));
+    wakeupWorkerThread();
+    return id;
 }
 
 bool RemoteInspectorSocketEndpoint::isListening(ConnectionID id)
@@ -104,6 +108,24 @@
     return false;
 }
 
+int RemoteInspectorSocketEndpoint::pollingTimeout()
+{
+    Optional<MonotonicTime> mostRecentWakeup;
+    for (const auto& connection : m_listeners) {
+        if (connection.value->nextRetryTime) {
+            if (mostRecentWakeup)
+                mostRecentWakeup = std::min<MonotonicTime>(*mostRecentWakeup, *connection.value->nextRetryTime);
+            else
+                mostRecentWakeup = connection.value->nextRetryTime;
+        }
+    }
+
+    if (mostRecentWakeup)
+        return static_cast<int>((*mostRecentWakeup - MonotonicTime::now()).milliseconds());
+
+    return -1;
+}
+
 void RemoteInspectorSocketEndpoint::workerThread()
 {
     PollingDescriptor wakeup = Socket::preparePolling(m_wakeupReceiveSocket);
@@ -128,13 +150,17 @@
                 ids.append(connection.key);
             }
             for (const auto& connection : m_listeners) {
-                pollfds.append(connection.value->poll);
-                ids.append(connection.key);
+                if (!connection.value->isListening() && connection.value->listen())
+                    connection.value->listener.didChangeStatus(*this, connection.key, Listener::Status::Listening);
+                if (connection.value->isListening()) {
+                    pollfds.append(connection.value->poll);
+                    ids.append(connection.key);
+                }
             }
         }
         pollfds.append(wakeup);
 
-        if (!Socket::poll(pollfds, -1))
+        if (!Socket::poll(pollfds, pollingTimeout()))
             continue;
 
         if (Socket::isReadable(pollfds.last())) {
@@ -180,6 +206,9 @@
     LockHolder lock(m_connectionsLock);
     auto id = generateConnectionID();
     auto connection = makeUnique<ClientConnection>(id, socket, client);
+    if (!Socket::isValid(connection->socket))
+        return WTF::nullopt;
+
     m_clients.add(id, WTFMove(connection));
     wakeupWorkerThread();
 
@@ -194,7 +223,7 @@
         m_listeners.remove(id);
         Socket::close(connection->socket);
         lock.unlockEarly();
-        connection->listener.didClose(*this, id);
+        connection->listener.didChangeStatus(*this, id, Listener::Status::Closed);
     } else if (const auto& connection = m_clients.get(id)) {
         m_clients.remove(id);
         Socket::close(connection->socket);
@@ -204,38 +233,6 @@
         LOG_ERROR("Error: Cannot disconnect: Invalid id");
 }
 
-Optional<ConnectionID> RemoteInspectorSocketEndpoint::createListener(PlatformSocketType socket, Listener& listener)
-{
-    ASSERT(Socket::isValid(socket));
-
-    if (!Socket::setup(socket))
-        return WTF::nullopt;
-
-    LockHolder lock(m_connectionsLock);
-    auto id = generateConnectionID();
-    auto connection = makeUnique<ListenerConnection>(id, socket, listener);
-    m_listeners.add(id, WTFMove(connection));
-    wakeupWorkerThread();
-
-    return id;
-}
-
-Optional<ConnectionID> RemoteInspectorSocketEndpoint::createListener(PlatformSocketType socket, Listener& listener, Client& client)
-{
-    ASSERT(Socket::isValid(socket));
-
-    if (!Socket::setup(socket))
-        return WTF::nullopt;
-
-    LockHolder lock(m_connectionsLock);
-    auto id = generateConnectionID();
-    auto connection = makeUnique<ListenerConnection>(id, socket, listener);
-    m_listeners.add(id, WTFMove(connection));
-    wakeupWorkerThread();
-
-    return id;
-}
-
 void RemoteInspectorSocketEndpoint::invalidateClient(Client& client)
 {
     LockHolder lock(m_connectionsLock);
@@ -359,7 +356,13 @@
             lock.unlockEarly();
             if (connection->listener.doAccept(*this, socket.value()))
                 return;
+
             Socket::close(*socket);
+        } else {
+            // If accept() returns error, we have to start over with bind() and listen().
+            // By closing socket here, listen() will be called again at the next loop of worker thread.
+            Socket::close(connection->socket);
+            connection->listener.didChangeStatus(*this, id, Listener::Status::Invalid);
         }
     }
 }

Modified: trunk/Source/_javascript_Core/inspector/remote/socket/RemoteInspectorSocketEndpoint.h (269127 => 269128)


--- trunk/Source/_javascript_Core/inspector/remote/socket/RemoteInspectorSocketEndpoint.h	2020-10-28 21:34:04 UTC (rev 269127)
+++ trunk/Source/_javascript_Core/inspector/remote/socket/RemoteInspectorSocketEndpoint.h	2020-10-28 23:51:45 UTC (rev 269128)
@@ -34,6 +34,7 @@
 #include <wtf/Lock.h>
 #include <wtf/Threading.h>
 #include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
 
 namespace Inspector {
 
@@ -43,6 +44,8 @@
     class Client {
     public:
         virtual ~Client() { }
+
+        // These callbacks are not guaranteed to be called from the main thread.
         virtual void didReceive(RemoteInspectorSocketEndpoint&, ConnectionID, Vector<uint8_t>&&) = 0;
         virtual void didClose(RemoteInspectorSocketEndpoint&, ConnectionID) = 0;
     };
@@ -49,9 +52,16 @@
 
     class Listener {
     public:
+        enum class Status : uint8_t {
+            Listening,
+            Invalid,
+            Closed,
+        };
         virtual ~Listener() { }
+
+        // These callbacks are not guaranteed to be called from the main thread.
         virtual Optional<ConnectionID> doAccept(RemoteInspectorSocketEndpoint&, PlatformSocketType) = 0;
-        virtual void didClose(RemoteInspectorSocketEndpoint&, ConnectionID) = 0;
+        virtual void didChangeStatus(RemoteInspectorSocketEndpoint&, ConnectionID, Status) = 0;
     };
 
     static RemoteInspectorSocketEndpoint& singleton();
@@ -69,7 +79,6 @@
     inline void send(ConnectionID id, const char* data, size_t length) { send(id, reinterpret_cast<const uint8_t*>(data), length); }
 
     Optional<ConnectionID> createClient(PlatformSocketType, Client&);
-    Optional<ConnectionID> createListener(PlatformSocketType, Listener&, Client&);
 
     Optional<uint16_t> getPort(ConnectionID) const;
 
@@ -79,14 +88,27 @@
     struct BaseConnection {
         WTF_MAKE_STRUCT_FAST_ALLOCATED;
 
-        BaseConnection(ConnectionID id, PlatformSocketType socket)
+        BaseConnection(ConnectionID id)
             : id { id }
-            , socket { socket }
-            , poll { Socket::preparePolling(socket) }
+            , socket { INVALID_SOCKET_VALUE }
         {
-            ASSERT(Socket::isValid(socket));
         }
 
+        bool setSocket(PlatformSocketType newSocket)
+        {
+            ASSERT(Socket::isValid(newSocket));
+
+            if (!Socket::setup(newSocket))
+                return false;
+
+            if (Socket::isValid(socket))
+                Socket::close(socket);
+
+            socket = newSocket;
+            poll = Socket::preparePolling(socket);
+            return true;
+        }
+
         ConnectionID id;
         PlatformSocketType socket;
         PollingDescriptor poll;
@@ -94,9 +116,10 @@
 
     struct ClientConnection : public BaseConnection {
         ClientConnection(ConnectionID id, PlatformSocketType socket, Client& client)
-            : BaseConnection(id, socket)
+            : BaseConnection(id)
             , client { client }
         {
+            setSocket(socket);
         }
 
         Client& client;
@@ -104,17 +127,52 @@
     };
 
     struct ListenerConnection : public BaseConnection {
-        ListenerConnection(ConnectionID id, PlatformSocketType socket, Listener& listener)
-            : BaseConnection(id, socket)
+        static constexpr Seconds initialRetryInterval { 200_ms };
+        static constexpr Seconds maxRetryInterval { 5_s };
+
+        ListenerConnection(ConnectionID id, Listener& listener, const char* address, uint16_t port)
+            : BaseConnection(id)
+            , address { address }
+            , port { port }
             , listener { listener }
         {
+            listen();
         }
 
+        bool listen()
+        {
+            ASSERT(!isListening());
+
+            if (nextRetryTime && *nextRetryTime > MonotonicTime::now())
+                return false;
+
+            if (auto newSocket = Socket::listen(address.utf8().data(), port)) {
+                if (setSocket(*newSocket)) {
+                    retryInterval = initialRetryInterval;
+                    return true;
+                }
+                Socket::close(*newSocket);
+            }
+
+            nextRetryTime = MonotonicTime::now() + retryInterval;
+            retryInterval = std::min<Seconds>(retryInterval * 2, maxRetryInterval);
+
+            return false;
+        }
+
+        bool isListening()
+        {
+            return Socket::isListening(socket);
+        }
+
+        String address;
+        uint16_t port;
         Listener& listener;
+        Optional<MonotonicTime> nextRetryTime;
+        Seconds retryInterval { initialRetryInterval };
     };
 
     ConnectionID generateConnectionID();
-    Optional<ConnectionID> createListener(PlatformSocketType, Listener&);
 
     void recvIfEnabled(ConnectionID);
     void sendIfEnabled(ConnectionID);
@@ -122,6 +180,7 @@
     void wakeupWorkerThread();
     void acceptInetSocketIfEnabled(ConnectionID);
     bool isListening(ConnectionID);
+    int pollingTimeout();
 
     mutable Lock m_connectionsLock;
     HashMap<ConnectionID, std::unique_ptr<ClientConnection>> m_clients;

Modified: trunk/Source/WebDriver/ChangeLog (269127 => 269128)


--- trunk/Source/WebDriver/ChangeLog	2020-10-28 21:34:04 UTC (rev 269127)
+++ trunk/Source/WebDriver/ChangeLog	2020-10-28 23:51:45 UTC (rev 269128)
@@ -1,3 +1,16 @@
+2020-10-28  Basuke Suzuki  <[email protected]>
+
+        [WinCairo][PlayStation] Add handling for accept failure case
+        https://bugs.webkit.org/show_bug.cgi?id=217353
+
+        Reviewed by Alex Christensen.
+
+        Following the interface change.
+
+        * HTTPServer.h:
+        * socket/HTTPServerSocket.cpp:
+        (WebDriver::HTTPServer::didStatusChanged):
+
 2020-10-22  Nitzan Uziely  <[email protected]>
 
         Elements in Shadow DOM are wrongly marked as stale by the WebDriver

Modified: trunk/Source/WebDriver/HTTPServer.h (269127 => 269128)


--- trunk/Source/WebDriver/HTTPServer.h	2020-10-28 21:34:04 UTC (rev 269127)
+++ trunk/Source/WebDriver/HTTPServer.h	2020-10-28 23:51:45 UTC (rev 269128)
@@ -95,7 +95,7 @@
 private:
 #if USE(INSPECTOR_SOCKET_SERVER)
     Optional<ConnectionID> doAccept(RemoteInspectorSocketEndpoint&, PlatformSocketType) final;
-    void didClose(RemoteInspectorSocketEndpoint&, ConnectionID) final;
+    void didChangeStatus(RemoteInspectorSocketEndpoint&, ConnectionID, RemoteInspectorSocketEndpoint::Listener::Status) final;
 #endif
 
     HTTPRequestHandler& m_requestHandler;

Modified: trunk/Source/WebDriver/socket/HTTPServerSocket.cpp (269127 => 269128)


--- trunk/Source/WebDriver/socket/HTTPServerSocket.cpp	2020-10-28 21:34:04 UTC (rev 269127)
+++ trunk/Source/WebDriver/socket/HTTPServerSocket.cpp	2020-10-28 23:51:45 UTC (rev 269128)
@@ -56,9 +56,10 @@
     return WTF::nullopt;
 }
 
-void HTTPServer::didClose(RemoteInspectorSocketEndpoint&, ConnectionID)
+void HTTPServer::didChangeStatus(RemoteInspectorSocketEndpoint&, ConnectionID, RemoteInspectorSocketEndpoint::Listener::Status status)
 {
-    m_server = WTF::nullopt;
+    if (status == Status::Closed)
+        m_server = WTF::nullopt;
 }
 
 void HTTPRequestHandler::connect(ConnectionID id)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to