Kernel: Make nonblocking sockets unblocking :)
This commit is contained in:
parent
c9132d984b
commit
15045cc486
|
@ -169,6 +169,7 @@ namespace Kernel
|
||||||
private:
|
private:
|
||||||
BAN::WeakPtr<SharedFileData> m_shared_region;
|
BAN::WeakPtr<SharedFileData> m_shared_region;
|
||||||
friend class FileBackedRegion;
|
friend class FileBackedRegion;
|
||||||
|
friend class OpenFileDescriptorSet;
|
||||||
friend class SharedFileData;
|
friend class SharedFileData;
|
||||||
friend class TTY;
|
friend class TTY;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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> 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<VirtualFileSystem::File> file_of(int) const;
|
||||||
BAN::ErrorOr<BAN::StringView> path_of(int) const;
|
BAN::ErrorOr<BAN::StringView> path_of(int) const;
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);
|
BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);
|
||||||
|
|
|
@ -226,51 +226,33 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> TCPSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len)
|
BAN::ErrorOr<size_t> TCPSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len)
|
||||||
{
|
{
|
||||||
|
(void)address;
|
||||||
|
(void)address_len;
|
||||||
|
|
||||||
if (address)
|
if (address)
|
||||||
return BAN::Error::from_errno(EISCONN);
|
return BAN::Error::from_errno(EISCONN);
|
||||||
if (!m_has_connected)
|
if (!m_has_connected)
|
||||||
return BAN::Error::from_errno(ENOTCONN);
|
return BAN::Error::from_errno(ENOTCONN);
|
||||||
|
|
||||||
if (message.size() > m_send_window.buffer->size())
|
while (m_send_window.data_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)
|
|
||||||
{
|
{
|
||||||
if (m_state != State::Established)
|
if (m_state != State::Established)
|
||||||
return return_with_maybe_zero();
|
return return_with_maybe_zero();
|
||||||
if (m_send_window.data_size + message.size() <= m_send_window.buffer->size())
|
|
||||||
break;
|
|
||||||
LockFreeGuard free(m_mutex);
|
LockFreeGuard free(m_mutex);
|
||||||
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
|
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());
|
auto* buffer = reinterpret_cast<uint8_t*>(m_send_window.buffer->vaddr());
|
||||||
memcpy(buffer + m_send_window.data_size, message.data(), message.size());
|
memcpy(buffer + m_send_window.data_size, message.data(), to_send);
|
||||||
m_send_window.data_size += message.size();
|
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();
|
m_thread_blocker.unblock();
|
||||||
|
|
||||||
while (m_send_window.current_ack < target_ack)
|
return to_send;
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TCPSocket::can_read_impl() const
|
bool TCPSocket::can_read_impl() const
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <kernel/FS/Pipe.h>
|
#include <kernel/FS/Pipe.h>
|
||||||
#include <kernel/FS/VirtualFileSystem.h>
|
#include <kernel/FS/VirtualFileSystem.h>
|
||||||
|
#include <kernel/Lock/LockGuard.h>
|
||||||
#include <kernel/Networking/NetworkManager.h>
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
#include <kernel/OpenFileDescriptorSet.h>
|
#include <kernel/OpenFileDescriptorSet.h>
|
||||||
|
|
||||||
|
@ -298,11 +299,13 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
auto& open_file = m_open_files[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))
|
if (!(open_file.status_flags() & O_RDONLY))
|
||||||
return BAN::Error::from_errno(EBADF);
|
return BAN::Error::from_errno(EBADF);
|
||||||
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read())
|
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read())
|
||||||
return 0;
|
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;
|
open_file.offset() += nread;
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
@ -311,13 +314,15 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
auto& open_file = m_open_files[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))
|
if (!(open_file.status_flags() & O_WRONLY))
|
||||||
return BAN::Error::from_errno(EBADF);
|
return BAN::Error::from_errno(EBADF);
|
||||||
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write())
|
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)
|
if (open_file.status_flags() & O_APPEND)
|
||||||
open_file.offset() = open_file.inode()->size();
|
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;
|
open_file.offset() += nwrite;
|
||||||
return 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
|
BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
|
|
|
@ -1321,16 +1321,8 @@ namespace Kernel
|
||||||
TRY(validate_pointer_access(arguments->message, arguments->length, false));
|
TRY(validate_pointer_access(arguments->message, arguments->length, false));
|
||||||
TRY(validate_pointer_access(arguments->dest_addr, arguments->dest_len, false));
|
TRY(validate_pointer_access(arguments->dest_addr, arguments->dest_len, false));
|
||||||
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(arguments->socket));
|
auto message = BAN::ConstByteSpan(static_cast<const uint8_t*>(arguments->message), arguments->length);
|
||||||
if (!inode->mode().ifsock())
|
return TRY(m_open_file_descriptors.sendto(arguments->socket, message, arguments->dest_addr, arguments->dest_len));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_recvfrom(sys_recvfrom_t* arguments)
|
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));
|
TRY(validate_pointer_access(arguments->address, *arguments->address_len, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(arguments->socket));
|
auto message = BAN::ByteSpan(static_cast<uint8_t*>(arguments->buffer), arguments->length);
|
||||||
if (!inode->mode().ifsock())
|
return TRY(m_open_file_descriptors.recvfrom(arguments->socket, message, arguments->address, arguments->address_len));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg)
|
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg)
|
||||||
|
|
Loading…
Reference in New Issue