Serenity Operating System
at master 299 lines 10 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/StringView.h> 8#include <Kernel/API/POSIX/errno.h> 9#include <Kernel/Debug.h> 10#include <Kernel/FileSystem/OpenFileDescription.h> 11#include <Kernel/Net/IPv4Socket.h> 12#include <Kernel/Net/LocalSocket.h> 13#include <Kernel/Net/NetworkingManagement.h> 14#include <Kernel/Net/Socket.h> 15#include <Kernel/Process.h> 16#include <Kernel/UnixTypes.h> 17 18namespace Kernel { 19 20ErrorOr<NonnullRefPtr<Socket>> Socket::create(int domain, int type, int protocol) 21{ 22 switch (domain) { 23 case AF_LOCAL: 24 return TRY(LocalSocket::try_create(type & SOCK_TYPE_MASK)); 25 case AF_INET: 26 return IPv4Socket::create(type & SOCK_TYPE_MASK, protocol); 27 default: 28 return EAFNOSUPPORT; 29 } 30} 31 32Socket::Socket(int domain, int type, int protocol) 33 : m_domain(domain) 34 , m_type(type) 35 , m_protocol(protocol) 36{ 37 set_origin(Process::current()); 38} 39 40Socket::~Socket() = default; 41 42void Socket::set_setup_state(SetupState new_setup_state) 43{ 44 dbgln_if(SOCKET_DEBUG, "Socket({}) setup state moving from {} to {}", this, to_string(m_setup_state), to_string(new_setup_state)); 45 m_setup_state = new_setup_state; 46 evaluate_block_conditions(); 47} 48 49RefPtr<Socket> Socket::accept() 50{ 51 MutexLocker locker(mutex()); 52 if (m_pending.is_empty()) 53 return nullptr; 54 dbgln_if(SOCKET_DEBUG, "Socket({}) de-queueing connection", this); 55 auto client = m_pending.take_first(); 56 VERIFY(!client->is_connected()); 57 auto& process = Process::current(); 58 client->set_acceptor(process); 59 client->m_connected = true; 60 client->set_role(Role::Accepted); 61 if (!m_pending.is_empty()) 62 evaluate_block_conditions(); 63 return client; 64} 65 66ErrorOr<void> Socket::queue_connection_from(NonnullRefPtr<Socket> peer) 67{ 68 dbgln_if(SOCKET_DEBUG, "Socket({}) queueing connection", this); 69 MutexLocker locker(mutex()); 70 if (m_pending.size() >= m_backlog) 71 return set_so_error(ECONNREFUSED); 72 SOCKET_TRY(m_pending.try_append(move(peer))); 73 evaluate_block_conditions(); 74 return {}; 75} 76 77ErrorOr<void> Socket::setsockopt(int level, int option, Userspace<void const*> user_value, socklen_t user_value_size) 78{ 79 MutexLocker locker(mutex()); 80 81 if (level != SOL_SOCKET) 82 return ENOPROTOOPT; 83 VERIFY(level == SOL_SOCKET); 84 switch (option) { 85 case SO_SNDTIMEO: 86 if (user_value_size != sizeof(timeval)) 87 return EINVAL; 88 m_send_timeout = TRY(copy_time_from_user(static_ptr_cast<timeval const*>(user_value))); 89 return {}; 90 case SO_RCVTIMEO: 91 if (user_value_size != sizeof(timeval)) 92 return EINVAL; 93 m_receive_timeout = TRY(copy_time_from_user(static_ptr_cast<timeval const*>(user_value))); 94 return {}; 95 case SO_BINDTODEVICE: { 96 if (user_value_size != IFNAMSIZ) 97 return EINVAL; 98 auto user_string = static_ptr_cast<char const*>(user_value); 99 auto ifname = TRY(try_copy_kstring_from_user(user_string, user_value_size)); 100 auto device = NetworkingManagement::the().lookup_by_name(ifname->view()); 101 if (!device) 102 return ENODEV; 103 m_bound_interface = move(device); 104 return {}; 105 } 106 case SO_DEBUG: 107 // NOTE: This is supposed to toggle collection of debugging information on/off, we don't have any right now, so this is a no-op. 108 return {}; 109 case SO_KEEPALIVE: 110 // FIXME: Obviously, this is not a real keepalive. 111 return {}; 112 case SO_TIMESTAMP: 113 if (user_value_size != sizeof(int)) 114 return EINVAL; 115 m_timestamp = TRY(copy_typed_from_user(static_ptr_cast<int const*>(user_value))); 116 if (m_timestamp != 0 && (domain() != AF_INET || type() == SOCK_STREAM)) { 117 // FIXME: Support SO_TIMESTAMP for more protocols? 118 m_timestamp = 0; 119 return ENOTSUP; 120 } 121 return {}; 122 case SO_DONTROUTE: { 123 if (user_value_size != sizeof(int)) 124 return EINVAL; 125 m_routing_disabled = TRY(copy_typed_from_user(static_ptr_cast<int const*>(user_value))) != 0; 126 return {}; 127 } 128 case SO_REUSEADDR: 129 dbgln("FIXME: SO_REUSEADDR requested, but not implemented."); 130 return {}; 131 default: 132 dbgln("setsockopt({}) at SOL_SOCKET not implemented.", option); 133 return ENOPROTOOPT; 134 } 135} 136 137ErrorOr<void> Socket::getsockopt(OpenFileDescription&, int level, int option, Userspace<void*> value, Userspace<socklen_t*> value_size) 138{ 139 MutexLocker locker(mutex()); 140 141 socklen_t size; 142 TRY(copy_from_user(&size, value_size.unsafe_userspace_ptr())); 143 144 // FIXME: Add TCP_NODELAY, IPPROTO_TCP and IPPROTO_IP (used in OpenSSH) 145 if (level != SOL_SOCKET) { 146 // Not sure if this is the correct error code, but it's only temporary until other levels are implemented. 147 return ENOPROTOOPT; 148 } 149 150 switch (option) { 151 case SO_SNDTIMEO: 152 if (size < sizeof(timeval)) 153 return EINVAL; 154 { 155 timeval tv = m_send_timeout.to_timeval(); 156 TRY(copy_to_user(static_ptr_cast<timeval*>(value), &tv)); 157 } 158 size = sizeof(timeval); 159 return copy_to_user(value_size, &size); 160 case SO_RCVTIMEO: 161 if (size < sizeof(timeval)) 162 return EINVAL; 163 { 164 timeval tv = m_receive_timeout.to_timeval(); 165 TRY(copy_to_user(static_ptr_cast<timeval*>(value), &tv)); 166 } 167 size = sizeof(timeval); 168 return copy_to_user(value_size, &size); 169 case SO_ERROR: { 170 if (size < sizeof(int)) 171 return EINVAL; 172 int errno = 0; 173 if (auto const& error = so_error(); error.has_value()) 174 errno = error.value(); 175 TRY(copy_to_user(static_ptr_cast<int*>(value), &errno)); 176 size = sizeof(int); 177 TRY(copy_to_user(value_size, &size)); 178 clear_so_error(); 179 return {}; 180 } 181 case SO_BINDTODEVICE: 182 if (size < IFNAMSIZ) 183 return EINVAL; 184 if (m_bound_interface) { 185 auto name = m_bound_interface->name(); 186 auto length = name.length() + 1; 187 auto characters = name.characters_without_null_termination(); 188 TRY(copy_to_user(static_ptr_cast<char*>(value), characters, length)); 189 size = length; 190 return copy_to_user(value_size, &size); 191 } else { 192 size = 0; 193 TRY(copy_to_user(value_size, &size)); 194 // FIXME: This return value looks suspicious. 195 return EFAULT; 196 } 197 case SO_TIMESTAMP: 198 if (size < sizeof(int)) 199 return EINVAL; 200 TRY(copy_to_user(static_ptr_cast<int*>(value), &m_timestamp)); 201 size = sizeof(int); 202 return copy_to_user(value_size, &size); 203 case SO_TYPE: 204 if (size < sizeof(int)) 205 return EINVAL; 206 TRY(copy_to_user(static_ptr_cast<int*>(value), &m_type)); 207 size = sizeof(int); 208 return copy_to_user(value_size, &size); 209 case SO_DEBUG: 210 // NOTE: This is supposed to toggle collection of debugging information on/off, we don't have any right now, so we just claim it's always off. 211 if (size < sizeof(int)) 212 return EINVAL; 213 TRY(memset_user(value.unsafe_userspace_ptr(), 0, sizeof(int))); 214 size = sizeof(int); 215 return copy_to_user(value_size, &size); 216 case SO_ACCEPTCONN: { 217 int accepting_connections = (m_role == Role::Listener) ? 1 : 0; 218 if (size < sizeof(accepting_connections)) 219 return EINVAL; 220 TRY(copy_to_user(static_ptr_cast<int*>(value), &accepting_connections)); 221 size = sizeof(accepting_connections); 222 return copy_to_user(value_size, &size); 223 } 224 case SO_DONTROUTE: { 225 int routing_disabled = m_routing_disabled ? 1 : 0; 226 if (size < sizeof(routing_disabled)) 227 return EINVAL; 228 TRY(copy_to_user(static_ptr_cast<int*>(value), &routing_disabled)); 229 size = sizeof(routing_disabled); 230 return copy_to_user(value_size, &size); 231 } 232 default: 233 dbgln("getsockopt({}) at SOL_SOCKET not implemented.", option); 234 return ENOPROTOOPT; 235 } 236} 237 238ErrorOr<size_t> Socket::read(OpenFileDescription& description, u64, UserOrKernelBuffer& buffer, size_t size) 239{ 240 if (is_shut_down_for_reading()) 241 return 0; 242 Time t {}; 243 return recvfrom(description, buffer, size, 0, {}, 0, t, description.is_blocking()); 244} 245 246ErrorOr<size_t> Socket::write(OpenFileDescription& description, u64, UserOrKernelBuffer const& data, size_t size) 247{ 248 if (is_shut_down_for_writing()) 249 return set_so_error(EPIPE); 250 return sendto(description, data, size, 0, {}, 0); 251} 252 253ErrorOr<void> Socket::shutdown(int how) 254{ 255 MutexLocker locker(mutex()); 256 if (type() == SOCK_STREAM && !is_connected()) 257 return set_so_error(ENOTCONN); 258 if (m_role == Role::Listener) 259 return set_so_error(ENOTCONN); 260 if (!m_shut_down_for_writing && (how == SHUT_WR || how == SHUT_RDWR)) { 261 shut_down_for_writing(); 262 m_shut_down_for_writing = true; 263 } 264 if (!m_shut_down_for_reading && (how == SHUT_RD || how == SHUT_RDWR)) { 265 shut_down_for_reading(); 266 m_shut_down_for_reading = true; 267 } 268 return {}; 269} 270 271ErrorOr<struct stat> Socket::stat() const 272{ 273 struct stat st = {}; 274 st.st_mode = S_IFSOCK; 275 return st; 276} 277 278void Socket::set_connected(bool connected) 279{ 280 MutexLocker locker(mutex()); 281 if (m_connected == connected) 282 return; 283 m_connected = connected; 284 evaluate_block_conditions(); 285} 286 287void Socket::set_origin(Process const& process) 288{ 289 auto credentials = process.credentials(); 290 m_origin = { process.pid().value(), credentials->uid().value(), credentials->gid().value() }; 291} 292 293void Socket::set_acceptor(Process const& process) 294{ 295 auto credentials = process.credentials(); 296 m_acceptor = { process.pid().value(), credentials->uid().value(), credentials->gid().value() }; 297} 298 299}