Kernel: Make nonblocking sockets unblocking :)

This commit is contained in:
Bananymous 2025-04-05 18:42:02 +03:00
parent c9132d984b
commit 15045cc486
5 changed files with 62 additions and 50 deletions

View File

@ -169,6 +169,7 @@ namespace Kernel
private:
BAN::WeakPtr<SharedFileData> m_shared_region;
friend class FileBackedRegion;
friend class OpenFileDescriptorSet;
friend class SharedFileData;
friend class TTY;
};

View File

@ -47,6 +47,9 @@ namespace Kernel
BAN::ErrorOr<size_t> read_dir_entries(int fd, struct dirent* list, size_t list_len);
BAN::ErrorOr<size_t> recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<size_t> sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<VirtualFileSystem::File> file_of(int) const;
BAN::ErrorOr<BAN::StringView> path_of(int) const;
BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);

View File

@ -226,51 +226,33 @@ namespace Kernel
BAN::ErrorOr<size_t> TCPSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len)
{
(void)address;
(void)address_len;
if (address)
return BAN::Error::from_errno(EISCONN);
if (!m_has_connected)
return BAN::Error::from_errno(ENOTCONN);
if (message.size() > m_send_window.buffer->size())
{
size_t nsent = 0;
while (nsent < message.size())
{
const size_t to_send = BAN::Math::min<size_t>(message.size() - nsent, m_send_window.buffer->size());
TRY(sendto_impl(message.slice(nsent, to_send), address, address_len));
nsent += to_send;
}
return nsent;
}
while (true)
while (m_send_window.data_size == m_send_window.buffer->size())
{
if (m_state != State::Established)
return return_with_maybe_zero();
if (m_send_window.data_size + message.size() <= m_send_window.buffer->size())
break;
LockFreeGuard free(m_mutex);
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
}
const size_t to_send = BAN::Math::min<size_t>(message.size(), m_send_window.buffer->size() - m_send_window.data_size);
{
auto* buffer = reinterpret_cast<uint8_t*>(m_send_window.buffer->vaddr());
memcpy(buffer + m_send_window.data_size, message.data(), message.size());
m_send_window.data_size += message.size();
memcpy(buffer + m_send_window.data_size, message.data(), to_send);
m_send_window.data_size += to_send;
}
const uint32_t target_ack = m_send_window.start_seq + m_send_window.data_size;
m_thread_blocker.unblock();
while (m_send_window.current_ack < target_ack)
{
if (m_state != State::Established)
return return_with_maybe_zero();
LockFreeGuard free(m_mutex);
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
}
return message.size();
return to_send;
}
bool TCPSocket::can_read_impl() const

View File

@ -1,5 +1,6 @@
#include <kernel/FS/Pipe.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Networking/NetworkManager.h>
#include <kernel/OpenFileDescriptorSet.h>
@ -298,11 +299,13 @@ namespace Kernel
{
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (open_file.inode()->mode().ifsock())
return recvfrom(fd, buffer, nullptr, nullptr);
if (!(open_file.status_flags() & O_RDONLY))
return BAN::Error::from_errno(EBADF);
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read())
return 0;
size_t nread = TRY(open_file.inode()->read(open_file.offset(), buffer));
const size_t nread = TRY(open_file.inode()->read(open_file.offset(), buffer));
open_file.offset() += nread;
return nread;
}
@ -311,13 +314,15 @@ namespace Kernel
{
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (open_file.inode()->mode().ifsock())
return sendto(fd, buffer, nullptr, 0);
if (!(open_file.status_flags() & O_WRONLY))
return BAN::Error::from_errno(EBADF);
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write())
return 0;
return BAN::Error::from_errno(EWOULDBLOCK);
if (open_file.status_flags() & O_APPEND)
open_file.offset() = open_file.inode()->size();
size_t nwrite = TRY(open_file.inode()->write(open_file.offset(), buffer));
const size_t nwrite = TRY(open_file.inode()->write(open_file.offset(), buffer));
open_file.offset() += nwrite;
return nwrite;
}
@ -340,6 +345,43 @@ namespace Kernel
}
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len)
{
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (!open_file.inode()->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
LockGuard _(open_file.inode()->m_mutex);
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read())
return BAN::Error::from_errno(EWOULDBLOCK);
return open_file.inode()->recvfrom(buffer, address, address_len);
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len)
{
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (!open_file.inode()->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write())
return BAN::Error::from_errno(EWOULDBLOCK);
LockGuard _(open_file.inode()->m_mutex);
size_t total_sent = 0;
while (total_sent < buffer.size())
{
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write())
return total_sent;
const size_t nsend = TRY(open_file.inode()->sendto(buffer.slice(total_sent), address, address_len));
if (nsend == 0)
return 0;
total_sent += nsend;
}
return total_sent;
}
BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const
{
TRY(validate_fd(fd));

View File

@ -1321,16 +1321,8 @@ namespace Kernel
TRY(validate_pointer_access(arguments->message, arguments->length, false));
TRY(validate_pointer_access(arguments->dest_addr, arguments->dest_len, false));
auto inode = TRY(m_open_file_descriptors.inode_of(arguments->socket));
if (!inode->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
const auto status_flags = TRY(m_open_file_descriptors.status_flags_of(arguments->socket));
if ((status_flags & O_NONBLOCK) && !inode->can_write())
return BAN::Error::from_errno(EAGAIN);
BAN::ConstByteSpan message { reinterpret_cast<const uint8_t*>(arguments->message), arguments->length };
return TRY(inode->sendto(message, arguments->dest_addr, arguments->dest_len));
auto message = BAN::ConstByteSpan(static_cast<const uint8_t*>(arguments->message), arguments->length);
return TRY(m_open_file_descriptors.sendto(arguments->socket, message, arguments->dest_addr, arguments->dest_len));
}
BAN::ErrorOr<long> Process::sys_recvfrom(sys_recvfrom_t* arguments)
@ -1349,16 +1341,8 @@ namespace Kernel
TRY(validate_pointer_access(arguments->address, *arguments->address_len, true));
}
auto inode = TRY(m_open_file_descriptors.inode_of(arguments->socket));
if (!inode->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
const auto status_flags = TRY(m_open_file_descriptors.status_flags_of(arguments->socket));
if ((status_flags & O_NONBLOCK) && !inode->can_read())
return BAN::Error::from_errno(EAGAIN);
BAN::ByteSpan buffer { reinterpret_cast<uint8_t*>(arguments->buffer), arguments->length };
return TRY(inode->recvfrom(buffer, arguments->address, arguments->address_len));
auto message = BAN::ByteSpan(static_cast<uint8_t*>(arguments->buffer), arguments->length);
return TRY(m_open_file_descriptors.recvfrom(arguments->socket, message, arguments->address, arguments->address_len));
}
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg)