ladybird/Libraries/LibDevTools/DevToolsServer.h
Sam Atkins 1b3296b574 LibDevTools: Avoid stale callbacks during server teardown
DevTools server callbacks can outlive the server when deferred work is
queued during connection shutdown. Capture weak pointers for those tasks
and clear socket callbacks while the server is being destroyed so later
actor cleanup cannot touch freed state.

Add protocol coverage that destroys a server with deferred actor cleanup
pending, before adding the style-rule actor path that depends on this.
2026-06-04 20:54:33 +01:00

76 lines
2 KiB
C++

/*
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Error.h>
#include <AK/HashMap.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/Weakable.h>
#include <LibCore/Socket.h>
#include <LibDevTools/Actors/RootActor.h>
#include <LibDevTools/Forward.h>
namespace DevTools {
using ActorRegistry = HashMap<String, NonnullRefPtr<Actor>>;
class DEVTOOLS_API DevToolsServer : public Weakable<DevToolsServer> {
public:
static ErrorOr<NonnullOwnPtr<DevToolsServer>> create(DevToolsDelegate&, u16 port);
~DevToolsServer();
RefPtr<Connection>& connection() { return m_connection; }
DevToolsDelegate const& delegate() const { return m_delegate; }
ActorRegistry const& actor_registry() const { return m_actor_registry; }
Optional<u16> local_port() const;
void unregister_actor(String const& name);
template<typename ActorType, typename... Args>
ActorType& register_actor(Args&&... args)
{
String name;
auto id = m_actor_count++;
if constexpr (IsSame<ActorType, RootActor>) {
name = String::from_utf8_without_validation(ActorType::base_name.bytes());
} else {
name = MUST(String::formatted("server{}-{}{}", m_server_id, ActorType::base_name, id));
}
auto actor = ActorType::create(*this, name, forward<Args>(args)...);
m_actor_registry.set(name, actor);
return actor;
}
void refresh_tab_list();
private:
explicit DevToolsServer(DevToolsDelegate&, NonnullRefPtr<Core::TCPServer>);
ErrorOr<void> on_new_client();
void on_message_received(JsonObject);
void close_connection();
NonnullRefPtr<Core::TCPServer> m_server;
RefPtr<Connection> m_connection;
DevToolsDelegate& m_delegate;
ActorRegistry m_actor_registry;
RefPtr<RootActor> m_root_actor { nullptr };
u64 m_server_id { 0 };
u64 m_actor_count { 0 };
bool m_is_shutting_down { false };
};
}