| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |  *    list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  *    this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  *    and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 10:20:07 +02:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-14 22:29:06 +01:00
										 |  |  | #include <AK/ByteBuffer.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-06 15:04:03 +01:00
										 |  |  | #include <LibCore/Event.h>
 | 
					
						
							|  |  |  | #include <LibCore/EventLoop.h>
 | 
					
						
							|  |  |  | #include <LibCore/LocalSocket.h>
 | 
					
						
							|  |  |  | #include <LibCore/Object.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-11 22:46:49 +02:00
										 |  |  | #include <LibCore/Timer.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-06 14:54:09 +01:00
										 |  |  | #include <LibIPC/Endpoint.h>
 | 
					
						
							|  |  |  | #include <LibIPC/Message.h>
 | 
					
						
							| 
									
										
										
										
											2019-07-17 10:20:07 +02:00
										 |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2019-07-27 10:50:26 +02:00
										 |  |  | #include <sys/socket.h>
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2019-07-17 10:20:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  | namespace IPC { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Event : public Core::Event { | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  | public: | 
					
						
							|  |  |  |     enum Type { | 
					
						
							|  |  |  |         Invalid = 2000, | 
					
						
							|  |  |  |         Disconnected, | 
					
						
							| 
									
										
										
										
											2019-07-27 10:50:26 +02:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |     Event() {} | 
					
						
							|  |  |  |     explicit Event(Type type) | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |         : Core::Event(type) | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2019-07-27 10:50:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  | class DisconnectedEvent : public Event { | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |     explicit DisconnectedEvent(int client_id) | 
					
						
							|  |  |  |         : Event(Disconnected) | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |         , m_client_id(client_id) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     int client_id() const { return m_client_id; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     int m_client_id { 0 }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename T, class... Args> | 
					
						
							|  |  |  | NonnullRefPtr<T> new_client_connection(Args&&... args) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return T::construct(forward<Args>(args)...) /* arghs */; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename Endpoint> | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  | class ClientConnection : public Core::Object { | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |     ClientConnection(Endpoint& endpoint, Core::LocalSocket& socket, int client_id) | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |         : m_endpoint(endpoint) | 
					
						
							|  |  |  |         , m_socket(socket) | 
					
						
							|  |  |  |         , m_client_id(client_id) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-12-06 18:39:59 +01:00
										 |  |  |         ASSERT(socket.is_connected()); | 
					
						
							|  |  |  |         ucred creds; | 
					
						
							|  |  |  |         socklen_t creds_size = sizeof(creds); | 
					
						
							|  |  |  |         if (getsockopt(m_socket->fd(), SOL_SOCKET, SO_PEERCRED, &creds, &creds_size) < 0) { | 
					
						
							|  |  |  |             ASSERT_NOT_REACHED(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         m_client_pid = creds.pid; | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |         add_child(socket); | 
					
						
							|  |  |  |         m_socket->on_ready_to_read = [this] { drain_messages_from_client(); }; | 
					
						
							| 
									
										
										
										
											2020-06-11 22:46:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-12 18:18:57 +02:00
										 |  |  |         m_responsiveness_timer = Core::Timer::create_single_shot(3000, [this] { may_have_become_unresponsive(); }); | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |     virtual ~ClientConnection() override | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-11 22:46:49 +02:00
										 |  |  |     virtual void may_have_become_unresponsive() {} | 
					
						
							| 
									
										
										
										
											2020-06-13 13:47:01 +02:00
										 |  |  |     virtual void did_become_responsive() {} | 
					
						
							| 
									
										
										
										
											2020-06-11 22:46:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |     void post_message(const Message& message) | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-01-25 10:19:53 +01:00
										 |  |  |         // NOTE: If this connection is being shut down, but has not yet been destroyed,
 | 
					
						
							|  |  |  |         //       the socket will be closed. Don't try to send more messages.
 | 
					
						
							|  |  |  |         if (!m_socket->is_open()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |         auto buffer = message.encode(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-01 12:35:09 +01:00
										 |  |  |         int nwritten = write(m_socket->fd(), buffer.data(), buffer.size()); | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |         if (nwritten < 0) { | 
					
						
							|  |  |  |             switch (errno) { | 
					
						
							|  |  |  |             case EPIPE: | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |                 dbg() << *this << "::post_message: Disconnected from peer"; | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |                 shutdown(); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             case EAGAIN: | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |                 dbg() << *this << "::post_message: Client buffer overflowed."; | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |                 did_misbehave(); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 perror("Connection::post_message write"); | 
					
						
							| 
									
										
										
										
											2020-05-30 22:37:24 +03:00
										 |  |  |                 shutdown(); | 
					
						
							|  |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-25 14:49:47 +01:00
										 |  |  |         ASSERT(static_cast<size_t>(nwritten) == buffer.size()); | 
					
						
							| 
									
										
										
										
											2020-06-13 13:47:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         m_responsiveness_timer->start(); | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-11-23 16:43:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     void drain_messages_from_client() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-05-30 22:37:24 +03:00
										 |  |  |         if (!m_socket->is_open()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |         Vector<u8> bytes; | 
					
						
							|  |  |  |         for (;;) { | 
					
						
							|  |  |  |             u8 buffer[4096]; | 
					
						
							|  |  |  |             ssize_t nread = recv(m_socket->fd(), buffer, sizeof(buffer), MSG_DONTWAIT); | 
					
						
							|  |  |  |             if (nread == 0 || (nread == -1 && errno == EAGAIN)) { | 
					
						
							|  |  |  |                 if (bytes.is_empty()) { | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |                     Core::EventLoop::current().post_event(*this, make<DisconnectedEvent>(client_id())); | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (nread < 0) { | 
					
						
							|  |  |  |                 perror("recv"); | 
					
						
							| 
									
										
										
										
											2020-05-30 22:37:24 +03:00
										 |  |  |                 shutdown(); | 
					
						
							|  |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |             bytes.append(buffer, nread); | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:47:01 +02:00
										 |  |  |         if (!bytes.is_empty()) { | 
					
						
							|  |  |  |             m_responsiveness_timer->stop(); | 
					
						
							|  |  |  |             did_become_responsive(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-11 22:46:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |         size_t decoded_bytes = 0; | 
					
						
							| 
									
										
										
										
											2020-03-01 12:35:09 +01:00
										 |  |  |         for (size_t index = 0; index < bytes.size(); index += decoded_bytes) { | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |             auto remaining_bytes = ByteBuffer::wrap(bytes.data() + index, bytes.size() - index); | 
					
						
							|  |  |  |             auto message = Endpoint::decode_message(remaining_bytes, decoded_bytes); | 
					
						
							|  |  |  |             if (!message) { | 
					
						
							|  |  |  |                 dbg() << "drain_messages_from_client: Endpoint didn't recognize message"; | 
					
						
							|  |  |  |                 did_misbehave(); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (auto response = m_endpoint.handle(*message)) | 
					
						
							|  |  |  |                 post_message(*response); | 
					
						
							|  |  |  |             ASSERT(decoded_bytes); | 
					
						
							| 
									
										
										
										
											2019-09-22 00:17:53 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-22 00:17:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     void did_misbehave() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |         dbg() << *this << " (id=" << m_client_id << ", pid=" << m_client_pid << ") misbehaved, disconnecting."; | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |         shutdown(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 15:55:14 +01:00
										 |  |  |     void did_misbehave(const char* message) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |         dbg() << *this << " (id=" << m_client_id << ", pid=" << m_client_pid << ") misbehaved (" << message << "), disconnecting."; | 
					
						
							| 
									
										
										
										
											2019-12-02 15:55:14 +01:00
										 |  |  |         shutdown(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     void shutdown() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_socket->close(); | 
					
						
							|  |  |  |         die(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     int client_id() const { return m_client_id; } | 
					
						
							|  |  |  |     pid_t client_pid() const { return m_client_pid; } | 
					
						
							| 
									
										
										
										
											2019-09-22 00:17:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     virtual void die() = 0; | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  | protected: | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     void event(Core::Event& event) override | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  |         if (event.type() == Event::Disconnected) { | 
					
						
							|  |  |  |             int client_id = static_cast<const DisconnectedEvent&>(event).client_id(); | 
					
						
							|  |  |  |             dbg() << *this << ": Client disconnected: " << client_id; | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |             die(); | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |         Core::Object::event(event); | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-03 19:41:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  | private: | 
					
						
							|  |  |  |     Endpoint& m_endpoint; | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     RefPtr<Core::LocalSocket> m_socket; | 
					
						
							| 
									
										
										
										
											2020-06-11 22:46:49 +02:00
										 |  |  |     RefPtr<Core::Timer> m_responsiveness_timer; | 
					
						
							| 
									
										
										
										
											2019-12-02 09:58:25 +01:00
										 |  |  |     int m_client_id { -1 }; | 
					
						
							|  |  |  |     int m_client_pid { -1 }; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-02-05 19:57:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |