WebKit Bugzilla
Attachment 360074 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]
patch
193806.diff (text/plain), 54.19 KB, created by
Christopher Reid
on 2019-01-24 19:40:37 PST
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Christopher Reid
Created:
2019-01-24 19:40:37 PST
Size:
54.19 KB
patch
obsolete
>diff --git a/ChangeLog b/ChangeLog >index a69b7ba021e..52f05bba983 100644 >--- a/ChangeLog >+++ b/ChangeLog >@@ -1,3 +1,12 @@ >+2019-01-24 Christopher Reid <chris.reid@sony.com> >+ >+ [PlayStaton] Upstream playstation's remote inspector server >+ https://bugs.webkit.org/show_bug.cgi?id=193806 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * Source/cmake/OptionsPlayStation.cmake: >+ > 2019-01-24 Guillaume Emont <guijemont@igalia.com> > > [JSC] Reenable baseline JIT on mips >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index de140b790bf..39e481dfff2 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,26 @@ >+2019-01-24 Christopher Reid <chris.reid@sony.com> >+ >+ [PlayStaton] Upstream playstation's remote inspector server >+ https://bugs.webkit.org/show_bug.cgi?id=193806 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Upstream a socket based inspector server for PlayStation. >+ This inspector protocol is based on glib's implementation >+ but using JSON RPC over TCP instead of DBUS. >+ Most of this protocol code will eventually be shared with WinCairo >+ as a client for inspecting PlayStation targets. >+ >+ * PlatformPlayStation.cmake: >+ * SourcesGTK.txt: >+ * inspector/remote/RemoteInspector.h: >+ * inspector/remote/generic/RemoteConnectionToTargetGeneric.cpp: Renamed from Source\JavaScriptCore\inspector\remote\glib\RemoteConnectionToTargetGlib.cpp. >+ * inspector/remote/generic/RemoteInspectorGeneric.cpp: Added. >+ * inspector/remote/generic/RemoteInspectorServer.h: Added. >+ * inspector/remote/generic/RemoteInspectorServerGeneric.cpp: Added. >+ * inspector/remote/playstation/RemoteInspectorSocket.h: Added. >+ * inspector/remote/playstation/RemoteInspectorSocketPlayStation.cpp: Added. >+ > 2019-01-24 Joseph Pecoraro <pecoraro@apple.com> > > Web Inspector: CPU Usage Timeline >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/inspector/remote/RemoteInspector.h b/Source/JavaScriptCore/inspector/remote/RemoteInspector.h >index 389e843fab6..5819f5eee51 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; >+}; >+typedef RefPtr<TargetInfo> TargetListing; >+ >+class InspectorEvent { >+public: >+ ClientID clientID { -1 }; >+ Optional<uint64_t> connectionID { std::nullopt }; >+ Optional<uint64_t> targetID { std::nullopt }; >+ Otional<String> message { std::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(ConnectionIdentifier); >+#endif > > private: > RemoteInspector(); >@@ -184,7 +218,21 @@ private: > void receivedAutomaticInspectionRejectMessage(NSDictionary *userInfo); > void receivedAutomationSessionRequestMessage(NSDictionary *userInfo); > #endif >+#if PLATFORM(PLAYSTATION) >+ using RemoteInspectorCall = void (RemoteInspector::*)(InspectorEvent&); >+ HashMap<String, RemoteInspectorCall>& methodTable(); >+ >+ void didReceiveData(Vector<uint8_t>&&); >+ void didClose(); > >+ void sendWebInspectorEvent(const String&); >+ void didReceiveWebInspectorEvent(Vector<uint8_t>&&); >+ >+ void receivedGetTargetListMessage(InspectorEvent&); >+ void receivedSetupMessage(InspectorEvent&); >+ void receivedDataMessage(InspectorEvent&); >+ void receivedCloseMessage(InspectorEvent&); >+#endif > static bool startEnabled; > > // Targets can be registered from any thread at any time. >@@ -205,6 +253,11 @@ private: > GRefPtr<GCancellable> m_cancellable; > #endif > >+#if PLATFORM(PLAYSTATION) >+ std::unique_ptr<RemoteInspectorSocketClient> m_socketConnection; >+ static ConnectionIdentifier connectionIdentifier; >+#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..692a63b6c98 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorGeneric.cpp >@@ -0,0 +1,347 @@ >+/* >+ * 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 { >+ >+ConnectionIdentifier RemoteInspector::connectionIdentifier = -1; >+ >+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) >+{ >+ m_socketConnection->send(event.utf8().data(), event.utf8().length()); >+} >+ >+void RemoteInspector::didReceiveWebInspectorEvent(Vector<uint8_t>&& data) >+{ >+ ASSERT(!isMainThread()); >+ >+ RunLoop::main().dispatch([this, 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("method"_s, methodName)) >+ return; >+ >+ auto methods = methodTable(); >+ if (methods.contains(methodName)) { >+ 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)); >+ >+ auto call = methods.get(methodName); >+ (this->*call)(event); >+ } >+ }); >+ >+} >+ >+void RemoteInspector::start() >+{ >+ std::lock_guard<Lock> lock(m_mutex); >+ >+ if (m_enabled || RemoteInspector::connectionIdentifier == -1) >+ return; >+ >+ m_enabled = true; >+ >+ m_socketConnection = RemoteInspectorSocketClient::create(); >+ >+ m_socketConnection->setDidReceiveDataListener([this](int clientID, Vector<uint8_t>&& data) { >+ didReceiveData(WTFMove(data)); >+ }); >+ m_socketConnection->setDidCloseListener([this](int clientID) { >+ didClose(); >+ }); >+ >+ if (!m_socketConnection->addClientConnectionIdentifier(RemoteInspector::connectionIdentifier)) >+ return; >+ >+ 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->close(); >+} >+ >+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->type = (target.type() == RemoteInspectionTarget::Type::Web)? "Web" : "JavaScript"; >+ info->name = target.name(); >+ info->url = target.url(); >+ info->hasLocalDebugger = target.hasLocalDebugger(); >+ return adoptRef(info); >+} >+ >+TargetListing RemoteInspector::listingForAutomationTarget(const RemoteAutomationTarget& target) const >+{ >+ return 0; >+} >+ >+void RemoteInspector::pushListingsNow() >+{ >+ ASSERT(isMainThread()); >+ >+ 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("event"_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->setArray("targetList"_s, WTFMove(targetListJson)); >+ 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* target) >+{ >+ return; >+} >+ >+void RemoteInspector::sendAutomaticInspectionCandidateMessage() >+{ >+ return; >+} >+ >+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(InspectorEvent&) >+{ >+ ASSERT(isMainThread()); >+ >+ std::lock_guard<Lock> lock(m_mutex); >+ pushListingsNow(); >+} >+ >+void RemoteInspector::receivedSetupMessage(InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ std::lock_guard<Lock> lock(m_mutex); >+ if (event.targetID) >+ setup(*event.targetID); >+} >+ >+void RemoteInspector::receivedDataMessage(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->utf8().data()); >+} >+ >+void RemoteInspector::receivedCloseMessage(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 = 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; >+ } >+ 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(ConnectionIdentifier 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..f75fb103483 >--- /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(ConnectionIdentifier); >+ >+private: >+ using RemoteInspectorCall = void (RemoteInspectorServer::*)(InspectorEvent&); >+ >+ void connectionClosed(uint64_t connectionID); >+ >+ void setTargetList(InspectorEvent&); >+ void setupInspectorClient(InspectorEvent&); >+ void setup(InspectorEvent&); >+ void close(InspectorEvent&); >+ void sendMessageToFrontend(InspectorEvent&); >+ void sendMessageToBackend(InspectorEvent&); >+ >+ void sendCloseEvent(uint64_t connectionID, uint64_t targetID); >+ void clientConnectionClosed(); >+ >+ void didAccept(ClientID, RemoteInspectorSocket::DomainType, const String& addr, int port); >+ 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<int> m_inspectorConnections; // webprocess connections >+ int m_clientConnection { -1 }; // 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..19eda28b665 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/remote/generic/RemoteInspectorServerGeneric.cpp >@@ -0,0 +1,302 @@ >+/* >+ * 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(ConnectionIdentifier identifier) >+{ >+ if (m_server) { >+ int clientID = m_server->addServerConnectionIdentifier(identifier); >+ if (clientID > 0) >+ m_inspectorConnections.append(clientID); >+ } >+} >+ >+void RemoteInspectorServer::didAccept(ClientID clientID, RemoteInspectorSocket::DomainType type, const String& addr, int port) >+{ >+ ASSERT(!isMainThread()); >+ >+ if (type == RemoteInspectorSocket::DomainType::Inet) { >+ if (m_clientConnection != -1) { >+ WTFLogAlways("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) >+{ >+ m_server->send(clientID, event.utf8().data(), event.utf8().length()); >+} >+ >+void RemoteInspectorServer::didReceiveWebInspectorEvent(ClientID clientID, Vector<uint8_t>&& data) >+{ >+ ASSERT(!isMainThread()); >+ >+ callOnMainThread([this, clientID, 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; >+ >+ auto& methods = methodTable(); >+ if (methods.contains(methodName)) { >+ 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)); >+ >+ WTFLogAlways("[Server] Got event: %s, clientID: %d connectionID: %d targetID: %d message: %s", >+ methodName.utf8().data(), >+ clientID, >+ event.connectionID.value_or(-1), >+ event.targetID.value_or(-1), >+ event.message.value_or("<empty>").utf8().data()); >+ >+ auto call = methods.get(methodName); >+ (this->*call)(event); >+ } >+ }); >+} >+ >+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, const String& addr, int port) { >+ didAccept(clientID, type, addr, port); >+ }); >+ m_server->setDidReceiveDataListener([this](int clientID, Vector<uint8_t>&& data) { >+ didReceiveData(clientID, WTFMove(data)); >+ }); >+ m_server->setDidCloseListener([this](int clientID) { >+ didClose(clientID); >+ }); >+ >+ int retInet = m_server->listenInet(port); >+ if (retInet < 0) { >+ m_server = nullptr; >+ return false; >+ } >+ >+ return true; >+} >+ >+void RemoteInspectorServer::setTargetList(InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ if (m_clientConnection == -1 || !event.message) >+ return; >+ >+ ASSERT(event.clientID != m_clientConnection); >+ >+ auto targetListEvent = JSON::Object::create(); >+ targetListEvent->setInteger("connectionID"_s, event.clientID); >+ sendWebInspectorEvent(m_clientConnection, targetListEvent->toJSONString()); >+} >+ >+void RemoteInspectorServer::setupInspectorClient(InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ if (event.message) { >+ auto setupEvent = JSON::Object::create(); >+ setupEvent->setString("event"_s, *event.message); >+ >+ for (auto connection : m_inspectorConnections) >+ sendWebInspectorEvent(connection, setupEvent->toJSONString()); >+ } >+} >+ >+void RemoteInspectorServer::setup(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(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 = -1; >+} >+ >+void RemoteInspectorServer::connectionClosed(uint64_t clientID) >+{ >+ ASSERT(isMainThread()); >+ >+ if (m_inspectorConnections.removeFirst(clientID)) { >+ 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(InspectorEvent& event) >+{ >+ ASSERT(isMainThread()); >+ >+ if (!event.connectionID || !event.targetID || !event.message) >+ return; >+ >+ auto sendEvent = JSON::Object::create(); >+ sendEvent->setString("event"_s, "SendMessageToBackend"_s); >+ sendEvent->setInteger("connectionID"_s, event.clientID); >+ sendWebInspectorEvent(*event.connectionID, sendEvent->toJSONString()); >+} >+ >+void RemoteInspectorServer::sendMessageToFrontend(InspectorEvent& event) >+{ >+ if (m_clientConnection == -1) >+ return; >+ >+ ASSERT(isMainThread()); >+ ASSERT(event.clientID != m_clientConnection); >+ >+ if (!event.connectionID || !event.targetID || !event.message) >+ return; >+ >+ auto sendEvent = JSON::Object::create(); >+ sendEvent->setString("event"_s, "SendMessageToFrontend"_s); >+ sendEvent->setInteger("connectionID"_s, *event.connectionID); >+ 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..f7ec0958b09 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/remote/playstation/RemoteInspectorSocket.h >@@ -0,0 +1,154 @@ >+/* >+ * 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/Lock.h> >+#include <wtf/Threading.h> >+#include <wtf/Vector.h> >+ >+#include <thread> >+ >+#if OS(UNIX) >+#include <poll.h> >+#endif >+ >+namespace Inspector { >+ >+using ClientID = int; >+#if PLATFORM(PLAYSTATION) >+using ConnectionIdentifier = int; >+#endif >+ >+class MessageParser; >+ >+class JS_EXPORT_PRIVATE RemoteInspectorSocket { >+public: >+ RemoteInspectorSocket(size_t numberOfConnections); >+ ~RemoteInspectorSocket(); >+ >+ enum class DomainType { >+ Unix, >+ Inet, >+ }; >+ >+ int send(ClientID, const void* 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 close(); >+ >+protected: >+ void recvIfEnabled(ClientID); >+ void sendIfEnabled(ClientID); >+ void workerThread(); >+ void wakeupWorkerThread(); >+ virtual void acceptInetSocketIfEnabled() { } >+ >+ Vector<struct pollfd> m_connections; >+ Vector<std::unique_ptr<MessageParser>> m_parsers; >+ Vector<Vector<uint8_t>> m_sendBuffers; >+ Vector<Lock> m_sendLocks; >+ RefPtr<Thread> m_workerThread; >+ std::atomic<bool> m_shouldAbortWorkerThread { false }; >+ int m_wakeupSocket; >+ ClientID m_wakeupClient; >+ >+ 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>(); >+ } >+ >+ RemoteInspectorSocketClient(); >+ ~RemoteInspectorSocketClient(); >+ >+ int connectInet(const char* serverAddr, int serverPort); >+ int send(const void* data, size_t size) { return RemoteInspectorSocket::send(FirstConnection, data, size); } >+ bool addClientConnectionIdentifier(ConnectionIdentifier); >+ >+private: >+ static const int ClientConnections { 1 }; >+ >+ enum connectionIndex : uint8_t { >+ FirstConnection, >+ NumberOfConnections = FirstConnection + ClientConnections, >+ }; >+}; >+ >+class JS_EXPORT_PRIVATE RemoteInspectorSocketServer : public RemoteInspectorSocket { >+public: >+ static std::unique_ptr<RemoteInspectorSocketServer> create() >+ { >+ return std::make_unique<RemoteInspectorSocketServer>(); >+ } >+ >+ RemoteInspectorSocketServer(); >+ ~RemoteInspectorSocketServer(); >+ >+ int listenInet(int port); >+ int addServerConnectionIdentifier(ConnectionIdentifier); >+ void setDidAcceptListener(std::function<void(ClientID, DomainType, const String&, int)>&& listener) >+ { >+ m_didAcceptListener = WTFMove(listener); >+ } >+ >+ >+private: >+ static const int ClientConnections { 5 }; >+ >+ enum connectionIndex : uint8_t { >+ AcceptInet, >+ FirstConnection, >+ NumberOfConnections = FirstConnection + ClientConnections, >+ }; >+ >+ void acceptInetSocketIfEnabled() override; >+ >+ Function<void(ClientID, DomainType, const String&, int)> m_didAcceptListener; >+}; >+ >+} // 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..0d31ab8fa95 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/remote/playstation/RemoteInspectorSocketPlayStation.cpp >@@ -0,0 +1,515 @@ >+/* >+ * 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/text/WTFString.h> >+ >+#if OS(UNIX) >+#include <arpa/inet.h> >+#include <netinet/in.h> >+#include <sys/socket.h> >+#include <sys/un.h> >+#include <unistd.h> >+#endif >+ >+namespace Inspector { >+ >+// ------------------------------------------------------------------------- >+// definitions, static functions, etc >+// ------------------------------------------------------------------------- >+ >+constexpr size_t SizeOfRecvBuffer = 65536; >+ >+class MessageParser { >+ /* >+ | <--- one message for send / didReceiveData ---> | >+ +--------------+----------------------------------+-------------- >+ | size | data | (next message) >+ | 4byte | variable length | >+ +--------------+----------------------------------+-------------- >+ | <------------ size ------------> | >+ */ >+public: >+ static Vector<uint8_t> createMessage(const void*, size_t); >+ >+ MessageParser(ClientID); >+ void pushReceivedData(const void*, size_t); >+ void setDidParseMessageListener(Function<void(ClientID, Vector<uint8_t>)>&& listener) >+ { >+ m_didParseMessageListener = WTFMove(listener); >+ } >+ void clearReceivedData(); >+private: >+ bool parse(); >+ ClientID m_clientID; >+ Function<void(ClientID, Vector<uint8_t>&&)> m_didParseMessageListener; >+ Vector<uint8_t> m_buffer; >+}; >+ >+static void initSockFd(ConnectionIdentifier 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, &SizeOfRecvBuffer, sizeof(SizeOfRecvBuffer)); >+ setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &SizeOfRecvBuffer, sizeof(SizeOfRecvBuffer)); >+} >+ >+// ------------------------------------------------------------------------- >+// RemoteInspectorSocket >+// ------------------------------------------------------------------------- >+ >+RemoteInspectorSocket::RemoteInspectorSocket(size_t numberOfConnections) >+ // m_connections uses one extra connection for the workerThread wakeup socket >+ : m_connections(numberOfConnections + 1) >+ , m_sendBuffers(numberOfConnections) >+ , m_parsers(numberOfConnections) >+ , m_sendLocks(numberOfConnections) >+{ >+ for (size_t i = 0; i < numberOfConnections; i++) { >+ m_connections[i].fd = -1; >+ m_connections[i].events = 0; >+ m_connections[i].revents = 0; >+ } >+ >+ // Create a unix socket for waking up the worker thread as the last connection >+ m_wakeupClient = numberOfConnections; >+ int sockets[2]; >+ if (!socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { >+ m_connections[m_wakeupClient].fd = sockets[0]; >+ m_connections[m_wakeupClient].events = POLLIN; >+ m_wakeupSocket = sockets[1]; >+ } else >+ LOG_ERROR("socketpair failed (errno: %d)", errno); >+ >+ m_workerThread = Thread::create("Remote Inspector Worker Thread"_s, [this] { >+ workerThread(); >+ }); >+} >+ >+RemoteInspectorSocket::~RemoteInspectorSocket() >+{ >+ ASSERT(m_workerThread.get() != &Thread::current()); >+ >+ m_shouldAbortWorkerThread = true; >+ wakeupWorkerThread(); >+ m_workerThread->waitForCompletion(); >+ >+ close(); >+} >+ >+ >+void RemoteInspectorSocket::close() >+{ >+ for (size_t i = 0; i < m_connections.size(); i++) { >+ m_sendBuffers[i].clear(); >+ >+ if (auto& parser = m_parsers[i]) >+ parser->clearReceivedData(); >+ >+ if (m_connections[i].fd != -1) { >+ ::close(m_connections[i].fd); >+ m_connections[i].fd = -1; >+ } >+ } >+} >+ >+void RemoteInspectorSocket::workerThread() >+{ >+ while (!m_shouldAbortWorkerThread) { >+ int ret = poll(m_connections.data(), m_connections.size(), -1); >+ >+ if (ret > 0) { >+ if (m_connections[m_wakeupClient].revents & POLLIN) { >+ char wakeMessage; >+ ::read(m_connections[m_wakeupClient].fd, &wakeMessage, sizeof(wakeMessage)); >+ } >+ >+ acceptInetSocketIfEnabled(); >+ >+ for (size_t i = 0; i < m_connections.size() - 1; i++) { >+ LockHolder lock(m_sendLocks[i]); >+ recvIfEnabled(i); >+ sendIfEnabled(i); >+ } >+ >+ } else >+ LOG_ERROR("poll: error (errno = %d)", errno); >+ } >+} >+ >+void RemoteInspectorSocket::recvIfEnabled(ClientID clientID) >+{ >+ ASSERT(clientID >= 0 && clientID < m_connections.size()); >+ if (m_connections[clientID].fd == -1 || !(m_connections[clientID].revents & POLLIN)) >+ return; >+ >+ Vector<uint8_t> recvBuffer(SizeOfRecvBuffer); >+ ssize_t readSize = ::read(m_connections[clientID].fd, recvBuffer.data(), SizeOfRecvBuffer); >+ if (readSize > 0) >+ m_parsers[clientID]->pushReceivedData(recvBuffer.data(), readSize); >+ else if (readSize < 0) >+ LOG_ERROR("read error (errno = %d)", errno); >+ else { >+ ::close(m_connections[clientID].fd); >+ m_connections[clientID].fd = -1; >+ m_connections[clientID].events = 0; >+ m_parsers[clientID] = nullptr; >+ m_sendBuffers[clientID].clear(); >+ if (m_didCloseListener) >+ m_didCloseListener(clientID); >+ } >+} >+ >+void RemoteInspectorSocket::sendIfEnabled(ClientID clientID) >+{ >+ ASSERT(clientID >= 0 && clientID < m_connections.size()); >+ if (m_connections[clientID].fd == -1 || !(m_connections[clientID].revents & POLLOUT)) >+ return; >+ >+ m_connections[clientID].events &= ~POLLOUT; >+ if (m_sendBuffers[clientID].isEmpty()) >+ return; >+ >+ ssize_t writeSize = ::write(m_connections[clientID].fd, m_sendBuffers[clientID].data(), m_sendBuffers[clientID].size()); >+ if (writeSize == m_sendBuffers[clientID].size()) { >+ // all data is sent >+ m_sendBuffers[clientID].clear(); >+ return; >+ } >+ >+ // some data remains or error >+ if (writeSize > 0) >+ m_sendBuffers[clientID].remove(0, writeSize); >+ else >+ LOG_ERROR("write error (errno = %d)", errno); >+ >+ // set POLLOUT again for resending remaining data >+ m_connections[clientID].events |= POLLOUT; >+} >+ >+int RemoteInspectorSocket::send(ClientID clientID, const void* data, size_t size) >+{ >+ ASSERT(clientID >= 0 && clientID < m_connections.size()); >+ if (m_connections[clientID].fd == -1) { >+ LOG_ERROR("connection error"); >+ return -1; >+ } >+ >+ auto message = MessageParser::createMessage(data, size); >+ if (message.isEmpty()) >+ return -1; >+ >+ LockHolder lock(m_sendLocks[clientID]); >+ ssize_t writeSize = 0; >+ if (m_sendBuffers[clientID].isEmpty()) { >+ // try to call send() directly if buffer is empty >+ writeSize = ::write(m_connections[clientID].fd, message.data(), message.size()); >+ if (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 >+ m_sendBuffers[clientID].appendRange(message.begin() + writeSize, message.end()); >+ m_connections[clientID].events |= POLLOUT; >+ >+ wakeupWorkerThread(); >+ return writeSize; >+} >+ >+void RemoteInspectorSocket::wakeupWorkerThread() >+{ >+ ::write(m_wakeupSocket, "1", 1); >+} >+ >+// ------------------------------------------------------------------------- >+// Client >+// ------------------------------------------------------------------------- >+ >+RemoteInspectorSocketClient::RemoteInspectorSocketClient() >+ : RemoteInspectorSocket(NumberOfConnections) >+{ >+ // make parser >+ m_parsers[FirstConnection] = std::make_unique<MessageParser>(0); >+ m_parsers[FirstConnection]->setDidParseMessageListener([this](int, Vector<uint8_t>&& data) { >+ if (m_didReceiveDataListener) >+ m_didReceiveDataListener(FirstConnection, WTFMove(data)); >+ }); >+} >+ >+RemoteInspectorSocketClient::~RemoteInspectorSocketClient() >+{ >+} >+ >+int RemoteInspectorSocketClient::connectInet(const char* serverAddr, int serverPort) >+{ >+ if (m_connections[FirstConnection].fd != -1) { >+ LOG_ERROR("Already connected to a server"); >+ return -1; >+ } >+ >+ struct sockaddr_in saServer = { 0 }; >+ saServer.sin_family = AF_INET; >+ inet_aton(serverAddr, &saServer.sin_addr); >+ saServer.sin_port = htons(serverPort); >+ >+ // socket() >+ 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 fd; >+ } >+ >+ // connect() >+ 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 ret; >+ } >+ >+ initSockFd(fd); >+ m_connections[FirstConnection].fd = fd; >+ m_connections[FirstConnection].events = POLLIN; >+ >+ wakeupWorkerThread(); >+ return fd; >+} >+ >+bool RemoteInspectorSocketClient::addClientConnectionIdentifier(ConnectionIdentifier identifier) >+{ >+ if (m_connections[FirstConnection].fd != -1) { >+ LOG_ERROR("Already connected to a server"); >+ return false; >+ } >+ >+ initSockFd(identifier); >+ m_connections[FirstConnection].fd = identifier; >+ m_connections[FirstConnection].events = POLLIN; >+ >+ wakeupWorkerThread(); >+ return true; >+} >+ >+// ------------------------------------------------------------------------- >+// Server >+// ------------------------------------------------------------------------- >+ >+RemoteInspectorSocketServer::RemoteInspectorSocketServer() >+ : RemoteInspectorSocket(NumberOfConnections) >+{ >+} >+ >+RemoteInspectorSocketServer::~RemoteInspectorSocketServer() >+{ >+} >+ >+int RemoteInspectorSocketServer::addServerConnectionIdentifier(ConnectionIdentifier identifier) >+{ >+ for (int i = FirstConnection; i < NumberOfConnections; i++) { >+ if (m_connections[i].fd != -1) >+ continue; >+ >+ initSockFd(identifier); >+ m_connections[i].fd = identifier; >+ m_connections[i].events = POLLIN; >+ >+ std::unique_ptr<MessageParser> parser = std::make_unique<MessageParser>(i); >+ parser->setDidParseMessageListener([this](ClientID clientID, Vector<uint8_t>&& data) { >+ if (m_didReceiveDataListener) >+ m_didReceiveDataListener(clientID, WTFMove(data)); >+ }); >+ m_parsers[i] = WTFMove(parser); >+ >+ return i; >+ } >+ LOG_ERROR("addServerConnection(%d) no free connection", identifier); >+ return -1; >+} >+ >+void RemoteInspectorSocketServer::acceptInetSocketIfEnabled() >+{ >+ if (!(m_connections[AcceptInet].revents & POLLIN)) >+ return; >+ >+ struct sockaddr_in saClient; >+ memset(&saClient, 0, sizeof(saClient)); >+ socklen_t len = sizeof(struct sockaddr_in); >+ int fd = accept(m_connections[AcceptInet].fd, (struct sockaddr*)&saClient, &len); >+ if (fd < 0) { >+ LOG_ERROR("accept(inet) error (errno = %d)", errno); >+ return; >+ } >+ >+ auto connectionIndex = addServerConnectionIdentifier(fd); >+ if (connectionIndex > 0) { >+ if (m_didAcceptListener) >+ m_didAcceptListener(connectionIndex, DomainType::Inet, String(inet_ntoa(saClient.sin_addr)), saClient.sin_port); >+ } else >+ ::close(fd); >+} >+ >+int RemoteInspectorSocketServer::listenInet(int port) >+{ >+ if (m_connections[AcceptInet].fd != -1) { >+ LOG_ERROR("Already listening for inet connections"); >+ return -1; >+ } >+ >+ struct sockaddr_in saServer = { 0 }; >+ >+ // socket() >+ int fdListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); >+ if (fdListen < 0) { >+ LOG_ERROR("socket() failed, ret = %d, errno = %d", fdListen, errno); >+ return fdListen; >+ } >+ >+ const int on = 1; >+ int ret = setsockopt(fdListen, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); >+ if (ret < 0) { >+ LOG_ERROR("setsockopt() SO_REUSEADDR failed, ret = %d, errno = %d", fdListen, errno); >+ return ret; >+ } >+ ret = setsockopt(fdListen, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)); >+ if (ret < 0) { >+ LOG_ERROR("setsockopt() SO_REUSEPORT, ret = %d, errno = %d", fdListen, errno); >+ return ret; >+ } >+ >+ // bind() >+ 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 ret; >+ } >+ >+ // listen() >+ ret = listen(fdListen, 1); >+ if (ret < 0) { >+ LOG_ERROR("listen() failed, ret = %d errno = %d", ret, errno); >+ ::close(fdListen); >+ return ret; >+ } >+ >+ // set fd to fd_set >+ m_connections[AcceptInet].fd = fdListen; >+ m_connections[AcceptInet].events = POLLIN; >+ >+ wakeupWorkerThread(); >+ return fdListen; >+} >+ >+// ------------------------------------------------------------------------- >+// MessageParser >+// ------------------------------------------------------------------------- >+MessageParser::MessageParser(ClientID clientID) >+ : m_clientID(clientID) >+{ >+ m_buffer.reserveCapacity(SizeOfRecvBuffer); >+} >+ >+Vector<uint8_t> MessageParser::createMessage(const void* data, size_t size) >+{ >+ if (!data || !size || size > INT_MAX) >+ return Vector<uint8_t>(); >+ >+ auto messageBuffer = Vector<uint8_t>(size + sizeof(int)); >+ int intSize = static_cast<int>(size); >+ memcpy(&messageBuffer[0], &intSize, sizeof(int)); >+ memcpy(&messageBuffer[sizeof(int)], data, intSize); >+ return messageBuffer; >+} >+ >+void MessageParser::pushReceivedData(const void* data, size_t size) >+{ >+ if (!data || !size) >+ return; >+ >+ auto p = reinterpret_cast<const char*>(data); >+ m_buffer.reserveCapacity(m_buffer.size() + size); >+ m_buffer.append(p, size); >+ >+ if (!parse()) >+ clearReceivedData(); >+} >+ >+void MessageParser::clearReceivedData() >+{ >+ m_buffer.clear(); >+} >+ >+bool MessageParser::parse() >+{ >+ while (!m_buffer.isEmpty()) { >+ if (m_buffer.size() < sizeof(int)) { >+ // wait next recv >+ return true; >+ } >+ >+ int dataSize = 0; >+ memcpy(&dataSize, &m_buffer[0], sizeof(int)); >+ if (dataSize <= 0) { >+ LOG_ERROR("Message Parser received an invalid message size"); >+ return false; >+ } >+ >+ size_t messageSize = (sizeof(int) + dataSize); >+ if (m_buffer.size() < messageSize) { >+ // wait next recv >+ return true; >+ } >+ >+ auto dataBuffer = Vector<uint8_t>(dataSize); >+ memcpy(&dataBuffer[0], &m_buffer[sizeof(int)], dataSize); >+ >+ if (m_didParseMessageListener) >+ m_didParseMessageListener(m_clientID, WTFMove(dataBuffer)); >+ >+ m_buffer.remove(0, messageSize); >+ } >+ >+ return true; >+} >+ >+} // namespace Inspector >+ >+#endif // ENABLE(REMOTE_INSPECTOR) >diff --git a/Source/cmake/OptionsPlayStation.cmake b/Source/cmake/OptionsPlayStation.cmake >index 501d048b5ae..b76cf9c10c3 100644 >--- a/Source/cmake/OptionsPlayStation.cmake >+++ b/Source/cmake/OptionsPlayStation.cmake >@@ -9,9 +9,6 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_JIT PRIVATE OFF) > WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTL_JIT PRIVATE OFF) > WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DFG_JIT PRIVATE OFF) > >-# Disable Remote Inspector until implementation lands >-WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_REMOTE_INSPECTOR PRIVATE OFF) >- > # Enabled features > WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ASYNC_SCROLLING PRIVATE ON) > WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SMOOTH_SCROLLING PRIVATE ON)
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
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193806
:
360074
|
360938
|
360940
|
361665
|
361668
|
361701
|
361707
|
362388
|
362940
|
363397
|
363398