summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Base/etc/SystemServer.ini6
-rw-r--r--Userland/Services/CMakeLists.txt1
-rw-r--r--Userland/Services/InspectorServer/CMakeLists.txt13
-rw-r--r--Userland/Services/InspectorServer/ClientConnection.cpp87
-rw-r--r--Userland/Services/InspectorServer/ClientConnection.h34
-rw-r--r--Userland/Services/InspectorServer/Forward.h13
-rw-r--r--Userland/Services/InspectorServer/InspectableProcess.cpp77
-rw-r--r--Userland/Services/InspectorServer/InspectableProcess.h30
-rw-r--r--Userland/Services/InspectorServer/InspectorClient.ipc4
-rw-r--r--Userland/Services/InspectorServer/InspectorServer.ipc10
-rw-r--r--Userland/Services/InspectorServer/main.cpp57
11 files changed, 332 insertions, 0 deletions
diff --git a/Base/etc/SystemServer.ini b/Base/etc/SystemServer.ini
index 5095292b25..157bedda11 100644
--- a/Base/etc/SystemServer.ini
+++ b/Base/etc/SystemServer.ini
@@ -78,6 +78,12 @@ Priority=high
KeepAlive=1
User=window
+[InspectorServer]
+Socket=/tmp/portal/inspector,/tmp/portal/inspectables
+SocketPermissions=600,666
+KeepAlive=1
+User=anon
+
[Clipboard]
Socket=/tmp/portal/clipboard
SocketPermissions=660
diff --git a/Userland/Services/CMakeLists.txt b/Userland/Services/CMakeLists.txt
index 8fa4fd1710..c126e2d09c 100644
--- a/Userland/Services/CMakeLists.txt
+++ b/Userland/Services/CMakeLists.txt
@@ -6,6 +6,7 @@ add_subdirectory(DHCPClient)
add_subdirectory(EchoServer)
add_subdirectory(FileOperation)
add_subdirectory(ImageDecoder)
+add_subdirectory(InspectorServer)
add_subdirectory(KeyboardPreferenceLoader)
add_subdirectory(LaunchServer)
add_subdirectory(LookupServer)
diff --git a/Userland/Services/InspectorServer/CMakeLists.txt b/Userland/Services/InspectorServer/CMakeLists.txt
new file mode 100644
index 0000000000..2adbe4a4d6
--- /dev/null
+++ b/Userland/Services/InspectorServer/CMakeLists.txt
@@ -0,0 +1,13 @@
+compile_ipc(InspectorServer.ipc InspectorServerEndpoint.h)
+compile_ipc(InspectorClient.ipc InspectorClientEndpoint.h)
+
+set(SOURCES
+ ClientConnection.cpp
+ main.cpp
+ InspectableProcess.cpp
+ InspectorServerEndpoint.h
+ InspectorClientEndpoint.h
+)
+
+serenity_bin(InspectorServer)
+target_link_libraries(InspectorServer LibIPC)
diff --git a/Userland/Services/InspectorServer/ClientConnection.cpp b/Userland/Services/InspectorServer/ClientConnection.cpp
new file mode 100644
index 0000000000..0fccb06c84
--- /dev/null
+++ b/Userland/Services/InspectorServer/ClientConnection.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "InspectableProcess.h"
+#include <InspectorServer/ClientConnection.h>
+
+namespace InspectorServer {
+
+static HashMap<int, RefPtr<ClientConnection>> s_connections;
+
+ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id)
+ : IPC::ClientConnection<InspectorClientEndpoint, InspectorServerEndpoint>(*this, move(socket), client_id)
+{
+ s_connections.set(client_id, *this);
+}
+
+ClientConnection::~ClientConnection()
+{
+}
+
+void ClientConnection::die()
+{
+ s_connections.remove(client_id());
+}
+
+void ClientConnection::greet()
+{
+}
+
+Messages::InspectorServer::GetAllObjectsResponse ClientConnection::get_all_objects(pid_t pid)
+{
+ auto process = InspectableProcess::from_pid(pid);
+ if (!process)
+ return { String {} };
+
+ JsonObject request;
+ request.set("type", "GetAllObjects");
+ process->send_request(request);
+ auto response = process->wait_for_response();
+ return { response };
+}
+
+Messages::InspectorServer::SetInspectedObjectResponse ClientConnection::set_inspected_object(pid_t pid, u64 object_id)
+{
+ auto process = InspectableProcess::from_pid(pid);
+ if (!process)
+ return { false };
+
+ JsonObject request;
+ request.set("type", "SetInspectedObject");
+ request.set("address", object_id);
+ process->send_request(request);
+ return { true };
+}
+
+Messages::InspectorServer::SetObjectPropertyResponse ClientConnection::set_object_property(pid_t pid, u64 object_id, String const& name, String const& value)
+{
+ auto process = InspectableProcess::from_pid(pid);
+ if (!process)
+ return { false };
+
+ JsonObject request;
+ request.set("type", "SetProperty");
+ request.set("address", object_id);
+ request.set("name", name);
+ request.set("value", value);
+ process->send_request(request);
+ return { true };
+}
+
+Messages::InspectorServer::IdentifyResponse ClientConnection::identify(pid_t pid)
+{
+ auto process = InspectableProcess::from_pid(pid);
+ if (!process)
+ return { String {} };
+
+ JsonObject request;
+ request.set("type", "Identify");
+ process->send_request(request);
+ auto response = process->wait_for_response();
+ return { response };
+}
+
+}
diff --git a/Userland/Services/InspectorServer/ClientConnection.h b/Userland/Services/InspectorServer/ClientConnection.h
new file mode 100644
index 0000000000..812f725081
--- /dev/null
+++ b/Userland/Services/InspectorServer/ClientConnection.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/HashMap.h>
+#include <InspectorServer/InspectorClientEndpoint.h>
+#include <InspectorServer/InspectorServerEndpoint.h>
+#include <LibIPC/ClientConnection.h>
+
+namespace InspectorServer {
+
+class ClientConnection final
+ : public IPC::ClientConnection<InspectorClientEndpoint, InspectorServerEndpoint> {
+ C_OBJECT(ClientConnection);
+
+public:
+ explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
+ ~ClientConnection() override;
+
+ virtual void die() override;
+
+private:
+ virtual void greet() override;
+ virtual Messages::InspectorServer::GetAllObjectsResponse get_all_objects(pid_t) override;
+ virtual Messages::InspectorServer::SetInspectedObjectResponse set_inspected_object(pid_t, u64 object_id) override;
+ virtual Messages::InspectorServer::SetObjectPropertyResponse set_object_property(pid_t, u64 object_id, String const& name, String const& value) override;
+ virtual Messages::InspectorServer::IdentifyResponse identify(pid_t) override;
+};
+
+}
diff --git a/Userland/Services/InspectorServer/Forward.h b/Userland/Services/InspectorServer/Forward.h
new file mode 100644
index 0000000000..97cdfba43c
--- /dev/null
+++ b/Userland/Services/InspectorServer/Forward.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+namespace SymbolServer {
+
+class ClientConnection;
+
+}
diff --git a/Userland/Services/InspectorServer/InspectableProcess.cpp b/Userland/Services/InspectorServer/InspectableProcess.cpp
new file mode 100644
index 0000000000..a064acd415
--- /dev/null
+++ b/Userland/Services/InspectorServer/InspectableProcess.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "InspectableProcess.h"
+
+namespace InspectorServer {
+
+HashMap<pid_t, NonnullOwnPtr<InspectableProcess>> g_processes;
+
+InspectableProcess* InspectableProcess::from_pid(pid_t pid)
+{
+ return g_processes.get(pid).value_or(nullptr);
+}
+
+InspectableProcess::InspectableProcess(pid_t pid, NonnullRefPtr<Core::LocalSocket> socket)
+ : m_pid(pid)
+ , m_socket(move(socket))
+{
+ m_socket->set_blocking(true);
+ m_socket->on_ready_to_read = [this] {
+ auto buffer = m_socket->read(1);
+ if (m_socket->eof()) {
+ g_processes.remove(m_pid);
+ return;
+ }
+ };
+}
+
+InspectableProcess::~InspectableProcess()
+{
+}
+
+String InspectableProcess::wait_for_response()
+{
+ if (m_socket->eof()) {
+ dbgln("InspectableProcess disconnected: PID {}", m_pid);
+ m_socket->close();
+ return {};
+ }
+
+ u32 length {};
+ auto nread = m_socket->read((u8*)&length, sizeof(length));
+ if (nread != sizeof(length)) {
+ dbgln("InspectableProcess got malformed data: PID {}", m_pid);
+ m_socket->close();
+ return {};
+ }
+
+ ByteBuffer data;
+ size_t remaining_bytes = length;
+
+ while (remaining_bytes) {
+ auto packet = m_socket->read(remaining_bytes);
+ if (packet.size() == 0)
+ break;
+ data.append(packet.data(), packet.size());
+ remaining_bytes -= packet.size();
+ }
+
+ VERIFY(data.size() == length);
+ dbgln("Got data size {} and read that many bytes", length);
+
+ return String::copy(data);
+}
+
+void InspectableProcess::send_request(JsonObject const& request)
+{
+ auto serialized = request.to_string();
+ auto length = serialized.length();
+ m_socket->write((u8 const*)&length, sizeof(length));
+ m_socket->write(serialized);
+}
+
+}
diff --git a/Userland/Services/InspectorServer/InspectableProcess.h b/Userland/Services/InspectorServer/InspectableProcess.h
new file mode 100644
index 0000000000..afefa0ba87
--- /dev/null
+++ b/Userland/Services/InspectorServer/InspectableProcess.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibCore/LocalSocket.h>
+
+namespace InspectorServer {
+
+class InspectableProcess {
+public:
+ InspectableProcess(pid_t, NonnullRefPtr<Core::LocalSocket>);
+ ~InspectableProcess();
+
+ void send_request(JsonObject const& request);
+ String wait_for_response();
+
+ static InspectableProcess* from_pid(pid_t);
+
+private:
+ pid_t m_pid { 0 };
+ NonnullRefPtr<Core::LocalSocket> m_socket;
+};
+
+extern HashMap<pid_t, NonnullOwnPtr<InspectorServer::InspectableProcess>> g_processes;
+
+}
diff --git a/Userland/Services/InspectorServer/InspectorClient.ipc b/Userland/Services/InspectorServer/InspectorClient.ipc
new file mode 100644
index 0000000000..bd0021d632
--- /dev/null
+++ b/Userland/Services/InspectorServer/InspectorClient.ipc
@@ -0,0 +1,4 @@
+endpoint InspectorClient
+{
+ dummy() =|
+}
diff --git a/Userland/Services/InspectorServer/InspectorServer.ipc b/Userland/Services/InspectorServer/InspectorServer.ipc
new file mode 100644
index 0000000000..ed1696274d
--- /dev/null
+++ b/Userland/Services/InspectorServer/InspectorServer.ipc
@@ -0,0 +1,10 @@
+endpoint InspectorServer
+{
+ greet() => ()
+
+ get_all_objects(i32 pid) => (String json)
+ set_inspected_object(i32 pid, u64 object_id) => (bool success)
+ set_object_property(i32 pid, u64 object_id, String name, String value) => (bool success)
+ identify(i32 pid) => (String json)
+
+}
diff --git a/Userland/Services/InspectorServer/main.cpp b/Userland/Services/InspectorServer/main.cpp
new file mode 100644
index 0000000000..de1e7d1704
--- /dev/null
+++ b/Userland/Services/InspectorServer/main.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "InspectableProcess.h"
+#include <InspectorServer/ClientConnection.h>
+#include <LibCore/EventLoop.h>
+#include <LibCore/LocalServer.h>
+#include <LibIPC/ClientConnection.h>
+
+int main(int, char**)
+{
+ Core::EventLoop event_loop(Core::EventLoop::MakeInspectable::No);
+ auto server = Core::LocalServer::construct();
+
+ if (pledge("stdio unix accept", nullptr) < 0) {
+ perror("pledge");
+ return 1;
+ }
+
+ bool ok = server->take_over_from_system_server("/tmp/portal/inspector");
+ VERIFY(ok);
+ server->on_ready_to_accept = [&] {
+ auto client_socket = server->accept();
+ if (!client_socket) {
+ dbgln("accept failed.");
+ return;
+ }
+ static int s_next_client_id = 0;
+ int client_id = ++s_next_client_id;
+ IPC::new_client_connection<InspectorServer::ClientConnection>(client_socket.release_nonnull(), client_id);
+ };
+
+ auto inspectables_server = Core::LocalServer::construct();
+ if (!inspectables_server->take_over_from_system_server("/tmp/portal/inspectables"))
+ VERIFY_NOT_REACHED();
+
+ inspectables_server->on_ready_to_accept = [&] {
+ auto client_socket = inspectables_server->accept();
+ if (!client_socket) {
+ dbgln("backdoor accept failed.");
+ return;
+ }
+ struct ucred creds = {};
+ socklen_t creds_size = sizeof(creds);
+ if (getsockopt(client_socket->fd(), SOL_SOCKET, SO_PEERCRED, &creds, &creds_size) < 0) {
+ dbgln("SO_PEERCRED failed");
+ return;
+ }
+
+ InspectorServer::g_processes.set(creds.pid, make<InspectorServer::InspectableProcess>(creds.pid, client_socket.release_nonnull()));
+ };
+
+ return event_loop.exec();
+}