⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 269128 in webkit


Ignore:
Timestamp:
Oct 28, 2020, 4:51:45 PM (6 years ago)
Author:
basuke.suzuki@sony.com
Message:

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

Reviewed by Alex Christensen.

Source/JavaScriptCore:

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):

Location:
trunk/Source
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r269115 r269128  
     12020-10-28  Basuke Suzuki  <basuke.suzuki@sony.com>
     2
     3        [WinCairo][PlayStation] Add handling for accept failure case
     4        https://bugs.webkit.org/show_bug.cgi?id=217353
     5
     6        Reviewed by Alex Christensen.
     7
     8        It is rare to happen, but listening socket can be invalid state (i.e. cable disconnection, interface error),
     9        and accept() will be called because of the poll's false report. In that situation, it is required to rebuild
     10        the listening socket from the scratch. The failure of accept is the good place to capture this situation.
     11
     12        This patch moves listening duty into Listener internal calss and it is possible to make the invalid state
     13        while maintained by SocketEndpoint. Also in case of failure continues, the retry will be gradually increasing
     14        the intervals.
     15
     16        * inspector/remote/socket/RemoteInspectorServer.h:
     17        * inspector/remote/socket/RemoteInspectorSocketEndpoint.cpp:
     18        (Inspector::RemoteInspectorSocketEndpoint::listenInet):
     19        (Inspector::RemoteInspectorSocketEndpoint::pollingTimeout):
     20        (Inspector::RemoteInspectorSocketEndpoint::workerThread):
     21        (Inspector::RemoteInspectorSocketEndpoint::createClient):
     22        (Inspector::RemoteInspectorSocketEndpoint::disconnect):
     23        (Inspector::RemoteInspectorSocketEndpoint::acceptInetSocketIfEnabled):
     24        * inspector/remote/socket/RemoteInspectorSocketEndpoint.h:
     25
    1262020-10-28  Saam Barati  <sbarati@apple.com>
    227
  • trunk/Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorServer.h

    r267370 r269128  
    4848
    4949    Optional<ConnectionID> doAccept(RemoteInspectorSocketEndpoint&, PlatformSocketType) final;
    50     void didClose(RemoteInspectorSocketEndpoint&, ConnectionID) final { };
     50    void didChangeStatus(RemoteInspectorSocketEndpoint&, ConnectionID, RemoteInspectorSocketEndpoint::Listener::Status) final { };
    5151
    5252    Optional<ConnectionID> m_server;
  • trunk/Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorSocketEndpoint.cpp

    r267370 r269128  
    3232#include <wtf/MainThread.h>
    3333#include <wtf/RunLoop.h>
    34 #include <wtf/text/WTFString.h>
    3534
    3635namespace Inspector {
     
    9190Optional<ConnectionID> RemoteInspectorSocketEndpoint::listenInet(const char* address, uint16_t port, Listener& listener)
    9291{
    93     if (auto socket = Socket::listen(address, port))
    94         return createListener(*socket, listener);
    95 
    96     return WTF::nullopt;
     92    LockHolder lock(m_connectionsLock);
     93    auto id = generateConnectionID();
     94    auto connection = makeUnique<ListenerConnection>(id, listener, address, port);
     95    if (!connection->isListening())
     96        return WTF::nullopt;
     97
     98    m_listeners.add(id, WTFMove(connection));
     99    wakeupWorkerThread();
     100    return id;
    97101}
    98102
     
    103107        return true;
    104108    return false;
     109}
     110
     111int RemoteInspectorSocketEndpoint::pollingTimeout()
     112{
     113    Optional<MonotonicTime> mostRecentWakeup;
     114    for (const auto& connection : m_listeners) {
     115        if (connection.value->nextRetryTime) {
     116            if (mostRecentWakeup)
     117                mostRecentWakeup = std::min<MonotonicTime>(*mostRecentWakeup, *connection.value->nextRetryTime);
     118            else
     119                mostRecentWakeup = connection.value->nextRetryTime;
     120        }
     121    }
     122
     123    if (mostRecentWakeup)
     124        return static_cast<int>((*mostRecentWakeup - MonotonicTime::now()).milliseconds());
     125
     126    return -1;
    105127}
    106128
     
    129151            }
    130152            for (const auto& connection : m_listeners) {
    131                 pollfds.append(connection.value->poll);
    132                 ids.append(connection.key);
     153                if (!connection.value->isListening() && connection.value->listen())
     154                    connection.value->listener.didChangeStatus(*this, connection.key, Listener::Status::Listening);
     155                if (connection.value->isListening()) {
     156                    pollfds.append(connection.value->poll);
     157                    ids.append(connection.key);
     158                }
    133159            }
    134160        }
    135161        pollfds.append(wakeup);
    136162
    137         if (!Socket::poll(pollfds, -1))
     163        if (!Socket::poll(pollfds, pollingTimeout()))
    138164            continue;
    139165
     
    181207    auto id = generateConnectionID();
    182208    auto connection = makeUnique<ClientConnection>(id, socket, client);
     209    if (!Socket::isValid(connection->socket))
     210        return WTF::nullopt;
     211
    183212    m_clients.add(id, WTFMove(connection));
    184213    wakeupWorkerThread();
     
    195224        Socket::close(connection->socket);
    196225        lock.unlockEarly();
    197         connection->listener.didClose(*this, id);
     226        connection->listener.didChangeStatus(*this, id, Listener::Status::Closed);
    198227    } else if (const auto& connection = m_clients.get(id)) {
    199228        m_clients.remove(id);
     
    203232    } else
    204233        LOG_ERROR("Error: Cannot disconnect: Invalid id");
    205 }
    206 
    207 Optional<ConnectionID> RemoteInspectorSocketEndpoint::createListener(PlatformSocketType socket, Listener& listener)
    208 {
    209     ASSERT(Socket::isValid(socket));
    210 
    211     if (!Socket::setup(socket))
    212         return WTF::nullopt;
    213 
    214     LockHolder lock(m_connectionsLock);
    215     auto id = generateConnectionID();
    216     auto connection = makeUnique<ListenerConnection>(id, socket, listener);
    217     m_listeners.add(id, WTFMove(connection));
    218     wakeupWorkerThread();
    219 
    220     return id;
    221 }
    222 
    223 Optional<ConnectionID> RemoteInspectorSocketEndpoint::createListener(PlatformSocketType socket, Listener& listener, Client& client)
    224 {
    225     ASSERT(Socket::isValid(socket));
    226 
    227     if (!Socket::setup(socket))
    228         return WTF::nullopt;
    229 
    230     LockHolder lock(m_connectionsLock);
    231     auto id = generateConnectionID();
    232     auto connection = makeUnique<ListenerConnection>(id, socket, listener);
    233     m_listeners.add(id, WTFMove(connection));
    234     wakeupWorkerThread();
    235 
    236     return id;
    237234}
    238235
     
    360357            if (connection->listener.doAccept(*this, socket.value()))
    361358                return;
     359
    362360            Socket::close(*socket);
     361        } else {
     362            // If accept() returns error, we have to start over with bind() and listen().
     363            // By closing socket here, listen() will be called again at the next loop of worker thread.
     364            Socket::close(connection->socket);
     365            connection->listener.didChangeStatus(*this, id, Listener::Status::Invalid);
    363366        }
    364367    }
  • trunk/Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorSocketEndpoint.h

    r267370 r269128  
    3535#include <wtf/Threading.h>
    3636#include <wtf/Vector.h>
     37#include <wtf/text/WTFString.h>
    3738
    3839namespace Inspector {
     
    4445    public:
    4546        virtual ~Client() { }
     47
     48        // These callbacks are not guaranteed to be called from the main thread.
    4649        virtual void didReceive(RemoteInspectorSocketEndpoint&, ConnectionID, Vector<uint8_t>&&) = 0;
    4750        virtual void didClose(RemoteInspectorSocketEndpoint&, ConnectionID) = 0;
     
    5053    class Listener {
    5154    public:
     55        enum class Status : uint8_t {
     56            Listening,
     57            Invalid,
     58            Closed,
     59        };
    5260        virtual ~Listener() { }
     61
     62        // These callbacks are not guaranteed to be called from the main thread.
    5363        virtual Optional<ConnectionID> doAccept(RemoteInspectorSocketEndpoint&, PlatformSocketType) = 0;
    54         virtual void didClose(RemoteInspectorSocketEndpoint&, ConnectionID) = 0;
     64        virtual void didChangeStatus(RemoteInspectorSocketEndpoint&, ConnectionID, Status) = 0;
    5565    };
    5666
     
    7080
    7181    Optional<ConnectionID> createClient(PlatformSocketType, Client&);
    72     Optional<ConnectionID> createListener(PlatformSocketType, Listener&, Client&);
    7382
    7483    Optional<uint16_t> getPort(ConnectionID) const;
     
    8089        WTF_MAKE_STRUCT_FAST_ALLOCATED;
    8190
    82         BaseConnection(ConnectionID id, PlatformSocketType socket)
     91        BaseConnection(ConnectionID id)
    8392            : id { id }
    84             , socket { socket }
    85             , poll { Socket::preparePolling(socket) }
     93            , socket { INVALID_SOCKET_VALUE }
    8694        {
    87             ASSERT(Socket::isValid(socket));
     95        }
     96
     97        bool setSocket(PlatformSocketType newSocket)
     98        {
     99            ASSERT(Socket::isValid(newSocket));
     100
     101            if (!Socket::setup(newSocket))
     102                return false;
     103
     104            if (Socket::isValid(socket))
     105                Socket::close(socket);
     106
     107            socket = newSocket;
     108            poll = Socket::preparePolling(socket);
     109            return true;
    88110        }
    89111
     
    95117    struct ClientConnection : public BaseConnection {
    96118        ClientConnection(ConnectionID id, PlatformSocketType socket, Client& client)
    97             : BaseConnection(id, socket)
     119            : BaseConnection(id)
    98120            , client { client }
    99121        {
     122            setSocket(socket);
    100123        }
    101124
     
    105128
    106129    struct ListenerConnection : public BaseConnection {
    107         ListenerConnection(ConnectionID id, PlatformSocketType socket, Listener& listener)
    108             : BaseConnection(id, socket)
     130        static constexpr Seconds initialRetryInterval { 200_ms };
     131        static constexpr Seconds maxRetryInterval { 5_s };
     132
     133        ListenerConnection(ConnectionID id, Listener& listener, const char* address, uint16_t port)
     134            : BaseConnection(id)
     135            , address { address }
     136            , port { port }
    109137            , listener { listener }
    110138        {
     139            listen();
    111140        }
    112141
     142        bool listen()
     143        {
     144            ASSERT(!isListening());
     145
     146            if (nextRetryTime && *nextRetryTime > MonotonicTime::now())
     147                return false;
     148
     149            if (auto newSocket = Socket::listen(address.utf8().data(), port)) {
     150                if (setSocket(*newSocket)) {
     151                    retryInterval = initialRetryInterval;
     152                    return true;
     153                }
     154                Socket::close(*newSocket);
     155            }
     156
     157            nextRetryTime = MonotonicTime::now() + retryInterval;
     158            retryInterval = std::min<Seconds>(retryInterval * 2, maxRetryInterval);
     159
     160            return false;
     161        }
     162
     163        bool isListening()
     164        {
     165            return Socket::isListening(socket);
     166        }
     167
     168        String address;
     169        uint16_t port;
    113170        Listener& listener;
     171        Optional<MonotonicTime> nextRetryTime;
     172        Seconds retryInterval { initialRetryInterval };
    114173    };
    115174
    116175    ConnectionID generateConnectionID();
    117     Optional<ConnectionID> createListener(PlatformSocketType, Listener&);
    118176
    119177    void recvIfEnabled(ConnectionID);
     
    123181    void acceptInetSocketIfEnabled(ConnectionID);
    124182    bool isListening(ConnectionID);
     183    int pollingTimeout();
    125184
    126185    mutable Lock m_connectionsLock;
  • trunk/Source/WebDriver/ChangeLog

    r268867 r269128  
     12020-10-28  Basuke Suzuki  <basuke.suzuki@sony.com>
     2
     3        [WinCairo][PlayStation] Add handling for accept failure case
     4        https://bugs.webkit.org/show_bug.cgi?id=217353
     5
     6        Reviewed by Alex Christensen.
     7
     8        Following the interface change.
     9
     10        * HTTPServer.h:
     11        * socket/HTTPServerSocket.cpp:
     12        (WebDriver::HTTPServer::didStatusChanged):
     13
    1142020-10-22  Nitzan Uziely  <linkgoron@gmail.com>
    215
  • trunk/Source/WebDriver/HTTPServer.h

    r267807 r269128  
    9696#if USE(INSPECTOR_SOCKET_SERVER)
    9797    Optional<ConnectionID> doAccept(RemoteInspectorSocketEndpoint&, PlatformSocketType) final;
    98     void didClose(RemoteInspectorSocketEndpoint&, ConnectionID) final;
     98    void didChangeStatus(RemoteInspectorSocketEndpoint&, ConnectionID, RemoteInspectorSocketEndpoint::Listener::Status) final;
    9999#endif
    100100
  • trunk/Source/WebDriver/socket/HTTPServerSocket.cpp

    r267807 r269128  
    5757}
    5858
    59 void HTTPServer::didClose(RemoteInspectorSocketEndpoint&, ConnectionID)
     59void HTTPServer::didChangeStatus(RemoteInspectorSocketEndpoint&, ConnectionID, RemoteInspectorSocketEndpoint::Listener::Status status)
    6060{
    61     m_server = WTF::nullopt;
     61    if (status == Status::Closed)
     62        m_server = WTF::nullopt;
    6263}
    6364
Note: See TracChangeset for help on using the changeset viewer.