Serenity Operating System
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}