Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 88b91a1

Browse files
committed
Kernel: Basic userspace socket functionality
Can only receive UDP packets so far. Much work remains to be done
1 parent 6537543 commit 88b91a1

32 files changed

+807
-18
lines changed

kernel/CMakeLists.txt

+5-1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ SET(KERNEL_SRCS
164164
syscall/read_write.cpp
165165
syscall/sigaction.cpp
166166
syscall/sleep.cpp
167+
syscall/socket.cpp
167168
syscall/stat.cpp
168169
syscall/thread.cpp
169170
syscall/truncate.cpp
@@ -174,7 +175,10 @@ SET(KERNEL_SRCS
174175
StackWalker.cpp
175176
net/NetworkAdapter.cpp
176177
net/E1000Adapter.cpp
177-
net/NetworkManager.cpp)
178+
net/NetworkManager.cpp
179+
net/Socket.cpp
180+
net/IPSocket.cpp
181+
net/UDPSocket.cpp)
178182

179183
add_custom_command(
180184
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated/duckos_version.h"

kernel/api/in.h

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later */
2+
/* Copyright © 2016-2024 Byteduck */
3+
4+
#pragma once
5+
6+
#include "socket.h"
7+
8+
__DECL_BEGIN
9+
10+
typedef uint16_t in_port_t;
11+
typedef uint32_t in_addr_t;
12+
13+
struct in_addr {
14+
in_addr_t s_addr;
15+
};
16+
17+
struct sockaddr_in {
18+
sa_family_t sin_family;
19+
in_port_t sin_port;
20+
struct in_addr sin_addr;
21+
};
22+
23+
# define INADDR_ANY ((uint32_t) 0x00000000)
24+
# define INADDR_NONE 0xffffffff
25+
# define INPORT_ANY 0
26+
#define IPPROTO_TCP 0
27+
#define IPPROTO_UDP 0
28+
29+
__DECL_END

kernel/api/ipv4.h

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ class __attribute__((packed)) IPv4Address {
1111
public:
1212
constexpr IPv4Address() = default;
1313

14+
constexpr IPv4Address(uint32_t addr) {
15+
m_data[0] = addr >> 24;
16+
m_data[1] = addr >> 16;
17+
m_data[2] = addr >> 8;
18+
m_data[3] = addr;
19+
}
20+
1421
constexpr IPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
1522
m_data[0] = a;
1623
m_data[1] = b;

kernel/api/socket.h

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later */
2+
/* Copyright © 2016-2024 Byteduck */
3+
4+
#pragma once
5+
6+
#include "cdefs.h"
7+
#include "types.h"
8+
#include "un.h"
9+
10+
__DECL_BEGIN
11+
12+
// Domains
13+
#define AF_UNSPEC 0
14+
#define AF_UNIX 1
15+
#define AF_LOCAL 2
16+
#define AF_INET 3
17+
#define AF_PACKET 4
18+
19+
// Types
20+
#define SOCK_STREAM 1
21+
#define SOCK_DGRAM 2
22+
#define SOCK_RAW 3
23+
24+
typedef uint16_t sa_family_t;
25+
typedef uint32_t socklen_t;
26+
27+
struct sockaddr {
28+
sa_family_t sa_family;
29+
char sa_data[14];
30+
};
31+
32+
struct iovec {
33+
void* iov_base;
34+
size_t iov_len;
35+
};
36+
37+
struct msghdr {
38+
void* msg_name;
39+
socklen_t msg_namelen;
40+
struct iovec* msg_iov;
41+
size_t msg_iovlen;
42+
void* msg_control;
43+
size_t msg_controllen;
44+
int msg_flags;
45+
};
46+
47+
struct sockaddr_storage {
48+
sa_family_t ss_family;
49+
struct sockaddr_un __un;
50+
};
51+
52+
__DECL_END

kernel/api/udp.h

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later */
2+
/* Copyright © 2016-2024 Byteduck */
3+
4+
#pragma once
5+
6+
#include "endian.h"
7+
8+
struct UDPPacket {
9+
BigEndian<uint16_t> source_port;
10+
BigEndian<uint16_t> dest_port;
11+
BigEndian<uint16_t> len;
12+
BigEndian<uint16_t> checksum = 0;
13+
uint8_t payload[];
14+
} __attribute__((packed));
15+
16+
static_assert(sizeof(UDPPacket) == 8);

kernel/api/un.h

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later */
2+
/* Copyright © 2016-2024 Byteduck */
3+
4+
#pragma once
5+
6+
#include "types.h"
7+
8+
__DECL_BEGIN
9+
10+
#define UNIX_PATH_MAX 100
11+
12+
struct sockaddr_un {
13+
uint16_t sun_family;
14+
char sun_path[UNIX_PATH_MAX];
15+
};
16+
17+
__DECL_END

kernel/filesystem/File.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ bool File::is_fifo() {
5252
return false;
5353
}
5454

55+
bool File::is_socket() {
56+
return false;
57+
}
58+
5559
ssize_t File::read(FileDescriptor &fd, size_t offset, SafePointer<uint8_t> buffer, size_t count) {
5660
return 0;
5761
}

kernel/filesystem/File.h

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class File {
3737
virtual bool is_pty_mux();
3838
virtual bool is_pty();
3939
virtual bool is_fifo();
40+
virtual bool is_socket();
4041
virtual int ioctl(unsigned request, SafePointer<void*> argp);
4142
virtual void open(FileDescriptor& fd, int options);
4243
virtual void close(FileDescriptor& fd);

kernel/kstd/ListQueue.h

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later */
2+
/* Copyright © 2016-2024 Byteduck */
3+
4+
#pragma once
5+
6+
#include "types.h"
7+
#include "Optional.h"
8+
9+
namespace kstd {
10+
11+
template<typename T, size_t max_count>
12+
class ListQueue {
13+
public:
14+
ListQueue() = default;
15+
16+
bool enqueue(const T& val) {
17+
if (m_count >= max_count)
18+
return false;
19+
20+
if (m_tail == nullptr) {
21+
m_head = new Entry {nullptr, val};
22+
m_head = m_tail;
23+
} else {
24+
m_tail->next = new Entry {nullptr, val};
25+
m_tail = m_tail->next;
26+
}
27+
28+
m_count++;
29+
30+
return true;
31+
}
32+
33+
Optional<T> dequeue() {
34+
if (!m_head)
35+
return nullopt;
36+
37+
m_count--;
38+
auto* ent = m_head;
39+
m_head = ent->next;
40+
if (m_tail == ent)
41+
m_tail = nullptr;
42+
return ent->val;
43+
}
44+
45+
Optional<T> peek() {
46+
if (!m_head)
47+
return nullopt;
48+
return m_head->val;
49+
}
50+
51+
[[nodiscard]] bool empty() const {
52+
return m_count == 0;
53+
}
54+
55+
[[nodiscard]] size_t count() const {
56+
return count;
57+
}
58+
59+
private:
60+
struct Entry {
61+
Entry* next;
62+
T val;
63+
};
64+
65+
Entry* m_head = nullptr;
66+
Entry* m_tail = nullptr;
67+
size_t m_count = 0;
68+
};
69+
70+
}

kernel/memory/SafePointer.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
template<typename T>
1010
class SafePointer {
1111
public:
12+
SafePointer() = default;
1213
explicit SafePointer(T* raw_ptr, bool is_user):
1314
m_ptr(raw_ptr), m_is_user(is_user) {}
1415
template<typename C> SafePointer(const SafePointer<C>& safe_ptr):
@@ -153,9 +154,14 @@ class SafePointer {
153154
});
154155
}
155156

157+
template<typename R>
158+
SafePointer<R> as() {
159+
return SafePointer<R>((R*) m_ptr, m_is_user);
160+
}
161+
156162
private:
157-
T* const m_ptr;
158-
const bool m_is_user;
163+
T* const m_ptr = nullptr;
164+
const bool m_is_user = false;
159165
};
160166

161167
template<typename T>

kernel/net/IPSocket.cpp

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later */
2+
/* Copyright © 2016-2024 Byteduck */
3+
4+
#include "IPSocket.h"
5+
#include "UDPSocket.h"
6+
#include "../api/in.h"
7+
#include "../kstd/KLog.h"
8+
#include "../tasking/PollBlocker.h"
9+
#include "../filesystem/FileDescriptor.h"
10+
11+
IPSocket::IPSocket(Socket::Type type, int protocol): Socket(Domain::Inet, type, protocol) {
12+
13+
}
14+
15+
ResultRet<kstd::Arc<IPSocket>> IPSocket::make(Socket::Type type, int protocol) {
16+
switch (type) {
17+
case Type::Dgram:
18+
return kstd::static_pointer_cast<IPSocket>(TRY(UDPSocket::make()));
19+
default:
20+
return Result(EINVAL);
21+
}
22+
}
23+
24+
Result IPSocket::bind(SafePointer<sockaddr> addr_ptr, socklen_t addrlen) {
25+
if (m_bound || addrlen != sizeof(sockaddr_in))
26+
return Result(set_error(EINVAL));
27+
28+
auto addr = addr_ptr.as<sockaddr_in>().get();
29+
if (addr.sin_family != AF_INET)
30+
return Result(set_error(EINVAL));
31+
32+
m_port = from_big_endian(addr.sin_port);
33+
m_addr = IPv4Address(from_big_endian(addr.sin_addr.s_addr));
34+
35+
return do_bind();
36+
}
37+
38+
ssize_t IPSocket::recvfrom(FileDescriptor& fd, SafePointer<uint8_t> buf, size_t len, int flags, SafePointer<sockaddr> src_addr, SafePointer<socklen_t> addrlen) {
39+
m_receive_queue_lock.acquire();
40+
41+
// Block until we have a packet to read
42+
while (m_receive_queue.empty()) {
43+
if (fd.nonblock()) {
44+
m_receive_queue_lock.release();
45+
return -EAGAIN;
46+
}
47+
48+
update_blocker();
49+
m_receive_queue_lock.release();
50+
TaskManager::current_thread()->block(m_receive_blocker);
51+
m_receive_queue_lock.acquire();
52+
}
53+
54+
// Read our packet
55+
auto* packet = m_receive_queue.pop_front();
56+
update_blocker();
57+
m_receive_queue_lock.release();
58+
auto res = do_recv(packet, buf, len);
59+
kfree(packet);
60+
return res;
61+
}
62+
63+
Result IPSocket::recv_packet(const void* buf, size_t len) {
64+
LOCK(m_receive_queue_lock);
65+
66+
if (m_receive_queue.size() == m_receive_queue.capacity()) {
67+
KLog::warn("IPSocket", "Dropping packet because receive queue is full");
68+
return Result(ENOSPC);
69+
}
70+
71+
auto* src_pkt = (const IPv4Packet*) buf;
72+
auto* new_pkt = (IPv4Packet*) kmalloc(len);
73+
memcpy(new_pkt, src_pkt, len);
74+
75+
m_receive_queue.push_back(new_pkt);
76+
update_blocker();
77+
78+
return Result(SUCCESS);
79+
}
80+
81+
bool IPSocket::can_read(const FileDescriptor& fd) {
82+
return !m_receive_queue.empty();
83+
}
84+
85+
void IPSocket::update_blocker() {
86+
m_receive_blocker.set_ready(!m_receive_queue.empty());
87+
}

kernel/net/IPSocket.h

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later */
2+
/* Copyright © 2016-2024 Byteduck */
3+
4+
#pragma once
5+
6+
#include "Socket.h"
7+
#include "../api/ipv4.h"
8+
#include "../kstd/ListQueue.h"
9+
10+
class IPSocket: public Socket {
11+
public:
12+
static ResultRet<kstd::Arc<IPSocket>> make(Socket::Type type, int protocol);
13+
14+
// Socket
15+
Result bind(SafePointer<sockaddr> addr, socklen_t addrlen) override;
16+
ssize_t recvfrom(FileDescriptor &fd, SafePointer<uint8_t> buf, size_t len, int flags, SafePointer<sockaddr> src_addr, SafePointer<socklen_t> addrlen) override;
17+
Result recv_packet(const void* buf, size_t len) override;
18+
19+
// File
20+
bool can_read(const FileDescriptor &fd) override;
21+
22+
protected:
23+
IPSocket(Socket::Type type, int protocol);
24+
25+
virtual ssize_t do_recv(const IPv4Packet* pkt, SafePointer<uint8_t> buf, size_t len) = 0;
26+
virtual Result do_bind() = 0;
27+
28+
void update_blocker();
29+
30+
bool m_bound = false;
31+
uint16_t m_port;
32+
IPv4Address m_addr;
33+
kstd::circular_queue<IPv4Packet*> m_receive_queue { 16 };
34+
Mutex m_receive_queue_lock { "IPSocket::receive_queue" };
35+
BooleanBlocker m_receive_blocker;
36+
};

0 commit comments

Comments
 (0)