Procházet zdrojové kódy

RequestServer: Add IPC to create a new client and return the sockets

We'll need this to implement single-instance RS for the Browser.
Andrew Kaster před 1 rokem
rodič
revize
5e18d157d0

+ 49 - 3
Userland/Services/RequestServer/ConnectionFromClient.cpp

@@ -5,6 +5,7 @@
  */
 
 #include <AK/Badge.h>
+#include <AK/IDAllocator.h>
 #include <AK/NonnullOwnPtr.h>
 #include <AK/RefCounted.h>
 #include <AK/Weakable.h>
@@ -21,20 +22,65 @@
 namespace RequestServer {
 
 static HashMap<int, RefPtr<ConnectionFromClient>> s_connections;
+static IDAllocator s_client_ids;
 
 ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr<Core::LocalSocket> socket)
-    : IPC::ConnectionFromClient<RequestClientEndpoint, RequestServerEndpoint>(*this, move(socket), 1)
+    : IPC::ConnectionFromClient<RequestClientEndpoint, RequestServerEndpoint>(*this, move(socket), s_client_ids.allocate())
 {
-    s_connections.set(1, *this);
+    s_connections.set(client_id(), *this);
 }
 
 void ConnectionFromClient::die()
 {
-    s_connections.remove(client_id());
+    auto client_id = this->client_id();
+    s_connections.remove(client_id);
+    s_client_ids.deallocate(client_id);
+
     if (s_connections.is_empty())
         Core::EventLoop::current().quit(0);
 }
 
+Messages::RequestServer::ConnectNewClientResponse ConnectionFromClient::connect_new_client()
+{
+    int socket_fds[2] {};
+    if (auto err = Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds); err.is_error()) {
+        dbgln("Failed to create client socketpair: {}", err.error());
+        return { -1, -1 };
+    }
+
+    auto client_socket_or_error = Core::LocalSocket::adopt_fd(socket_fds[0]);
+    if (client_socket_or_error.is_error()) {
+        close(socket_fds[0]);
+        close(socket_fds[1]);
+        dbgln("Failed to adopt client socket: {}", client_socket_or_error.error());
+        return { -1, -1 };
+    }
+    auto client_socket = client_socket_or_error.release_value();
+    // Note: A ref is stored in the static s_connections map
+    auto client = adopt_ref(*new ConnectionFromClient(move(client_socket)));
+
+    int fd_passing_socket_fds[2] {};
+    if (auto err = Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds); err.is_error()) {
+        close(socket_fds[1]);
+        dbgln("Failed to create fd-passing socketpair: {}", err.error());
+        return { -1, -1 };
+    }
+
+    auto fd_passing_socket_or_error = Core::LocalSocket::adopt_fd(fd_passing_socket_fds[0]);
+    if (fd_passing_socket_or_error.is_error()) {
+        // socket_fds[0] is already owned by client
+        close(socket_fds[1]);
+        close(fd_passing_socket_fds[0]);
+        close(fd_passing_socket_fds[1]);
+        dbgln("Failed to adopt fd-passing socket: {}", fd_passing_socket_or_error.error());
+        return { -1, -1 };
+    }
+    auto fd_passing_socket = fd_passing_socket_or_error.release_value();
+    client->set_fd_passing_socket(move(fd_passing_socket));
+
+    return { IPC::File(socket_fds[1], IPC::File::CloseAfterSending), IPC::File(fd_passing_socket_fds[1], IPC::File::CloseAfterSending) };
+}
+
 Messages::RequestServer::IsSupportedProtocolResponse ConnectionFromClient::is_supported_protocol(ByteString const& protocol)
 {
     bool supported = Protocol::find_by_name(protocol.to_lowercase());

+ 1 - 0
Userland/Services/RequestServer/ConnectionFromClient.h

@@ -32,6 +32,7 @@ public:
 private:
     explicit ConnectionFromClient(NonnullOwnPtr<Core::LocalSocket>);
 
+    virtual Messages::RequestServer::ConnectNewClientResponse connect_new_client() override;
     virtual Messages::RequestServer::IsSupportedProtocolResponse is_supported_protocol(ByteString const&) override;
     virtual void start_request(i32 request_id, ByteString const&, URL::URL const&, HashMap<ByteString, ByteString> const&, ByteBuffer const&, Core::ProxyData const&) override;
     virtual Messages::RequestServer::StopRequestResponse stop_request(i32) override;

+ 2 - 0
Userland/Services/RequestServer/RequestServer.ipc

@@ -3,6 +3,8 @@
 
 endpoint RequestServer
 {
+    connect_new_client() => (IPC::File client_socket, IPC::File client_fd_passing_socket)
+
     // Test if a specific protocol is supported, e.g "http"
     is_supported_protocol(ByteString protocol) => (bool supported)