Message.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Checked.h>
  7. #include <LibCore/Socket.h>
  8. #include <LibCore/System.h>
  9. #include <LibIPC/Message.h>
  10. #include <sched.h>
  11. namespace IPC {
  12. using MessageSizeType = u32;
  13. MessageBuffer::MessageBuffer()
  14. {
  15. m_data.resize(sizeof(MessageSizeType));
  16. }
  17. ErrorOr<void> MessageBuffer::extend_data_capacity(size_t capacity)
  18. {
  19. TRY(m_data.try_ensure_capacity(m_data.size() + capacity));
  20. return {};
  21. }
  22. ErrorOr<void> MessageBuffer::append_data(u8 const* values, size_t count)
  23. {
  24. TRY(m_data.try_append(values, count));
  25. return {};
  26. }
  27. ErrorOr<void> MessageBuffer::append_file_descriptor(int fd)
  28. {
  29. auto auto_fd = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AutoCloseFileDescriptor(fd)));
  30. TRY(m_fds.try_append(move(auto_fd)));
  31. return {};
  32. }
  33. ErrorOr<void> MessageBuffer::transfer_message(Core::LocalSocket& socket)
  34. {
  35. Checked<MessageSizeType> checked_message_size { m_data.size() };
  36. checked_message_size -= sizeof(MessageSizeType);
  37. if (checked_message_size.has_overflow())
  38. return Error::from_string_literal("Message is too large for IPC encoding");
  39. MessageSizeType const message_size = checked_message_size.value();
  40. m_data.span().overwrite(0, reinterpret_cast<u8 const*>(&message_size), sizeof(message_size));
  41. auto raw_fds = Vector<int, 1> {};
  42. auto num_fds_to_transfer = m_fds.size();
  43. if (num_fds_to_transfer > 0) {
  44. raw_fds.ensure_capacity(num_fds_to_transfer);
  45. for (auto& owned_fd : m_fds) {
  46. raw_fds.unchecked_append(owned_fd->value());
  47. }
  48. }
  49. ReadonlyBytes bytes_to_write { m_data.span() };
  50. while (!bytes_to_write.is_empty()) {
  51. ErrorOr<ssize_t> maybe_nwritten = 0;
  52. if (num_fds_to_transfer > 0) {
  53. maybe_nwritten = socket.send_message(bytes_to_write, 0, raw_fds);
  54. if (!maybe_nwritten.is_error())
  55. num_fds_to_transfer = 0;
  56. } else {
  57. maybe_nwritten = socket.write_some(bytes_to_write);
  58. }
  59. if (maybe_nwritten.is_error()) {
  60. if (auto error = maybe_nwritten.release_error(); error.is_errno() && (error.code() == EAGAIN || error.code() == EWOULDBLOCK)) {
  61. Vector<struct pollfd, 1> pollfds;
  62. if (pollfds.is_empty())
  63. pollfds.append({ .fd = socket.fd().value(), .events = POLLOUT, .revents = 0 });
  64. ErrorOr<int> result { 0 };
  65. do {
  66. constexpr u32 POLL_TIMEOUT_MS = 100;
  67. result = Core::System::poll(pollfds, POLL_TIMEOUT_MS);
  68. } while (result.is_error() && result.error().code() == EINTR);
  69. if (!result.is_error() && result.value() != 0)
  70. continue;
  71. switch (error.code()) {
  72. case EPIPE:
  73. return Error::from_string_literal("IPC::transfer_message: Disconnected from peer");
  74. case EAGAIN:
  75. return Error::from_string_literal("IPC::transfer_message: Timed out waiting for socket to become writable");
  76. default:
  77. return Error::from_syscall("IPC::transfer_message write"sv, -error.code());
  78. }
  79. } else {
  80. return error;
  81. }
  82. }
  83. bytes_to_write = bytes_to_write.slice(maybe_nwritten.value());
  84. }
  85. return {};
  86. }
  87. }