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/IntrusiveList.h>
10#include <Kernel/DoubleBuffer.h>
11#include <Kernel/Net/Socket.h>
12
13namespace Kernel {
14
15class OpenFileDescription;
16
17struct SocketPair {
18 NonnullRefPtr<OpenFileDescription> description0;
19 NonnullRefPtr<OpenFileDescription> description1;
20};
21
22class LocalSocket final : public Socket {
23
24public:
25 static ErrorOr<NonnullRefPtr<LocalSocket>> try_create(int type);
26 static ErrorOr<SocketPair> try_create_connected_pair(int type);
27 virtual ~LocalSocket() override;
28
29 ErrorOr<void> sendfd(OpenFileDescription const& socket_description, NonnullRefPtr<OpenFileDescription> passing_description);
30 ErrorOr<NonnullRefPtr<OpenFileDescription>> recvfd(OpenFileDescription const& socket_description);
31 ErrorOr<Vector<NonnullRefPtr<OpenFileDescription>>> recvfds(OpenFileDescription const& socket_description, int n);
32
33 static void for_each(Function<void(LocalSocket const&)>);
34 static ErrorOr<void> try_for_each(Function<ErrorOr<void>(LocalSocket const&)>);
35
36 StringView socket_path() const;
37 ErrorOr<NonnullOwnPtr<KString>> pseudo_path(OpenFileDescription const& description) const override;
38
39 // ^Socket
40 virtual ErrorOr<void> bind(Credentials const&, Userspace<sockaddr const*>, socklen_t) override;
41 virtual ErrorOr<void> connect(Credentials const&, OpenFileDescription&, Userspace<sockaddr const*>, socklen_t) override;
42 virtual ErrorOr<void> listen(size_t) override;
43 virtual void get_local_address(sockaddr*, socklen_t*) override;
44 virtual void get_peer_address(sockaddr*, socklen_t*) override;
45 virtual ErrorOr<void> attach(OpenFileDescription&) override;
46 virtual void detach(OpenFileDescription&) override;
47 virtual bool can_read(OpenFileDescription const&, u64) const override;
48 virtual bool can_write(OpenFileDescription const&, u64) const override;
49 virtual ErrorOr<size_t> sendto(OpenFileDescription&, UserOrKernelBuffer const&, size_t, int, Userspace<sockaddr const*>, socklen_t) override;
50 virtual ErrorOr<size_t> recvfrom(OpenFileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>, Time&, bool blocking) override;
51 virtual ErrorOr<void> getsockopt(OpenFileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
52 virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) override;
53 virtual ErrorOr<void> chown(Credentials const&, OpenFileDescription&, UserID, GroupID) override;
54 virtual ErrorOr<void> chmod(Credentials const&, OpenFileDescription&, mode_t) override;
55
56private:
57 explicit LocalSocket(int type, NonnullOwnPtr<DoubleBuffer> client_buffer, NonnullOwnPtr<DoubleBuffer> server_buffer);
58 virtual StringView class_name() const override { return "LocalSocket"sv; }
59 virtual bool is_local() const override { return true; }
60 bool has_attached_peer(OpenFileDescription const&) const;
61 DoubleBuffer* receive_buffer_for(OpenFileDescription&);
62 DoubleBuffer* send_buffer_for(OpenFileDescription&);
63 Vector<NonnullRefPtr<OpenFileDescription>>& sendfd_queue_for(OpenFileDescription const&);
64 Vector<NonnullRefPtr<OpenFileDescription>>& recvfd_queue_for(OpenFileDescription const&);
65
66 void set_connect_side_role(Role connect_side_role, bool force_evaluate_block_conditions = false)
67 {
68 auto previous = m_connect_side_role;
69 m_connect_side_role = connect_side_role;
70 if (previous != m_connect_side_role || force_evaluate_block_conditions)
71 evaluate_block_conditions();
72 }
73
74 ErrorOr<void> try_set_path(StringView);
75
76 // The inode this socket is bound to.
77 RefPtr<Inode> m_inode;
78
79 UserID m_prebind_uid { 0 };
80 GroupID m_prebind_gid { 0 };
81 mode_t m_prebind_mode { 0 };
82
83 // A single LocalSocket is shared between two file descriptions
84 // on the connect side and the accept side; so we need to store
85 // an additional role for the connect side and differentiate
86 // between them.
87 Role m_connect_side_role { Role::None };
88 OpenFileDescription* m_connect_side_fd { nullptr };
89
90 virtual Role role(OpenFileDescription const& description) const override
91 {
92 if (m_connect_side_fd == &description)
93 return m_connect_side_role;
94 return m_role;
95 }
96
97 bool m_bound { false };
98 bool m_accept_side_fd_open { false };
99 OwnPtr<KString> m_path;
100
101 NonnullOwnPtr<DoubleBuffer> m_for_client;
102 NonnullOwnPtr<DoubleBuffer> m_for_server;
103
104 Vector<NonnullRefPtr<OpenFileDescription>> m_fds_for_client;
105 Vector<NonnullRefPtr<OpenFileDescription>> m_fds_for_server;
106
107 IntrusiveListNode<LocalSocket> m_list_node;
108
109public:
110 using List = IntrusiveList<&LocalSocket::m_list_node>;
111};
112
113}