123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- /*
- * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/ByteString.h>
- #include <AK/Format.h>
- #include <LibCore/MachPort.h>
- #if defined(AK_OS_GNU_HURD)
- extern "C" {
- # include <mach_error.h>
- }
- // This is in <mach/mach_error.h> on Darwin, and doesn't seem to be required.
- #endif
- #if defined(AK_OS_MACOS)
- # include <bootstrap.h>
- #endif
- namespace Core {
- static constexpr MachPort::PortRight associated_port_right(MachPort::MessageRight right)
- {
- switch (right) {
- case MachPort::MessageRight::MoveReceive:
- return MachPort::PortRight::Receive;
- case MachPort::MessageRight::MoveSend:
- case MachPort::MessageRight::CopySend:
- case MachPort::MessageRight::MakeSend:
- return MachPort::PortRight::Send;
- case MachPort::MessageRight::MoveSendOnce:
- case MachPort::MessageRight::MakeSendOnce:
- return MachPort::PortRight::SendOnce;
- #if defined(AK_OS_MACOS)
- case MachPort::MessageRight::CopyReceive:
- case MachPort::MessageRight::DisposeReceive:
- return MachPort::PortRight::Receive;
- case MachPort::MessageRight::DisposeSend:
- return MachPort::PortRight::Send;
- case MachPort::MessageRight::DisposeSendOnce:
- return MachPort::PortRight::SendOnce;
- #endif
- }
- VERIFY_NOT_REACHED();
- }
- Error mach_error_to_error(kern_return_t error)
- {
- char const* err_string = mach_error_string(error);
- StringView const err_view(err_string, strlen(err_string));
- return Error::from_string_view(err_view);
- }
- #if defined(AK_OS_MACOS)
- static Error bootstrap_error_to_error(kern_return_t error)
- {
- char const* err_string = bootstrap_strerror(error);
- StringView const err_view(err_string, strlen(err_string));
- return Error::from_string_view(err_view);
- }
- #endif
- MachPort::MachPort(PortRight right, mach_port_t port)
- : m_right(right)
- , m_port(port)
- {
- }
- MachPort::~MachPort()
- {
- unref_port();
- }
- MachPort::MachPort(MachPort&& other)
- : m_right(other.m_right)
- , m_port(other.release())
- {
- }
- MachPort& MachPort::operator=(MachPort&& other)
- {
- if (this != &other) {
- unref_port();
- m_right = other.m_right;
- m_port = other.release();
- }
- return *this;
- }
- void MachPort::unref_port()
- {
- if (!MACH_PORT_VALID(m_port))
- return;
- kern_return_t res = KERN_FAILURE;
- switch (m_right) {
- case PortRight::Send:
- case PortRight::SendOnce:
- case PortRight::DeadName:
- res = mach_port_deallocate(mach_task_self(), m_port);
- break;
- case PortRight::Receive:
- case PortRight::PortSet:
- res = mach_port_mod_refs(mach_task_self(), m_port, to_underlying(m_right), -1);
- break;
- }
- VERIFY(res == KERN_SUCCESS);
- }
- ErrorOr<MachPort> MachPort::create_with_right(PortRight right)
- {
- mach_port_t port = MACH_PORT_NULL;
- auto const ret = mach_port_allocate(mach_task_self(), to_underlying(right), &port);
- if (ret != KERN_SUCCESS) {
- dbgln("Unable to allocate port with right: {}", to_underlying(right));
- return mach_error_to_error(ret);
- }
- return MachPort(right, port);
- }
- MachPort MachPort::adopt_right(mach_port_t port, PortRight right)
- {
- return MachPort(right, port);
- }
- mach_port_t MachPort::release()
- {
- return exchange(m_port, MACH_PORT_NULL);
- }
- ErrorOr<MachPort> MachPort::insert_right(MessageRight right)
- {
- auto const ret = mach_port_insert_right(mach_task_self(), m_port, m_port, to_underlying(right));
- if (ret != KERN_SUCCESS) {
- dbgln("Unable to insert message right: {}", to_underlying(right));
- return mach_error_to_error(ret);
- }
- return MachPort(associated_port_right(right), m_port);
- }
- #if defined(AK_OS_MACOS)
- # pragma GCC diagnostic push
- # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- // bootstrap_register has been deprecated since macOS 10.5, but rules are more 'guidelines' than actual rules
- ErrorOr<void> MachPort::register_with_bootstrap_server(ByteString const& service_name)
- {
- if (service_name.length() > sizeof(name_t) - 1)
- return Error::from_errno(E2BIG);
- auto const ret = bootstrap_register(bootstrap_port, const_cast<char*>(service_name.characters()), m_port);
- if (ret != KERN_SUCCESS) {
- dbgln("Unable to register {} with bootstrap on port {:p}", service_name, m_port);
- return bootstrap_error_to_error(ret);
- }
- return {};
- }
- # pragma GCC diagnostic pop
- ErrorOr<MachPort> MachPort::look_up_from_bootstrap_server(ByteString const& service_name)
- {
- if (service_name.length() > sizeof(name_t) - 1)
- return Error::from_errno(E2BIG);
- mach_port_t port = MACH_PORT_NULL;
- auto const ret = bootstrap_look_up(bootstrap_port, service_name.characters(), &port);
- if (ret != KERN_SUCCESS) {
- dbgln("Unable to look up service {} in bootstrap", service_name);
- return bootstrap_error_to_error(ret);
- }
- return MachPort(PortRight::Send, port);
- }
- #endif
- }
|