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 <Kernel/Devices/RandomDevice.h>
28#include <Kernel/Net/NetworkAdapter.h>
29#include <Kernel/Net/Routing.h>
30#include <Kernel/Net/UDP.h>
31#include <Kernel/Net/UDPSocket.h>
32#include <Kernel/Process.h>
33#include <Kernel/Random.h>
34
35namespace Kernel {
36
37void UDPSocket::for_each(Function<void(UDPSocket&)> callback)
38{
39 LOCKER(sockets_by_port().lock());
40 for (auto it : sockets_by_port().resource())
41 callback(*it.value);
42}
43
44Lockable<HashMap<u16, UDPSocket*>>& UDPSocket::sockets_by_port()
45{
46 static Lockable<HashMap<u16, UDPSocket*>>* s_map;
47 if (!s_map)
48 s_map = new Lockable<HashMap<u16, UDPSocket*>>;
49 return *s_map;
50}
51
52SocketHandle<UDPSocket> UDPSocket::from_port(u16 port)
53{
54 RefPtr<UDPSocket> socket;
55 {
56 LOCKER(sockets_by_port().lock());
57 auto it = sockets_by_port().resource().find(port);
58 if (it == sockets_by_port().resource().end())
59 return {};
60 socket = (*it).value;
61 ASSERT(socket);
62 }
63 return { *socket };
64}
65
66UDPSocket::UDPSocket(int protocol)
67 : IPv4Socket(SOCK_DGRAM, protocol)
68{
69}
70
71UDPSocket::~UDPSocket()
72{
73 LOCKER(sockets_by_port().lock());
74 sockets_by_port().resource().remove(local_port());
75}
76
77NonnullRefPtr<UDPSocket> UDPSocket::create(int protocol)
78{
79 return adopt(*new UDPSocket(protocol));
80}
81
82int UDPSocket::protocol_receive(const KBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags)
83{
84 (void)flags;
85 auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.data());
86 auto& udp_packet = *static_cast<const UDPPacket*>(ipv4_packet.payload());
87 ASSERT(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier.
88 ASSERT(buffer_size >= (udp_packet.length() - sizeof(UDPPacket)));
89 memcpy(buffer, udp_packet.payload(), udp_packet.length() - sizeof(UDPPacket));
90 return udp_packet.length() - sizeof(UDPPacket);
91}
92
93int UDPSocket::protocol_send(const void* data, size_t data_length)
94{
95 auto routing_decision = route_to(peer_address(), local_address());
96 if (routing_decision.is_zero())
97 return -EHOSTUNREACH;
98 auto buffer = ByteBuffer::create_zeroed(sizeof(UDPPacket) + data_length);
99 auto& udp_packet = *(UDPPacket*)(buffer.data());
100 udp_packet.set_source_port(local_port());
101 udp_packet.set_destination_port(peer_port());
102 udp_packet.set_length(sizeof(UDPPacket) + data_length);
103 memcpy(udp_packet.payload(), data, data_length);
104 kprintf("sending as udp packet from %s:%u to %s:%u!\n",
105 routing_decision.adapter->ipv4_address().to_string().characters(),
106 local_port(),
107 peer_address().to_string().characters(),
108 peer_port());
109 routing_decision.adapter->send_ipv4(routing_decision.next_hop, peer_address(), IPv4Protocol::UDP, buffer.data(), buffer.size(), ttl());
110 return data_length;
111}
112
113KResult UDPSocket::protocol_connect(FileDescription&, ShouldBlock)
114{
115 m_role = Role::Connected;
116 set_connected(true);
117 return KSuccess;
118}
119
120int UDPSocket::protocol_allocate_local_port()
121{
122 static const u16 first_ephemeral_port = 32768;
123 static const u16 last_ephemeral_port = 60999;
124 static const u16 ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port;
125 u16 first_scan_port = first_ephemeral_port + get_good_random<u16>() % ephemeral_port_range_size;
126
127 LOCKER(sockets_by_port().lock());
128 for (u16 port = first_scan_port;;) {
129 auto it = sockets_by_port().resource().find(port);
130 if (it == sockets_by_port().resource().end()) {
131 set_local_port(port);
132 sockets_by_port().resource().set(port, this);
133 return port;
134 }
135 ++port;
136 if (port > last_ephemeral_port)
137 port = first_ephemeral_port;
138 if (port == first_scan_port)
139 break;
140 }
141 return -EADDRINUSE;
142}
143
144KResult UDPSocket::protocol_bind()
145{
146 LOCKER(sockets_by_port().lock());
147 if (sockets_by_port().resource().contains(local_port()))
148 return KResult(-EADDRINUSE);
149 sockets_by_port().resource().set(local_port(), this);
150 return KSuccess;
151}
152
153}