Message.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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 <LibIPC/Message.h>
  9. #include <sched.h>
  10. namespace IPC {
  11. using MessageSizeType = u32;
  12. MessageBuffer::MessageBuffer()
  13. {
  14. m_data.resize(sizeof(MessageSizeType));
  15. }
  16. ErrorOr<void> MessageBuffer::extend_data_capacity(size_t capacity)
  17. {
  18. TRY(m_data.try_ensure_capacity(m_data.size() + capacity));
  19. return {};
  20. }
  21. ErrorOr<void> MessageBuffer::append_data(u8 const* values, size_t count)
  22. {
  23. TRY(m_data.try_append(values, count));
  24. return {};
  25. }
  26. ErrorOr<void> MessageBuffer::append_file_descriptor(int fd)
  27. {
  28. auto auto_fd = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AutoCloseFileDescriptor(fd)));
  29. TRY(m_fds.try_append(move(auto_fd)));
  30. return {};
  31. }
  32. ErrorOr<void> MessageBuffer::transfer_message(Core::LocalSocket& socket)
  33. {
  34. Checked<MessageSizeType> checked_message_size { m_data.size() };
  35. checked_message_size -= sizeof(MessageSizeType);
  36. if (checked_message_size.has_overflow())
  37. return Error::from_string_literal("Message is too large for IPC encoding");
  38. MessageSizeType const message_size = checked_message_size.value();
  39. m_data.span().overwrite(0, reinterpret_cast<u8 const*>(&message_size), sizeof(message_size));
  40. auto raw_fds = Vector<int, 1> {};
  41. auto num_fds_to_transfer = m_fds.size();
  42. if (num_fds_to_transfer > 0) {
  43. raw_fds.ensure_capacity(num_fds_to_transfer);
  44. for (auto& owned_fd : m_fds) {
  45. raw_fds.unchecked_append(owned_fd->value());
  46. }
  47. }
  48. ReadonlyBytes bytes_to_write { m_data.span() };
  49. size_t writes_done = 0;
  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. ++writes_done;
  60. if (maybe_nwritten.is_error()) {
  61. if (auto error = maybe_nwritten.release_error(); error.is_errno()) {
  62. // FIXME: This is a hacky way to at least not crash on large messages
  63. // The limit of 100 writes is arbitrary, and there to prevent indefinite spinning on the EventLoop
  64. if (error.code() == EAGAIN && writes_done < 100) {
  65. sched_yield();
  66. continue;
  67. }
  68. switch (error.code()) {
  69. case EPIPE:
  70. return Error::from_string_literal("IPC::transfer_message: Disconnected from peer");
  71. case EAGAIN:
  72. return Error::from_string_literal("IPC::transfer_message: Peer buffer overflowed");
  73. default:
  74. return Error::from_syscall("IPC::transfer_message write"sv, -error.code());
  75. }
  76. } else {
  77. return error;
  78. }
  79. }
  80. bytes_to_write = bytes_to_write.slice(maybe_nwritten.value());
  81. }
  82. if (writes_done > 1) {
  83. dbgln("LibIPC::transfer_message FIXME Warning, needed {} writes needed to send message of size {}B, this is pretty bad, as it spins on the EventLoop", writes_done, m_data.size());
  84. }
  85. return {};
  86. }
  87. }