mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-06 19:19:44 +03:00
SystemServer: Add support for accepting socket connections :^)
You can now ask SystemServer to not only listen for connections on the socket, but to actually accept them, and to spawn an instance of the service for each client connection. In this case, it's the accepted, not listening, socket that the service processes will receive using socket takeover. This mode obviously requires the service to be a multi-instance service.
This commit is contained in:
parent
ac4c2f890f
commit
701994bfd1
Notes:
sideshowbarker
2024-07-19 05:44:09 +09:00
Author: https://github.com/bugaevc Commit: https://github.com/SerenityOS/serenity/commit/701994bfd19 Pull-request: https://github.com/SerenityOS/serenity/pull/2534
@ -158,11 +158,26 @@ void Service::setup_notifier()
|
||||
|
||||
m_socket_notifier = Core::Notifier::construct(m_socket_fd, Core::Notifier::Event::Read, this);
|
||||
m_socket_notifier->on_ready_to_read = [this] {
|
||||
dbg() << "Ready to read on behalf of " << name();
|
||||
handle_socket_connection();
|
||||
};
|
||||
}
|
||||
|
||||
void Service::handle_socket_connection()
|
||||
{
|
||||
dbg() << "Ready to read on behalf of " << name();
|
||||
if (m_accept_socket_connections) {
|
||||
int accepted_fd = accept(m_socket_fd, nullptr, nullptr);
|
||||
if (accepted_fd < 0) {
|
||||
perror("accept");
|
||||
return;
|
||||
}
|
||||
spawn(accepted_fd);
|
||||
close(accepted_fd);
|
||||
} else {
|
||||
remove_child(*m_socket_notifier);
|
||||
m_socket_notifier = nullptr;
|
||||
spawn();
|
||||
};
|
||||
spawn(m_socket_fd);
|
||||
}
|
||||
}
|
||||
|
||||
void Service::activate()
|
||||
@ -172,10 +187,10 @@ void Service::activate()
|
||||
if (m_lazy)
|
||||
setup_notifier();
|
||||
else
|
||||
spawn();
|
||||
spawn(m_socket_fd);
|
||||
}
|
||||
|
||||
void Service::spawn()
|
||||
void Service::spawn(int socket_fd)
|
||||
{
|
||||
dbg() << "Spawning " << name();
|
||||
|
||||
@ -231,11 +246,12 @@ void Service::spawn()
|
||||
dup2(STDIN_FILENO, STDERR_FILENO);
|
||||
}
|
||||
|
||||
if (!m_socket_path.is_null()) {
|
||||
ASSERT(m_socket_fd > 2);
|
||||
dup2(m_socket_fd, 3);
|
||||
if (socket_fd >= 0) {
|
||||
ASSERT(!m_socket_path.is_null());
|
||||
ASSERT(socket_fd > 2);
|
||||
dup2(socket_fd, 3);
|
||||
// The new descriptor is !CLOEXEC here.
|
||||
// This is true even if m_socket_fd == 3.
|
||||
// This is true even if socket_fd == 3.
|
||||
setenv("SOCKET_TAKEOVER", "1", true);
|
||||
}
|
||||
|
||||
@ -330,11 +346,14 @@ Service::Service(const Core::ConfigFile& config, const StringView& name)
|
||||
m_environment = config.read_entry(name, "Environment").split(' ');
|
||||
m_boot_modes = config.read_entry(name, "BootModes", "graphical").split(',');
|
||||
m_multi_instance = config.read_bool_entry(name, "MultiInstance");
|
||||
m_accept_socket_connections = config.read_bool_entry(name, "AcceptSocketConnections");
|
||||
|
||||
m_socket_path = config.read_entry(name, "Socket");
|
||||
|
||||
// Lazy requires Socket.
|
||||
ASSERT(!m_lazy || !m_socket_path.is_null());
|
||||
// AcceptSocketConnections always requires Socket, Lazy, and MultiInstance.
|
||||
ASSERT(!m_accept_socket_connections || (!m_socket_path.is_null() && m_lazy && m_multi_instance));
|
||||
// MultiInstance doesn't work with KeepAlive.
|
||||
ASSERT(!m_multi_instance || !m_keep_alive);
|
||||
|
||||
@ -379,6 +398,7 @@ void Service::save_to(JsonObject& json)
|
||||
json.set("uid", m_uid);
|
||||
json.set("gid", m_gid);
|
||||
json.set("multi_instance", m_multi_instance);
|
||||
json.set("accept_socket_connections", m_accept_socket_connections);
|
||||
|
||||
if (m_pid > 0)
|
||||
json.set("pid", m_pid);
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
private:
|
||||
Service(const Core::ConfigFile&, const StringView& name);
|
||||
|
||||
void spawn();
|
||||
void spawn(int socket_fd = -1);
|
||||
|
||||
// Path to the executable. By default this is /bin/{m_name}.
|
||||
String m_executable_path;
|
||||
@ -62,6 +62,10 @@ private:
|
||||
String m_socket_path;
|
||||
// File system permissions for the socket.
|
||||
mode_t m_socket_permissions { 0 };
|
||||
// Whether we should accept connections on the socket and pass the accepted
|
||||
// (and not listening) socket to the service. This requires a multi-instance
|
||||
// service.
|
||||
bool m_accept_socket_connections { false };
|
||||
// Whether we should only spawn this service once somebody connects to the socket.
|
||||
bool m_lazy;
|
||||
// The name of the user we should run this service as.
|
||||
@ -93,4 +97,5 @@ private:
|
||||
void resolve_user();
|
||||
void setup_socket();
|
||||
void setup_notifier();
|
||||
void handle_socket_connection();
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user