/* * Copyright (c) 2024, Andrew Kaster * Copyright (c) 2025, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace IPC { class AutoCloseFileDescriptor : public RefCounted { public: AutoCloseFileDescriptor(int fd) : m_fd(fd) { } ~AutoCloseFileDescriptor() { if (m_fd != -1) (void)Core::System::close(m_fd); } int value() const { return m_fd; } int take_fd() { int fd = m_fd; m_fd = -1; return fd; } private: int m_fd; }; class SendQueue : public AtomicRefCounted { public: enum class Running { No, Yes, }; Running block_until_message_enqueued(); void stop(); void enqueue_message(Vector&& bytes, Vector&& fds); struct BytesAndFds { Vector bytes; Vector fds; }; BytesAndFds dequeue(size_t max_bytes); void return_unsent_data_to_front_of_queue(ReadonlyBytes const& bytes, Vector const& fds); private: Vector m_bytes; Vector m_fds; Threading::Mutex m_mutex; Threading::ConditionVariable m_condition { m_mutex }; bool m_running { true }; }; class TransportSocket { AK_MAKE_NONCOPYABLE(TransportSocket); AK_MAKE_NONMOVABLE(TransportSocket); public: static constexpr socklen_t SOCKET_BUFFER_SIZE = 128 * KiB; explicit TransportSocket(NonnullOwnPtr socket); ~TransportSocket(); void set_up_read_hook(Function); bool is_open() const; void close(); void wait_until_readable(); void post_message(Vector const&, Vector> const&); enum class ShouldShutdown { No, Yes, }; struct Message { Vector bytes; Queue fds; }; ShouldShutdown read_as_many_messages_as_possible_without_blocking(Function&& schedule_shutdown); // Obnoxious name to make it clear that this is a dangerous operation. ErrorOr release_underlying_transport_for_transfer(); ErrorOr clone_for_transfer(); private: static ErrorOr send_message(Core::LocalSocket&, ReadonlyBytes& bytes, Vector& unowned_fds); NonnullOwnPtr m_socket; ByteBuffer m_unprocessed_bytes; Queue m_unprocessed_fds; // After file descriptor is sent, it is moved to the wait queue until an acknowledgement is received from the peer. // This is necessary to handle a specific behavior of the macOS kernel, which may prematurely garbage-collect the file // descriptor contained in the message before the peer receives it. https://openradar.me/9477351 Queue> m_fds_retained_until_received_by_peer; RefPtr m_send_thread; RefPtr m_send_queue; }; }