Serenity Operating System
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
27#include <AK/StringBuilder.h>
28#include <AK/StringView.h>
29#include <Kernel/FileSystem/FileDescription.h>
30#include <Kernel/Net/IPv4Socket.h>
31#include <Kernel/Net/LocalSocket.h>
32#include <Kernel/Net/Socket.h>
33#include <Kernel/Process.h>
34#include <Kernel/UnixTypes.h>
35#include <LibC/errno_numbers.h>
36
37//#define SOCKET_DEBUG
38
39namespace Kernel {
40
41KResultOr<NonnullRefPtr<Socket>> Socket::create(int domain, int type, int protocol)
42{
43 switch (domain) {
44 case AF_LOCAL:
45 return LocalSocket::create(type & SOCK_TYPE_MASK);
46 case AF_INET:
47 return IPv4Socket::create(type & SOCK_TYPE_MASK, protocol);
48 default:
49 return KResult(-EAFNOSUPPORT);
50 }
51}
52
53Socket::Socket(int domain, int type, int protocol)
54 : m_domain(domain)
55 , m_type(type)
56 , m_protocol(protocol)
57{
58 auto& process = *Process::current;
59 m_origin = { process.pid(), process.uid(), process.gid() };
60}
61
62Socket::~Socket()
63{
64}
65
66void Socket::set_setup_state(SetupState new_setup_state)
67{
68#ifdef SOCKET_DEBUG
69 dbg() << "Socket{" << this << "} setup state moving from " << to_string(m_setup_state) << " to " << to_string(new_setup_state);
70#endif
71
72 m_setup_state = new_setup_state;
73}
74
75RefPtr<Socket> Socket::accept()
76{
77 LOCKER(m_lock);
78 if (m_pending.is_empty())
79 return nullptr;
80#ifdef SOCKET_DEBUG
81 dbg() << "Socket{" << this << "} de-queueing connection";
82#endif
83 auto client = m_pending.take_first();
84 ASSERT(!client->is_connected());
85 auto& process = *Process::current;
86 client->m_acceptor = { process.pid(), process.uid(), process.gid() };
87 client->m_connected = true;
88 client->m_role = Role::Accepted;
89 return client;
90}
91
92KResult Socket::queue_connection_from(NonnullRefPtr<Socket> peer)
93{
94#ifdef SOCKET_DEBUG
95 dbg() << "Socket{" << this << "} queueing connection";
96#endif
97 LOCKER(m_lock);
98 if (m_pending.size() >= m_backlog)
99 return KResult(-ECONNREFUSED);
100 m_pending.append(peer);
101 return KSuccess;
102}
103
104KResult Socket::setsockopt(int level, int option, const void* value, socklen_t value_size)
105{
106 ASSERT(level == SOL_SOCKET);
107 switch (option) {
108 case SO_SNDTIMEO:
109 if (value_size != sizeof(timeval))
110 return KResult(-EINVAL);
111 m_send_timeout = *(const timeval*)value;
112 return KSuccess;
113 case SO_RCVTIMEO:
114 if (value_size != sizeof(timeval))
115 return KResult(-EINVAL);
116 m_receive_timeout = *(const timeval*)value;
117 return KSuccess;
118 case SO_BINDTODEVICE: {
119 if (value_size != IFNAMSIZ)
120 return KResult(-EINVAL);
121 StringView ifname { (const char*)value };
122 auto device = NetworkAdapter::lookup_by_name(ifname);
123 if (!device)
124 return KResult(-ENODEV);
125 m_bound_interface = device;
126 return KSuccess;
127 }
128 case SO_KEEPALIVE:
129 // FIXME: Obviously, this is not a real keepalive.
130 return KSuccess;
131 default:
132 dbg() << "setsockopt(" << option << ") at SOL_SOCKET not implemented.";
133 return KResult(-ENOPROTOOPT);
134 }
135}
136
137KResult Socket::getsockopt(FileDescription&, int level, int option, void* value, socklen_t* value_size)
138{
139 ASSERT(level == SOL_SOCKET);
140 switch (option) {
141 case SO_SNDTIMEO:
142 if (*value_size < sizeof(timeval))
143 return KResult(-EINVAL);
144 *(timeval*)value = m_send_timeout;
145 *value_size = sizeof(timeval);
146 return KSuccess;
147 case SO_RCVTIMEO:
148 if (*value_size < sizeof(timeval))
149 return KResult(-EINVAL);
150 *(timeval*)value = m_receive_timeout;
151 *value_size = sizeof(timeval);
152 return KSuccess;
153 case SO_ERROR:
154 if (*value_size < sizeof(int))
155 return KResult(-EINVAL);
156 dbg() << "getsockopt(SO_ERROR): FIXME!";
157 *(int*)value = 0;
158 *value_size = sizeof(int);
159 return KSuccess;
160 case SO_BINDTODEVICE:
161 if (*value_size < IFNAMSIZ)
162 return KResult(-EINVAL);
163 if (m_bound_interface) {
164 const auto& name = m_bound_interface->name();
165 auto length = name.length() + 1;
166 memcpy(value, name.characters(), length);
167 *value_size = length;
168 return KSuccess;
169 } else {
170 *value_size = 0;
171 return KResult(-EFAULT);
172 }
173 default:
174 dbg() << "getsockopt(" << option << ") at SOL_SOCKET not implemented.";
175 return KResult(-ENOPROTOOPT);
176 }
177}
178
179ssize_t Socket::read(FileDescription& description, u8* buffer, ssize_t size)
180{
181 if (is_shut_down_for_reading())
182 return 0;
183 return recvfrom(description, buffer, size, 0, nullptr, 0);
184}
185
186ssize_t Socket::write(FileDescription& description, const u8* data, ssize_t size)
187{
188 if (is_shut_down_for_writing())
189 return -EPIPE;
190 return sendto(description, data, size, 0, nullptr, 0);
191}
192
193KResult Socket::shutdown(int how)
194{
195 if (type() == SOCK_STREAM && !is_connected())
196 return KResult(-ENOTCONN);
197 if (m_role == Role::Listener)
198 return KResult(-ENOTCONN);
199 if (!m_shut_down_for_writing && (how & SHUT_WR))
200 shut_down_for_writing();
201 if (!m_shut_down_for_reading && (how & SHUT_RD))
202 shut_down_for_reading();
203 m_shut_down_for_reading |= (how & SHUT_RD) != 0;
204 m_shut_down_for_writing |= (how & SHUT_WR) != 0;
205 return KSuccess;
206}
207
208}