ClientConnection.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #pragma once
  27. #include <AK/ByteBuffer.h>
  28. #include <LibCore/Event.h>
  29. #include <LibCore/EventLoop.h>
  30. #include <LibCore/IODevice.h>
  31. #include <LibCore/LocalSocket.h>
  32. #include <LibCore/Notifier.h>
  33. #include <LibCore/Object.h>
  34. #include <LibIPC/Endpoint.h>
  35. #include <LibIPC/Message.h>
  36. #include <errno.h>
  37. #include <stdio.h>
  38. #include <sys/socket.h>
  39. #include <sys/types.h>
  40. #include <unistd.h>
  41. namespace IPC {
  42. class Event : public Core::Event {
  43. public:
  44. enum Type {
  45. Invalid = 2000,
  46. Disconnected,
  47. };
  48. Event() {}
  49. explicit Event(Type type)
  50. : Core::Event(type)
  51. {
  52. }
  53. };
  54. class DisconnectedEvent : public Event {
  55. public:
  56. explicit DisconnectedEvent(int client_id)
  57. : Event(Disconnected)
  58. , m_client_id(client_id)
  59. {
  60. }
  61. int client_id() const { return m_client_id; }
  62. private:
  63. int m_client_id { 0 };
  64. };
  65. template<typename T, class... Args>
  66. NonnullRefPtr<T> new_client_connection(Args&&... args)
  67. {
  68. return T::construct(forward<Args>(args)...) /* arghs */;
  69. }
  70. template<typename Endpoint>
  71. class ClientConnection : public Core::Object {
  72. public:
  73. ClientConnection(Endpoint& endpoint, Core::LocalSocket& socket, int client_id)
  74. : m_endpoint(endpoint)
  75. , m_socket(socket)
  76. , m_client_id(client_id)
  77. {
  78. ASSERT(socket.is_connected());
  79. ucred creds;
  80. socklen_t creds_size = sizeof(creds);
  81. if (getsockopt(m_socket->fd(), SOL_SOCKET, SO_PEERCRED, &creds, &creds_size) < 0) {
  82. ASSERT_NOT_REACHED();
  83. }
  84. m_client_pid = creds.pid;
  85. add_child(socket);
  86. m_socket->on_ready_to_read = [this] { drain_messages_from_client(); };
  87. }
  88. virtual ~ClientConnection() override
  89. {
  90. }
  91. void post_message(const Message& message)
  92. {
  93. // NOTE: If this connection is being shut down, but has not yet been destroyed,
  94. // the socket will be closed. Don't try to send more messages.
  95. if (!m_socket->is_open())
  96. return;
  97. auto buffer = message.encode();
  98. int nwritten = write(m_socket->fd(), buffer.data(), (size_t)buffer.size());
  99. if (nwritten < 0) {
  100. switch (errno) {
  101. case EPIPE:
  102. dbg() << *this << "::post_message: Disconnected from peer";
  103. shutdown();
  104. return;
  105. case EAGAIN:
  106. dbg() << *this << "::post_message: Client buffer overflowed.";
  107. did_misbehave();
  108. return;
  109. default:
  110. perror("Connection::post_message write");
  111. ASSERT_NOT_REACHED();
  112. }
  113. }
  114. ASSERT(static_cast<size_t>(nwritten) == buffer.size());
  115. }
  116. void drain_messages_from_client()
  117. {
  118. Vector<u8> bytes;
  119. for (;;) {
  120. u8 buffer[4096];
  121. ssize_t nread = recv(m_socket->fd(), buffer, sizeof(buffer), MSG_DONTWAIT);
  122. if (nread == 0 || (nread == -1 && errno == EAGAIN)) {
  123. if (bytes.is_empty()) {
  124. Core::EventLoop::current().post_event(*this, make<DisconnectedEvent>(client_id()));
  125. return;
  126. }
  127. break;
  128. }
  129. if (nread < 0) {
  130. perror("recv");
  131. ASSERT_NOT_REACHED();
  132. }
  133. bytes.append(buffer, nread);
  134. }
  135. size_t decoded_bytes = 0;
  136. for (size_t index = 0; index < (size_t)bytes.size(); index += decoded_bytes) {
  137. auto remaining_bytes = ByteBuffer::wrap(bytes.data() + index, bytes.size() - index);
  138. auto message = Endpoint::decode_message(remaining_bytes, decoded_bytes);
  139. if (!message) {
  140. dbg() << "drain_messages_from_client: Endpoint didn't recognize message";
  141. did_misbehave();
  142. return;
  143. }
  144. if (auto response = m_endpoint.handle(*message))
  145. post_message(*response);
  146. ASSERT(decoded_bytes);
  147. }
  148. }
  149. void did_misbehave()
  150. {
  151. dbg() << *this << " (id=" << m_client_id << ", pid=" << m_client_pid << ") misbehaved, disconnecting.";
  152. shutdown();
  153. }
  154. void did_misbehave(const char* message)
  155. {
  156. dbg() << *this << " (id=" << m_client_id << ", pid=" << m_client_pid << ") misbehaved (" << message << "), disconnecting.";
  157. shutdown();
  158. }
  159. void shutdown()
  160. {
  161. m_socket->close();
  162. die();
  163. }
  164. int client_id() const { return m_client_id; }
  165. pid_t client_pid() const { return m_client_pid; }
  166. virtual void die() = 0;
  167. protected:
  168. void event(Core::Event& event) override
  169. {
  170. if (event.type() == Event::Disconnected) {
  171. int client_id = static_cast<const DisconnectedEvent&>(event).client_id();
  172. dbg() << *this << ": Client disconnected: " << client_id;
  173. die();
  174. return;
  175. }
  176. Core::Object::event(event);
  177. }
  178. private:
  179. Endpoint& m_endpoint;
  180. RefPtr<Core::LocalSocket> m_socket;
  181. int m_client_id { -1 };
  182. int m_client_pid { -1 };
  183. };
  184. }