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