WebKit Bugzilla
Attachment 361707 Details for
Bug 193806
: [PlayStation] Upstream playstation's remote inspector server
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Inspector Server
rwi-4.diff (text/plain), 50.50 KB, created by
Christopher Reid
on 2019-02-11 13:34:09 PST
(
hide
)
Description:
Inspector Server
Filename:
MIME Type:
Creator:
Christopher Reid
Created:
2019-02-11 13:34:09 PST
Size:
50.50 KB
patch
obsolete
>diff --git a/Source/JavaScriptCore/PlatformPlayStation.cmake b/Source/JavaScriptCore/PlatformPlayStation.cmake >index 02fcb4e01e2..9834b8b2325 100644 >--- a/Source/JavaScriptCore/PlatformPlayStation.cmake >+++ b/Source/JavaScriptCore/PlatformPlayStation.cmake >@@ -1,3 +1,35 @@ >+list(APPEND JavaScriptCore_PRIVATE_INCLUDE_DIRECTORIES >+ "${JAVASCRIPTCORE_DIR}/inspector/remote/generic" >+ "${JAVASCRIPTCORE_DIR}/inspector/remote/playstation" >+) >+ >+list(APPEND JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS >+ inspector/remote/RemoteAutomationTarget.h >+ inspector/remote/RemoteConnectionToTarget.h >+ inspector/remote/RemoteControllableTarget.h >+ inspector/remote/RemoteInspectionTarget.h >+ inspector/remote/RemoteInspector.h >+ >+ inspector/remote/generic/RemoteInspectorServer.h >+ >+ inspector/remote/playstation/RemoteInspectorSocket.h >+) >+ >+list(APPEND JavaScriptCore_SOURCES >+ API/JSRemoteInspector.cpp >+ >+ inspector/remote/RemoteAutomationTarget.cpp >+ inspector/remote/RemoteControllableTarget.cpp >+ inspector/remote/RemoteInspectionTarget.cpp >+ inspector/remote/RemoteInspector.cpp >+ >+ inspector/remote/generic/RemoteConnectionToTargetGeneric.cpp >+ inspector/remote/generic/RemoteInspectorGeneric.cpp >+ inspector/remote/generic/RemoteInspectorServerGeneric.cpp >+ >+ inspector/remote/playstation/RemoteInspectorSocketPlayStation.cpp >+) >+ > if (${WTF_LIBRARY_TYPE} STREQUAL "STATIC") > add_definitions(-DSTATICALLY_LINKED_WITH_WTF) > endif () >diff --git a/Source/JavaScriptCore/SourcesGTK.txt b/Source/JavaScriptCore/SourcesGTK.txt >index d72613fb2f9..555a2c80698 100644 >--- a/Source/JavaScriptCore/SourcesGTK.txt >+++ b/Source/JavaScriptCore/SourcesGTK.txt >@@ -28,7 +28,8 @@ inspector/remote/RemoteControllableTarget.cpp > inspector/remote/RemoteInspectionTarget.cpp > inspector/remote/RemoteInspector.cpp > >-inspector/remote/glib/RemoteConnectionToTargetGlib.cpp >+inspector/remote/generic/RemoteConnectionToTargetGeneric.cpp >+ > inspector/remote/glib/RemoteInspectorGlib.cpp > inspector/remote/glib/RemoteInspectorServer.cpp > inspector/remote/glib/RemoteInspectorUtils.cpp >diff --git a/Source/JavaScriptCore/SourcesWPE.txt b/Source/JavaScriptCore/SourcesWPE.txt >index d72613fb2f9..555a2c80698 100644 >--- a/Source/JavaScriptCore/SourcesWPE.txt >+++ b/Source/JavaScriptCore/SourcesWPE.txt >@@ -28,7 +28,8 @@ inspector/remote/RemoteControllableTarget.cpp > inspector/remote/RemoteInspectionTarget.cpp > inspector/remote/RemoteInspector.cpp > >-inspector/remote/glib/RemoteConnectionToTargetGlib.cpp >+inspector/remote/generic/RemoteConnectionToTargetGeneric.cpp >+ > inspector/remote/glib/RemoteInspectorGlib.cpp > inspector/remote/glib/RemoteInspectorServer.cpp > inspector/remote/glib/RemoteInspectorUtils.cpp >diff --git a/Source/JavaScriptCore/inspector/remote/RemoteInspector.h b/Source/JavaScriptCore/inspector/remote/RemoteInspector.h >index 389e843fab6..e5f125ba6b8 100644 >--- a/Source/JavaScriptCore/inspector/remote/RemoteInspector.h >+++ b/Source/JavaScriptCore/inspector/remote/RemoteInspector.h >@@ -51,6 +51,35 @@ typedef struct _GDBusConnection GDBusConnection; > typedef struct _GDBusInterfaceVTable GDBusInterfaceVTable; > #endif > >+#if PLATFORM(PLAYSTATION) >+#include "RemoteConnectionToTarget.h" >+#include "RemoteInspectorSocket.h" >+#include <wtf/RefCounted.h> >+#include <wtf/RefPtr.h> >+ >+namespace Inspector { >+ >+class TargetInfo : public RefCounted<TargetInfo> { >+public: >+ uint64_t targetIdentifier; >+ String type; >+ String name; >+ String url; >+ bool hasLocalDebugger; >+}; >+using TargetListing = RefPtr<TargetInfo>; >+ >+class InspectorEvent { >+public: >+ ClientID clientID; >+ Optional<uint64_t> connectionID { WTF::nullopt }; >+ Optional<uint64_t> targetID { WTF::nullopt }; >+ Optional<String> message { WTF::nullopt }; >+}; >+ >+} >+#endif >+ > namespace Inspector { > > class RemoteAutomationTarget; >@@ -131,6 +160,11 @@ public: > void setup(unsigned targetIdentifier); > void sendMessageToTarget(unsigned targetIdentifier, const char* message); > #endif >+#if PLATFORM(PLAYSTATION) >+ void setup(unsigned targetIdentifier); >+ void sendMessageToTarget(unsigned targetIdentifier, const char* message); >+ static void setConnectionIdentifier(PlatformSocketType); >+#endif > > private: > RemoteInspector(); >@@ -184,7 +218,21 @@ private: > void receivedAutomaticInspectionRejectMessage(NSDictionary *userInfo); > void receivedAutomationSessionRequestMessage(NSDictionary *userInfo); > #endif >+#if PLATFORM(PLAYSTATION) >+ using RemoteInspectorCall = void (RemoteInspector::*)(const InspectorEvent&); >+ HashMap<String, RemoteInspectorCall>& methodTable(); >+ >+ void didReceiveData(Vector<uint8_t>&&); >+ void didClose(); > >+ void sendWebInspectorEvent(const String&); >+ void didReceiveWebInspectorEvent(Vector<uint8_t>&&); >+ >+ void receivedGetTargetListMessage(const InspectorEvent&); >+ void receivedSetupMessage(const InspectorEvent&); >+ void receivedDataMessage(const InspectorEvent&); >+ void receivedCloseMessage(const InspectorEvent&); >+#endif > static bool startEnabled; > > // Targets can be registered from any thread at any time. >@@ -205,6 +253,12 @@ private: > GRefPtr<GCancellable> m_cancellable; > #endif > >+#if PLATFORM(PLAYSTATION) >+ std::unique_ptr<RemoteInspectorSocketClient> m_socketConnection; >+ static PlatformSocketType connectionIdentifier; >+ Optional<ClientID> m_clientID; >+#endif >+ > RemoteInspector::Client* m_client { nullptr }; > Optional<RemoteInspector::Client::Capabilities> m_clientCapabilities; > >diff --git a/Source/JavaScriptCore/inspector/remote/glib/RemoteConnectionToTargetGlib.cpp b/Source/JavaScriptCore/inspector/remote/generic/RemoteConnectionToTargetGeneric.cpp >similarity index 100% >rename from Source/JavaScriptCore/inspector/remote/glib/RemoteConnectionToTargetGlib.cpp >rename to Source/JavaScriptCore/inspector/remote/generic/RemoteConnectionToTargetGeneric.cpp >diff --git a/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorGeneric.cpp b/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorGeneric.cpp >new file mode 100644 >index 00000000000..6834ce57de9 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorGeneric.cpp >@@ -0,0 +1,362 @@ >+/* >+ * Copyright (C) 2019 Sony Interactive Entertainment Inc. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "RemoteInspector.h" >+ >+#if ENABLE(REMOTE_INSPECTOR) >+ >+#include "RemoteAutomationTarget.h" >+#include "RemoteInspectionTarget.h" >+#include <wtf/JSONValues.h> >+#include <wtf/MainThread.h> >+#include <wtf/NeverDestroyed.h> >+#include <wtf/RunLoop.h> >+ >+namespace Inspector { >+ >+PlatformSocketType RemoteInspector::connectionIdentifier = INVALID_SOCKET_VALUE; >+ >+RemoteInspector& RemoteInspector::singleton() >+{ >+ static NeverDestroyed<RemoteInspector> shared; >+ return shared; >+} >+ >+RemoteInspector::RemoteInspector() >+{ >+ start(); >+} >+ >+void RemoteInspector::didReceiveData(Vector<uint8_t>&& data) >+{ >+ ASSERT(!isMainThread()); >+ >+ if (data.isEmpty()) >+ return; >+ >+ didReceiveWebInspectorEvent(WTFMove(data)); >+} >+ >+void RemoteInspector::didClose() >+{ >+ ASSERT(!isMainThread()); >+ >+ // FIXME: >+ // glib port doesn't implement event handler for the "closed" signal. >+ // we should consider whether this function is unnecessary, >+ // or should call receivedCloseMessage() instead. >+} >+ >+HashMap<String, RemoteInspector::RemoteInspectorCall>& RemoteInspector::methodTable() >+{ >+ static NeverDestroyed<HashMap<String, RemoteInspectorCall>> methods = HashMap<String, RemoteInspectorCall>({ >+ {"GetTargetList"_s, &RemoteInspector::receivedGetTargetListMessage}, >+ {"Setup"_s, &RemoteInspector::receivedSetupMessage}, >+ {"SendMessageToTarget"_s, &RemoteInspector::receivedDataMessage}, >+ {"FrontendDidClose"_s, &RemoteInspector::receivedCloseMessage}, >+ }); >+ >+ return methods; >+} >+ >+void RemoteInspector::sendWebInspectorEvent(const String& event) >+{ >+ if (!m_clientID) >+ return; >+ >+ const CString& message = event.utf8(); >+ m_socketConnection->send(*m_clientID, reinterpret_cast<const uint8_t*>(message.data()), message.length()); >+} >+ >+void RemoteInspector::didReceiveWebInspectorEvent(Vector<uint8_t>&& data) >+{ >+ ASSERT(!isMainThread()); >+ >+ auto jsonData = String::adopt(WTFMove(data)); >+ RefPtr<JSON::Value> messageValue; >+ if (!JSON::Value::parseJSON(jsonData, messageValue)) >+ return; >+ >+ RefPtr<JSON::Object> messageObject; >+ if (!messageValue->asObject(messageObject)) >+ return; >+ >+ String methodName; >+ if (!messageObject->getString("event"_s, methodName)) >+ return; >+ >+ InspectorEvent event; >+ uint64_t connectionID; >+ uint64_t targetID; >+ String message; >+ >+ if (messageObject->getInteger("connectionID"_s, connectionID)) >+ event.connectionID = Optional<uint64_t>(connectionID); >+ >+ if (messageObject->getInteger("targetID"_s, targetID)) >+ event.targetID = Optional<uint64_t>(targetID); >+ >+ if (messageObject->getString("message"_s, message)) >+ event.message = Optional<String>(WTFMove(message)); >+ >+ RunLoop::main().dispatch([this, methodName, event = WTFMove(event)] { >+ auto methods = methodTable(); >+ if (methods.contains(methodName)) { >+ auto call = methods.get(methodName); >+ (this->*call)(event); >+ } else >+ LOG_ERROR("Unknown method: %s", methodName.utf8().data()); >+ }); >+} >+ >+void RemoteInspector::start() >+{ >+ std::lock_guard<Lock> lock(m_mutex); >+ >+ if (m_enabled || connectionIdentifier == INVALID_SOCKET_VALUE) >+ return; >+ >+ m_enabled = true; >+ >+ m_socketConnection = RemoteInspectorSocketClient::create(); >+ >+ m_socketConnection->setDidReceiveDataListener([this](ClientID, Vector<uint8_t>&& data) { >+ didReceiveData(WTFMove(data)); >+ }); >+ m_socketConnection->setDidCloseListener([this](ClientID) { >+ didClose(); >+ }); >+ >+ m_clientID = m_socketConnection->createClient(connectionIdentifier); >+ >+ if (!m_targetMap.isEmpty()) >+ pushListingsSoon(); >+} >+ >+void RemoteInspector::stopInternal(StopSource) >+{ >+ if (!m_enabled) >+ return; >+ >+ m_enabled = false; >+ m_pushScheduled = false; >+ >+ for (auto targetConnection : m_targetConnectionMap.values()) >+ targetConnection->close(); >+ m_targetConnectionMap.clear(); >+ >+ updateHasActiveDebugSession(); >+ >+ m_automaticInspectionPaused = false; >+ m_socketConnection = nullptr; >+} >+ >+TargetListing RemoteInspector::listingForInspectionTarget(const RemoteInspectionTarget& target) const >+{ >+ >+ if (!target.remoteDebuggingAllowed()) >+ return nullptr; >+ >+ // FIXME: Support remote debugging of a ServiceWorker. >+ if (target.type() == RemoteInspectionTarget::Type::ServiceWorker) >+ return nullptr; >+ >+ TargetInfo* info = new TargetInfo(); >+ info->targetIdentifier = target.targetIdentifier(); >+ info->name = target.name(); >+ info->url = target.url(); >+ info->hasLocalDebugger = target.hasLocalDebugger(); >+ if (target.type() == RemoteInspectionTarget::Type::Web) >+ info->type = "Web"_s; >+ else if (target.type() == RemoteInspectionTarget::Type::JavaScript) >+ info->type = "JavaScript"_s; >+ else if (target.type() == RemoteInspectionTarget::Type::ServiceWorker) >+ info->type = "ServiceWorker"_s; >+ >+ return adoptRef(info); >+} >+ >+TargetListing RemoteInspector::listingForAutomationTarget(const RemoteAutomationTarget&) const >+{ >+ // FIXME: not implemented >+ return nullptr; >+} >+ >+void RemoteInspector::pushListingsNow() >+{ >+ if (!m_socketConnection) >+ return; >+ >+ m_pushScheduled = false; >+ >+ auto targetListJSON = JSON::Array::create(); >+ for (auto listing : m_targetListingMap.values()) { >+ auto target = JSON::Object::create(); >+ target->setInteger("targetID"_s, listing->targetIdentifier); >+ target->setString("type"_s, listing->type); >+ target->setString("name"_s, listing->name); >+ target->setString("url"_s, listing->url); >+ target->setBoolean("hasLocalDebugger"_s, listing->hasLocalDebugger); >+ targetListJSON->pushObject(WTFMove(target)); >+ } >+ >+ auto jsonEvent = JSON::Object::create(); >+ jsonEvent->setString("event"_s, "SetTargetList"_s); >+ jsonEvent->setString("message"_s, targetListJSON->toJSONString()); >+ sendWebInspectorEvent(jsonEvent->toJSONString()); >+} >+ >+void RemoteInspector::pushListingsSoon() >+{ >+ if (!m_socketConnection) >+ return; >+ >+ if (m_pushScheduled) >+ return; >+ >+ m_pushScheduled = true; >+ >+ WTF::RunLoop::current().dispatch([=] { >+ std::lock_guard<Lock> lock(m_mutex); >+ if (m_pushScheduled) >+ pushListingsNow(); >+ }); >+} >+ >+void RemoteInspector::updateAutomaticInspectionCandidate(RemoteInspectionTarget*) >+{ >+} >+ >+void RemoteInspector::sendAutomaticInspectionCandidateMessage() >+{ >+} >+ >+void RemoteInspector::sendMessageToRemote(unsigned targetIdentifier, const String& message) >+{ >+ std::lock_guard<Lock> lock(m_mutex); >+ if (!m_socketConnection) >+ return; >+ >+ auto sendMessageEvent = JSON::Object::create(); >+ sendMessageEvent->setInteger("targetID"_s, targetIdentifier); >+ sendMessageEvent->setString("event"_s, "SendMessageToFrontend"_s); >+ sendMessageEvent->setString("message"_s, message.utf8().data()); >+ sendWebInspectorEvent(sendMessageEvent->toJSONString()); >+} >+ >+void RemoteInspector::receivedGetTargetListMessage(const InspectorEvent&) >+{ >+ ASSERT(isMainThread()); >+ >+ std::lock_guard<Lock> lock(m_mutex); >+ pushListingsNow(); >+} >+ >+void RemoteInspector::receivedSetupMessage(const InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ if (event.targetID) >+ setup(*event.targetID); >+} >+ >+void RemoteInspector::receivedDataMessage(const InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ if (!event.targetID || !event.message) >+ return; >+ >+ RefPtr<RemoteConnectionToTarget> connectionToTarget; >+ { >+ std::lock_guard<Lock> lock(m_mutex); >+ connectionToTarget = m_targetConnectionMap.get(*event.targetID); >+ if (!connectionToTarget) >+ return; >+ } >+ >+ connectionToTarget->sendMessageToTarget(*event.message); >+} >+ >+void RemoteInspector::receivedCloseMessage(const InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ if (!event.targetID) >+ return; >+ >+ RefPtr<RemoteConnectionToTarget> connectionToTarget; >+ { >+ std::lock_guard<Lock> lock(m_mutex); >+ RemoteControllableTarget* target = m_targetMap.get(*event.targetID); >+ if (!target) >+ return; >+ >+ connectionToTarget = m_targetConnectionMap.take(*event.targetID); >+ updateHasActiveDebugSession(); >+ } >+ >+ if (connectionToTarget) >+ connectionToTarget->close(); >+} >+ >+void RemoteInspector::setup(unsigned targetIdentifier) >+{ >+ RemoteControllableTarget* target; >+ { >+ std::lock_guard<Lock> lock(m_mutex); >+ target = m_targetMap.get(targetIdentifier); >+ if (!target) >+ return; >+ } >+ >+ auto connectionToTarget = adoptRef(*new RemoteConnectionToTarget(*target)); >+ ASSERT(is<RemoteInspectionTarget>(target) || is<RemoteAutomationTarget>(target)); >+ if (!connectionToTarget->setup()) { >+ connectionToTarget->close(); >+ return; >+ } >+ >+ std::lock_guard<Lock> lock(m_mutex); >+ m_targetConnectionMap.set(targetIdentifier, WTFMove(connectionToTarget)); >+ >+ updateHasActiveDebugSession(); >+} >+ >+void RemoteInspector::sendMessageToTarget(unsigned targetIdentifier, const char* message) >+{ >+ if (auto connectionToTarget = m_targetConnectionMap.get(targetIdentifier)) >+ connectionToTarget->sendMessageToTarget(String::fromUTF8(message)); >+} >+ >+void RemoteInspector::setConnectionIdentifier(PlatformSocketType connectionIdentifier) >+{ >+ RemoteInspector::connectionIdentifier = connectionIdentifier; >+} >+ >+} // namespace Inspector >+ >+#endif // ENABLE(REMOTE_INSPECTOR) >diff --git a/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorServer.h b/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorServer.h >new file mode 100644 >index 00000000000..b4681b8cab4 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorServer.h >@@ -0,0 +1,80 @@ >+/* >+ * Copyright (C) 2019 Sony Interactive Entertainment Inc. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(REMOTE_INSPECTOR) >+ >+#include "RemoteInspector.h" >+ >+#include "RemoteInspectorSocket.h" >+#include <wtf/HashMap.h> >+#include <wtf/HashSet.h> >+ >+namespace Inspector { >+ >+class RemoteInspectorServer { >+public: >+ JS_EXPORT_PRIVATE static RemoteInspectorServer& singleton(); >+ >+ JS_EXPORT_PRIVATE bool start(const char*, unsigned); >+ bool isRunning() const { return !!m_server; } >+ >+ JS_EXPORT_PRIVATE void addServerConnection(PlatformSocketType); >+ >+private: >+ using RemoteInspectorCall = void (RemoteInspectorServer::*)(const InspectorEvent&); >+ >+ void connectionClosed(uint64_t connectionID); >+ >+ void setTargetList(const InspectorEvent&); >+ void setupInspectorClient(const InspectorEvent&); >+ void setup(const InspectorEvent&); >+ void close(const InspectorEvent&); >+ void sendMessageToFrontend(const InspectorEvent&); >+ void sendMessageToBackend(const InspectorEvent&); >+ >+ void sendCloseEvent(uint64_t connectionID, uint64_t targetID); >+ void clientConnectionClosed(); >+ >+ void didAccept(ClientID, RemoteInspectorSocket::DomainType); >+ void didReceiveData(ClientID, Vector<uint8_t>&&); >+ void didClose(ClientID); >+ >+ void sendWebInspectorEvent(ClientID, const String&); >+ void didReceiveWebInspectorEvent(ClientID, Vector<uint8_t>&&); >+ >+ HashMap<String, RemoteInspectorCall>& methodTable(); >+ >+ HashSet<std::pair<uint64_t, uint64_t>> m_inspectionTargets; >+ >+ std::unique_ptr<RemoteInspectorSocketServer> m_server; >+ Vector<ClientID> m_inspectorConnections; // webprocess connections >+ Optional<ClientID> m_clientConnection { WTF::nullopt }; // connection from RemoteInspectorClient >+}; >+ >+} // namespace Inspector >+ >+#endif // ENABLE(REMOTE_INSPECTOR) >diff --git a/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorServerGeneric.cpp b/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorServerGeneric.cpp >new file mode 100644 >index 00000000000..c3183b1713b >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorServerGeneric.cpp >@@ -0,0 +1,300 @@ >+/* >+ * Copyright (C) 2019 Sony Interactive Entertainment Inc. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "RemoteInspectorServer.h" >+ >+#if ENABLE(REMOTE_INSPECTOR) >+ >+#include <wtf/JSONValues.h> >+#include <wtf/MainThread.h> >+ >+namespace Inspector { >+ >+void RemoteInspectorServer::addServerConnection(PlatformSocketType identifier) >+{ >+ if (m_server) { >+ if (auto id = m_server->createClient(identifier)) >+ m_inspectorConnections.append(*id); >+ } >+} >+ >+void RemoteInspectorServer::didAccept(ClientID clientID, RemoteInspectorSocket::DomainType type) >+{ >+ ASSERT(!isMainThread()); >+ >+ if (type == RemoteInspectorSocket::DomainType::Inet) { >+ if (m_clientConnection) { >+ LOG_ERROR("Inspector server can accept only 1 client"); >+ return; >+ } >+ m_clientConnection = clientID; >+ } else if (type == RemoteInspectorSocket::DomainType::Unix) >+ m_inspectorConnections.append(clientID); >+} >+ >+void RemoteInspectorServer::didReceiveData(ClientID clientID, Vector<uint8_t>&& data) >+{ >+ ASSERT(!isMainThread()); >+ >+ if (data.isEmpty()) >+ return; >+ >+ didReceiveWebInspectorEvent(clientID, WTFMove(data)); >+} >+ >+void RemoteInspectorServer::didClose(ClientID clientID) >+{ >+ ASSERT(!isMainThread()); >+ >+ if (clientID == m_clientConnection) { >+ // connection from client(frontend) is closed >+ callOnMainThread([this] { >+ clientConnectionClosed(); >+ }); >+ return; >+ } >+ >+ // connection from webprocess(backend) is closed >+ callOnMainThread([this, clientID] { >+ connectionClosed(clientID); >+ }); >+} >+ >+HashMap<String, RemoteInspectorServer::RemoteInspectorCall>& RemoteInspectorServer::methodTable() >+{ >+ static NeverDestroyed<HashMap<String, RemoteInspectorCall>> methods = HashMap<String, RemoteInspectorCall>({ >+ {"SetTargetList"_s, &RemoteInspectorServer::setTargetList}, >+ {"SetupInspectorClient"_s, &RemoteInspectorServer::setupInspectorClient}, >+ {"Setup"_s, &RemoteInspectorServer::setup}, >+ {"FrontendDidClose"_s, &RemoteInspectorServer::close}, >+ {"SendMessageToFrontend"_s, &RemoteInspectorServer::sendMessageToFrontend}, >+ {"SendMessageToBackend"_s, &RemoteInspectorServer::sendMessageToBackend}, >+ }); >+ >+ return methods; >+} >+ >+void RemoteInspectorServer::sendWebInspectorEvent(ClientID clientID, const String& event) >+{ >+ const CString& message = event.utf8(); >+ m_server->send(clientID, reinterpret_cast<const uint8_t*>(message.data()), message.length()); >+} >+ >+void RemoteInspectorServer::didReceiveWebInspectorEvent(ClientID clientID, Vector<uint8_t>&& data) >+{ >+ ASSERT(!isMainThread()); >+ >+ String jsonData = String::adopt(WTFMove(data)); >+ >+ RefPtr<JSON::Value> messageValue; >+ if (!JSON::Value::parseJSON(jsonData, messageValue)) >+ return; >+ >+ RefPtr<JSON::Object> messageObject; >+ if (!messageValue->asObject(messageObject)) >+ return; >+ >+ String methodName; >+ if (!messageObject->getString("event"_s, methodName)) >+ return; >+ >+ InspectorEvent event; >+ event.clientID = clientID; >+ uint64_t connectionID; >+ uint64_t targetID; >+ String message; >+ >+ if (messageObject->getInteger("connectionID"_s, connectionID)) >+ event.connectionID = Optional<uint64_t>(connectionID); >+ >+ if (messageObject->getInteger("targetID"_s, targetID)) >+ event.targetID = Optional<uint64_t>(targetID); >+ >+ if (messageObject->getString("message"_s, message)) >+ event.message = Optional<String>(WTFMove(message)); >+ >+ callOnMainThread([this, methodName, event = WTFMove(event)] { >+ auto& methods = methodTable(); >+ if (methods.contains(methodName)) { >+ auto call = methods.get(methodName); >+ (this->*call)(event); >+ } else >+ LOG_ERROR("Unknown event: %s", methodName.utf8().data()); >+ }); >+} >+ >+RemoteInspectorServer& RemoteInspectorServer::singleton() >+{ >+ static NeverDestroyed<RemoteInspectorServer> server; >+ return server; >+} >+ >+bool RemoteInspectorServer::start(const char* /* address */, unsigned port) >+{ >+ m_server = RemoteInspectorSocketServer::create(); >+ >+ m_server->setDidAcceptListener([this](int clientID, RemoteInspectorSocket::DomainType type) { >+ didAccept(clientID, type); >+ }); >+ m_server->setDidReceiveDataListener([this](int clientID, Vector<uint8_t>&& data) { >+ didReceiveData(clientID, WTFMove(data)); >+ }); >+ m_server->setDidCloseListener([this](int clientID) { >+ didClose(clientID); >+ }); >+ >+ if (!m_server->listenInet(port)) { >+ m_server = nullptr; >+ return false; >+ } >+ >+ return true; >+} >+ >+void RemoteInspectorServer::setTargetList(const InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ if (!m_clientConnection || !event.message) >+ return; >+ >+ ASSERT(event.clientID != m_clientConnection); >+ >+ // FIXME: This shouldn't recreate the JSON event when the message doesn't change >+ auto targetListEvent = JSON::Object::create(); >+ targetListEvent->setString("event"_s, "SetTargetList"_s); >+ targetListEvent->setInteger("connectionID"_s, event.clientID); >+ targetListEvent->setString("message"_s, *event.message); >+ sendWebInspectorEvent(*m_clientConnection, targetListEvent->toJSONString()); >+} >+ >+void RemoteInspectorServer::setupInspectorClient(const InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ auto setupEvent = JSON::Object::create(); >+ setupEvent->setString("event"_s, "GetTargetList"_s); >+ >+ for (auto connection : m_inspectorConnections) >+ sendWebInspectorEvent(connection, setupEvent->toJSONString()); >+} >+ >+void RemoteInspectorServer::setup(const InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ if (!event.targetID || !event.connectionID) >+ return; >+ >+ m_inspectionTargets.add(std::make_pair(*event.connectionID, *event.targetID)); >+ >+ auto setupEvent = JSON::Object::create(); >+ setupEvent->setString("event"_s, "Setup"_s); >+ setupEvent->setInteger("targetID"_s, *event.targetID); >+ sendWebInspectorEvent(*event.connectionID, setupEvent->toJSONString()); >+} >+ >+void RemoteInspectorServer::sendCloseEvent(uint64_t connectionID, uint64_t targetID) >+{ >+ ASSERT(isMainThread()); >+ ASSERT(m_inspectionTargets.contains(std::make_pair(connectionID, targetID))); >+ >+ auto closeEvent = JSON::Object::create(); >+ closeEvent->setString("event"_s, "FrontendDidClose"_s); >+ closeEvent->setInteger("targetID"_s, targetID); >+ sendWebInspectorEvent(connectionID, closeEvent->toJSONString()); >+} >+ >+void RemoteInspectorServer::close(const InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ ASSERT(m_inspectionTargets.contains(std::make_pair(*event.connectionID, *event.targetID))); >+ >+ sendCloseEvent(*event.connectionID, *event.targetID); >+ m_inspectionTargets.remove(std::make_pair(*event.connectionID, *event.targetID)); >+} >+ >+void RemoteInspectorServer::clientConnectionClosed() >+{ >+ ASSERT(isMainThread()); >+ >+ for (auto connectionTargetPair : m_inspectionTargets) >+ sendCloseEvent(connectionTargetPair.first, connectionTargetPair.second); >+ >+ m_inspectionTargets.clear(); >+ m_clientConnection = WTF::nullopt; >+} >+ >+void RemoteInspectorServer::connectionClosed(uint64_t clientID) >+{ >+ ASSERT(isMainThread()); >+ >+ if (m_inspectorConnections.removeFirst(clientID) && m_clientConnection) { >+ auto closedEvent = JSON::Object::create(); >+ closedEvent->setString("event"_s, "SetTargetList"_s); >+ closedEvent->setInteger("connectionID"_s, clientID); >+ auto targetList = JSON::Array::create(); >+ closedEvent->setArray("targetList"_s, WTFMove(targetList)); >+ sendWebInspectorEvent(*m_clientConnection, closedEvent->toJSONString()); >+ } >+} >+ >+void RemoteInspectorServer::sendMessageToBackend(const InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ if (!event.connectionID || !event.targetID || !event.message) >+ return; >+ >+ auto sendEvent = JSON::Object::create(); >+ sendEvent->setString("event"_s, "SendMessageToTarget"_s); >+ sendEvent->setInteger("targetID"_s, *event.targetID); >+ sendEvent->setString("message"_s, *event.message); >+ sendWebInspectorEvent(*event.connectionID, sendEvent->toJSONString()); >+} >+ >+void RemoteInspectorServer::sendMessageToFrontend(const InspectorEvent& event) >+{ >+ if (!m_clientConnection) >+ return; >+ >+ ASSERT(isMainThread()); >+ ASSERT(event.clientID != *m_clientConnection); >+ >+ if (!event.targetID || !event.message) >+ return; >+ >+ auto sendEvent = JSON::Object::create(); >+ sendEvent->setString("event"_s, "SendMessageToFrontend"_s); >+ sendEvent->setInteger("targetID"_s, *event.targetID); >+ sendEvent->setInteger("connectionID"_s, event.clientID); >+ sendEvent->setString("message"_s, *event.message); >+ sendWebInspectorEvent(*m_clientConnection, sendEvent->toJSONString()); >+} >+ >+} // namespace Inspector >+ >+#endif // ENABLE(REMOTE_INSPECTOR) >diff --git a/Source/JavaScriptCore/inspector/remote/playstation/RemoteInspectorSocket.h b/Source/JavaScriptCore/inspector/remote/playstation/RemoteInspectorSocket.h >new file mode 100644 >index 00000000000..67b1334c63c >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/remote/playstation/RemoteInspectorSocket.h >@@ -0,0 +1,130 @@ >+/* >+ * Copyright (C) 2019 Sony Interactive Entertainment Inc. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(REMOTE_INSPECTOR) >+ >+#include <wtf/Condition.h> >+#include <wtf/Function.h> >+#include <wtf/HashMap.h> >+#include <wtf/Lock.h> >+#include <wtf/Threading.h> >+#include <wtf/Vector.h> >+#include <wtf/WorkerPool.h> >+ >+#include <poll.h> >+#include <thread> >+ >+namespace Inspector { >+ >+using ClientID = unsigned; >+using PlatformSocketType = int; >+constexpr PlatformSocketType INVALID_SOCKET_VALUE = -1; >+ >+class MessageParser; >+ >+class JS_EXPORT_PRIVATE RemoteInspectorSocket { >+public: >+ RemoteInspectorSocket(); >+ ~RemoteInspectorSocket(); >+ >+ enum class DomainType { >+ Unix, >+ Inet, >+ }; >+ >+ bool send(ClientID, const uint8_t* data, size_t); >+ >+ void setDidReceiveDataListener(Function<void(ClientID, Vector<uint8_t>&&)>&& listener) >+ { >+ m_didReceiveDataListener = WTFMove(listener); >+ } >+ >+ void setDidCloseListener(Function<void(ClientID)>&& listener) >+ { >+ m_didCloseListener = WTFMove(listener); >+ } >+ >+ void setDidAcceptListener(Function<void(ClientID, DomainType)>&& listener) >+ { >+ m_didAcceptListener = WTFMove(listener); >+ } >+ >+ Optional<ClientID> createClient(PlatformSocketType fd); >+ >+protected: >+ void recvIfEnabled(ClientID); >+ void sendIfEnabled(ClientID); >+ void workerThread(); >+ void wakeupWorkerThread(); >+ void acceptInetSocketIfEnabled(ClientID); >+ bool isListening(ClientID); >+ >+ struct connection { >+ std::unique_ptr<MessageParser> parser; >+ Vector<uint8_t> sendBuffer; >+ struct pollfd poll; >+ PlatformSocketType socket { INVALID_SOCKET_VALUE }; >+ Lock lock; >+ }; >+ >+ HashMap<ClientID, std::unique_ptr<struct connection>> m_connections; >+ PlatformSocketType m_wakeupSendSocket { INVALID_SOCKET_VALUE }; >+ PlatformSocketType m_wakeupReceiveSocket { INVALID_SOCKET_VALUE }; >+ >+ RefPtr<Thread> m_workerThread; >+ std::atomic<bool> m_shouldAbortWorkerThread { false }; >+ Lock m_lock; >+ >+ Function<void(ClientID, DomainType)> m_didAcceptListener; >+ Function<void(ClientID, Vector<uint8_t>&&)> m_didReceiveDataListener; >+ Function<void(ClientID)> m_didCloseListener; >+}; >+ >+class JS_EXPORT_PRIVATE RemoteInspectorSocketClient : public RemoteInspectorSocket { >+public: >+ >+ static std::unique_ptr<RemoteInspectorSocketClient> create() >+ { >+ return std::make_unique<RemoteInspectorSocketClient>(); >+ } >+ >+ Optional<ClientID> connectInet(const char* serverAddr, int serverPort); >+}; >+ >+class JS_EXPORT_PRIVATE RemoteInspectorSocketServer : public RemoteInspectorSocket { >+public: >+ static std::unique_ptr<RemoteInspectorSocketServer> create() >+ { >+ return std::make_unique<RemoteInspectorSocketServer>(); >+ } >+ >+ bool listenInet(int port); >+}; >+ >+} // namespace Inspector >+ >+#endif // ENABLE(REMOTE_INSPECTOR) >diff --git a/Source/JavaScriptCore/inspector/remote/playstation/RemoteInspectorSocketPlayStation.cpp b/Source/JavaScriptCore/inspector/remote/playstation/RemoteInspectorSocketPlayStation.cpp >new file mode 100644 >index 00000000000..8a561433ac9 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/remote/playstation/RemoteInspectorSocketPlayStation.cpp >@@ -0,0 +1,457 @@ >+/* >+ * Copyright (C) 2019 Sony Interactive Entertainment Inc. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "RemoteInspectorSocket.h" >+ >+#if ENABLE(REMOTE_INSPECTOR) >+ >+#include <wtf/MainThread.h> >+#include <wtf/RandomNumber.h> >+#include <wtf/text/WTFString.h> >+ >+#include <arpa/inet.h> >+#include <fcntl.h> >+#include <netinet/in.h> >+#include <sys/socket.h> >+#include <sys/un.h> >+#include <unistd.h> >+ >+namespace Inspector { >+ >+constexpr size_t SocketBufferSize = 65536; >+ >+class MessageParser { >+ /* >+ | <--- one message for send / didReceiveData ---> | >+ +--------------+----------------------------------+-------------- >+ | size | data | (next message) >+ | 4byte | variable length | >+ +--------------+----------------------------------+-------------- >+ | <------------ size ------------> | >+ */ >+public: >+ static Vector<uint8_t> createMessage(const uint8_t*, size_t); >+ >+ MessageParser(ClientID); >+ void pushReceivedData(const uint8_t*, size_t); >+ void setDidParseMessageListener(Function<void(ClientID, Vector<uint8_t>)>&& listener) >+ { >+ m_didParseMessageListener = WTFMove(listener); >+ } >+ void clearReceivedData(); >+ >+private: >+ bool parse(); >+ Function<void(ClientID, Vector<uint8_t>&&)> m_didParseMessageListener; >+ Vector<uint8_t> m_buffer; >+ ClientID m_clientID; >+}; >+ >+static void initializeSocket(PlatformSocketType sockfd) >+{ >+ fcntl(sockfd, F_SETFD, FD_CLOEXEC); >+ int flags = fcntl(sockfd, F_GETFL, 0); >+ fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); >+ >+ setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &SocketBufferSize, sizeof(SocketBufferSize)); >+ setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &SocketBufferSize, sizeof(SocketBufferSize)); >+} >+ >+// ------------------------------------------------------------------------- >+// RemoteInspectorSocket >+// ------------------------------------------------------------------------- >+ >+RemoteInspectorSocket::RemoteInspectorSocket() >+{ >+ PlatformSocketType sockets[2]; >+ if (!socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { >+ m_wakeupSendSocket = sockets[0]; >+ m_wakeupReceiveSocket = sockets[1]; >+ } >+ >+ m_workerThread = Thread::create("Remote Inspector Worker"_s, [this] { >+ workerThread(); >+ }); >+} >+ >+RemoteInspectorSocket::~RemoteInspectorSocket() >+{ >+ ASSERT(m_workerThread.get() != &Thread::current()); >+ >+ m_shouldAbortWorkerThread = true; >+ wakeupWorkerThread(); >+ m_workerThread->waitForCompletion(); >+ >+ ::close(m_wakeupSendSocket); >+ ::close(m_wakeupReceiveSocket); >+ for (const auto& connection : m_connections.values()) { >+ if (connection->socket != INVALID_SOCKET_VALUE) >+ ::close(connection->socket); >+ } >+} >+ >+void RemoteInspectorSocket::wakeupWorkerThread() >+{ >+ if (m_wakeupSendSocket != INVALID_SOCKET_VALUE) >+ ::write(m_wakeupSendSocket, "1", 1); >+} >+ >+bool RemoteInspectorSocket::isListening(ClientID id) >+{ >+ if (const auto& connection = m_connections.get(id)) { >+ int out; >+ socklen_t outSize = sizeof(out); >+ if (getsockopt(connection->socket, SOL_SOCKET, SO_ACCEPTCONN, &out, &outSize) != -1) >+ return out; >+ LOG_ERROR("getsockopt errno = %d", errno); >+ } >+ return false; >+} >+ >+void RemoteInspectorSocket::workerThread() >+{ >+ struct pollfd wakeup; >+ wakeup.fd = m_wakeupReceiveSocket; >+ wakeup.events = POLLIN; >+ >+ while (!m_shouldAbortWorkerThread) { >+ Vector<struct pollfd> pollfds; >+ Vector<ClientID> ids; >+ { >+ LockHolder lock(m_lock); >+ for (const auto& connection : m_connections) { >+ pollfds.append(connection.value->poll); >+ ids.append(connection.key); >+ } >+ } >+ pollfds.append(wakeup); >+ >+ int ret = poll(pollfds.data(), pollfds.size(), -1); >+ if (ret > 0) { >+ if (pollfds.last().revents & POLLIN) { >+ char wakeMessage; >+ ::read(m_wakeupReceiveSocket, &wakeMessage, sizeof(wakeMessage)); >+ continue; >+ } >+ >+ for (size_t i = 0; i < ids.size(); i++) { >+ auto id = ids[i]; >+ LockHolder lock(m_connections.get(id)->lock); >+ >+ if ((pollfds[i].revents & POLLIN) && isListening(id)) >+ acceptInetSocketIfEnabled(id); >+ else if (pollfds[i].revents & POLLIN) >+ recvIfEnabled(id); >+ else if (pollfds[i].revents & POLLOUT) >+ sendIfEnabled(id); >+ } >+ } >+ } >+} >+ >+Optional<ClientID> RemoteInspectorSocket::createClient(PlatformSocketType fd) >+{ >+ if (fd == INVALID_SOCKET_VALUE) >+ return WTF::nullopt; >+ >+ LockHolder lock(m_lock); >+ >+ ClientID id; >+ do { >+ id = std::numeric_limits<ClientID>::max() * randomNumber(); >+ } while (m_connections.contains(id)); >+ >+ initializeSocket(fd); >+ >+ auto connection = std::make_unique<struct connection>(); >+ connection->poll.fd = fd; >+ connection->poll.events = POLLIN; >+ connection->parser = std::make_unique<MessageParser>(id); >+ connection->socket = fd; >+ connection->parser->setDidParseMessageListener([this](ClientID id, Vector<uint8_t>&& data) { >+ if (m_didReceiveDataListener) >+ m_didReceiveDataListener(id, WTFMove(data)); >+ }); >+ >+ m_connections.add(id, WTFMove(connection)); >+ wakeupWorkerThread(); >+ >+ return id; >+} >+ >+void RemoteInspectorSocket::recvIfEnabled(ClientID clientID) >+{ >+ if (const auto& connection = m_connections.get(clientID)) { >+ Vector<uint8_t> recvBuffer(SocketBufferSize); >+ ssize_t readSize = ::read(connection->socket, recvBuffer.data(), recvBuffer.size()); >+ if (readSize > 0) >+ connection->parser->pushReceivedData(recvBuffer.data(), readSize); >+ else if (readSize < 0) >+ LOG_ERROR("read error (errno = %d)", errno); >+ else { >+ ::close(connection->socket); >+ m_connections.remove(clientID); >+ if (m_didCloseListener) >+ m_didCloseListener(clientID); >+ } >+ } >+} >+ >+void RemoteInspectorSocket::sendIfEnabled(ClientID clientID) >+{ >+ if (const auto& connection = m_connections.get(clientID)) { >+ connection->poll.events &= ~POLLOUT; >+ if (connection->sendBuffer.isEmpty()) >+ return; >+ >+ ssize_t writeSize = ::write(connection->socket, connection->sendBuffer.data(), std::min(connection->sendBuffer.size(), SocketBufferSize)); >+ if (writeSize > 0 && static_cast<size_t>(writeSize) == connection->sendBuffer.size()) { >+ // all data is sent >+ connection->sendBuffer.clear(); >+ return; >+ } >+ >+ // some data remains or error >+ if (writeSize > 0) >+ connection->sendBuffer.remove(0, writeSize); >+ else >+ LOG_ERROR("write error (errno = %d)", errno); >+ >+ // set POLLOUT again for resending remaining data >+ connection->poll.events |= POLLOUT; >+ } >+} >+ >+bool RemoteInspectorSocket::send(ClientID clientID, const uint8_t* data, size_t size) >+{ >+ if (const auto& connection = m_connections.get(clientID)) { >+ auto message = MessageParser::createMessage(data, size); >+ if (message.isEmpty()) >+ return false; >+ >+ LockHolder lock(connection->lock); >+ ssize_t writeSize = 0; >+ if (connection->sendBuffer.isEmpty()) { >+ // try to call send() directly if buffer is empty >+ writeSize = ::write(connection->socket, message.data(), std::min(message.size(), SocketBufferSize)); >+ if (writeSize > 0 && static_cast<size_t>(writeSize) == message.size()) { >+ // all data is sent >+ return writeSize; >+ } >+ if (writeSize < 0) { >+ LOG_ERROR("write error (errno = %d)", errno); >+ writeSize = 0; >+ } >+ } >+ >+ // copy remaining data to buffer, and entrust to worker thread >+ connection->sendBuffer.appendRange(message.begin() + writeSize, message.end()); >+ connection->poll.events |= POLLOUT; >+ >+ wakeupWorkerThread(); >+ return writeSize; >+ } >+ return false; >+} >+ >+void RemoteInspectorSocket::acceptInetSocketIfEnabled(ClientID id) >+{ >+ if (!isListening(id)) >+ return; >+ >+ if (const auto& connection = m_connections.get(id)) { >+ >+ struct sockaddr_in saClient; >+ memset(&saClient, 0, sizeof(saClient)); >+ socklen_t len = sizeof(struct sockaddr_in); >+ int fd = accept(connection->socket, (struct sockaddr*)&saClient, &len); >+ if (fd < 0) { >+ LOG_ERROR("accept(inet) error (errno = %d)", errno); >+ return; >+ } >+ >+ auto newID = createClient(fd); >+ if (newID && m_didAcceptListener) >+ m_didAcceptListener(*newID, DomainType::Inet); >+ else >+ ::close(fd); >+ } >+} >+ >+// ------------------------------------------------------------------------- >+// RemoteInspectorSocketClient >+// ------------------------------------------------------------------------- >+ >+Optional<ClientID> RemoteInspectorSocketClient::connectInet(const char* serverAddr, int serverPort) >+{ >+ struct sockaddr_in saServer = { 0 }; >+ saServer.sin_family = AF_INET; >+ inet_aton(serverAddr, &saServer.sin_addr); >+ saServer.sin_port = htons(serverPort); >+ >+ int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); >+ if (fd < 0) { >+ LOG_ERROR("socket() failed, server = %s:%d, ret = %d, errno = %d", serverAddr, serverPort, fd, errno); >+ return WTF::nullopt; >+ } >+ >+ int ret = connect(fd, (struct sockaddr *)&saServer, sizeof(saServer)); >+ if (ret < 0) { >+ LOG_ERROR("connect() failed, server = %s:%d, ret = %d, errno = %d", serverAddr, serverPort, ret, errno); >+ ::close(fd); >+ return WTF::nullopt; >+ } >+ >+ return createClient(fd); >+} >+ >+// ------------------------------------------------------------------------- >+// RemoteInspectorSocketServer >+// ------------------------------------------------------------------------- >+ >+bool RemoteInspectorSocketServer::listenInet(int port) >+{ >+ struct sockaddr_in saServer = { 0 }; >+ >+ int fdListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); >+ if (fdListen < 0) { >+ LOG_ERROR("socket() failed, ret = %d, errno = %d", fdListen, errno); >+ return false; >+ } >+ >+ const int enabled = 1; >+ int ret = setsockopt(fdListen, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)); >+ if (ret < 0) { >+ LOG_ERROR("setsockopt() SO_REUSEADDR failed, ret = %d, errno = %d", fdListen, errno); >+ return false; >+ } >+ ret = setsockopt(fdListen, SOL_SOCKET, SO_REUSEPORT, &enabled, sizeof(enabled)); >+ if (ret < 0) { >+ LOG_ERROR("setsockopt() SO_REUSEPORT, ret = %d, errno = %d", fdListen, errno); >+ return false; >+ } >+ >+ // FIXME: Support AF_INET6 connections >+ saServer.sin_family = AF_INET; >+ saServer.sin_addr.s_addr = htonl(INADDR_ANY); >+ saServer.sin_port = htons(port); >+ ret = bind(fdListen, (struct sockaddr *)&saServer, sizeof(saServer)); >+ if (ret < 0) { >+ LOG_ERROR("bind() failed, ret = %d, errno = %d", ret, errno); >+ ::close(fdListen); >+ return false; >+ } >+ >+ ret = listen(fdListen, 1); >+ if (ret < 0) { >+ LOG_ERROR("listen() failed, ret = %d errno = %d", ret, errno); >+ ::close(fdListen); >+ return false; >+ } >+ >+ >+ if (createClient(fdListen)) >+ return true; >+ >+ return false; >+} >+ >+// ------------------------------------------------------------------------- >+// MessageParser >+// ------------------------------------------------------------------------- >+ >+MessageParser::MessageParser(ClientID clientID) >+ : m_clientID(clientID) >+{ >+ m_buffer.reserveCapacity(SocketBufferSize); >+} >+ >+Vector<uint8_t> MessageParser::createMessage(const uint8_t* data, size_t size) >+{ >+ if (!data || !size || size > UINT_MAX) >+ return Vector<uint8_t>(); >+ >+ auto messageBuffer = Vector<uint8_t>(size + sizeof(uint32_t)); >+ uint32_t uintSize = static_cast<uint32_t>(size); >+ memcpy(&messageBuffer[0], &uintSize, sizeof(uint32_t)); >+ memcpy(&messageBuffer[sizeof(uint32_t)], data, uintSize); >+ return messageBuffer; >+} >+ >+void MessageParser::pushReceivedData(const uint8_t* data, size_t size) >+{ >+ if (!data || !size) >+ return; >+ >+ m_buffer.reserveCapacity(m_buffer.size() + size); >+ m_buffer.append(data, size); >+ >+ if (!parse()) >+ clearReceivedData(); >+} >+ >+void MessageParser::clearReceivedData() >+{ >+ m_buffer.clear(); >+} >+ >+bool MessageParser::parse() >+{ >+ while (!m_buffer.isEmpty()) { >+ if (m_buffer.size() < sizeof(uint32_t)) { >+ // wait next recv >+ return true; >+ } >+ >+ uint32_t dataSize = 0; >+ memcpy(&dataSize, &m_buffer[0], sizeof(uint32_t)); >+ if (!dataSize) { >+ LOG_ERROR("Message Parser received an invalid message size"); >+ return false; >+ } >+ >+ size_t messageSize = (sizeof(uint32_t) + dataSize); >+ if (m_buffer.size() < messageSize) { >+ // wait next recv >+ return true; >+ } >+ >+ // FIXME: This should avoid re-creating a new data Vector >+ auto dataBuffer = Vector<uint8_t>(dataSize); >+ memcpy(&dataBuffer[0], &m_buffer[sizeof(uint32_t)], dataSize); >+ >+ if (m_didParseMessageListener) >+ m_didParseMessageListener(m_clientID, WTFMove(dataBuffer)); >+ >+ m_buffer.remove(0, messageSize); >+ } >+ >+ return true; >+} >+ >+} // namespace Inspector >+ >+#endif // ENABLE(REMOTE_INSPECTOR)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
joepeck
:
review-
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193806
:
360074
|
360938
|
360940
|
361665
|
361668
|
361701
|
361707
|
362388
|
362940
|
363397
|
363398