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#pragma once
8
9#include <AK/Error.h>
10#include <AK/Time.h>
11#include <Kernel/FileSystem/File.h>
12#include <Kernel/Library/LockRefPtr.h>
13#include <Kernel/Locking/Mutex.h>
14#include <Kernel/Net/NetworkAdapter.h>
15#include <Kernel/UnixTypes.h>
16
17namespace Kernel {
18
19class OpenFileDescription;
20
21class Socket : public File {
22public:
23 static ErrorOr<NonnullRefPtr<Socket>> create(int domain, int type, int protocol);
24 virtual ~Socket() override;
25
26 int domain() const { return m_domain; }
27 int type() const { return m_type; }
28 int protocol() const { return m_protocol; }
29
30 bool is_shut_down_for_writing() const { return m_shut_down_for_writing; }
31 bool is_shut_down_for_reading() const { return m_shut_down_for_reading; }
32
33 enum class SetupState {
34 Unstarted, // we haven't tried to set the socket up yet
35 InProgress, // we're in the process of setting things up - for TCP maybe we've sent a SYN packet
36 Completed, // the setup process is complete, but not necessarily successful
37 };
38
39 enum class Role : u8 {
40 None,
41 Listener,
42 Accepted,
43 Connected,
44 Connecting
45 };
46
47 static StringView to_string(SetupState setup_state)
48 {
49 switch (setup_state) {
50 case SetupState::Unstarted:
51 return "Unstarted"sv;
52 case SetupState::InProgress:
53 return "InProgress"sv;
54 case SetupState::Completed:
55 return "Completed"sv;
56 default:
57 return "None"sv;
58 }
59 }
60
61 SetupState setup_state() const { return m_setup_state; }
62 void set_setup_state(SetupState setup_state);
63
64 virtual Role role(OpenFileDescription const&) const { return m_role; }
65
66 bool is_connected() const { return m_connected; }
67 void set_connected(bool);
68
69 bool can_accept() const { return !m_pending.is_empty(); }
70 RefPtr<Socket> accept();
71
72 ErrorOr<void> shutdown(int how);
73
74 virtual ErrorOr<void> bind(Credentials const&, Userspace<sockaddr const*>, socklen_t) = 0;
75 virtual ErrorOr<void> connect(Credentials const&, OpenFileDescription&, Userspace<sockaddr const*>, socklen_t) = 0;
76 virtual ErrorOr<void> listen(size_t) = 0;
77 virtual void get_local_address(sockaddr*, socklen_t*) = 0;
78 virtual void get_peer_address(sockaddr*, socklen_t*) = 0;
79 virtual bool is_local() const { return false; }
80 virtual bool is_ipv4() const { return false; }
81 virtual ErrorOr<size_t> sendto(OpenFileDescription&, UserOrKernelBuffer const&, size_t, int flags, Userspace<sockaddr const*>, socklen_t) = 0;
82 virtual ErrorOr<size_t> recvfrom(OpenFileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>, Time&, bool blocking) = 0;
83
84 virtual ErrorOr<void> setsockopt(int level, int option, Userspace<void const*>, socklen_t);
85 virtual ErrorOr<void> getsockopt(OpenFileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>);
86
87 ProcessID origin_pid() const { return m_origin.pid; }
88 UserID origin_uid() const { return m_origin.uid; }
89 GroupID origin_gid() const { return m_origin.gid; }
90 ProcessID acceptor_pid() const { return m_acceptor.pid; }
91 UserID acceptor_uid() const { return m_acceptor.uid; }
92 GroupID acceptor_gid() const { return m_acceptor.gid; }
93 LockRefPtr<NetworkAdapter> const bound_interface() const { return m_bound_interface; }
94
95 Mutex& mutex() { return m_mutex; }
96
97 // ^File
98 virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override final;
99 virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) override final;
100 virtual ErrorOr<struct stat> stat() const override;
101 virtual ErrorOr<NonnullOwnPtr<KString>> pseudo_path(OpenFileDescription const&) const override = 0;
102
103 bool has_receive_timeout() const { return m_receive_timeout != Time::zero(); }
104 Time const& receive_timeout() const { return m_receive_timeout; }
105
106 bool has_send_timeout() const { return m_send_timeout != Time::zero(); }
107 Time const& send_timeout() const { return m_send_timeout; }
108
109 bool wants_timestamp() const { return m_timestamp; }
110
111protected:
112 Socket(int domain, int type, int protocol);
113
114 ErrorOr<void> queue_connection_from(NonnullRefPtr<Socket>);
115
116 size_t backlog() const { return m_backlog; }
117 void set_backlog(size_t backlog) { m_backlog = backlog; }
118
119 virtual StringView class_name() const override { return "Socket"sv; }
120
121 virtual void shut_down_for_reading() { }
122 virtual void shut_down_for_writing() { }
123
124 Role m_role { Role::None };
125
126 Optional<ErrnoCode> const& so_error() const
127 {
128 VERIFY(m_mutex.is_exclusively_locked_by_current_thread());
129 return m_so_error;
130 }
131
132 Error set_so_error(ErrnoCode error_code)
133 {
134 MutexLocker locker(mutex());
135 m_so_error = error_code;
136
137 return Error::from_errno(error_code);
138 }
139
140 Error set_so_error(Error error)
141 {
142 MutexLocker locker(mutex());
143 m_so_error = static_cast<ErrnoCode>(error.code());
144
145 return error;
146 }
147
148 void clear_so_error()
149 {
150 m_so_error = {};
151 }
152
153 void set_origin(Process const&);
154 void set_acceptor(Process const&);
155
156 void set_role(Role role) { m_role = role; }
157
158 ucred m_origin { 0, 0, 0 };
159 ucred m_acceptor { 0, 0, 0 };
160 bool m_routing_disabled { false };
161
162private:
163 virtual bool is_socket() const final { return true; }
164
165 Mutex m_mutex { "Socket"sv };
166
167 int m_domain { 0 };
168 int m_type { 0 };
169 int m_protocol { 0 };
170 size_t m_backlog { 0 };
171 SetupState m_setup_state { SetupState::Unstarted };
172 bool m_connected { false };
173 bool m_shut_down_for_reading { false };
174 bool m_shut_down_for_writing { false };
175
176 LockRefPtr<NetworkAdapter> m_bound_interface { nullptr };
177
178 Time m_receive_timeout {};
179 Time m_send_timeout {};
180 int m_timestamp { 0 };
181
182 Optional<ErrnoCode> m_so_error;
183
184 Vector<NonnullRefPtr<Socket>> m_pending;
185};
186
187// This is a special variant of TRY() that also updates the socket's SO_ERROR field on error.
188#define SOCKET_TRY(expression) \
189 ({ \
190 auto&& result = (expression); \
191 if (result.is_error()) \
192 return set_so_error(result.release_error()); \
193 static_assert(!::AK::Detail::IsLvalueReference<decltype(result.release_value())>, \
194 "Do not return a reference from a fallible expression"); \
195 result.release_value(); \
196 })
197
198}