/* * Copyright (c) 2024, Andrew Kaster * Copyright (c) 2025, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include namespace IPC { class AutoCloseFileDescriptor : public RefCounted { public: AutoCloseFileDescriptor(int fd); ~AutoCloseFileDescriptor(); 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 peek(size_t max_bytes); void discard(size_t bytes_count, size_t fds_count); private: AllocatingMemoryStream m_stream; 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 close_after_sending_all_pending_messages(); 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&&); // Obnoxious name to make it clear that this is a dangerous operation. ErrorOr release_underlying_transport_for_transfer(); ErrorOr clone_for_transfer(); private: enum class TransferState { Continue, SocketClosed, }; [[nodiscard]] TransferState transfer_data(ReadonlyBytes& bytes, Vector& fds); static ErrorOr send_message(Core::LocalSocket&, ReadonlyBytes& bytes, Vector& unowned_fds); void stop_send_thread(); NonnullOwnPtr m_socket; mutable Threading::RWLock m_socket_rw_lock; 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; }; }