Serenity Operating System
at master 139 lines 3.5 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibCore/LocalServer.h> 8#include <LibCore/Notifier.h> 9#include <LibCore/SessionManagement.h> 10#include <LibCore/Socket.h> 11#include <LibCore/System.h> 12#include <LibCore/SystemServerTakeover.h> 13#include <fcntl.h> 14#include <stdio.h> 15#include <sys/socket.h> 16#include <sys/stat.h> 17#include <unistd.h> 18 19#ifndef SOCK_NONBLOCK 20# include <sys/ioctl.h> 21#endif 22 23namespace Core { 24 25LocalServer::LocalServer(Object* parent) 26 : Object(parent) 27{ 28} 29 30LocalServer::~LocalServer() 31{ 32 if (m_fd >= 0) 33 ::close(m_fd); 34} 35 36ErrorOr<void> LocalServer::take_over_from_system_server(DeprecatedString const& socket_path) 37{ 38 if (m_listening) 39 return Error::from_string_literal("Core::LocalServer: Can't perform socket takeover when already listening"); 40 41 auto const parsed_path = TRY(Core::SessionManagement::parse_path_with_sid(socket_path)); 42 auto socket = TRY(take_over_socket_from_system_server(parsed_path)); 43 m_fd = TRY(socket->release_fd()); 44 45 m_listening = true; 46 setup_notifier(); 47 return {}; 48} 49 50void LocalServer::setup_notifier() 51{ 52 m_notifier = Notifier::construct(m_fd, Notifier::Event::Read, this); 53 m_notifier->on_ready_to_read = [this] { 54 if (on_accept) { 55 auto maybe_client_socket = accept(); 56 if (maybe_client_socket.is_error()) { 57 dbgln("LocalServer::on_ready_to_read: Error accepting a connection: {}", maybe_client_socket.error()); 58 if (on_accept_error) 59 on_accept_error(maybe_client_socket.release_error()); 60 return; 61 } 62 63 on_accept(maybe_client_socket.release_value()); 64 } 65 }; 66} 67 68bool LocalServer::listen(DeprecatedString const& address) 69{ 70 if (m_listening) 71 return false; 72 73 int rc; 74 75#ifdef SOCK_NONBLOCK 76 m_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); 77#else 78 m_fd = socket(AF_LOCAL, SOCK_STREAM, 0); 79 int option = 1; 80 ioctl(m_fd, FIONBIO, &option); 81 fcntl(m_fd, F_SETFD, FD_CLOEXEC); 82#endif 83 VERIFY(m_fd >= 0); 84#ifndef AK_OS_MACOS 85 rc = fchmod(m_fd, 0600); 86 if (rc < 0) { 87 perror("fchmod"); 88 VERIFY_NOT_REACHED(); 89 } 90#endif 91 92 auto socket_address = SocketAddress::local(address); 93 auto un_optional = socket_address.to_sockaddr_un(); 94 if (!un_optional.has_value()) { 95 perror("bind"); 96 return false; 97 } 98 auto un = un_optional.value(); 99 rc = ::bind(m_fd, (sockaddr const*)&un, sizeof(un)); 100 if (rc < 0) { 101 perror("bind"); 102 return false; 103 } 104 105 rc = ::listen(m_fd, 5); 106 if (rc < 0) { 107 perror("listen"); 108 return false; 109 } 110 111 m_listening = true; 112 setup_notifier(); 113 return true; 114} 115 116ErrorOr<NonnullOwnPtr<LocalSocket>> LocalServer::accept() 117{ 118 VERIFY(m_listening); 119 sockaddr_un un; 120 socklen_t un_size = sizeof(un); 121#ifndef AK_OS_MACOS 122 int accepted_fd = ::accept4(m_fd, (sockaddr*)&un, &un_size, SOCK_NONBLOCK | SOCK_CLOEXEC); 123#else 124 int accepted_fd = ::accept(m_fd, (sockaddr*)&un, &un_size); 125#endif 126 if (accepted_fd < 0) { 127 return Error::from_syscall("accept"sv, -errno); 128 } 129 130#ifdef AK_OS_MACOS 131 int option = 1; 132 ioctl(m_fd, FIONBIO, &option); 133 (void)fcntl(accepted_fd, F_SETFD, FD_CLOEXEC); 134#endif 135 136 return LocalSocket::adopt_fd(accepted_fd, Socket::PreventSIGPIPE::Yes); 137} 138 139}