diff --git a/Libraries/LibCore/LocalSocket.cpp b/Libraries/LibCore/LocalSocket.cpp index 3d347d23932..725f5747d6a 100644 --- a/Libraries/LibCore/LocalSocket.cpp +++ b/Libraries/LibCore/LocalSocket.cpp @@ -26,7 +26,9 @@ #include #include +#include #include +#include #ifndef SOCK_NONBLOCK # include @@ -70,4 +72,38 @@ LocalSocket::~LocalSocket() { } +RefPtr LocalSocket::take_over_accepted_socket_from_system_server() +{ + constexpr auto socket_takeover = "SOCKET_TAKEOVER"; + if (!getenv(socket_takeover)) + return nullptr; + + dbg() << "Taking the accepted socket over from SystemServer"; + + // The SystemServer has passed us the socket as fd 3, + // so use that instead of creating our own. + constexpr int fd = 3; + + // Sanity check: it has to be a socket. + struct stat stat; + int rc = fstat(fd, &stat); + if (rc < 0 || !S_ISSOCK(stat.st_mode)) { + if (rc != 0) + perror("fstat"); + dbg() << "ERROR: The fd we got from SystemServer is not a socket"; + return nullptr; + } + + auto socket = LocalSocket::construct(fd); + + // It had to be !CLOEXEC for obvious reasons, but we + // don't need it to be !CLOEXEC anymore, so set the + // CLOEXEC flag now. + fcntl(fd, F_SETFD, FD_CLOEXEC); + // We wouldn't want our children to think we're passing + // them a socket either, so unset the env variable. + unsetenv(socket_takeover); + return socket; +} + } diff --git a/Libraries/LibCore/LocalSocket.h b/Libraries/LibCore/LocalSocket.h index 1feee980f56..921e16aaa2b 100644 --- a/Libraries/LibCore/LocalSocket.h +++ b/Libraries/LibCore/LocalSocket.h @@ -35,6 +35,8 @@ class LocalSocket final : public Socket { public: virtual ~LocalSocket() override; + static RefPtr take_over_accepted_socket_from_system_server(); + private: explicit LocalSocket(Object* parent = nullptr); LocalSocket(int fd, Object* parent = nullptr);