From 6b0bc66fd24f696446a1f38e386adc1b5adbfc87 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 27 Jul 2023 16:31:57 +0200 Subject: [PATCH 01/16] libluna: Add new socket-related errno codes --- libluna/include/luna/SystemError.h | 4 ++++ libluna/src/SystemError.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/libluna/include/luna/SystemError.h b/libluna/include/luna/SystemError.h index 869f7a7f..43b2579c 100644 --- a/libluna/include/luna/SystemError.h +++ b/libluna/include/luna/SystemError.h @@ -45,11 +45,15 @@ #define EOVERFLOW 75 // Value too large for defined data type #define EILSEQ 84 // Invalid or incomplete multibyte or wide character #define ENOTSOCK 88 // Socket operation on non-socket +#define EDESTADDRREQ 89 // Destination address required +#define EPROTOTYPE 91 // Protocol wrong type for socket #define ENOTSUP 95 // Operation not supported #define EOPNOTSUPP 95 // Operation not supported +#define EAFNOSUPPORT 97 // Address family not supported by protocol #define EADDRINUSE 98 // Address already in use #define ENETRESET 102 // Network dropped connection on reset #define ECONNRESET 104 // Connection reset by peer #define EISCONN 106 // Transport endpoint is already connected +#define ENOTCONN 107 // Transport endpoint is not connected #define ETIMEDOUT 110 // Connection timed out #define EALREADY 114 // Operation already in progress diff --git a/libluna/src/SystemError.cpp b/libluna/src/SystemError.cpp index 9b7bf473..744ae86d 100644 --- a/libluna/src/SystemError.cpp +++ b/libluna/src/SystemError.cpp @@ -56,6 +56,10 @@ const char* error_string(int error) case EISCONN: return "Transport endpoint is already connected"; case ETIMEDOUT: return "Connection timed out"; case EALREADY: return "Operation already in progress"; + case EDESTADDRREQ: return "Destination address required"; + case EPROTOTYPE: return "Protocol wrong type for socket"; + case EAFNOSUPPORT: return "Address family not supported by protocol"; + case ENOTCONN: return "Transport endpoint is not connected"; default: return "Unknown error"; } } -- 2.34.1 From 200bb6c24043e473980754fe1ffaa6ce4d5eeb86 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 27 Jul 2023 16:35:27 +0200 Subject: [PATCH 02/16] kernel+libc+libos: Add inode type for sockets --- kernel/src/fs/VFS.h | 1 + kernel/src/sys/open.cpp | 2 ++ kernel/src/sys/stat.cpp | 1 + libc/include/bits/modes.h | 2 ++ libos/src/Mode.cpp | 1 + 5 files changed, 7 insertions(+) diff --git a/kernel/src/fs/VFS.h b/kernel/src/fs/VFS.h index 7dcee9d5..3dc369fb 100644 --- a/kernel/src/fs/VFS.h +++ b/kernel/src/fs/VFS.h @@ -17,6 +17,7 @@ namespace VFS BlockDevice, Symlink, FIFO, + Socket, }; class Inode; diff --git a/kernel/src/sys/open.cpp b/kernel/src/sys/open.cpp index ce160a19..0a3de817 100644 --- a/kernel/src/sys/open.cpp +++ b/kernel/src/sys/open.cpp @@ -55,6 +55,8 @@ Result sys_openat(Registers*, SyscallArgs args) // This should only be possible if O_NOFOLLOW was in flags. if (inode->type() == VFS::InodeType::Symlink) return err(ELOOP); + if (inode->type() == VFS::InodeType::Socket) return err(ENXIO); + if (flags & O_TMPFILE) { if (inode->type() != VFS::InodeType::Directory) return err(EINVAL); diff --git a/kernel/src/sys/stat.cpp b/kernel/src/sys/stat.cpp index 85c534cd..55e35699 100644 --- a/kernel/src/sys/stat.cpp +++ b/kernel/src/sys/stat.cpp @@ -18,6 +18,7 @@ static mode_t make_mode(mode_t mode, VFS::InodeType type) case VFS::InodeType::BlockDevice: result |= S_IFBLK; break; case VFS::InodeType::Symlink: result |= S_IFLNK; break; case VFS::InodeType::FIFO: result |= S_IFIFO; break; + case VFS::InodeType::Socket: result |= S_IFSOCK; break; default: break; } diff --git a/libc/include/bits/modes.h b/libc/include/bits/modes.h index 6f567339..b46df7c2 100644 --- a/libc/include/bits/modes.h +++ b/libc/include/bits/modes.h @@ -10,6 +10,7 @@ #define S_IFBLK 030000 #define S_IFDIR 040000 #define S_IFCHR 050000 +#define S_IFSOCK 060000 #define __CHECK_TYPE(mode, type) (((mode)&S_IFMT) == type) @@ -19,6 +20,7 @@ #define S_ISBLK(mode) __CHECK_TYPE(mode, S_IFBLK) #define S_ISLNK(mode) __CHECK_TYPE(mode, S_IFLNK) #define S_ISFIFO(mode) __CHECK_TYPE(mode, S_IFIFO) +#define S_ISSOCK(mode) __CHECK_TYPE(mode, S_IFSOCK) #define S_IRWXU 0700 #define S_IRUSR 0400 diff --git a/libos/src/Mode.cpp b/libos/src/Mode.cpp index 2c6e6cbb..1b3d3c86 100644 --- a/libos/src/Mode.cpp +++ b/libos/src/Mode.cpp @@ -21,6 +21,7 @@ namespace os if (S_ISBLK(mode)) return 'b'; if (S_ISLNK(mode)) return 'l'; if (S_ISFIFO(mode)) return 'p'; + if (S_ISSOCK(mode)) return 's'; return '?'; } -- 2.34.1 From c1d08b904e870b89693c751e480ecb886544024d Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 27 Jul 2023 16:35:52 +0200 Subject: [PATCH 03/16] kernel+libluna: Add Buffer::dequeue_data() --- kernel/src/fs/devices/ConsoleDevice.cpp | 8 +------- libluna/include/luna/Buffer.h | 2 ++ libluna/src/Buffer.cpp | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/kernel/src/fs/devices/ConsoleDevice.cpp b/kernel/src/fs/devices/ConsoleDevice.cpp index 6f1218e9..0d469c65 100644 --- a/kernel/src/fs/devices/ConsoleDevice.cpp +++ b/kernel/src/fs/devices/ConsoleDevice.cpp @@ -49,13 +49,7 @@ Result ConsoleDevice::read(u8* buf, usize, usize length) const { TRY(handle_background_process_group(false, SIGTTIN)); - if (length > m_input_buffer.size()) length = m_input_buffer.size(); - - memcpy(buf, m_input_buffer.data(), length); - - memmove(m_input_buffer.data(), m_input_buffer.data() + length, m_input_buffer.size() - length); - - m_input_buffer.try_resize(m_input_buffer.size() - length).release_value(); + length = m_input_buffer.dequeue_data(buf, length); if (!length && m_may_read_without_blocking) m_may_read_without_blocking = false; diff --git a/libluna/include/luna/Buffer.h b/libluna/include/luna/Buffer.h index 405c7dd9..6b378815 100644 --- a/libluna/include/luna/Buffer.h +++ b/libluna/include/luna/Buffer.h @@ -21,6 +21,8 @@ class Buffer Result append_data(const u8* data, usize size); + usize dequeue_data(u8* data, usize size); + u8* data() { return m_data; diff --git a/libluna/src/Buffer.cpp b/libluna/src/Buffer.cpp index 960e848d..57f53051 100644 --- a/libluna/src/Buffer.cpp +++ b/libluna/src/Buffer.cpp @@ -53,6 +53,20 @@ Result Buffer::append_data(const u8* data, usize size) return {}; } +usize Buffer::dequeue_data(u8* data, usize size) +{ + if (size > m_size) size = m_size; + if (!size) return 0; + + memcpy(data, m_data, size); + + memmove(m_data, m_data + size, m_size - size); + + m_size -= size; + + return size; +} + u8* Buffer::release_data() { u8* data = m_data; -- 2.34.1 From c4e30c3029885c54707841496a28e779e0eb3508 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 27 Jul 2023 16:36:36 +0200 Subject: [PATCH 04/16] kernel: Add functionality to allow external inodes (such as sockets) to acquire an inode number from a file system This is only implemented in tmpfs. --- kernel/src/fs/VFS.h | 5 +++++ kernel/src/fs/tmpfs/FileSystem.cpp | 5 +++++ kernel/src/fs/tmpfs/FileSystem.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/kernel/src/fs/VFS.h b/kernel/src/fs/VFS.h index 3dc369fb..b38dc171 100644 --- a/kernel/src/fs/VFS.h +++ b/kernel/src/fs/VFS.h @@ -35,6 +35,11 @@ namespace VFS virtual Result> create_symlink_inode(StringView link) = 0; + virtual Result allocate_inode_number() + { + return err(ENOTSUP); + } + virtual Result set_mount_dir(SharedPtr parent) = 0; virtual Result reset_mount_dir() = 0; diff --git a/kernel/src/fs/tmpfs/FileSystem.cpp b/kernel/src/fs/tmpfs/FileSystem.cpp index e871e2b5..71d0488c 100644 --- a/kernel/src/fs/tmpfs/FileSystem.cpp +++ b/kernel/src/fs/tmpfs/FileSystem.cpp @@ -16,6 +16,11 @@ namespace TmpFS return (SharedPtr)fs; } + Result FileSystem::allocate_inode_number() + { + return m_next_inode_number++; + } + Result> FileSystem::create_file_inode() { SharedPtr inode = TRY(make_shared()); diff --git a/kernel/src/fs/tmpfs/FileSystem.h b/kernel/src/fs/tmpfs/FileSystem.h index 2542c740..2d598a9c 100644 --- a/kernel/src/fs/tmpfs/FileSystem.h +++ b/kernel/src/fs/tmpfs/FileSystem.h @@ -18,6 +18,8 @@ namespace TmpFS Result> create_device_inode(u32 major, u32 minor) override; Result> create_symlink_inode(StringView link) override; + Result allocate_inode_number() override; + Result set_mount_dir(SharedPtr parent) override; Result reset_mount_dir() override; -- 2.34.1 From a12b018b038142383b219fedc06711dfe363639a Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 27 Jul 2023 16:37:10 +0200 Subject: [PATCH 05/16] kernel+libc: Add basic Unix sockets (creation and binding) --- kernel/CMakeLists.txt | 2 + kernel/src/net/Socket.h | 114 +++++++++++++++++++++++++++++++++ kernel/src/net/UnixSocket.cpp | 104 ++++++++++++++++++++++++++++++ kernel/src/net/UnixSocket.h | 46 +++++++++++++ kernel/src/sys/socket.cpp | 49 ++++++++++++++ libc/CMakeLists.txt | 1 + libc/include/bits/socket.h | 30 +++++++++ libc/include/sys/socket.h | 23 +++++++ libc/include/sys/un.h | 14 ++++ libc/src/sys/socket.cpp | 19 ++++++ libluna/include/luna/Syscall.h | 2 +- 11 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 kernel/src/net/Socket.h create mode 100644 kernel/src/net/UnixSocket.cpp create mode 100644 kernel/src/net/UnixSocket.h create mode 100644 kernel/src/sys/socket.cpp create mode 100644 libc/include/bits/socket.h create mode 100644 libc/include/sys/socket.h create mode 100644 libc/include/sys/un.h create mode 100644 libc/src/sys/socket.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 216b4046..8f311108 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -41,11 +41,13 @@ set(SOURCES src/sys/mount.cpp src/sys/resource.cpp src/sys/signal.cpp + src/sys/socket.cpp src/fs/VFS.cpp src/fs/Pipe.cpp src/fs/Mount.cpp src/fs/MBR.cpp src/fs/GPT.cpp + src/net/UnixSocket.cpp src/fs/tmpfs/FileSystem.cpp src/fs/tmpfs/Inode.cpp src/fs/ext2/FileSystem.cpp diff --git a/kernel/src/net/Socket.h b/kernel/src/net/Socket.h new file mode 100644 index 00000000..766a7b58 --- /dev/null +++ b/kernel/src/net/Socket.h @@ -0,0 +1,114 @@ +#pragma once +#include "fs/VFS.h" +#include + +class Socket : public VFS::FileInode +{ + public: + Socket() = default; + + VFS::InodeType type() const override + { + return VFS::InodeType::Socket; + } + + void set_fs(VFS::FileSystem* fs) + { + m_fs = fs; + } + + void set_inode_number(usize inum) + { + m_inode_number = inum; + } + + VFS::FileSystem* fs() const override + { + return m_fs; + } + + usize inode_number() const override + { + return m_inode_number; + } + + Result read(u8* buf, usize, usize length) const override + { + return recv(buf, length, 0); + } + + Result write(const u8* buf, usize, usize length) override + { + return send(buf, length, 0); + } + + virtual Result send(const u8*, usize, int) = 0; + + virtual Result recv(u8*, usize, int) const = 0; + + virtual Result bind(SharedPtr, struct sockaddr*, socklen_t) = 0; + virtual Result connect(struct sockaddr*, socklen_t) = 0; + + Result truncate(usize) override + { + return err(EINVAL); + } + + usize size() const override + { + return 0; + } + + mode_t mode() const override + { + return m_mode; + } + + u32 uid() const override + { + return m_uid; + } + + u32 gid() const override + { + return m_gid; + } + + nlink_t nlinks() const override + { + return (nlink_t)m_nlinks; + } + + Result chmod(mode_t mode) override + { + m_mode = mode; + return {}; + } + + Result chown(u32 uid, u32 gid) override + { + m_uid = uid; + m_gid = gid; + return {}; + } + + void did_link() override + { + m_nlinks++; + } + + void did_unlink() override + { + m_nlinks--; + } + + virtual ~Socket() = default; + + protected: + VFS::FileSystem* m_fs; + usize m_inode_number { 0 }; + mode_t m_mode; + u32 m_uid { 0 }; + u32 m_gid { 0 }; + u32 m_nlinks { 0 }; +}; diff --git a/kernel/src/net/UnixSocket.cpp b/kernel/src/net/UnixSocket.cpp new file mode 100644 index 00000000..c5514bd8 --- /dev/null +++ b/kernel/src/net/UnixSocket.cpp @@ -0,0 +1,104 @@ +#include "net/UnixSocket.h" +#include +#include + +UnixSocket::UnixSocket() +{ +} + +UnixSocket::UnixSocket(UnixSocket* peer) : m_state(State::Connected), m_peer(peer) +{ +} + +UnixSocket::~UnixSocket() +{ + if (m_peer) + { + m_peer->m_peer = nullptr; + m_peer->m_state = State::Reset; + } +} + +void UnixSocket::connect_to_peer(UnixSocket* peer) +{ + m_peer = peer; + m_state = State::Connected; +} + +Result UnixSocket::send(const u8* buf, usize length, int) +{ + if (m_state == State::Reset) return err(ECONNRESET); + if (m_state != State::Connected) return err(ENOTCONN); + + check(m_peer); + + TRY(m_peer->m_data.append_data(buf, length)); + + return length; +} + +Result UnixSocket::recv(u8* buf, usize length, int) const +{ + if (m_state == State::Reset) return err(ECONNRESET); + if (m_state != State::Connected) return err(ENOTCONN); + + return m_data.dequeue_data(buf, length); +} + +static Result bind_socket_to_fs(const char* path, Credentials auth, SharedPtr working_directory, + SharedPtr socket) +{ + auto parent_path = TRY(PathParser::dirname(path)); + + auto parent_inode = TRY(VFS::resolve_path(parent_path.chars(), auth, working_directory)); + + if (!VFS::can_write(parent_inode, auth)) return err(EACCES); + + auto child_name = TRY(PathParser::basename(path)); + + TRY(VFS::validate_filename(child_name.view())); + + socket->set_inode_number(TRY(parent_inode->fs()->allocate_inode_number())); + socket->set_fs(parent_inode->fs()); + + return parent_inode->add_entry(socket, child_name.chars()); +} + +Result UnixSocket::bind(SharedPtr socket, struct sockaddr* addr, socklen_t addrlen) +{ + if (!addr) return err(EDESTADDRREQ); + if (addr->sa_family != AF_UNIX) return err(EAFNOSUPPORT); + if ((usize)addrlen > sizeof(sockaddr_un)) return err(EINVAL); + + if (m_state == State::Connected) return err(EISCONN); + if (m_state != State::Inactive) return err(EINVAL); + + struct sockaddr_un* un_address = (struct sockaddr_un*)addr; + + String path = TRY(String::from_string_view( + StringView::from_fixed_size_cstring(un_address->sun_path, addrlen - sizeof(sa_family_t)))); + + auto* current = Scheduler::current(); + + socket->chmod(0777 & ~current->umask); + socket->chown(current->auth.euid, current->auth.egid); + + auto rc = bind_socket_to_fs(path.chars(), current->auth, current->current_directory, socket); + if (rc.has_error()) + { + if (rc.error() == EEXIST) return err(EADDRINUSE); + return rc.release_error(); + } + + memcpy(&m_addr, un_address, addrlen); + m_addrlen = addrlen; + + m_state = State::Bound; + + return {}; +} + +Result UnixSocket::connect(struct sockaddr*, socklen_t) +{ + return err(ENOSYS); +} diff --git a/kernel/src/net/UnixSocket.h b/kernel/src/net/UnixSocket.h new file mode 100644 index 00000000..f03959c1 --- /dev/null +++ b/kernel/src/net/UnixSocket.h @@ -0,0 +1,46 @@ +#pragma once +#include "net/Socket.h" +#include +#include +#include + +class UnixSocket : public Socket +{ + public: + UnixSocket(); + UnixSocket(UnixSocket* peer); + + bool blocking() const override + { + return !m_data.size(); + } + + Result send(const u8*, usize, int) override; + Result recv(u8*, usize, int) const override; + + Result bind(SharedPtr, struct sockaddr*, socklen_t) override; + Result connect(struct sockaddr*, socklen_t) override; + + void connect_to_peer(UnixSocket* peer); + + virtual ~UnixSocket(); + + private: + enum State + { + Inactive, + Bound, + Listening, + Connecting, + Connected, + Reset, + }; + + State m_state = State::Inactive; + UnixSocket* m_peer; + + mutable Buffer m_data; + + struct sockaddr_un m_addr = { .sun_family = AF_UNIX, .sun_path = {} }; + socklen_t m_addrlen = sizeof(sa_family_t); +}; diff --git a/kernel/src/sys/socket.cpp b/kernel/src/sys/socket.cpp new file mode 100644 index 00000000..0a486818 --- /dev/null +++ b/kernel/src/sys/socket.cpp @@ -0,0 +1,49 @@ +#include "net/Socket.h" +#include "memory/MemoryManager.h" +#include "net/UnixSocket.h" +#include "sys/Syscall.h" +#include "thread/Scheduler.h" +#include + +Result sys_socket(Registers*, SyscallArgs args) +{ + int domain = (int)args[0]; + int type = (int)args[1]; + // protocol is not used for now. + + if (type != SOCK_STREAM) return err(EPROTOTYPE); + if (domain != AF_UNIX) return err(EAFNOSUPPORT); + + auto socket = TRY(make_shared()); + + auto* current = Scheduler::current(); + + int fd = TRY(current->allocate_fd(0)); + + current->fd_table[fd] = FileDescriptor { socket, 0, O_RDWR }; + + return fd; +} + +Result sys_bind(Registers*, SyscallArgs args) +{ + int sockfd = (int)args[0]; + struct sockaddr* addr = (struct sockaddr*)args[1]; + socklen_t addrlen = (socklen_t)args[2]; + + struct sockaddr_storage storage; + if ((usize)addrlen > sizeof(storage)) return err(EINVAL); + if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT); + + auto* current = Scheduler::current(); + + auto inode = TRY(current->resolve_fd(sockfd))->inode; + + if (inode->type() != VFS::InodeType::Socket) return err(ENOTSOCK); + + auto socket = (SharedPtr)inode; + + TRY(socket->bind(socket, (struct sockaddr*)&storage, addrlen)); + + return 0; +} diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 19d4c7d2..54c95acf 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -31,6 +31,7 @@ set(SOURCES src/sys/mount.cpp src/sys/pstat.cpp src/sys/resource.cpp + src/sys/socket.cpp ) if(${LUNA_ARCH} STREQUAL "x86_64") diff --git a/libc/include/bits/socket.h b/libc/include/bits/socket.h new file mode 100644 index 00000000..16d18e17 --- /dev/null +++ b/libc/include/bits/socket.h @@ -0,0 +1,30 @@ +/* bits/socket.h: Socket-related types and structures. */ + +#ifndef _BITS_SOCKET_H +#define _BITS_SOCKET_H + +typedef int socklen_t; +typedef unsigned sa_family_t; + +struct sockaddr +{ + sa_family_t sa_family; + char sa_data[4]; +}; + +struct sockaddr_storage +{ + sa_family_t ss_family; + union { + char _sun_path[108]; // AF_UNIX + }; +}; + +#define SOCK_STREAM 0 + +#define AF_UNSPEC 0 +#define AF_UNIX 1 +#define AF_INET 2 +#define AF_INET6 3 + +#endif diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h new file mode 100644 index 00000000..5183e974 --- /dev/null +++ b/libc/include/sys/socket.h @@ -0,0 +1,23 @@ +/* sys/socket.h: Communication sockets. */ + +#ifndef _SYS_SOCKET_H +#define _SYS_SOCKET_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Create a new socket and return a file descriptor pointing to it. */ + int socket(int domain, int type, int protocol); + + /* Bind a socket to an address. */ + int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/sys/un.h b/libc/include/sys/un.h new file mode 100644 index 00000000..7b0dea2f --- /dev/null +++ b/libc/include/sys/un.h @@ -0,0 +1,14 @@ +/* sys/un.h: The sockaddr_un structure for AF_UNIX sockets. */ + +#ifndef _SYS_UN_H +#define _SYS_UN_H + +#include + +struct sockaddr_un +{ + sa_family_t sun_family; + char sun_path[108]; +}; + +#endif diff --git a/libc/src/sys/socket.cpp b/libc/src/sys/socket.cpp new file mode 100644 index 00000000..686d4da7 --- /dev/null +++ b/libc/src/sys/socket.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include + +extern "C" +{ + int socket(int domain, int type, int protocol) + { + long rc = syscall(SYS_socket, domain, type, protocol); + __errno_return(rc, int); + } + + int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen) + { + long rc = syscall(SYS_bind, sockfd, addr, addrlen); + __errno_return(rc, int); + } +} diff --git a/libluna/include/luna/Syscall.h b/libluna/include/luna/Syscall.h index b8ea05d5..f82a9c72 100644 --- a/libluna/include/luna/Syscall.h +++ b/libluna/include/luna/Syscall.h @@ -7,7 +7,7 @@ _e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(pipe) _e(mount) \ _e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \ _e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \ - _e(getpgid) + _e(getpgid) _e(socket) _e(bind) enum Syscalls { -- 2.34.1 From 9303c44269c18b7b1276b3378a61ce116812fbff Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 27 Jul 2023 16:37:17 +0200 Subject: [PATCH 06/16] apps: Add socket-test --- apps/CMakeLists.txt | 1 + apps/socket-test.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 apps/socket-test.cpp diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 20d24f19..a892f745 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -42,3 +42,4 @@ luna_app(cp.cpp cp) luna_app(kill.cpp kill) luna_app(gol.cpp gol) luna_app(buffer-test.cpp buffer-test) +luna_app(socket-test.cpp socket-test) diff --git a/apps/socket-test.cpp b/apps/socket-test.cpp new file mode 100644 index 00000000..3907ec3c --- /dev/null +++ b/apps/socket-test.cpp @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +int main() +{ + int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) + { + perror("socket"); + return 0; + } + + struct sockaddr_un un; + un.sun_family = AF_UNIX; + strncpy(un.sun_path, "/tmp/local.sock", sizeof(un.sun_path)); + + if (bind(sockfd, (struct sockaddr*)&un, sizeof(un)) < 0) + { + perror("bind"); + return 1; + } +} -- 2.34.1 From fb08594a18632cdb6156b32943a040c3e2f68bd2 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 27 Jul 2023 19:21:23 +0200 Subject: [PATCH 07/16] kernel: Separate FileDescriptors and OpenFileDescription Also, add a did_close() callback for OpenFileDescriptions losing all their references. --- kernel/src/fs/VFS.h | 4 +++ kernel/src/sys/exec.cpp | 12 ++------- kernel/src/sys/file.cpp | 45 +++++++++++++++++---------------- kernel/src/sys/getdents.cpp | 4 +-- kernel/src/sys/open.cpp | 6 +---- kernel/src/sys/socket.cpp | 4 +-- kernel/src/thread/Scheduler.cpp | 5 ---- kernel/src/thread/Thread.cpp | 25 +++++++++++++----- kernel/src/thread/Thread.h | 22 ++++++++++++++-- 9 files changed, 72 insertions(+), 55 deletions(-) diff --git a/kernel/src/fs/VFS.h b/kernel/src/fs/VFS.h index b38dc171..c0959394 100644 --- a/kernel/src/fs/VFS.h +++ b/kernel/src/fs/VFS.h @@ -92,6 +92,10 @@ namespace VFS return err(ENOTTY); } + virtual void did_close() + { + } + // Directory-specific methods virtual Result> find(const char* name) const = 0; diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp index 2f42be68..6ca0c021 100644 --- a/kernel/src/sys/exec.cpp +++ b/kernel/src/sys/exec.cpp @@ -92,11 +92,7 @@ Result sys_execve(Registers* regs, SyscallArgs args) { auto& descriptor = current->fd_table[i]; if (!descriptor.has_value()) continue; - if (descriptor->flags & O_CLOEXEC) - { - descriptor->inode->remove_handle(); - descriptor = {}; - } + if (descriptor->description->flags & O_CLOEXEC) { descriptor = {}; } } if (VFS::is_setuid(inode)) current->auth.euid = current->auth.suid = inode->uid(); @@ -148,11 +144,7 @@ Result sys_fork(Registers* regs, SyscallArgs) thread->umask = current->umask; thread->parent = current; - for (int i = 0; i < FD_MAX; i++) - { - thread->fd_table[i] = current->fd_table[i]; - if (current->fd_table[i].has_value()) current->fd_table[i]->inode->add_handle(); - } + for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; } image->apply(thread); diff --git a/kernel/src/sys/file.cpp b/kernel/src/sys/file.cpp index 058d05f0..75403566 100644 --- a/kernel/src/sys/file.cpp +++ b/kernel/src/sys/file.cpp @@ -26,7 +26,7 @@ Result sys_read(Registers* regs, SyscallArgs args) if (!descriptor.is_readable()) return err(EBADF); - while (descriptor.inode->blocking()) + while (descriptor.inode()->blocking()) { if (descriptor.should_block()) kernel_sleep(10); else @@ -40,9 +40,9 @@ Result sys_read(Registers* regs, SyscallArgs args) } } - usize nread = TRY(descriptor.inode->read(buf, descriptor.offset, size)); + usize nread = TRY(descriptor.inode()->read(buf, descriptor.offset, size)); - if (VFS::is_seekable(descriptor.inode)) descriptor.offset += nread; + if (VFS::is_seekable(descriptor.inode())) descriptor.offset += nread; return nread; } @@ -63,11 +63,12 @@ Result sys_write(Registers*, SyscallArgs args) if (!descriptor.is_writable()) return err(EBADF); - if (descriptor.should_append() && VFS::is_seekable(descriptor.inode)) descriptor.offset = descriptor.inode->size(); + if (descriptor.should_append() && VFS::is_seekable(descriptor.inode())) + descriptor.offset = descriptor.inode()->size(); - usize nwritten = TRY(descriptor.inode->write(buf, descriptor.offset, size)); + usize nwritten = TRY(descriptor.inode()->write(buf, descriptor.offset, size)); - if (VFS::is_seekable(descriptor.inode)) descriptor.offset += nwritten; + if (VFS::is_seekable(descriptor.inode())) descriptor.offset += nwritten; return nwritten; } @@ -82,9 +83,9 @@ Result sys_lseek(Registers*, SyscallArgs args) auto& descriptor = *TRY(current->resolve_fd(fd)); - if (descriptor.inode->type() == VFS::InodeType::FIFO) return err(ESPIPE); + if (descriptor.inode()->type() == VFS::InodeType::FIFO) return err(ESPIPE); - if (!VFS::is_seekable(descriptor.inode)) return descriptor.offset; + if (!VFS::is_seekable(descriptor.inode())) return descriptor.offset; off_t new_offset; @@ -92,7 +93,7 @@ Result sys_lseek(Registers*, SyscallArgs args) { case SEEK_SET: new_offset = offset; break; case SEEK_CUR: new_offset = TRY(safe_add((long)descriptor.offset, offset)); break; - case SEEK_END: new_offset = TRY(safe_add((long)descriptor.inode->size(), offset)); break; + case SEEK_END: new_offset = TRY(safe_add((long)descriptor.inode()->size(), offset)); break; default: return err(EINVAL); } @@ -123,28 +124,28 @@ Result sys_fcntl(Registers*, SyscallArgs args) current->fd_table[new_fd] = descriptor; - if (is_cloexec) current->fd_table[new_fd]->flags |= O_CLOEXEC; + if (is_cloexec) current->fd_table[new_fd]->flags() |= O_CLOEXEC; else - current->fd_table[new_fd]->flags &= ~O_CLOEXEC; + current->fd_table[new_fd]->flags() &= ~O_CLOEXEC; return (u64)new_fd; } - case F_GETFD: return (u64) !!(descriptor.flags & O_CLOEXEC); + case F_GETFD: return (u64) !!(descriptor.flags() & O_CLOEXEC); case F_SETFD: { int arg = (int)args[2]; - if (arg == FD_CLOEXEC) descriptor.flags |= O_CLOEXEC; + if (arg == FD_CLOEXEC) descriptor.flags() |= O_CLOEXEC; else - descriptor.flags &= ~O_CLOEXEC; + descriptor.flags() &= ~O_CLOEXEC; return 0; } - case F_GETFL: return (u64)(descriptor.flags & ~O_CLOEXEC); + case F_GETFL: return (u64)(descriptor.flags() & ~O_CLOEXEC); case F_SETFL: { int arg = (int)args[2]; - descriptor.flags &= ~(O_APPEND | O_NONBLOCK); + descriptor.flags() &= ~(O_APPEND | O_NONBLOCK); arg &= (O_APPEND | O_NONBLOCK); - descriptor.flags |= arg; + descriptor.flags() |= arg; return 0; } @@ -161,7 +162,7 @@ Result sys_ioctl(Registers*, SyscallArgs args) Thread* current = Scheduler::current(); auto& descriptor = *TRY(current->resolve_fd(fd)); - return descriptor.inode->ioctl(request, arg); + return descriptor.inode()->ioctl(request, arg); } Result sys_isatty(Registers*, SyscallArgs args) @@ -171,7 +172,7 @@ Result sys_isatty(Registers*, SyscallArgs args) Thread* current = Scheduler::current(); auto& descriptor = *TRY(current->resolve_fd(fd)); - return descriptor.inode->isatty(); + return descriptor.inode()->isatty(); } Result sys_dup2(Registers*, SyscallArgs args) @@ -188,7 +189,7 @@ Result sys_dup2(Registers*, SyscallArgs args) if (newfd == oldfd) return (u64)newfd; current->fd_table[newfd] = descriptor; - current->fd_table[newfd]->flags &= ~O_CLOEXEC; + current->fd_table[newfd]->flags() &= ~O_CLOEXEC; return (u64)newfd; } @@ -210,8 +211,8 @@ Result sys_pipe(Registers*, SyscallArgs args) TRY(Pipe::create(rpipe, wpipe)); - current->fd_table[rfd] = FileDescriptor { rpipe, 0, O_RDONLY }; - current->fd_table[wfd] = FileDescriptor { wpipe, 0, O_WRONLY }; + current->fd_table[rfd] = FileDescriptor { TRY(make_shared(rpipe, O_RDONLY)), 0 }; + current->fd_table[wfd] = FileDescriptor { TRY(make_shared(wpipe, O_WRONLY)), 0 }; return 0; } diff --git a/kernel/src/sys/getdents.cpp b/kernel/src/sys/getdents.cpp index 77c1e76c..129799f2 100644 --- a/kernel/src/sys/getdents.cpp +++ b/kernel/src/sys/getdents.cpp @@ -14,13 +14,13 @@ Result sys_getdents(Registers*, SyscallArgs args) auto& descriptor = *TRY(current->resolve_fd(fd)); - if (descriptor.inode->type() != VFS::InodeType::Directory) return err(ENOTDIR); + if (descriptor.inode()->type() != VFS::InodeType::Directory) return err(ENOTDIR); usize nwrite = 0; while (nwrite < count) { VFS::DirectoryEntry entry; - bool ok = descriptor.inode->get(descriptor.offset).try_set_value(entry); + bool ok = descriptor.inode()->get(descriptor.offset).try_set_value(entry); if (!ok) break; descriptor.offset++; diff --git a/kernel/src/sys/open.cpp b/kernel/src/sys/open.cpp index 0a3de817..0f359ec2 100644 --- a/kernel/src/sys/open.cpp +++ b/kernel/src/sys/open.cpp @@ -82,9 +82,7 @@ Result sys_openat(Registers*, SyscallArgs args) kdbgln("openat: opening file %s from dirfd %d, flags %d, mode %#o = fd %d", path.chars(), dirfd, flags, mode, fd); #endif - inode->add_handle(); - - current->fd_table[fd] = FileDescriptor { inode, 0, flags & FLAGS_TO_KEEP }; + current->fd_table[fd] = FileDescriptor { TRY(make_shared(inode, flags & FLAGS_TO_KEEP)), 0 }; return (u64)fd; } @@ -100,8 +98,6 @@ Result sys_close(Registers*, SyscallArgs args) if (!descriptor.has_value()) return err(EBADF); - descriptor->inode->remove_handle(); - descriptor = {}; return 0; diff --git a/kernel/src/sys/socket.cpp b/kernel/src/sys/socket.cpp index 0a486818..d6d3ade7 100644 --- a/kernel/src/sys/socket.cpp +++ b/kernel/src/sys/socket.cpp @@ -20,7 +20,7 @@ Result sys_socket(Registers*, SyscallArgs args) int fd = TRY(current->allocate_fd(0)); - current->fd_table[fd] = FileDescriptor { socket, 0, O_RDWR }; + current->fd_table[fd] = FileDescriptor { TRY(make_shared(socket, O_RDWR)), 0 }; return fd; } @@ -37,7 +37,7 @@ Result sys_bind(Registers*, SyscallArgs args) auto* current = Scheduler::current(); - auto inode = TRY(current->resolve_fd(sockfd))->inode; + auto inode = TRY(current->resolve_fd(sockfd))->inode(); if (inode->type() != VFS::InodeType::Socket) return err(ENOTSOCK); diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index f56bf161..c2270eb7 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -192,11 +192,6 @@ namespace Scheduler { auto stack = thread->kernel_stack; MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value(); - - for (int i = 0; i < FD_MAX; i++) - { - if (thread->fd_table[i].has_value()) thread->fd_table[i]->inode->remove_handle(); - } } delete thread; diff --git a/kernel/src/thread/Thread.cpp b/kernel/src/thread/Thread.cpp index e39e447e..5128b35e 100644 --- a/kernel/src/thread/Thread.cpp +++ b/kernel/src/thread/Thread.cpp @@ -71,11 +71,11 @@ Result> Thread::resolve_atfile(int dirfd, const String& pa auto descriptor = TRY(resolve_fd(dirfd)); - if (parent_inode) *parent_inode = descriptor->inode; + if (parent_inode) *parent_inode = descriptor->inode(); - if (path.is_empty() && allow_empty_path) return descriptor->inode; + if (path.is_empty() && allow_empty_path) return descriptor->inode(); - return VFS::resolve_path(path.chars(), this->auth, descriptor->inode, follow_last_symlink); + return VFS::resolve_path(path.chars(), this->auth, descriptor->inode(), follow_last_symlink); } [[noreturn]] void Thread::exit_and_signal_parent(int _status) @@ -215,22 +215,33 @@ void Thread::send_signal(int signo) } } +OpenFileDescription::OpenFileDescription(SharedPtr ino, int fl) : inode(ino), flags(fl) +{ + inode->add_handle(); +} + +OpenFileDescription::~OpenFileDescription() +{ + inode->remove_handle(); + inode->did_close(); +} + bool FileDescriptor::should_append() { - return flags & O_APPEND; + return description->flags & O_APPEND; } bool FileDescriptor::should_block() { - return !(flags & O_NONBLOCK); + return !(description->flags & O_NONBLOCK); } bool FileDescriptor::is_readable() { - return flags & O_RDONLY; + return description->flags & O_RDONLY; } bool FileDescriptor::is_writable() { - return flags & O_WRONLY; + return description->flags & O_WRONLY; } diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h index c3e44958..1e5db949 100644 --- a/kernel/src/thread/Thread.h +++ b/kernel/src/thread/Thread.h @@ -28,16 +28,34 @@ enum class ThreadState Dying }; -struct FileDescriptor +struct OpenFileDescription { SharedPtr inode; - usize offset { 0 }; int flags { 0 }; + OpenFileDescription(SharedPtr, int); + ~OpenFileDescription(); +}; + +struct FileDescriptor +{ + SharedPtr description; + usize offset { 0 }; + bool should_append(); bool should_block(); bool is_writable(); bool is_readable(); + + SharedPtr inode() + { + return description->inode; + } + + int& flags() + { + return description->flags; + } }; static constexpr int FD_MAX = 64; -- 2.34.1 From 7a7ae086f5d012a57c4155dfc916328f97163e99 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 27 Jul 2023 19:21:46 +0200 Subject: [PATCH 08/16] kernel: Use a did_close callback for UnixSockets --- kernel/src/net/UnixSocket.cpp | 6 ++++++ kernel/src/net/UnixSocket.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/kernel/src/net/UnixSocket.cpp b/kernel/src/net/UnixSocket.cpp index c5514bd8..e389d50e 100644 --- a/kernel/src/net/UnixSocket.cpp +++ b/kernel/src/net/UnixSocket.cpp @@ -11,12 +11,18 @@ UnixSocket::UnixSocket(UnixSocket* peer) : m_state(State::Connected), m_peer(pee } UnixSocket::~UnixSocket() +{ + did_close(); +} + +void UnixSocket::did_close() { if (m_peer) { m_peer->m_peer = nullptr; m_peer->m_state = State::Reset; } + m_state = State::Inactive; } void UnixSocket::connect_to_peer(UnixSocket* peer) diff --git a/kernel/src/net/UnixSocket.h b/kernel/src/net/UnixSocket.h index f03959c1..0f376cbf 100644 --- a/kernel/src/net/UnixSocket.h +++ b/kernel/src/net/UnixSocket.h @@ -21,6 +21,8 @@ class UnixSocket : public Socket Result bind(SharedPtr, struct sockaddr*, socklen_t) override; Result connect(struct sockaddr*, socklen_t) override; + void did_close() override; + void connect_to_peer(UnixSocket* peer); virtual ~UnixSocket(); -- 2.34.1 From cca806f08803e47bb1514e71cce58bff0167450e Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 28 Jul 2023 17:28:18 +0200 Subject: [PATCH 09/16] libluna: Add a variant of CircularQueue that dynamically allocates its buffer at runtime This is needed to implement the backlog queue for listening sockets. --- libluna/include/luna/CircularQueue.h | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/libluna/include/luna/CircularQueue.h b/libluna/include/luna/CircularQueue.h index 3960854e..583bcbae 100644 --- a/libluna/include/luna/CircularQueue.h +++ b/libluna/include/luna/CircularQueue.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include #include template class CircularQueue @@ -55,3 +57,68 @@ template class CircularQueue Atomic m_head = 0; Atomic m_tail = 0; }; + +template class DynamicCircularQueue +{ + + public: + DynamicCircularQueue() + { + } + + ~DynamicCircularQueue() + { + if (m_data) free_impl(m_data); + } + + Result set_size(usize size) + { + m_data = (T*)TRY(calloc_impl(size + 1, sizeof(T), false)); + m_capacity = size + 1; + return {}; + } + + bool try_push(const T& value) + { + check(m_capacity); + usize current_tail = m_tail.load(MemoryOrder::Relaxed); + const usize new_tail = (current_tail + 1) % m_capacity; + if (new_tail == m_head.load(MemoryOrder::Acquire)) + { + // Queue is full + return false; + } + m_data[current_tail] = value; + if (!m_tail.compare_exchange_strong(current_tail, new_tail, MemoryOrder::Release, MemoryOrder::Relaxed)) + { + // Someone else updated the tail + return false; + } + return true; + } + + bool try_pop(T& value) + { + check(m_capacity); + usize current_head = m_head.load(MemoryOrder::Relaxed); + if (current_head == m_tail.load(MemoryOrder::Acquire)) + { + // Queue is empty + return false; + } + value = m_data[current_head]; + const usize new_head = (current_head + 1) % m_capacity; + if (!m_head.compare_exchange_strong(current_head, new_head, MemoryOrder::Release, MemoryOrder::Relaxed)) + { + // Someone else updated the head + return false; + } + return true; + } + + private: + T* m_data = nullptr; + usize m_capacity = 0; + Atomic m_head = 0; + Atomic m_tail = 0; +}; -- 2.34.1 From bb3127c2125e8156d1023396cbd5c5f94d48c396 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 28 Jul 2023 17:30:20 +0200 Subject: [PATCH 10/16] kernel: Implement listen(), connect() and accept() --- kernel/src/net/Socket.h | 10 +++- kernel/src/net/UnixSocket.cpp | 102 +++++++++++++++++++++++++++++++-- kernel/src/net/UnixSocket.h | 15 ++++- kernel/src/sys/socket.cpp | 80 ++++++++++++++++++++++++++ libluna/include/luna/Syscall.h | 2 +- 5 files changed, 199 insertions(+), 10 deletions(-) diff --git a/kernel/src/net/Socket.h b/kernel/src/net/Socket.h index 766a7b58..fa7eb101 100644 --- a/kernel/src/net/Socket.h +++ b/kernel/src/net/Socket.h @@ -1,5 +1,7 @@ #pragma once +#include "arch/CPU.h" #include "fs/VFS.h" +#include "thread/Thread.h" #include class Socket : public VFS::FileInode @@ -47,7 +49,11 @@ class Socket : public VFS::FileInode virtual Result recv(u8*, usize, int) const = 0; virtual Result bind(SharedPtr, struct sockaddr*, socklen_t) = 0; - virtual Result connect(struct sockaddr*, socklen_t) = 0; + virtual Result connect(Registers*, int, struct sockaddr*, socklen_t) = 0; + + virtual Result> accept(Registers*, int, struct sockaddr**, socklen_t*) = 0; + + virtual Result listen(int backlog) = 0; Result truncate(usize) override { @@ -105,7 +111,7 @@ class Socket : public VFS::FileInode virtual ~Socket() = default; protected: - VFS::FileSystem* m_fs; + VFS::FileSystem* m_fs { nullptr }; usize m_inode_number { 0 }; mode_t m_mode; u32 m_uid { 0 }; diff --git a/kernel/src/net/UnixSocket.cpp b/kernel/src/net/UnixSocket.cpp index e389d50e..8530c3d3 100644 --- a/kernel/src/net/UnixSocket.cpp +++ b/kernel/src/net/UnixSocket.cpp @@ -1,4 +1,5 @@ #include "net/UnixSocket.h" +#include #include #include @@ -45,8 +46,8 @@ Result UnixSocket::send(const u8* buf, usize length, int) Result UnixSocket::recv(u8* buf, usize length, int) const { - if (m_state == State::Reset) return err(ECONNRESET); - if (m_state != State::Connected) return err(ENOTCONN); + if (m_state == State::Reset && !m_data.size()) return err(ECONNRESET); + if (m_state != State::Connected && m_state != State::Reset) return err(ENOTCONN); return m_data.dequeue_data(buf, length); } @@ -104,7 +105,100 @@ Result UnixSocket::bind(SharedPtr socket, struct sockaddr* addr, s return {}; } -Result UnixSocket::connect(struct sockaddr*, socklen_t) +Result UnixSocket::connect(Registers* regs, int flags, struct sockaddr* addr, socklen_t addrlen) { - return err(ENOSYS); + if (!addr) return err(EINVAL); + if (addr->sa_family != AF_UNIX) return err(EAFNOSUPPORT); + if ((usize)addrlen > sizeof(sockaddr_un)) return err(EINVAL); + + if (m_state == State::Connected) return err(EISCONN); + if (m_state == State::Connecting) return err(EALREADY); + if (m_state != State::Inactive) return err(EINVAL); + + struct sockaddr_un* un_address = (struct sockaddr_un*)addr; + + String path = TRY(String::from_string_view( + StringView::from_fixed_size_cstring(un_address->sun_path, addrlen - sizeof(sa_family_t)))); + + auto* current = Scheduler::current(); + + auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory)); + if (inode->type() != VFS::InodeType::Socket) + return err(ENOTSOCK); // FIXME: POSIX doesn't say what error to return here? + if (!VFS::can_write(inode, current->auth)) return err(EACCES); + + auto socket = (SharedPtr)inode; + if (socket->m_state != State::Listening) return err(ECONNREFUSED); + if (!socket->m_listen_queue.try_push(this)) return err(ECONNREFUSED); + if (socket->m_blocked_thread) socket->m_blocked_thread->wake_up(); + + m_state = Connecting; + if (flags & O_NONBLOCK) return err(EINPROGRESS); + + while (1) + { + m_blocked_thread = current; + kernel_wait_for_event(); + m_blocked_thread = nullptr; + if (current->interrupted) + { + if (current->will_invoke_signal_handler()) return err(EINTR); + current->process_pending_signals(regs); + continue; + } + break; + } + + check(m_state == Connected); + check(m_peer); + + return {}; +} + +Result UnixSocket::listen(int backlog) +{ + if (backlog < 0) backlog = 0; + if (m_state == State::Listening || m_state == State::Connected) return err(EINVAL); + if (m_state != State::Bound) return err(EDESTADDRREQ); + TRY(m_listen_queue.set_size(backlog)); + m_state = State::Listening; + return {}; +} + +Result> UnixSocket::accept(Registers* regs, int flags, struct sockaddr** addr, + socklen_t* addrlen) +{ + if (m_state != State::Listening) return err(EINVAL); + + auto* current = Scheduler::current(); + + UnixSocket* peer = nullptr; + while (!m_listen_queue.try_pop(peer)) + { + if (flags & O_NONBLOCK) return err(EAGAIN); + m_blocked_thread = current; + kernel_wait_for_event(); + m_blocked_thread = nullptr; + if (current->interrupted) + { + if (current->will_invoke_signal_handler()) return err(EINTR); + current->process_pending_signals(regs); + continue; + } + } + + check(peer); + + auto socket = TRY(make_shared(peer)); + auto description = TRY(make_shared(socket, O_RDWR)); + + peer->m_peer = socket.ptr(); + peer->m_state = State::Connected; + + if (peer->m_blocked_thread) peer->m_blocked_thread->wake_up(); + + *addr = (struct sockaddr*)&peer->m_addr; + *addrlen = peer->m_addrlen; + + return description; } diff --git a/kernel/src/net/UnixSocket.h b/kernel/src/net/UnixSocket.h index 0f376cbf..88c8150e 100644 --- a/kernel/src/net/UnixSocket.h +++ b/kernel/src/net/UnixSocket.h @@ -1,6 +1,8 @@ #pragma once #include "net/Socket.h" +#include "thread/Thread.h" #include +#include #include #include @@ -12,14 +14,17 @@ class UnixSocket : public Socket bool blocking() const override { - return !m_data.size(); + return (m_state == Connected || m_state == Reset) && !m_data.size(); } Result send(const u8*, usize, int) override; Result recv(u8*, usize, int) const override; Result bind(SharedPtr, struct sockaddr*, socklen_t) override; - Result connect(struct sockaddr*, socklen_t) override; + Result connect(Registers*, int, struct sockaddr*, socklen_t) override; + Result> accept(Registers*, int, struct sockaddr**, socklen_t*) override; + + Result listen(int backlog) override; void did_close() override; @@ -39,10 +44,14 @@ class UnixSocket : public Socket }; State m_state = State::Inactive; - UnixSocket* m_peer; + UnixSocket* m_peer = nullptr; mutable Buffer m_data; + Thread* m_blocked_thread { nullptr }; + + DynamicCircularQueue m_listen_queue; + struct sockaddr_un m_addr = { .sun_family = AF_UNIX, .sun_path = {} }; socklen_t m_addrlen = sizeof(sa_family_t); }; diff --git a/kernel/src/sys/socket.cpp b/kernel/src/sys/socket.cpp index d6d3ade7..eed20db2 100644 --- a/kernel/src/sys/socket.cpp +++ b/kernel/src/sys/socket.cpp @@ -47,3 +47,83 @@ Result sys_bind(Registers*, SyscallArgs args) return 0; } + +Result sys_connect(Registers* regs, SyscallArgs args) +{ + int sockfd = (int)args[0]; + struct sockaddr* addr = (struct sockaddr*)args[1]; + socklen_t addrlen = (socklen_t)args[2]; + + struct sockaddr_storage storage; + if ((usize)addrlen > sizeof(storage)) return err(EINVAL); + if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT); + + auto* current = Scheduler::current(); + + auto description = TRY(current->resolve_fd(sockfd))->description; + + if (description->inode->type() != VFS::InodeType::Socket) return err(ENOTSOCK); + + auto socket = (SharedPtr)description->inode; + + TRY(socket->connect(regs, description->flags, (struct sockaddr*)&storage, addrlen)); + + return 0; +} + +Result sys_listen(Registers*, SyscallArgs args) +{ + int sockfd = (int)args[0]; + int backlog = (int)args[1]; + + auto* current = Scheduler::current(); + + auto inode = TRY(current->resolve_fd(sockfd))->inode(); + + if (inode->type() != VFS::InodeType::Socket) return err(ENOTSOCK); + + auto socket = (SharedPtr)inode; + + TRY(socket->listen(backlog)); + + return 0; +} + +Result sys_accept(Registers* regs, SyscallArgs args) +{ + int sockfd = (int)args[0]; + struct sockaddr* addr = (struct sockaddr*)args[1]; + socklen_t* addrlen = (socklen_t*)args[2]; + + if (addr && !addrlen) return err(EINVAL); + + socklen_t len; + if (addr) + { + if (!MemoryManager::copy_from_user_typed(addrlen, &len)) return err(EFAULT); + } + + auto* current = Scheduler::current(); + + auto description = TRY(current->resolve_fd(sockfd))->description; + + if (description->inode->type() != VFS::InodeType::Socket) return err(ENOTSOCK); + + auto socket = (SharedPtr)description->inode; + + struct sockaddr* client; + socklen_t client_len; + auto new_description = TRY(socket->accept(regs, description->flags, &client, &client_len)); + + int fd = TRY(current->allocate_fd(0)); + current->fd_table[fd] = FileDescriptor { new_description, 0 }; + + if (client_len < len) len = client_len; + if (addr) + { + MemoryManager::copy_to_user(addr, client, len); + MemoryManager::copy_to_user_typed(addrlen, &client_len); + } + + return fd; +} diff --git a/libluna/include/luna/Syscall.h b/libluna/include/luna/Syscall.h index f82a9c72..b663a02d 100644 --- a/libluna/include/luna/Syscall.h +++ b/libluna/include/luna/Syscall.h @@ -7,7 +7,7 @@ _e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(pipe) _e(mount) \ _e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \ _e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \ - _e(getpgid) _e(socket) _e(bind) + _e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) enum Syscalls { -- 2.34.1 From 8d3b3aaf05abdbd7ba12f750fe757fd1b52bf398 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 28 Jul 2023 17:30:35 +0200 Subject: [PATCH 11/16] libluna: Add a few more network-related errno codes --- libluna/include/luna/SystemError.h | 117 +++++++++++++++-------------- libluna/src/SystemError.cpp | 10 +++ 2 files changed, 70 insertions(+), 57 deletions(-) diff --git a/libluna/include/luna/SystemError.h b/libluna/include/luna/SystemError.h index 43b2579c..1571a839 100644 --- a/libluna/include/luna/SystemError.h +++ b/libluna/include/luna/SystemError.h @@ -1,59 +1,62 @@ #pragma once -#define EPERM 1 // Operation not permitted -#define ENOENT 2 // No such file or directory -#define ESRCH 3 // No such process -#define EINTR 4 // Interrupted system call -#define EIO 5 // Input/output error -#define ENXIO 6 // No such device or address -#define E2BIG 7 // Argument list too long -#define ENOEXEC 8 // Exec format error -#define EBADF 9 // Bad file descriptor -#define ECHILD 10 // No child processes -#define EAGAIN 11 // Resource temporarily unavailable -#define EWOULDBLOCK 11 // Resource temporarily unavailable -#define ENOMEM 12 // Cannot allocate memory -#define EACCES 13 // Permission denied -#define EFAULT 14 // Bad address -#define ENOTBLK 15 // Block device required -#define EBUSY 16 // Device or resource busy -#define EEXIST 17 // File exists -#define EXDEV 18 // Invalid cross-device link -#define ENODEV 19 // No such device -#define ENOTDIR 20 // Not a directory -#define EISDIR 21 // Is a directory -#define EINVAL 22 // Invalid argument -#define ENFILE 23 // Too many open files in system -#define EMFILE 24 // Too many open files -#define ENOTTY 25 // Inappropriate ioctl for device -#define ETXTBSY 26 // Text file busy -#define EFBIG 27 // File too large -#define ENOSPC 28 // No space left on device -#define ESPIPE 29 // Illegal seek -#define EROFS 30 // Read-only file system -#define EMLINK 31 // Too many links -#define EPIPE 32 // Broken pipe -#define EDOM 33 // Numerical argument out of domain -#define ERANGE 34 // Numerical result out of range -#define EDEADLK 35 // Resource deadlock avoided -#define ENAMETOOLONG 36 // File name too long -#define ENOLCK 37 // No locks available -#define ENOSYS 38 // Function not implemented -#define ENOTEMPTY 39 // Directory not empty -#define ELOOP 40 // Too many levels of symbolic links -#define ENOMSG 42 // No message of desired type -#define EOVERFLOW 75 // Value too large for defined data type -#define EILSEQ 84 // Invalid or incomplete multibyte or wide character -#define ENOTSOCK 88 // Socket operation on non-socket -#define EDESTADDRREQ 89 // Destination address required -#define EPROTOTYPE 91 // Protocol wrong type for socket -#define ENOTSUP 95 // Operation not supported -#define EOPNOTSUPP 95 // Operation not supported -#define EAFNOSUPPORT 97 // Address family not supported by protocol -#define EADDRINUSE 98 // Address already in use -#define ENETRESET 102 // Network dropped connection on reset -#define ECONNRESET 104 // Connection reset by peer -#define EISCONN 106 // Transport endpoint is already connected -#define ENOTCONN 107 // Transport endpoint is not connected -#define ETIMEDOUT 110 // Connection timed out -#define EALREADY 114 // Operation already in progress +#define EPERM 1 // Operation not permitted +#define ENOENT 2 // No such file or directory +#define ESRCH 3 // No such process +#define EINTR 4 // Interrupted system call +#define EIO 5 // Input/output error +#define ENXIO 6 // No such device or address +#define E2BIG 7 // Argument list too long +#define ENOEXEC 8 // Exec format error +#define EBADF 9 // Bad file descriptor +#define ECHILD 10 // No child processes +#define EAGAIN 11 // Resource temporarily unavailable +#define EWOULDBLOCK 11 // Resource temporarily unavailable +#define ENOMEM 12 // Cannot allocate memory +#define EACCES 13 // Permission denied +#define EFAULT 14 // Bad address +#define ENOTBLK 15 // Block device required +#define EBUSY 16 // Device or resource busy +#define EEXIST 17 // File exists +#define EXDEV 18 // Invalid cross-device link +#define ENODEV 19 // No such device +#define ENOTDIR 20 // Not a directory +#define EISDIR 21 // Is a directory +#define EINVAL 22 // Invalid argument +#define ENFILE 23 // Too many open files in system +#define EMFILE 24 // Too many open files +#define ENOTTY 25 // Inappropriate ioctl for device +#define ETXTBSY 26 // Text file busy +#define EFBIG 27 // File too large +#define ENOSPC 28 // No space left on device +#define ESPIPE 29 // Illegal seek +#define EROFS 30 // Read-only file system +#define EMLINK 31 // Too many links +#define EPIPE 32 // Broken pipe +#define EDOM 33 // Numerical argument out of domain +#define ERANGE 34 // Numerical result out of range +#define EDEADLK 35 // Resource deadlock avoided +#define ENAMETOOLONG 36 // File name too long +#define ENOLCK 37 // No locks available +#define ENOSYS 38 // Function not implemented +#define ENOTEMPTY 39 // Directory not empty +#define ELOOP 40 // Too many levels of symbolic links +#define ENOMSG 42 // No message of desired type +#define EOVERFLOW 75 // Value too large for defined data type +#define EILSEQ 84 // Invalid or incomplete multibyte or wide character +#define ENOTSOCK 88 // Socket operation on non-socket +#define EDESTADDRREQ 89 // Destination address required +#define EPROTOTYPE 91 // Protocol wrong type for socket +#define ENOTSUP 95 // Operation not supported +#define EOPNOTSUPP 95 // Operation not supported +#define EAFNOSUPPORT 97 // Address family not supported by protocol +#define EADDRINUSE 98 // Address already in use +#define EADDRNOTAVAIL 99 // Cannot assign requested address +#define ENETRESET 102 // Network dropped connection on reset +#define ECONNRESET 104 // Connection reset by peer +#define EISCONN 106 // Transport endpoint is already connected +#define ENOTCONN 107 // Transport endpoint is not connected +#define ETIMEDOUT 110 // Connection timed out +#define ECONNREFUSED 111 // Connection refused +#define EALREADY 114 // Operation already in progress +#define EINPROGRESS 115 // Operation now in progress diff --git a/libluna/src/SystemError.cpp b/libluna/src/SystemError.cpp index 744ae86d..3e669f54 100644 --- a/libluna/src/SystemError.cpp +++ b/libluna/src/SystemError.cpp @@ -60,6 +60,9 @@ const char* error_string(int error) case EPROTOTYPE: return "Protocol wrong type for socket"; case EAFNOSUPPORT: return "Address family not supported by protocol"; case ENOTCONN: return "Transport endpoint is not connected"; + case EADDRNOTAVAIL: return "Cannot assign requested address"; + case ECONNREFUSED: return "Connection refused"; + case EINPROGRESS: return "Operation now in progress"; default: return "Unknown error"; } } @@ -122,6 +125,13 @@ const char* error_name(int error) ERROR(EISCONN); ERROR(ETIMEDOUT); ERROR(EALREADY); + ERROR(EDESTADDRREQ); + ERROR(EPROTOTYPE); + ERROR(EAFNOSUPPORT); + ERROR(ENOTCONN); + ERROR(EADDRNOTAVAIL); + ERROR(ECONNREFUSED); + ERROR(EINPROGRESS); default: return nullptr; } -- 2.34.1 From 7b24a4d1c6d1ecf4ce237496d24eb8fd13316da5 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 28 Jul 2023 17:30:59 +0200 Subject: [PATCH 12/16] libc: Add wrappers for listen(), connect(), and accept() --- libc/include/sys/socket.h | 9 +++++++++ libc/src/sys/socket.cpp | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h index 5183e974..07f918dd 100644 --- a/libc/include/sys/socket.h +++ b/libc/include/sys/socket.h @@ -16,6 +16,15 @@ extern "C" /* Bind a socket to an address. */ int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen); + /* Connect a socket to a remote address. */ + int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen); + + /* Start listening on a socket. */ + int listen(int sockfd, int backlog); + + /* Wait for an incoming connection on a socket. */ + int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen); + #ifdef __cplusplus } #endif diff --git a/libc/src/sys/socket.cpp b/libc/src/sys/socket.cpp index 686d4da7..1f8432a4 100644 --- a/libc/src/sys/socket.cpp +++ b/libc/src/sys/socket.cpp @@ -16,4 +16,22 @@ extern "C" long rc = syscall(SYS_bind, sockfd, addr, addrlen); __errno_return(rc, int); } + + int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen) + { + long rc = syscall(SYS_connect, sockfd, addr, addrlen); + __errno_return(rc, int); + } + + int listen(int sockfd, int backlog) + { + long rc = syscall(SYS_listen, sockfd, backlog); + __errno_return(rc, int); + } + + int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen) + { + long rc = syscall(SYS_accept, sockfd, addr, addrlen); + __errno_return(rc, int); + } } -- 2.34.1 From 63745565db5e5c26a5b982d00654c15ba82223a8 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 28 Jul 2023 17:31:27 +0200 Subject: [PATCH 13/16] apps: Add socket client --- apps/CMakeLists.txt | 1 + apps/socket-client.cpp | 40 ++++++++++++++++++++++++++++++++ apps/socket-test.cpp | 51 +++++++++++++++++++++++++++++++++++++++++ base/etc/init/98-listen | 6 +++++ 4 files changed, 98 insertions(+) create mode 100644 apps/socket-client.cpp create mode 100644 base/etc/init/98-listen diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index a892f745..2b86ec4a 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -43,3 +43,4 @@ luna_app(kill.cpp kill) luna_app(gol.cpp gol) luna_app(buffer-test.cpp buffer-test) luna_app(socket-test.cpp socket-test) +luna_app(socket-client.cpp socket-client) diff --git a/apps/socket-client.cpp b/apps/socket-client.cpp new file mode 100644 index 00000000..67d2f3d2 --- /dev/null +++ b/apps/socket-client.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +int main() +{ + int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) + { + perror("socket"); + return 0; + } + + struct sockaddr_un un; + un.sun_family = AF_UNIX; + strncpy(un.sun_path, "/tmp/local.sock", sizeof(un.sun_path)); + + if (connect(sockfd, (struct sockaddr*)&un, sizeof(un)) < 0) + { + perror("connect"); + return 1; + } + + char buf[4096]; + ssize_t nread = read(sockfd, buf, sizeof(buf) - 1); + if (nread > 0) + { + buf[nread] = 0; + printf("Message from server: %s\n", buf); + } + + const char* message = "EXIT"; + write(sockfd, message, strlen(message)); + + close(sockfd); + + return 0; +} diff --git a/apps/socket-test.cpp b/apps/socket-test.cpp index 3907ec3c..b4279c17 100644 --- a/apps/socket-test.cpp +++ b/apps/socket-test.cpp @@ -1,10 +1,18 @@ +#include #include #include #include +#include #include +#include int main() { + setgid(1000); + setuid(1000); + + remove("/tmp/local.sock"); + int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd < 0) { @@ -21,4 +29,47 @@ int main() perror("bind"); return 1; } + + if (listen(sockfd, 10) < 0) + { + perror("listen"); + return 1; + } + + while (1) + { + int fd = accept(sockfd, NULL, NULL); + if (fd < 0) + { + perror("accept"); + return 1; + } + + puts("New connection from client, sending hello"); + + const char* message = "Hello, client!"; + write(fd, message, strlen(message)); + + puts("Now waiting for client to message back"); + + char buf[4096]; + ssize_t nread = read(fd, buf, sizeof(buf) - 1); + if (nread >= 0) + { + buf[nread] = 0; + printf("Message from client: %s\n", buf); + if (!strcasecmp(buf, "exit")) + { + close(fd); + close(sockfd); + remove("/tmp/local.sock"); + return 0; + } + } + else { printf("Error reading from client: %s\n", strerror(errno)); } + + puts("Transmission ended, closing connection"); + + close(fd); + } } diff --git a/base/etc/init/98-listen b/base/etc/init/98-listen new file mode 100644 index 00000000..a27cf204 --- /dev/null +++ b/base/etc/init/98-listen @@ -0,0 +1,6 @@ +Name=listen +Description=Start a Unix domain socket test server. +Command=/usr/bin/socket-test +StandardOutput=/dev/uart0 +StandardError=/dev/uart0 +Restart=true -- 2.34.1 From 0c873923e8a7135774b216679f6942cced318c1c Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 30 Jul 2023 11:33:46 +0200 Subject: [PATCH 14/16] kernel: Make OpenFileDescription shareable --- kernel/src/thread/Thread.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h index 1e5db949..98014448 100644 --- a/kernel/src/thread/Thread.h +++ b/kernel/src/thread/Thread.h @@ -28,7 +28,7 @@ enum class ThreadState Dying }; -struct OpenFileDescription +struct OpenFileDescription : public Shareable { SharedPtr inode; int flags { 0 }; -- 2.34.1 From 187f0ff83ed71bf31e53db089b57726e596a4550 Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 30 Jul 2023 11:41:53 +0200 Subject: [PATCH 15/16] kernel: Rename Inode::blocking() to Inode::will_block_if_read() --- kernel/src/arch/x86_64/disk/ATA.h | 2 +- kernel/src/fs/MBR.h | 2 +- kernel/src/fs/Mount.h | 2 +- kernel/src/fs/Pipe.cpp | 2 +- kernel/src/fs/Pipe.h | 6 +++--- kernel/src/fs/VFS.h | 4 ++-- kernel/src/fs/devices/ConsoleDevice.cpp | 2 +- kernel/src/fs/devices/ConsoleDevice.h | 2 +- kernel/src/fs/devices/Device.h | 2 +- kernel/src/fs/devices/FramebufferDevice.cpp | 2 +- kernel/src/fs/devices/FramebufferDevice.h | 2 +- kernel/src/fs/devices/FullDevice.h | 2 +- kernel/src/fs/devices/NullDevice.h | 2 +- kernel/src/fs/devices/UARTDevice.h | 2 +- kernel/src/fs/devices/ZeroDevice.h | 2 +- kernel/src/fs/ext2/Inode.h | 2 +- kernel/src/fs/tmpfs/Inode.h | 6 +++--- kernel/src/net/UnixSocket.h | 2 +- kernel/src/sys/file.cpp | 2 +- 19 files changed, 24 insertions(+), 24 deletions(-) diff --git a/kernel/src/arch/x86_64/disk/ATA.h b/kernel/src/arch/x86_64/disk/ATA.h index 6b3e367d..2cc4bc0b 100644 --- a/kernel/src/arch/x86_64/disk/ATA.h +++ b/kernel/src/arch/x86_64/disk/ATA.h @@ -310,7 +310,7 @@ class ATADevice : public Device return err(ENOTSUP); } - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/fs/MBR.h b/kernel/src/fs/MBR.h index 7203febb..184a339c 100644 --- a/kernel/src/fs/MBR.h +++ b/kernel/src/fs/MBR.h @@ -41,7 +41,7 @@ namespace MBR Result write(const u8* buf, usize offset, usize length) override; - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/fs/Mount.h b/kernel/src/fs/Mount.h index e3f74faf..bb8ee36d 100644 --- a/kernel/src/fs/Mount.h +++ b/kernel/src/fs/Mount.h @@ -37,7 +37,7 @@ class MountInode : public VFS::Inode, public LinkedListNode return err(EISDIR); } - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/fs/Pipe.cpp b/kernel/src/fs/Pipe.cpp index 5b232b7b..edbb180f 100644 --- a/kernel/src/fs/Pipe.cpp +++ b/kernel/src/fs/Pipe.cpp @@ -46,7 +46,7 @@ Result Pipe::write(const u8* buf, usize, usize length) return length; } -bool Pipe::blocking() const +bool Pipe::will_block_if_read() const { return !m_data_buffer.size() && m_writer; } diff --git a/kernel/src/fs/Pipe.h b/kernel/src/fs/Pipe.h index e84368ef..76bc0d73 100644 --- a/kernel/src/fs/Pipe.h +++ b/kernel/src/fs/Pipe.h @@ -15,7 +15,7 @@ class Pipe : public Shareable Result write(const u8* buf, usize, usize length); - bool blocking() const; + bool will_block_if_read() const; private: Buffer m_data_buffer; @@ -40,9 +40,9 @@ class PipeInodeBase : public VFS::FileInode return err(ENOTSUP); } - bool blocking() const override + bool will_block_if_read() const override { - return m_pipe->blocking(); + return m_pipe->will_block_if_read(); } usize size() const override diff --git a/kernel/src/fs/VFS.h b/kernel/src/fs/VFS.h index c0959394..e7dff461 100644 --- a/kernel/src/fs/VFS.h +++ b/kernel/src/fs/VFS.h @@ -120,7 +120,7 @@ namespace VFS virtual Result truncate(usize size) = 0; - virtual bool blocking() const = 0; + virtual bool will_block_if_read() const = 0; // Symlink-specific methods virtual Result readlink() @@ -231,7 +231,7 @@ namespace VFS return 0; } - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/fs/devices/ConsoleDevice.cpp b/kernel/src/fs/devices/ConsoleDevice.cpp index 0d469c65..5b21e486 100644 --- a/kernel/src/fs/devices/ConsoleDevice.cpp +++ b/kernel/src/fs/devices/ConsoleDevice.cpp @@ -64,7 +64,7 @@ Result ConsoleDevice::write(const u8* buf, usize, usize length) return length; } -bool ConsoleDevice::blocking() const +bool ConsoleDevice::will_block_if_read() const { return m_may_read_without_blocking ? false : m_input_buffer.size() == 0; } diff --git a/kernel/src/fs/devices/ConsoleDevice.h b/kernel/src/fs/devices/ConsoleDevice.h index 0408a9e8..d6b7d186 100644 --- a/kernel/src/fs/devices/ConsoleDevice.h +++ b/kernel/src/fs/devices/ConsoleDevice.h @@ -16,7 +16,7 @@ class ConsoleDevice : public Device static void did_press_or_release_key(u8 scancode); - bool blocking() const override; + bool will_block_if_read() const override; Result ioctl(int request, void* arg) override; diff --git a/kernel/src/fs/devices/Device.h b/kernel/src/fs/devices/Device.h index e72a9e24..130aec8d 100644 --- a/kernel/src/fs/devices/Device.h +++ b/kernel/src/fs/devices/Device.h @@ -41,7 +41,7 @@ class Device : public Shareable // Path in devfs. virtual StringView device_path() const = 0; - virtual bool blocking() const = 0; + virtual bool will_block_if_read() const = 0; virtual ~Device() = default; }; diff --git a/kernel/src/fs/devices/FramebufferDevice.cpp b/kernel/src/fs/devices/FramebufferDevice.cpp index c42b8904..23ab7b32 100644 --- a/kernel/src/fs/devices/FramebufferDevice.cpp +++ b/kernel/src/fs/devices/FramebufferDevice.cpp @@ -28,7 +28,7 @@ usize FramebufferDevice::size() const return Framebuffer::size(); } -bool FramebufferDevice::blocking() const +bool FramebufferDevice::will_block_if_read() const { return false; } diff --git a/kernel/src/fs/devices/FramebufferDevice.h b/kernel/src/fs/devices/FramebufferDevice.h index 4bf2928c..76b5ebb7 100644 --- a/kernel/src/fs/devices/FramebufferDevice.h +++ b/kernel/src/fs/devices/FramebufferDevice.h @@ -11,7 +11,7 @@ class FramebufferDevice : public Device Result write(const u8*, usize, usize) override; - bool blocking() const override; + bool will_block_if_read() const override; bool is_block_device() const override { diff --git a/kernel/src/fs/devices/FullDevice.h b/kernel/src/fs/devices/FullDevice.h index 9102db20..fa9e67b9 100644 --- a/kernel/src/fs/devices/FullDevice.h +++ b/kernel/src/fs/devices/FullDevice.h @@ -19,7 +19,7 @@ class FullDevice : public Device return err(ENOSPC); } - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/fs/devices/NullDevice.h b/kernel/src/fs/devices/NullDevice.h index 9f434718..fd245edb 100644 --- a/kernel/src/fs/devices/NullDevice.h +++ b/kernel/src/fs/devices/NullDevice.h @@ -17,7 +17,7 @@ class NullDevice : public Device return 0; } - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/fs/devices/UARTDevice.h b/kernel/src/fs/devices/UARTDevice.h index 7c2bed02..24017130 100644 --- a/kernel/src/fs/devices/UARTDevice.h +++ b/kernel/src/fs/devices/UARTDevice.h @@ -14,7 +14,7 @@ class UARTDevice : public Device Result write(const u8*, usize, usize) override; - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/fs/devices/ZeroDevice.h b/kernel/src/fs/devices/ZeroDevice.h index 8b2fed80..98fb20e8 100644 --- a/kernel/src/fs/devices/ZeroDevice.h +++ b/kernel/src/fs/devices/ZeroDevice.h @@ -19,7 +19,7 @@ class ZeroDevice : public Device return 0; } - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/fs/ext2/Inode.h b/kernel/src/fs/ext2/Inode.h index 2f7a2484..5c9c0c7c 100644 --- a/kernel/src/fs/ext2/Inode.h +++ b/kernel/src/fs/ext2/Inode.h @@ -122,7 +122,7 @@ namespace Ext2 return m_entries.size(); } - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/fs/tmpfs/Inode.h b/kernel/src/fs/tmpfs/Inode.h index e2815a91..cdf87f70 100644 --- a/kernel/src/fs/tmpfs/Inode.h +++ b/kernel/src/fs/tmpfs/Inode.h @@ -281,9 +281,9 @@ namespace TmpFS return m_device->isatty(); } - bool blocking() const override + bool will_block_if_read() const override { - return m_device->blocking(); + return m_device->will_block_if_read(); } usize size() const override @@ -385,7 +385,7 @@ namespace TmpFS return err(EISDIR); } - bool blocking() const override + bool will_block_if_read() const override { return false; } diff --git a/kernel/src/net/UnixSocket.h b/kernel/src/net/UnixSocket.h index 88c8150e..9d8114d5 100644 --- a/kernel/src/net/UnixSocket.h +++ b/kernel/src/net/UnixSocket.h @@ -12,7 +12,7 @@ class UnixSocket : public Socket UnixSocket(); UnixSocket(UnixSocket* peer); - bool blocking() const override + bool will_block_if_read() const override { return (m_state == Connected || m_state == Reset) && !m_data.size(); } diff --git a/kernel/src/sys/file.cpp b/kernel/src/sys/file.cpp index 75403566..6a7d2ddd 100644 --- a/kernel/src/sys/file.cpp +++ b/kernel/src/sys/file.cpp @@ -26,7 +26,7 @@ Result sys_read(Registers* regs, SyscallArgs args) if (!descriptor.is_readable()) return err(EBADF); - while (descriptor.inode()->blocking()) + while (descriptor.inode()->will_block_if_read()) { if (descriptor.should_block()) kernel_sleep(10); else -- 2.34.1 From 8475a3aad93e7cdd080acd5d96cf05a929a2868e Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 30 Jul 2023 11:46:53 +0200 Subject: [PATCH 16/16] socket-client: Send a user-provided message to the server --- apps/socket-client.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/socket-client.cpp b/apps/socket-client.cpp index 67d2f3d2..9ea4fd29 100644 --- a/apps/socket-client.cpp +++ b/apps/socket-client.cpp @@ -1,11 +1,20 @@ +#include #include #include #include #include #include -int main() +Result luna_main(int argc, char** argv) { + StringView message; + + os::ArgumentParser parser; + parser.add_description("A UNIX domain socket client, to test said sockets."); + parser.add_system_program_info("socket-client"_sv); + parser.add_positional_argument(message, "message"_sv, "exit"_sv); + parser.parse(argc, argv); + int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd < 0) { @@ -31,8 +40,7 @@ int main() printf("Message from server: %s\n", buf); } - const char* message = "EXIT"; - write(sockfd, message, strlen(message)); + write(sockfd, message.chars(), message.length()); close(sockfd); -- 2.34.1