Compare commits
6 Commits
34e680d792
...
f2e41f71d6
Author | SHA1 | Date |
---|---|---|
|
f2e41f71d6 | |
|
3a11a5a9a0 | |
|
f8e3ae0525 | |
|
c790bad667 | |
|
d54489bbcb | |
|
808c97020a |
|
@ -3,8 +3,7 @@
|
||||||
#include <BAN/UniqPtr.h>
|
#include <BAN/UniqPtr.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
|
#include <kernel/ThreadBlocker.h>
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -42,6 +41,10 @@ namespace Kernel
|
||||||
size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); }
|
size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); }
|
||||||
size_t physical_page_count() const { return m_physical_page_count; }
|
size_t physical_page_count() const { return m_physical_page_count; }
|
||||||
|
|
||||||
|
void pin() { m_pinned_count++; }
|
||||||
|
void unpin() { if (--m_pinned_count == 0) m_pinned_blocker.unblock(); }
|
||||||
|
void wait_not_pinned() { while (m_pinned_count) m_pinned_blocker.block_with_timeout_ms(100); }
|
||||||
|
|
||||||
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0;
|
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0;
|
||||||
|
|
||||||
// Returns error if no memory was available
|
// Returns error if no memory was available
|
||||||
|
@ -64,6 +67,9 @@ namespace Kernel
|
||||||
const PageTable::flags_t m_flags;
|
const PageTable::flags_t m_flags;
|
||||||
vaddr_t m_vaddr { 0 };
|
vaddr_t m_vaddr { 0 };
|
||||||
size_t m_physical_page_count { 0 };
|
size_t m_physical_page_count { 0 };
|
||||||
|
|
||||||
|
BAN::Atomic<size_t> m_pinned_count { 0 };
|
||||||
|
ThreadBlocker m_pinned_blocker;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace Kernel
|
||||||
BAN::ErrorOr<size_t> sendto(int fd, BAN::ConstByteSpan buffer, const 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::String> path_of(int) const;
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);
|
BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);
|
||||||
BAN::ErrorOr<int> status_flags_of(int) const;
|
BAN::ErrorOr<int> status_flags_of(int) const;
|
||||||
|
|
||||||
|
@ -98,6 +98,7 @@ namespace Kernel
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Credentials& m_credentials;
|
const Credentials& m_credentials;
|
||||||
|
mutable Mutex m_mutex;
|
||||||
|
|
||||||
BAN::Array<OpenFile, OPEN_MAX> m_open_files;
|
BAN::Array<OpenFile, OPEN_MAX> m_open_files;
|
||||||
};
|
};
|
||||||
|
|
|
@ -241,6 +241,7 @@ namespace Kernel
|
||||||
BAN::ErrorOr<void> validate_string_access(const char*);
|
BAN::ErrorOr<void> validate_string_access(const char*);
|
||||||
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write);
|
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write);
|
||||||
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write);
|
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write);
|
||||||
|
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
|
||||||
|
|
||||||
uint64_t signal_pending_mask() const
|
uint64_t signal_pending_mask() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,7 +53,8 @@ namespace Kernel
|
||||||
// Returns true if pending signal can be added to thread
|
// Returns true if pending signal can be added to thread
|
||||||
bool can_add_signal_to_execute() const;
|
bool can_add_signal_to_execute() const;
|
||||||
bool will_execute_signal() const;
|
bool will_execute_signal() const;
|
||||||
void handle_signal(int signal = 0);
|
// Returns true if handled signal had SA_RESTART
|
||||||
|
bool handle_signal(int signal = 0);
|
||||||
bool add_signal(int signal);
|
bool add_signal(int signal);
|
||||||
|
|
||||||
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout
|
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace Kernel
|
||||||
|
|
||||||
MemoryRegion::~MemoryRegion()
|
MemoryRegion::~MemoryRegion()
|
||||||
{
|
{
|
||||||
|
ASSERT(m_pinned_count == 0);
|
||||||
if (m_vaddr)
|
if (m_vaddr)
|
||||||
m_page_table.unmap_range(m_vaddr, m_size);
|
m_page_table.unmap_range(m_vaddr, m_size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,10 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
auto& connection_info = m_info.get<ConnectionInfo>();
|
auto& connection_info = m_info.get<ConnectionInfo>();
|
||||||
if (auto connection = connection_info.connection.lock(); connection && connection->m_info.has<ConnectionInfo>())
|
if (auto connection = connection_info.connection.lock(); connection && connection->m_info.has<ConnectionInfo>())
|
||||||
|
{
|
||||||
connection->m_info.get<ConnectionInfo>().target_closed = true;
|
connection->m_info.get<ConnectionInfo>().target_closed = true;
|
||||||
|
connection->m_packet_thread_blocker.unblock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,19 +354,19 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> UnixDomainSocket::recvfrom_impl(BAN::ByteSpan buffer, sockaddr*, socklen_t*)
|
BAN::ErrorOr<size_t> UnixDomainSocket::recvfrom_impl(BAN::ByteSpan buffer, sockaddr*, socklen_t*)
|
||||||
{
|
{
|
||||||
if (m_info.has<ConnectionInfo>())
|
|
||||||
{
|
|
||||||
auto& connection_info = m_info.get<ConnectionInfo>();
|
|
||||||
bool expected = true;
|
|
||||||
if (connection_info.target_closed.compare_exchange(expected, false))
|
|
||||||
return 0;
|
|
||||||
if (!connection_info.connection)
|
|
||||||
return BAN::Error::from_errno(ENOTCONN);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto state = m_packet_lock.lock();
|
auto state = m_packet_lock.lock();
|
||||||
while (m_packet_size_total == 0)
|
while (m_packet_size_total == 0)
|
||||||
{
|
{
|
||||||
|
if (m_info.has<ConnectionInfo>())
|
||||||
|
{
|
||||||
|
auto& connection_info = m_info.get<ConnectionInfo>();
|
||||||
|
bool expected = true;
|
||||||
|
if (connection_info.target_closed.compare_exchange(expected, false))
|
||||||
|
return 0;
|
||||||
|
if (!connection_info.connection)
|
||||||
|
return BAN::Error::from_errno(ENOTCONN);
|
||||||
|
}
|
||||||
|
|
||||||
m_packet_lock.unlock(state);
|
m_packet_lock.unlock(state);
|
||||||
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker));
|
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker));
|
||||||
state = m_packet_lock.lock();
|
state = m_packet_lock.lock();
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace Kernel
|
||||||
|
|
||||||
OpenFileDescriptorSet& OpenFileDescriptorSet::operator=(OpenFileDescriptorSet&& other)
|
OpenFileDescriptorSet& OpenFileDescriptorSet::operator=(OpenFileDescriptorSet&& other)
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
for (size_t i = 0; i < m_open_files.size(); i++)
|
for (size_t i = 0; i < m_open_files.size(); i++)
|
||||||
m_open_files[i] = BAN::move(other.m_open_files[i]);
|
m_open_files[i] = BAN::move(other.m_open_files[i]);
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -30,6 +31,8 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::clone_from(const OpenFileDescriptorSet& other)
|
BAN::ErrorOr<void> OpenFileDescriptorSet::clone_from(const OpenFileDescriptorSet& other)
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
close_all();
|
close_all();
|
||||||
|
|
||||||
for (int fd = 0; fd < (int)other.m_open_files.size(); fd++)
|
for (int fd = 0; fd < (int)other.m_open_files.size(); fd++)
|
||||||
|
@ -67,11 +70,11 @@ namespace Kernel
|
||||||
if ((flags & O_TRUNC) && (flags & O_WRONLY) && file.inode->mode().ifreg())
|
if ((flags & O_TRUNC) && (flags & O_WRONLY) && file.inode->mode().ifreg())
|
||||||
TRY(file.inode->truncate(0));
|
TRY(file.inode->truncate(0));
|
||||||
|
|
||||||
|
LockGuard _(m_mutex);
|
||||||
constexpr int status_mask = O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC | O_ACCMODE;
|
constexpr int status_mask = O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC | O_ACCMODE;
|
||||||
int fd = TRY(get_free_fd());
|
int fd = TRY(get_free_fd());
|
||||||
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(BAN::move(file), 0, flags & status_mask));
|
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(BAN::move(file), 0, flags & status_mask));
|
||||||
m_open_files[fd].descriptor_flags = flags & O_CLOEXEC;
|
m_open_files[fd].descriptor_flags = flags & O_CLOEXEC;
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +138,7 @@ namespace Kernel
|
||||||
|
|
||||||
auto socket = TRY(NetworkManager::get().create_socket(sock_domain, sock_type, 0777, m_credentials.euid(), m_credentials.egid()));
|
auto socket = TRY(NetworkManager::get().create_socket(sock_domain, sock_type, 0777, m_credentials.euid(), m_credentials.egid()));
|
||||||
|
|
||||||
|
LockGuard _(m_mutex);
|
||||||
int fd = TRY(get_free_fd());
|
int fd = TRY(get_free_fd());
|
||||||
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, "<socket>"_sv), 0, O_RDWR | status_flags));
|
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, "<socket>"_sv), 0, O_RDWR | status_flags));
|
||||||
m_open_files[fd].descriptor_flags = descriptor_flags;
|
m_open_files[fd].descriptor_flags = descriptor_flags;
|
||||||
|
@ -143,6 +147,8 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::pipe(int fds[2])
|
BAN::ErrorOr<void> OpenFileDescriptorSet::pipe(int fds[2])
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
TRY(get_free_fd_pair(fds));
|
TRY(get_free_fd_pair(fds));
|
||||||
|
|
||||||
auto pipe = TRY(Pipe::create(m_credentials));
|
auto pipe = TRY(Pipe::create(m_credentials));
|
||||||
|
@ -159,6 +165,8 @@ namespace Kernel
|
||||||
if (fildes2 < 0 || fildes2 >= (int)m_open_files.size())
|
if (fildes2 < 0 || fildes2 >= (int)m_open_files.size())
|
||||||
return BAN::Error::from_errno(EBADF);
|
return BAN::Error::from_errno(EBADF);
|
||||||
|
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
TRY(validate_fd(fildes));
|
TRY(validate_fd(fildes));
|
||||||
if (fildes == fildes2)
|
if (fildes == fildes2)
|
||||||
return fildes;
|
return fildes;
|
||||||
|
@ -179,6 +187,8 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<int> OpenFileDescriptorSet::fcntl(int fd, int cmd, int extra)
|
BAN::ErrorOr<int> OpenFileDescriptorSet::fcntl(int fd, int cmd, int extra)
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
|
@ -223,6 +233,8 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<off_t> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence)
|
BAN::ErrorOr<off_t> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence)
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
|
|
||||||
off_t base_offset;
|
off_t base_offset;
|
||||||
|
@ -252,18 +264,22 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<off_t> OpenFileDescriptorSet::tell(int fd) const
|
BAN::ErrorOr<off_t> OpenFileDescriptorSet::tell(int fd) const
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return m_open_files[fd].offset();
|
return m_open_files[fd].offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::truncate(int fd, off_t length)
|
BAN::ErrorOr<void> OpenFileDescriptorSet::truncate(int fd, off_t length)
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return m_open_files[fd].inode()->truncate(length);
|
return m_open_files[fd].inode()->truncate(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::close(int fd)
|
BAN::ErrorOr<void> OpenFileDescriptorSet::close(int fd)
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
|
|
||||||
if (m_open_files[fd].path() == "<pipe wr>"_sv)
|
if (m_open_files[fd].path() == "<pipe wr>"_sv)
|
||||||
|
@ -280,12 +296,14 @@ namespace Kernel
|
||||||
|
|
||||||
void OpenFileDescriptorSet::close_all()
|
void OpenFileDescriptorSet::close_all()
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
||||||
(void)close(fd);
|
(void)close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenFileDescriptorSet::close_cloexec()
|
void OpenFileDescriptorSet::close_cloexec()
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
||||||
{
|
{
|
||||||
if (validate_fd(fd).is_error())
|
if (validate_fd(fd).is_error())
|
||||||
|
@ -297,83 +315,155 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read(int fd, BAN::ByteSpan buffer)
|
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read(int fd, BAN::ByteSpan buffer)
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
BAN::RefPtr<Inode> inode;
|
||||||
auto& open_file = m_open_files[fd];
|
bool is_nonblock;
|
||||||
if (open_file.inode()->mode().ifsock())
|
off_t offset;
|
||||||
|
|
||||||
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
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);
|
||||||
|
inode = open_file.inode();
|
||||||
|
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
|
||||||
|
offset = open_file.offset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inode->mode().ifsock())
|
||||||
return recvfrom(fd, buffer, nullptr, nullptr);
|
return recvfrom(fd, buffer, nullptr, nullptr);
|
||||||
if (!(open_file.status_flags() & O_RDONLY))
|
|
||||||
return BAN::Error::from_errno(EBADF);
|
size_t nread;
|
||||||
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read())
|
{
|
||||||
return 0;
|
LockGuard _(inode->m_mutex);
|
||||||
const size_t nread = TRY(open_file.inode()->read(open_file.offset(), buffer));
|
if (is_nonblock && !inode->can_read())
|
||||||
open_file.offset() += nread;
|
return 0;
|
||||||
|
nread = TRY(inode->read(offset, buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
// NOTE: race condition with offset, its UB per POSIX
|
||||||
|
if (!validate_fd(fd).is_error())
|
||||||
|
m_open_files[fd].offset() = offset + nread;
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> OpenFileDescriptorSet::write(int fd, BAN::ConstByteSpan buffer)
|
BAN::ErrorOr<size_t> OpenFileDescriptorSet::write(int fd, BAN::ConstByteSpan buffer)
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
BAN::RefPtr<Inode> inode;
|
||||||
auto& open_file = m_open_files[fd];
|
bool is_nonblock;
|
||||||
if (open_file.inode()->mode().ifsock())
|
off_t offset;
|
||||||
|
|
||||||
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
TRY(validate_fd(fd));
|
||||||
|
auto& open_file = m_open_files[fd];
|
||||||
|
if (!(open_file.status_flags() & O_WRONLY))
|
||||||
|
return BAN::Error::from_errno(EBADF);
|
||||||
|
inode = open_file.inode();
|
||||||
|
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
|
||||||
|
offset = (open_file.status_flags() & O_APPEND) ? inode->size() : open_file.offset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inode->mode().ifsock())
|
||||||
return sendto(fd, buffer, nullptr, 0);
|
return sendto(fd, buffer, nullptr, 0);
|
||||||
if (!(open_file.status_flags() & O_WRONLY))
|
|
||||||
return BAN::Error::from_errno(EBADF);
|
size_t nwrite;
|
||||||
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write())
|
{
|
||||||
return BAN::Error::from_errno(EWOULDBLOCK);
|
LockGuard _(inode->m_mutex);
|
||||||
if (open_file.status_flags() & O_APPEND)
|
if (is_nonblock && !inode->can_write())
|
||||||
open_file.offset() = open_file.inode()->size();
|
return BAN::Error::from_errno(EWOULDBLOCK);
|
||||||
const size_t nwrite = TRY(open_file.inode()->write(open_file.offset(), buffer));
|
nwrite = TRY(inode->write(offset, buffer));
|
||||||
open_file.offset() += nwrite;
|
}
|
||||||
|
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
// NOTE: race condition with offset, its UB per POSIX
|
||||||
|
if (!validate_fd(fd).is_error())
|
||||||
|
m_open_files[fd].offset() = offset + nwrite;
|
||||||
return nwrite;
|
return nwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read_dir_entries(int fd, struct dirent* list, size_t list_len)
|
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read_dir_entries(int fd, struct dirent* list, size_t list_len)
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
BAN::RefPtr<Inode> inode;
|
||||||
auto& open_file = m_open_files[fd];
|
off_t offset;
|
||||||
if (!(open_file.status_flags() & O_RDONLY))
|
|
||||||
return BAN::Error::from_errno(EACCES);
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
TRY(validate_fd(fd));
|
||||||
|
auto& open_file = m_open_files[fd];
|
||||||
|
if (!(open_file.status_flags() & O_RDONLY))
|
||||||
|
return BAN::Error::from_errno(EACCES);
|
||||||
|
inode = open_file.inode();
|
||||||
|
offset = open_file.offset();
|
||||||
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
auto ret = open_file.inode()->list_next_inodes(open_file.offset(), list, list_len);
|
auto ret = inode->list_next_inodes(offset, list, list_len);
|
||||||
if (ret.is_error() && ret.error().get_error_code() != ENODATA)
|
if (ret.is_error() && ret.error().get_error_code() != ENODATA)
|
||||||
return ret;
|
return ret;
|
||||||
open_file.offset()++;
|
offset++;
|
||||||
if (ret.is_error())
|
if (ret.is_error())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
// NOTE: race condition with offset, its UB per POSIX
|
||||||
|
if (!validate_fd(fd).is_error())
|
||||||
|
m_open_files[fd].offset() = offset;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> OpenFileDescriptorSet::recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len)
|
BAN::ErrorOr<size_t> OpenFileDescriptorSet::recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len)
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
BAN::RefPtr<Inode> inode;
|
||||||
auto& open_file = m_open_files[fd];
|
bool is_nonblock;
|
||||||
if (!open_file.inode()->mode().ifsock())
|
|
||||||
return BAN::Error::from_errno(ENOTSOCK);
|
{
|
||||||
LockGuard _(open_file.inode()->m_mutex);
|
LockGuard _(m_mutex);
|
||||||
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read())
|
TRY(validate_fd(fd));
|
||||||
|
auto& open_file = m_open_files[fd];
|
||||||
|
if (!open_file.inode()->mode().ifsock())
|
||||||
|
return BAN::Error::from_errno(ENOTSOCK);
|
||||||
|
inode = open_file.inode();
|
||||||
|
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
LockGuard _(inode->m_mutex);
|
||||||
|
if (is_nonblock && !inode->can_read())
|
||||||
return BAN::Error::from_errno(EWOULDBLOCK);
|
return BAN::Error::from_errno(EWOULDBLOCK);
|
||||||
return open_file.inode()->recvfrom(buffer, address, address_len);
|
return inode->recvfrom(buffer, address, address_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> OpenFileDescriptorSet::sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len)
|
BAN::ErrorOr<size_t> OpenFileDescriptorSet::sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len)
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
BAN::RefPtr<Inode> inode;
|
||||||
auto& open_file = m_open_files[fd];
|
bool is_nonblock;
|
||||||
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);
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
TRY(validate_fd(fd));
|
||||||
|
auto& open_file = m_open_files[fd];
|
||||||
|
if (!open_file.inode()->mode().ifsock())
|
||||||
|
return BAN::Error::from_errno(ENOTSOCK);
|
||||||
|
inode = open_file.inode();
|
||||||
|
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
LockGuard _(inode->m_mutex);
|
||||||
|
|
||||||
|
if (is_nonblock && !inode->can_write())
|
||||||
|
return BAN::Error::from_errno(EWOULDBLOCK);
|
||||||
|
|
||||||
size_t total_sent = 0;
|
size_t total_sent = 0;
|
||||||
while (total_sent < buffer.size())
|
while (total_sent < buffer.size())
|
||||||
{
|
{
|
||||||
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write())
|
if (is_nonblock && !inode->can_write())
|
||||||
return total_sent;
|
return total_sent;
|
||||||
const size_t nsend = TRY(open_file.inode()->sendto(buffer.slice(total_sent), address, address_len));
|
const size_t nsend = TRY(inode->sendto(buffer.slice(total_sent), address, address_len));
|
||||||
if (nsend == 0)
|
if (nsend == 0)
|
||||||
return 0;
|
return 0;
|
||||||
total_sent += nsend;
|
total_sent += nsend;
|
||||||
|
@ -384,30 +474,37 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const
|
BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return TRY(m_open_files[fd].description->file.clone());
|
return TRY(m_open_files[fd].description->file.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::StringView> OpenFileDescriptorSet::path_of(int fd) const
|
BAN::ErrorOr<BAN::String> OpenFileDescriptorSet::path_of(int fd) const
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return m_open_files[fd].path();
|
BAN::String path;
|
||||||
|
TRY(path.append(m_open_files[fd].path()));
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> OpenFileDescriptorSet::inode_of(int fd)
|
BAN::ErrorOr<BAN::RefPtr<Inode>> OpenFileDescriptorSet::inode_of(int fd)
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return m_open_files[fd].inode();
|
return m_open_files[fd].inode();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<int> OpenFileDescriptorSet::status_flags_of(int fd) const
|
BAN::ErrorOr<int> OpenFileDescriptorSet::status_flags_of(int fd) const
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return m_open_files[fd].status_flags();
|
return m_open_files[fd].status_flags();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::validate_fd(int fd) const
|
BAN::ErrorOr<void> OpenFileDescriptorSet::validate_fd(int fd) const
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
if (fd < 0 || fd >= (int)m_open_files.size())
|
if (fd < 0 || fd >= (int)m_open_files.size())
|
||||||
return BAN::Error::from_errno(EBADF);
|
return BAN::Error::from_errno(EBADF);
|
||||||
if (!m_open_files[fd].description)
|
if (!m_open_files[fd].description)
|
||||||
|
@ -417,6 +514,7 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<int> OpenFileDescriptorSet::get_free_fd() const
|
BAN::ErrorOr<int> OpenFileDescriptorSet::get_free_fd() const
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
||||||
if (!m_open_files[fd].description)
|
if (!m_open_files[fd].description)
|
||||||
return fd;
|
return fd;
|
||||||
|
@ -425,6 +523,7 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::get_free_fd_pair(int fds[2]) const
|
BAN::ErrorOr<void> OpenFileDescriptorSet::get_free_fd_pair(int fds[2]) const
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
size_t found = 0;
|
size_t found = 0;
|
||||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1051,28 +1051,36 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_close(int fd)
|
BAN::ErrorOr<long> Process::sys_close(int fd)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
|
||||||
TRY(m_open_file_descriptors.close(fd));
|
TRY(m_open_file_descriptors.close(fd));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count)
|
BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
TRY(m_open_file_descriptors.inode_of(fd));
|
TRY(m_open_file_descriptors.inode_of(fd));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
TRY(validate_pointer_access(buffer, count, true));
|
|
||||||
return TRY(m_open_file_descriptors.read(fd, BAN::ByteSpan((uint8_t*)buffer, count)));
|
// FIXME: buffer_region can be null as stack is not MemoryRegion
|
||||||
|
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, true));
|
||||||
|
BAN::ScopeGuard _([&] { if (buffer_region) buffer_region->unpin(); });
|
||||||
|
return TRY(m_open_file_descriptors.read(fd, BAN::ByteSpan(static_cast<uint8_t*>(buffer), count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count)
|
BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
if (count == 0)
|
||||||
TRY(validate_pointer_access(buffer, count, false));
|
{
|
||||||
return TRY(m_open_file_descriptors.write(fd, BAN::ByteSpan((uint8_t*)buffer, count)));
|
TRY(m_open_file_descriptors.inode_of(fd));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: buffer_region can be null as stack is not MemoryRegion
|
||||||
|
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, false));
|
||||||
|
BAN::ScopeGuard _([&] { if (buffer_region) buffer_region->unpin(); });
|
||||||
|
return TRY(m_open_file_descriptors.write(fd, BAN::ConstByteSpan(static_cast<const uint8_t*>(buffer), count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_access(const char* path, int amode)
|
BAN::ErrorOr<long> Process::sys_access(const char* path, int amode)
|
||||||
|
@ -1296,19 +1304,24 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_accept(int socket, sockaddr* address, socklen_t* address_len, int flags)
|
BAN::ErrorOr<long> Process::sys_accept(int socket, sockaddr* address, socklen_t* address_len, int flags)
|
||||||
{
|
{
|
||||||
if (address && !address_len)
|
if (!address != !address_len)
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
if (!address && address_len)
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
if (flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC))
|
if (flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC))
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
LockGuard _(m_process_lock);
|
MemoryRegion* address_region1 = nullptr;
|
||||||
if (address)
|
MemoryRegion* address_region2 = nullptr;
|
||||||
{
|
|
||||||
TRY(validate_pointer_access(address_len, sizeof(*address_len), true));
|
BAN::ScopeGuard _([&] {
|
||||||
TRY(validate_pointer_access(address, *address_len, true));
|
if (address_region1)
|
||||||
}
|
address_region1->unpin();
|
||||||
|
if (address_region2)
|
||||||
|
address_region2->unpin();
|
||||||
|
});
|
||||||
|
|
||||||
|
address_region1 = TRY(validate_and_pin_pointer_access(address_len, sizeof(address_len), true));
|
||||||
|
const socklen_t address_len_safe = address_len ? *address_len : 0;
|
||||||
|
address_region2 = TRY(validate_and_pin_pointer_access(address, address_len_safe, true));
|
||||||
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
|
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
|
||||||
if (!inode->mode().ifsock())
|
if (!inode->mode().ifsock())
|
||||||
|
@ -1338,13 +1351,13 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_connect(int socket, const sockaddr* address, socklen_t address_len)
|
BAN::ErrorOr<long> Process::sys_connect(int socket, const sockaddr* address, socklen_t address_len)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
|
||||||
TRY(validate_pointer_access(address, address_len, false));
|
|
||||||
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
|
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
|
||||||
if (!inode->mode().ifsock())
|
if (!inode->mode().ifsock())
|
||||||
return BAN::Error::from_errno(ENOTSOCK);
|
return BAN::Error::from_errno(ENOTSOCK);
|
||||||
|
|
||||||
|
auto* address_region = TRY(validate_and_pin_pointer_access(address, address_len, true));
|
||||||
|
BAN::ScopeGuard _([&] { if (address_region) address_region->unpin(); });
|
||||||
|
|
||||||
TRY(inode->connect(address, address_len));
|
TRY(inode->connect(address, address_len));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1361,35 +1374,69 @@ namespace Kernel
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_sendto(const sys_sendto_t* arguments)
|
BAN::ErrorOr<long> Process::sys_sendto(const sys_sendto_t* _arguments)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
sys_sendto_t arguments;
|
||||||
TRY(validate_pointer_access(arguments, sizeof(sys_sendto_t), false));
|
|
||||||
TRY(validate_pointer_access(arguments->message, arguments->length, false));
|
|
||||||
TRY(validate_pointer_access(arguments->dest_addr, arguments->dest_len, false));
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (arguments->address && !arguments->address_len)
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
if (!arguments->address && arguments->address_len)
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
|
|
||||||
LockGuard _(m_process_lock);
|
|
||||||
TRY(validate_pointer_access(arguments, sizeof(sys_recvfrom_t), false));
|
|
||||||
TRY(validate_pointer_access(arguments->buffer, arguments->length, true));
|
|
||||||
if (arguments->address)
|
|
||||||
{
|
{
|
||||||
TRY(validate_pointer_access(arguments->address_len, sizeof(*arguments->address_len), true));
|
LockGuard _(m_process_lock);
|
||||||
TRY(validate_pointer_access(arguments->address, *arguments->address_len, true));
|
TRY(validate_pointer_access(_arguments, sizeof(sys_sendto_t), false));
|
||||||
|
arguments = *_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto message = BAN::ByteSpan(static_cast<uint8_t*>(arguments->buffer), arguments->length);
|
if (arguments.length == 0)
|
||||||
return TRY(m_open_file_descriptors.recvfrom(arguments->socket, message, arguments->address, arguments->address_len));
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
|
MemoryRegion* message_region = nullptr;
|
||||||
|
MemoryRegion* address_region = nullptr;
|
||||||
|
|
||||||
|
BAN::ScopeGuard _([&] {
|
||||||
|
if (message_region)
|
||||||
|
message_region->unpin();
|
||||||
|
if (address_region)
|
||||||
|
address_region->unpin();
|
||||||
|
});
|
||||||
|
|
||||||
|
message_region = TRY(validate_and_pin_pointer_access(arguments.message, arguments.length, false));
|
||||||
|
address_region = TRY(validate_and_pin_pointer_access(arguments.dest_addr, arguments.dest_len, false));
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
sys_recvfrom_t arguments;
|
||||||
|
{
|
||||||
|
LockGuard _(m_process_lock);
|
||||||
|
TRY(validate_pointer_access(_arguments, sizeof(sys_sendto_t), false));
|
||||||
|
arguments = *_arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!arguments.address != !arguments.address_len)
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
if (arguments.length == 0)
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
|
MemoryRegion* buffer_region = nullptr;
|
||||||
|
MemoryRegion* address_region1 = nullptr;
|
||||||
|
MemoryRegion* address_region2 = nullptr;
|
||||||
|
|
||||||
|
BAN::ScopeGuard _([&] {
|
||||||
|
if (buffer_region)
|
||||||
|
buffer_region->unpin();
|
||||||
|
if (address_region1)
|
||||||
|
address_region1->unpin();
|
||||||
|
if (address_region2)
|
||||||
|
address_region2->unpin();
|
||||||
|
});
|
||||||
|
|
||||||
|
buffer_region = TRY(validate_and_pin_pointer_access(arguments.buffer, arguments.length, true));
|
||||||
|
address_region1 = TRY(validate_and_pin_pointer_access(arguments.address_len, sizeof(*arguments.address_len), true));
|
||||||
|
const socklen_t address_len_safe = arguments.address_len ? *arguments.address_len : 0;
|
||||||
|
address_region2 = TRY(validate_and_pin_pointer_access(arguments.address, address_len_safe, true));
|
||||||
|
|
||||||
|
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)
|
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg)
|
||||||
|
@ -1399,37 +1446,56 @@ namespace Kernel
|
||||||
return TRY(inode->ioctl(request, arg));
|
return TRY(inode->ioctl(request, arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_pselect(sys_pselect_t* arguments)
|
BAN::ErrorOr<long> Process::sys_pselect(sys_pselect_t* _arguments)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
sys_pselect_t arguments;
|
||||||
|
|
||||||
TRY(validate_pointer_access(arguments, sizeof(sys_pselect_t), false));
|
{
|
||||||
if (arguments->readfds)
|
LockGuard _(m_process_lock);
|
||||||
TRY(validate_pointer_access(arguments->readfds, sizeof(fd_set), true));
|
TRY(validate_pointer_access(_arguments, sizeof(sys_pselect_t), false));
|
||||||
if (arguments->writefds)
|
arguments = *_arguments;
|
||||||
TRY(validate_pointer_access(arguments->writefds, sizeof(fd_set), true));
|
}
|
||||||
if (arguments->errorfds)
|
|
||||||
TRY(validate_pointer_access(arguments->errorfds, sizeof(fd_set), true));
|
MemoryRegion* readfd_region = nullptr;
|
||||||
if (arguments->timeout)
|
MemoryRegion* writefd_region = nullptr;
|
||||||
TRY(validate_pointer_access(arguments->timeout, sizeof(timespec), false));
|
MemoryRegion* errorfd_region = nullptr;
|
||||||
if (arguments->sigmask)
|
MemoryRegion* timeout_region = nullptr;
|
||||||
TRY(validate_pointer_access(arguments->sigmask, sizeof(sigset_t), false));
|
MemoryRegion* sigmask_region = nullptr;
|
||||||
|
|
||||||
|
BAN::ScopeGuard _([&] {
|
||||||
|
if (readfd_region)
|
||||||
|
readfd_region->unpin();
|
||||||
|
if (writefd_region)
|
||||||
|
writefd_region->unpin();
|
||||||
|
if (errorfd_region)
|
||||||
|
errorfd_region->unpin();
|
||||||
|
if (timeout_region)
|
||||||
|
timeout_region->unpin();
|
||||||
|
if (sigmask_region)
|
||||||
|
sigmask_region->unpin();
|
||||||
|
});
|
||||||
|
|
||||||
|
readfd_region = TRY(validate_and_pin_pointer_access(arguments.readfds, sizeof(fd_set), true));
|
||||||
|
writefd_region = TRY(validate_and_pin_pointer_access(arguments.writefds, sizeof(fd_set), true));
|
||||||
|
errorfd_region = TRY(validate_and_pin_pointer_access(arguments.errorfds, sizeof(fd_set), true));
|
||||||
|
timeout_region = TRY(validate_and_pin_pointer_access(arguments.timeout, sizeof(timespec), false));
|
||||||
|
sigmask_region = TRY(validate_and_pin_pointer_access(arguments.sigmask, sizeof(sigset_t), false));
|
||||||
|
|
||||||
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
||||||
if (arguments->sigmask)
|
if (arguments.sigmask)
|
||||||
Thread::current().m_signal_block_mask = *arguments->sigmask;
|
Thread::current().m_signal_block_mask = *arguments.sigmask;
|
||||||
BAN::ScopeGuard sigmask_restore([old_sigmask] { Thread::current().m_signal_block_mask = old_sigmask; });
|
BAN::ScopeGuard sigmask_restore([old_sigmask] { Thread::current().m_signal_block_mask = old_sigmask; });
|
||||||
|
|
||||||
uint64_t timedout_ns = SystemTimer::get().ns_since_boot();
|
uint64_t timedout_ns = SystemTimer::get().ns_since_boot();
|
||||||
if (arguments->timeout)
|
if (arguments.timeout)
|
||||||
{
|
{
|
||||||
timedout_ns += arguments->timeout->tv_sec * 1'000'000'000;
|
timedout_ns += arguments.timeout->tv_sec * 1'000'000'000;
|
||||||
timedout_ns += arguments->timeout->tv_nsec;
|
timedout_ns += arguments.timeout->tv_nsec;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_set readfds; FD_ZERO(&readfds);
|
fd_set readfds; FD_ZERO(&readfds);
|
||||||
fd_set writefds; FD_ZERO(&writefds);
|
fd_set writefds; FD_ZERO(&writefds);
|
||||||
fd_set errorfds; FD_ZERO(&errorfds);
|
fd_set errorfds; FD_ZERO(&errorfds);
|
||||||
|
|
||||||
int set_bits = 0;
|
int set_bits = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -1455,38 +1521,38 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < arguments->nfds; i++)
|
for (int i = 0; i < arguments.nfds; i++)
|
||||||
{
|
{
|
||||||
update_fds(i, arguments->readfds, &readfds, &Inode::can_read);
|
update_fds(i, arguments.readfds, &readfds, &Inode::can_read);
|
||||||
update_fds(i, arguments->writefds, &writefds, &Inode::can_write);
|
update_fds(i, arguments.writefds, &writefds, &Inode::can_write);
|
||||||
update_fds(i, arguments->errorfds, &errorfds, &Inode::has_error);
|
update_fds(i, arguments.errorfds, &errorfds, &Inode::has_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set_bits > 0)
|
if (set_bits > 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (arguments->timeout && SystemTimer::get().ns_since_boot() >= timedout_ns)
|
if (arguments.timeout && SystemTimer::get().ns_since_boot() >= timedout_ns)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
LockFreeGuard free(m_process_lock);
|
// FIXME: implement some multi thread blocker system?
|
||||||
TRY(Thread::current().sleep_or_eintr_ms(1));
|
TRY(Thread::current().sleep_or_eintr_ms(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments->readfds)
|
if (arguments.readfds)
|
||||||
FD_ZERO(arguments->readfds);
|
FD_ZERO(arguments.readfds);
|
||||||
if (arguments->writefds)
|
if (arguments.writefds)
|
||||||
FD_ZERO(arguments->writefds);
|
FD_ZERO(arguments.writefds);
|
||||||
if (arguments->errorfds)
|
if (arguments.errorfds)
|
||||||
FD_ZERO(arguments->errorfds);
|
FD_ZERO(arguments.errorfds);
|
||||||
|
|
||||||
for (int i = 0; i < arguments->nfds; i++)
|
for (int i = 0; i < arguments.nfds; i++)
|
||||||
{
|
{
|
||||||
if (arguments->readfds && FD_ISSET(i, &readfds))
|
if (arguments.readfds && FD_ISSET(i, &readfds))
|
||||||
FD_SET(i, arguments->readfds);
|
FD_SET(i, arguments.readfds);
|
||||||
if (arguments->writefds && FD_ISSET(i, &writefds))
|
if (arguments.writefds && FD_ISSET(i, &writefds))
|
||||||
FD_SET(i, arguments->writefds);
|
FD_SET(i, arguments.writefds);
|
||||||
if (arguments->errorfds && FD_ISSET(i, &errorfds))
|
if (arguments.errorfds && FD_ISSET(i, &errorfds))
|
||||||
FD_SET(i, arguments->errorfds);
|
FD_SET(i, arguments.errorfds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return set_bits;
|
return set_bits;
|
||||||
|
@ -1806,7 +1872,10 @@ namespace Kernel
|
||||||
const vaddr_t region_s = region->vaddr();
|
const vaddr_t region_s = region->vaddr();
|
||||||
const vaddr_t region_e = region->vaddr() + region->size();
|
const vaddr_t region_e = region->vaddr() + region->size();
|
||||||
if (vaddr <= region_s && region_e <= vaddr + len)
|
if (vaddr <= region_s && region_e <= vaddr + len)
|
||||||
|
{
|
||||||
|
region->wait_not_pinned();
|
||||||
m_mapped_regions.remove(i--);
|
m_mapped_regions.remove(i--);
|
||||||
|
}
|
||||||
else if (region->overlaps(vaddr, len))
|
else if (region->overlaps(vaddr, len))
|
||||||
dwarnln("TODO: partial region munmap");
|
dwarnln("TODO: partial region munmap");
|
||||||
}
|
}
|
||||||
|
@ -2073,9 +2142,7 @@ namespace Kernel
|
||||||
|
|
||||||
if (act)
|
if (act)
|
||||||
{
|
{
|
||||||
if (act->sa_flags == SA_RESTART)
|
if (act->sa_flags & ~(SA_RESTART))
|
||||||
dwarnln("FIXME: sigaction ignoring SA_RESTART", signal, act->sa_flags);
|
|
||||||
else if (act->sa_flags)
|
|
||||||
{
|
{
|
||||||
dwarnln("TODO: sigaction({}, {H})", signal, act->sa_flags);
|
dwarnln("TODO: sigaction({}, {H})", signal, act->sa_flags);
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
@ -2683,4 +2750,19 @@ unauthorized_access:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)
|
||||||
|
{
|
||||||
|
LockGuard _(m_process_lock);
|
||||||
|
TRY(validate_pointer_access(ptr, size, needs_write));
|
||||||
|
for (auto& region : m_mapped_regions)
|
||||||
|
{
|
||||||
|
if (!region->contains_fully(reinterpret_cast<vaddr_t>(ptr), size))
|
||||||
|
continue;
|
||||||
|
region->pin();
|
||||||
|
return region.ptr();
|
||||||
|
}
|
||||||
|
// FIXME: Make stack MemoryRegion?
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,9 @@ namespace Kernel
|
||||||
|
|
||||||
auto& current_thread = Thread::current();
|
auto& current_thread = Thread::current();
|
||||||
if (current_thread.can_add_signal_to_execute())
|
if (current_thread.can_add_signal_to_execute())
|
||||||
current_thread.handle_signal();
|
if (current_thread.handle_signal())
|
||||||
|
if (ret.is_error() && ret.error().get_error_code() == EINTR)
|
||||||
|
ret = BAN::Error::from_errno(ERESTART);
|
||||||
|
|
||||||
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
|
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
|
||||||
|
|
||||||
|
|
|
@ -435,7 +435,7 @@ namespace Kernel
|
||||||
return interrupt_stack.ip == (uintptr_t)signal_trampoline;
|
return interrupt_stack.ip == (uintptr_t)signal_trampoline;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::handle_signal(int signal)
|
bool Thread::handle_signal(int signal)
|
||||||
{
|
{
|
||||||
ASSERT(&Thread::current() == this);
|
ASSERT(&Thread::current() == this);
|
||||||
ASSERT(is_userspace());
|
ASSERT(is_userspace());
|
||||||
|
@ -463,10 +463,12 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
vaddr_t signal_handler;
|
vaddr_t signal_handler;
|
||||||
|
bool has_sa_restart;
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_process->m_signal_lock);
|
SpinLockGuard _(m_process->m_signal_lock);
|
||||||
ASSERT(!(m_process->m_signal_handlers[signal].sa_flags & SA_SIGINFO));
|
ASSERT(!(m_process->m_signal_handlers[signal].sa_flags & SA_SIGINFO));
|
||||||
signal_handler = (vaddr_t)m_process->m_signal_handlers[signal].sa_handler;
|
signal_handler = (vaddr_t)m_process->m_signal_handlers[signal].sa_handler;
|
||||||
|
has_sa_restart = !!(m_process->m_signal_handlers[signal].sa_flags & SA_RESTART);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_signal_pending_mask &= ~(1ull << signal);
|
m_signal_pending_mask &= ~(1ull << signal);
|
||||||
|
@ -534,6 +536,8 @@ namespace Kernel
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return has_sa_restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::add_signal(int signal)
|
bool Thread::add_signal(int signal)
|
||||||
|
|
|
@ -90,6 +90,7 @@ __BEGIN_DECLS
|
||||||
#define EXDEV 81
|
#define EXDEV 81
|
||||||
#define ENOTBLK 82
|
#define ENOTBLK 82
|
||||||
|
|
||||||
|
#define ERESTART 0xFE /* internal errno for SA_RESTART */
|
||||||
#define EUNKNOWN 0xFF
|
#define EUNKNOWN 0xFF
|
||||||
|
|
||||||
#define errno (*__errno_location())
|
#define errno (*__errno_location())
|
||||||
|
|
|
@ -107,7 +107,7 @@ int getaddrinfo(const char* __restrict nodename, const char* __restrict servname
|
||||||
goto error_close_socket;
|
goto error_close_socket;
|
||||||
|
|
||||||
sockaddr_storage storage;
|
sockaddr_storage storage;
|
||||||
if (recv(resolver_sock, &storage, sizeof(storage), 0) == -1)
|
if (recv(resolver_sock, &storage, sizeof(storage), 0) < static_cast<ssize_t>(sizeof(sockaddr_in)))
|
||||||
goto error_close_socket;
|
goto error_close_socket;
|
||||||
|
|
||||||
close(resolver_sock);
|
close(resolver_sock);
|
||||||
|
@ -115,12 +115,12 @@ int getaddrinfo(const char* __restrict nodename, const char* __restrict servname
|
||||||
if (storage.ss_family != AF_INET)
|
if (storage.ss_family != AF_INET)
|
||||||
return EAI_FAIL;
|
return EAI_FAIL;
|
||||||
|
|
||||||
ipv4_addr = *reinterpret_cast<in_addr_t*>(storage.ss_storage);
|
ipv4_addr = reinterpret_cast<sockaddr_in&>(storage).sin_addr.s_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
addrinfo* ai = (addrinfo*)malloc(sizeof(addrinfo) + sizeof(sockaddr_in));
|
addrinfo* ai = (addrinfo*)malloc(sizeof(addrinfo) + sizeof(sockaddr_in));
|
||||||
if (*res == nullptr)
|
if (ai == nullptr)
|
||||||
return EAI_MEMORY;
|
return EAI_MEMORY;
|
||||||
|
|
||||||
sockaddr_in* sa_in = reinterpret_cast<sockaddr_in*>(reinterpret_cast<uintptr_t>(ai) + sizeof(addrinfo));
|
sockaddr_in* sa_in = reinterpret_cast<sockaddr_in*>(reinterpret_cast<uintptr_t>(ai) + sizeof(addrinfo));
|
||||||
|
@ -193,7 +193,7 @@ struct hostent* gethostbyname(const char* name)
|
||||||
goto error_close_socket;
|
goto error_close_socket;
|
||||||
|
|
||||||
sockaddr_storage storage;
|
sockaddr_storage storage;
|
||||||
if (recv(socket, &storage, sizeof(storage), 0) == -1)
|
if (recv(socket, &storage, sizeof(storage), 0) < static_cast<ssize_t>(sizeof(sockaddr_in)))
|
||||||
goto error_close_socket;
|
goto error_close_socket;
|
||||||
|
|
||||||
close(socket);
|
close(socket);
|
||||||
|
@ -201,7 +201,7 @@ struct hostent* gethostbyname(const char* name)
|
||||||
if (storage.ss_family != AF_INET)
|
if (storage.ss_family != AF_INET)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
addr_buffer = *reinterpret_cast<in_addr_t*>(storage.ss_storage);
|
addr_buffer = reinterpret_cast<sockaddr_in&>(storage).sin_addr.s_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return &hostent;
|
return &hostent;
|
||||||
|
|
|
@ -83,7 +83,10 @@ long syscall(long syscall, ...)
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
long ret = Kernel::syscall(syscall, arg1, arg2, arg3, arg4, arg5);
|
long ret;
|
||||||
|
do
|
||||||
|
ret = Kernel::syscall(syscall, arg1, arg2, arg3, arg4, arg5);
|
||||||
|
while (ret == -ERESTART);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#define MAX(a, b) ((a) < (b) ? (b) : (a))
|
#define MAX(a, b) ((a) < (b) ? (b) : (a))
|
||||||
|
|
||||||
|
@ -16,39 +13,37 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket = ::socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
const addrinfo hints {
|
||||||
if (socket == -1)
|
.ai_flags = 0,
|
||||||
|
.ai_family = AF_INET,
|
||||||
|
.ai_socktype = SOCK_STREAM,
|
||||||
|
.ai_protocol = 0,
|
||||||
|
.ai_addrlen = 0,
|
||||||
|
.ai_addr = nullptr,
|
||||||
|
.ai_canonname = nullptr,
|
||||||
|
.ai_next = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
addrinfo* result;
|
||||||
|
if (int ret = getaddrinfo(argv[1], nullptr, &hints, &result); ret != 0)
|
||||||
{
|
{
|
||||||
perror("socket");
|
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr_un addr;
|
for (addrinfo* ai = result; ai; ai = ai->ai_next)
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
strcpy(addr.sun_path, "/tmp/resolver.sock");
|
|
||||||
if (connect(socket, (sockaddr*)&addr, sizeof(addr)) == -1)
|
|
||||||
{
|
{
|
||||||
perror("connect");
|
if (ai->ai_family != AF_INET)
|
||||||
return 1;
|
continue;
|
||||||
|
|
||||||
|
char buffer[NI_MAXHOST];
|
||||||
|
if (inet_ntop(ai->ai_family, &reinterpret_cast<sockaddr_in*>(ai->ai_addr)->sin_addr, buffer, sizeof(buffer)) == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
printf("%s\n", buffer);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send(socket, argv[1], strlen(argv[1]), 0) == -1)
|
fprintf(stderr, "no address information available\n");
|
||||||
{
|
|
||||||
perror("send");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sockaddr_storage storage;
|
|
||||||
if (recv(socket, &storage, sizeof(storage), 0) == -1)
|
|
||||||
{
|
|
||||||
perror("recv");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(socket);
|
|
||||||
|
|
||||||
char buffer[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
|
|
||||||
printf("%s\n", inet_ntop(storage.ss_family, storage.ss_storage, buffer, sizeof(buffer)));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,4 +6,6 @@ add_executable(resolver ${SOURCES})
|
||||||
banan_link_library(resolver ban)
|
banan_link_library(resolver ban)
|
||||||
banan_link_library(resolver libc)
|
banan_link_library(resolver libc)
|
||||||
|
|
||||||
|
target_compile_options(resolver PRIVATE -Wno-maybe-uninitialized)
|
||||||
|
|
||||||
install(TARGETS resolver OPTIONAL)
|
install(TARGETS resolver OPTIONAL)
|
||||||
|
|
|
@ -43,6 +43,7 @@ static_assert(sizeof(DNSAnswer) == 12);
|
||||||
|
|
||||||
enum QTYPE : uint16_t
|
enum QTYPE : uint16_t
|
||||||
{
|
{
|
||||||
|
INVALID = 0x0000,
|
||||||
A = 0x0001,
|
A = 0x0001,
|
||||||
CNAME = 0x0005,
|
CNAME = 0x0005,
|
||||||
AAAA = 0x001C,
|
AAAA = 0x001C,
|
||||||
|
@ -50,14 +51,83 @@ enum QTYPE : uint16_t
|
||||||
|
|
||||||
struct DNSEntry
|
struct DNSEntry
|
||||||
{
|
{
|
||||||
time_t valid_until { 0 };
|
DNSEntry(BAN::IPv4Address&& address, time_t valid_until)
|
||||||
BAN::IPv4Address address { 0 };
|
: type(QTYPE::A)
|
||||||
|
, valid_until(valid_until)
|
||||||
|
, address(BAN::move(address))
|
||||||
|
{}
|
||||||
|
|
||||||
|
DNSEntry(BAN::String&& cname, time_t valid_until)
|
||||||
|
: type(QTYPE::CNAME)
|
||||||
|
, valid_until(valid_until)
|
||||||
|
, cname(BAN::move(cname))
|
||||||
|
{}
|
||||||
|
|
||||||
|
DNSEntry(DNSEntry&& other)
|
||||||
|
{
|
||||||
|
*this = BAN::move(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DNSEntry() { clear(); }
|
||||||
|
|
||||||
|
DNSEntry& operator=(DNSEntry&& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
valid_until = other.valid_until;
|
||||||
|
switch (type = other.type)
|
||||||
|
{
|
||||||
|
case QTYPE::A:
|
||||||
|
new (&address) BAN::IPv4Address(BAN::move(other.address));
|
||||||
|
break;
|
||||||
|
case QTYPE::CNAME:
|
||||||
|
new (&cname) BAN::String(BAN::move(other.cname));
|
||||||
|
break;
|
||||||
|
case QTYPE::INVALID:
|
||||||
|
case QTYPE::AAAA:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
other.clear();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case QTYPE::A:
|
||||||
|
using BAN::IPv4Address;
|
||||||
|
address.~IPv4Address();
|
||||||
|
break;
|
||||||
|
case QTYPE::CNAME:
|
||||||
|
using BAN::String;
|
||||||
|
cname.~String();
|
||||||
|
break;
|
||||||
|
case QTYPE::AAAA:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
case QTYPE::INVALID:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
type = QTYPE::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTYPE type;
|
||||||
|
time_t valid_until;
|
||||||
|
union {
|
||||||
|
BAN::IPv4Address address;
|
||||||
|
BAN::String cname;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DNSResponse
|
struct DNSResponse
|
||||||
{
|
{
|
||||||
|
struct NameEntryPair
|
||||||
|
{
|
||||||
|
BAN::String name;
|
||||||
|
DNSEntry entry;
|
||||||
|
};
|
||||||
|
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
DNSEntry entry;
|
BAN::Vector<NameEntryPair> entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool send_dns_query(int socket, BAN::StringView domain, uint16_t id)
|
bool send_dns_query(int socket, BAN::StringView domain, uint16_t id)
|
||||||
|
@ -110,36 +180,83 @@ BAN::Optional<DNSResponse> read_dns_response(int socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
DNSPacket& reply = *reinterpret_cast<DNSPacket*>(buffer);
|
DNSPacket& reply = *reinterpret_cast<DNSPacket*>(buffer);
|
||||||
if (reply.flags & 0x0F)
|
|
||||||
{
|
|
||||||
dprintln("DNS error (rcode {})", (unsigned)(reply.flags & 0xF));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = 0;
|
|
||||||
for (size_t i = 0; i < reply.question_count; i++)
|
|
||||||
{
|
|
||||||
while (reply.data[idx])
|
|
||||||
idx += reply.data[idx] + 1;
|
|
||||||
idx += 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
DNSAnswer& answer = *reinterpret_cast<DNSAnswer*>(&reply.data[idx]);
|
|
||||||
if (answer.type() != QTYPE::A)
|
|
||||||
{
|
|
||||||
dprintln("Not A record, but {}", static_cast<uint16_t>(answer.type()));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (answer.data_len() != 4)
|
|
||||||
{
|
|
||||||
dprintln("corrupted package");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
DNSResponse result;
|
DNSResponse result;
|
||||||
result.id = reply.identification;
|
result.id = reply.identification;
|
||||||
result.entry.valid_until = time(nullptr) + answer.ttl();
|
|
||||||
result.entry.address = BAN::IPv4Address(*reinterpret_cast<uint32_t*>(answer.data));
|
if (reply.flags & 0x0F)
|
||||||
|
{
|
||||||
|
dprintln("DNS error (rcode {})", (unsigned)(reply.flags & 0xF));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idx = reply.data - buffer;
|
||||||
|
for (size_t i = 0; i < reply.question_count; i++)
|
||||||
|
{
|
||||||
|
while (buffer[idx])
|
||||||
|
idx += buffer[idx] + 1;
|
||||||
|
idx += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto read_name =
|
||||||
|
[](size_t idx) -> BAN::String
|
||||||
|
{
|
||||||
|
BAN::String result;
|
||||||
|
while (buffer[idx])
|
||||||
|
{
|
||||||
|
if ((buffer[idx] & 0xC0) == 0xC0)
|
||||||
|
{
|
||||||
|
idx = ((buffer[idx] & 0x3F) << 8) | buffer[idx + 1];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUST(result.append(BAN::StringView(reinterpret_cast<const char*>(&buffer[idx + 1]), buffer[idx])));
|
||||||
|
MUST(result.push_back('.'));
|
||||||
|
idx += buffer[idx] + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.empty())
|
||||||
|
result.pop_back();
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < reply.answer_count; i++)
|
||||||
|
{
|
||||||
|
auto& answer = *reinterpret_cast<DNSAnswer*>(&buffer[idx]);
|
||||||
|
|
||||||
|
auto name = read_name(answer.__storage - buffer);
|
||||||
|
|
||||||
|
if (answer.type() == QTYPE::A)
|
||||||
|
{
|
||||||
|
if (answer.data_len() != 4)
|
||||||
|
{
|
||||||
|
dprintln("Invalid A record size {}", (uint16_t)answer.data_len());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUST(result.entries.push_back({
|
||||||
|
.name = BAN::move(name),
|
||||||
|
.entry = {
|
||||||
|
BAN::IPv4Address(*reinterpret_cast<uint32_t*>(answer.data)),
|
||||||
|
time(nullptr) + answer.ttl(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else if (answer.type() == QTYPE::CNAME)
|
||||||
|
{
|
||||||
|
auto target = read_name(answer.data - buffer);
|
||||||
|
|
||||||
|
MUST(result.entries.push_back({
|
||||||
|
.name = BAN::move(name),
|
||||||
|
.entry = {
|
||||||
|
BAN::move(target),
|
||||||
|
time(nullptr) + answer.ttl()
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
idx += sizeof(DNSAnswer) + answer.data_len();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -193,6 +310,33 @@ BAN::Optional<BAN::String> read_service_query(int socket)
|
||||||
return BAN::String(buffer);
|
return BAN::String(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::Optional<BAN::IPv4Address> resolve_from_dns_cache(BAN::HashMap<BAN::String, DNSEntry>& dns_cache, const BAN::String& domain)
|
||||||
|
{
|
||||||
|
for (auto it = dns_cache.find(domain); it != dns_cache.end();)
|
||||||
|
{
|
||||||
|
if (time(nullptr) > it->value.valid_until)
|
||||||
|
{
|
||||||
|
dprintln("{} timedout", it->key);
|
||||||
|
dns_cache.remove(it);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (it->value.type)
|
||||||
|
{
|
||||||
|
case QTYPE::A:
|
||||||
|
return it->value.address;
|
||||||
|
case QTYPE::CNAME:
|
||||||
|
it = dns_cache.find(it->value.cname);
|
||||||
|
break;
|
||||||
|
case QTYPE::AAAA:
|
||||||
|
case QTYPE::INVALID:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int main(int, char**)
|
int main(int, char**)
|
||||||
{
|
{
|
||||||
srand(time(nullptr));
|
srand(time(nullptr));
|
||||||
|
@ -266,17 +410,42 @@ int main(int, char**)
|
||||||
if (!result.has_value())
|
if (!result.has_value())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
for (auto&& [name, entry] : result->entries)
|
||||||
|
MUST(dns_cache.insert_or_assign(BAN::move(name), BAN::move(entry)));
|
||||||
|
|
||||||
for (auto& client : clients)
|
for (auto& client : clients)
|
||||||
{
|
{
|
||||||
if (client.query_id != result->id)
|
if (client.query_id != result->id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
(void)dns_cache.insert(client.query, result->entry);
|
auto resolved = resolve_from_dns_cache(dns_cache, client.query);
|
||||||
|
if (!resolved.has_value())
|
||||||
|
{
|
||||||
|
auto it = dns_cache.find(client.query);
|
||||||
|
if (it == dns_cache.end())
|
||||||
|
{
|
||||||
|
client.close = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ASSERT(it->value.type == QTYPE::CNAME);
|
||||||
|
auto next = dns_cache.find(it->value.cname);
|
||||||
|
if (next == dns_cache.end())
|
||||||
|
break;
|
||||||
|
it = next;
|
||||||
|
}
|
||||||
|
send_dns_query(service_socket, it->value.cname, client.query_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
sockaddr_storage storage;
|
const sockaddr_in addr {
|
||||||
storage.ss_family = AF_INET;
|
.sin_family = AF_INET,
|
||||||
memcpy(storage.ss_storage, &result->entry.address.raw, sizeof(result->entry.address.raw));
|
.sin_port = 0,
|
||||||
if (send(client.socket, &storage, sizeof(storage), 0) == -1)
|
.sin_addr = { .s_addr = resolved->raw },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (send(client.socket, &addr, sizeof(addr), 0) == -1)
|
||||||
dprintln("send: {}", strerror(errno));
|
dprintln("send: {}", strerror(errno));
|
||||||
client.close = true;
|
client.close = true;
|
||||||
break;
|
break;
|
||||||
|
@ -308,30 +477,22 @@ int main(int, char**)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::Optional<DNSEntry> result;
|
BAN::Optional<BAN::IPv4Address> result;
|
||||||
|
|
||||||
if (*hostname && strcmp(query->data(), hostname) == 0)
|
if (*hostname && strcmp(query->data(), hostname) == 0)
|
||||||
{
|
result = BAN::IPv4Address(ntohl(INADDR_LOOPBACK));
|
||||||
result = DNSEntry {
|
else if (auto resolved = resolve_from_dns_cache(dns_cache, query.value()); resolved.has_value())
|
||||||
.valid_until = time(nullptr),
|
result = resolved.release_value();
|
||||||
.address = ntohl(INADDR_LOOPBACK),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (dns_cache.contains(*query))
|
|
||||||
{
|
|
||||||
auto& cached = dns_cache[*query];
|
|
||||||
if (time(nullptr) <= cached.valid_until)
|
|
||||||
result = cached;
|
|
||||||
else
|
|
||||||
dns_cache.remove(*query);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.has_value())
|
if (result.has_value())
|
||||||
{
|
{
|
||||||
sockaddr_storage storage;
|
const sockaddr_in addr {
|
||||||
storage.ss_family = AF_INET;
|
.sin_family = AF_INET,
|
||||||
memcpy(storage.ss_storage, &result->address.raw, sizeof(result->address.raw));
|
.sin_port = 0,
|
||||||
if (send(client.socket, &storage, sizeof(storage), 0) == -1)
|
.sin_addr = { .s_addr = result->raw },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (send(client.socket, &addr, sizeof(addr), 0) == -1)
|
||||||
dprintln("send: {}", strerror(errno));
|
dprintln("send: {}", strerror(errno));
|
||||||
client.close = true;
|
client.close = true;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -8,44 +9,26 @@
|
||||||
|
|
||||||
in_addr_t get_ipv4_address(const char* query)
|
in_addr_t get_ipv4_address(const char* query)
|
||||||
{
|
{
|
||||||
if (in_addr_t ipv4 = inet_addr(query); ipv4 != (in_addr_t)(-1))
|
const addrinfo hints {
|
||||||
return ipv4;
|
.ai_flags = 0,
|
||||||
|
.ai_family = AF_INET,
|
||||||
|
.ai_socktype = SOCK_STREAM,
|
||||||
|
.ai_protocol = 0,
|
||||||
|
.ai_addrlen = 0,
|
||||||
|
.ai_addr = nullptr,
|
||||||
|
.ai_canonname = nullptr,
|
||||||
|
.ai_next = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
int socket = ::socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
addrinfo* result;
|
||||||
if (socket == -1)
|
if (getaddrinfo(query, nullptr, &hints, &result) != 0)
|
||||||
{
|
|
||||||
perror("socket");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
sockaddr_un addr;
|
for (addrinfo* ai = result; ai; ai = ai->ai_next)
|
||||||
addr.sun_family = AF_UNIX;
|
if (ai->ai_family != AF_INET)
|
||||||
strcpy(addr.sun_path, "/tmp/resolver.sock");
|
return reinterpret_cast<sockaddr_in*>(ai->ai_addr)->sin_addr.s_addr;
|
||||||
if (connect(socket, (sockaddr*)&addr, sizeof(addr)) == -1)
|
|
||||||
{
|
|
||||||
perror("connect");
|
|
||||||
close(socket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (send(socket, query, strlen(query), 0) == -1)
|
return -1;
|
||||||
{
|
|
||||||
perror("send");
|
|
||||||
close(socket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sockaddr_storage storage;
|
|
||||||
if (recv(socket, &storage, sizeof(storage), 0) == -1)
|
|
||||||
{
|
|
||||||
perror("recv");
|
|
||||||
close(socket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(socket);
|
|
||||||
|
|
||||||
return *reinterpret_cast<in_addr_t*>(storage.ss_storage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
|
|
Loading…
Reference in New Issue