MachPort.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/ByteString.h>
  7. #include <AK/Format.h>
  8. #include <LibCore/MachPort.h>
  9. #if defined(AK_OS_GNU_HURD)
  10. extern "C" {
  11. # include <mach_error.h>
  12. }
  13. // This is in <mach/mach_error.h> on Darwin, and doesn't seem to be required.
  14. #endif
  15. #if defined(AK_OS_MACOS)
  16. # include <bootstrap.h>
  17. #endif
  18. namespace Core {
  19. static constexpr MachPort::PortRight associated_port_right(MachPort::MessageRight right)
  20. {
  21. switch (right) {
  22. case MachPort::MessageRight::MoveReceive:
  23. return MachPort::PortRight::Receive;
  24. case MachPort::MessageRight::MoveSend:
  25. case MachPort::MessageRight::CopySend:
  26. case MachPort::MessageRight::MakeSend:
  27. return MachPort::PortRight::Send;
  28. case MachPort::MessageRight::MoveSendOnce:
  29. case MachPort::MessageRight::MakeSendOnce:
  30. return MachPort::PortRight::SendOnce;
  31. #if defined(AK_OS_MACOS)
  32. case MachPort::MessageRight::CopyReceive:
  33. case MachPort::MessageRight::DisposeReceive:
  34. return MachPort::PortRight::Receive;
  35. case MachPort::MessageRight::DisposeSend:
  36. return MachPort::PortRight::Send;
  37. case MachPort::MessageRight::DisposeSendOnce:
  38. return MachPort::PortRight::SendOnce;
  39. #endif
  40. }
  41. VERIFY_NOT_REACHED();
  42. }
  43. Error mach_error_to_error(kern_return_t error)
  44. {
  45. char const* err_string = mach_error_string(error);
  46. StringView const err_view(err_string, strlen(err_string));
  47. return Error::from_string_view(err_view);
  48. }
  49. #if defined(AK_OS_MACOS)
  50. static Error bootstrap_error_to_error(kern_return_t error)
  51. {
  52. char const* err_string = bootstrap_strerror(error);
  53. StringView const err_view(err_string, strlen(err_string));
  54. return Error::from_string_view(err_view);
  55. }
  56. #endif
  57. MachPort::MachPort(PortRight right, mach_port_t port)
  58. : m_right(right)
  59. , m_port(port)
  60. {
  61. }
  62. MachPort::~MachPort()
  63. {
  64. unref_port();
  65. }
  66. MachPort::MachPort(MachPort&& other)
  67. : m_right(other.m_right)
  68. , m_port(other.release())
  69. {
  70. }
  71. MachPort& MachPort::operator=(MachPort&& other)
  72. {
  73. if (this != &other) {
  74. unref_port();
  75. m_right = other.m_right;
  76. m_port = other.release();
  77. }
  78. return *this;
  79. }
  80. void MachPort::unref_port()
  81. {
  82. if (!MACH_PORT_VALID(m_port))
  83. return;
  84. kern_return_t res = KERN_FAILURE;
  85. switch (m_right) {
  86. case PortRight::Send:
  87. case PortRight::SendOnce:
  88. case PortRight::DeadName:
  89. res = mach_port_deallocate(mach_task_self(), m_port);
  90. break;
  91. case PortRight::Receive:
  92. case PortRight::PortSet:
  93. res = mach_port_mod_refs(mach_task_self(), m_port, to_underlying(m_right), -1);
  94. break;
  95. }
  96. VERIFY(res == KERN_SUCCESS);
  97. }
  98. ErrorOr<MachPort> MachPort::create_with_right(PortRight right)
  99. {
  100. mach_port_t port = MACH_PORT_NULL;
  101. auto const ret = mach_port_allocate(mach_task_self(), to_underlying(right), &port);
  102. if (ret != KERN_SUCCESS) {
  103. dbgln("Unable to allocate port with right: {}", to_underlying(right));
  104. return mach_error_to_error(ret);
  105. }
  106. return MachPort(right, port);
  107. }
  108. MachPort MachPort::adopt_right(mach_port_t port, PortRight right)
  109. {
  110. return MachPort(right, port);
  111. }
  112. mach_port_t MachPort::release()
  113. {
  114. return exchange(m_port, MACH_PORT_NULL);
  115. }
  116. ErrorOr<MachPort> MachPort::insert_right(MessageRight right)
  117. {
  118. auto const ret = mach_port_insert_right(mach_task_self(), m_port, m_port, to_underlying(right));
  119. if (ret != KERN_SUCCESS) {
  120. dbgln("Unable to insert message right: {}", to_underlying(right));
  121. return mach_error_to_error(ret);
  122. }
  123. return MachPort(associated_port_right(right), m_port);
  124. }
  125. #if defined(AK_OS_MACOS)
  126. # pragma GCC diagnostic push
  127. # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  128. // bootstrap_register has been deprecated since macOS 10.5, but rules are more 'guidelines' than actual rules
  129. ErrorOr<void> MachPort::register_with_bootstrap_server(ByteString const& service_name)
  130. {
  131. if (service_name.length() > sizeof(name_t) - 1)
  132. return Error::from_errno(E2BIG);
  133. auto const ret = bootstrap_register(bootstrap_port, const_cast<char*>(service_name.characters()), m_port);
  134. if (ret != KERN_SUCCESS) {
  135. dbgln("Unable to register {} with bootstrap on port {:p}", service_name, m_port);
  136. return bootstrap_error_to_error(ret);
  137. }
  138. return {};
  139. }
  140. # pragma GCC diagnostic pop
  141. ErrorOr<MachPort> MachPort::look_up_from_bootstrap_server(ByteString const& service_name)
  142. {
  143. if (service_name.length() > sizeof(name_t) - 1)
  144. return Error::from_errno(E2BIG);
  145. mach_port_t port = MACH_PORT_NULL;
  146. auto const ret = bootstrap_look_up(bootstrap_port, service_name.characters(), &port);
  147. if (ret != KERN_SUCCESS) {
  148. dbgln("Unable to look up service {} in bootstrap", service_name);
  149. return bootstrap_error_to_error(ret);
  150. }
  151. return MachPort(PortRight::Send, port);
  152. }
  153. #endif
  154. }