Compare commits
24 Commits
6be3b1d7f2
...
7691b019e2
Author | SHA1 | Date |
---|---|---|
|
7691b019e2 | |
|
f55d6b11c5 | |
|
f52877abb4 | |
|
ee7c9b6731 | |
|
4721344518 | |
|
e0d986dcd7 | |
|
c7be3dcd5b | |
|
89c9bfd052 | |
|
12b93567f7 | |
|
2f37776614 | |
|
f778bca3f2 | |
|
a945d19750 | |
|
7f04b2c96c | |
|
8aa4e4ff1e | |
|
7eade002a7 | |
|
a8f8d27f4e | |
|
356935bd4f | |
|
bce3dd045f | |
|
79a2b84c81 | |
|
44b762f916 | |
|
5d80c880c8 | |
|
b907263f35 | |
|
0f0accf82c | |
|
ddcf414107 |
|
@ -111,6 +111,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<size_t> sendto(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len);
|
||||
BAN::ErrorOr<size_t> recvfrom(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len);
|
||||
BAN::ErrorOr<void> getsockname(sockaddr* address, socklen_t* address_len);
|
||||
BAN::ErrorOr<void> getpeername(sockaddr* address, socklen_t* address_len);
|
||||
|
||||
// General API
|
||||
BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer);
|
||||
|
@ -153,6 +154,7 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
|
||||
// General API
|
||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Kernel
|
|||
BAN::Vector<BAN::RefPtr<NetworkInterface>>& interfaces() { return m_interfaces; }
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Socket>> create_socket(Socket::Domain, Socket::Type, mode_t, uid_t, gid_t);
|
||||
BAN::ErrorOr<void> connect_sockets(Socket::Domain, BAN::RefPtr<Socket>, BAN::RefPtr<Socket>);
|
||||
|
||||
void on_receive(NetworkInterface&, BAN::ConstByteSpan);
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace Kernel
|
|||
|
||||
virtual BAN::ErrorOr<long> ioctl_impl(int request, void* arg) override;
|
||||
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) override;
|
||||
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override = 0;
|
||||
|
||||
protected:
|
||||
NetworkLayer& m_network_layer;
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
|
||||
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
|
||||
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override;
|
||||
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
|
||||
|
||||
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override;
|
||||
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) override;
|
||||
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len) override;
|
||||
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); }
|
||||
|
||||
virtual bool can_read_impl() const override { return !m_packets.empty(); }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Kernel
|
|||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> create(Socket::Type, const Socket::Info&);
|
||||
BAN::ErrorOr<void> make_socket_pair(UnixDomainSocket&);
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) override;
|
||||
|
@ -25,6 +26,7 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
|
||||
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
|
||||
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override;
|
||||
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
|
||||
|
||||
virtual bool can_read_impl() const override;
|
||||
virtual bool can_write_impl() const override;
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<int> open(BAN::StringView absolute_path, int flags);
|
||||
|
||||
BAN::ErrorOr<int> socket(int domain, int type, int protocol);
|
||||
BAN::ErrorOr<void> socketpair(int domain, int type, int protocol, int socket_vector[2]);
|
||||
|
||||
BAN::ErrorOr<void> pipe(int fds[2]);
|
||||
|
||||
|
|
|
@ -112,12 +112,15 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2);
|
||||
|
||||
BAN::ErrorOr<long> sys_pread(int fd, void* buffer, size_t count, off_t offset);
|
||||
BAN::ErrorOr<long> sys_pwrite(int fd, const void* buffer, size_t count, off_t offset);
|
||||
|
||||
BAN::ErrorOr<long> sys_fchmodat(int fd, const char* path, mode_t mode, int flag);
|
||||
BAN::ErrorOr<long> sys_fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag);
|
||||
|
||||
BAN::ErrorOr<long> sys_socket(int domain, int type, int protocol);
|
||||
BAN::ErrorOr<long> sys_socketpair(int domain, int type, int protocol, int socket_vector[2]);
|
||||
BAN::ErrorOr<long> sys_getsockname(int socket, sockaddr* address, socklen_t* address_len);
|
||||
BAN::ErrorOr<long> sys_getpeername(int socket, sockaddr* address, socklen_t* address_len);
|
||||
BAN::ErrorOr<long> sys_getsockopt(int socket, int level, int option_name, void* option_value, socklen_t* option_len);
|
||||
BAN::ErrorOr<long> sys_setsockopt(int socket, int level, int option_name, const void* option_value, socklen_t option_len);
|
||||
|
||||
|
|
|
@ -186,6 +186,14 @@ namespace Kernel
|
|||
return getsockname_impl(address, address_len);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::getpeername(sockaddr* address, socklen_t* address_len)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
if (!mode().ifsock())
|
||||
return BAN::Error::from_errno(ENOTSOCK);
|
||||
return getpeername_impl(address, address_len);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
|
|
@ -237,21 +237,28 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> E1000::enable_interrupt()
|
||||
{
|
||||
TRY(m_pci_device.reserve_interrupts(1));
|
||||
|
||||
write32(REG_ITR, 0x1000);
|
||||
|
||||
write32(REG_IVAR, 1 << 3);
|
||||
write32(REG_EITR, 0x1000);
|
||||
if (m_pci_device.interrupt_mechanism() == PCI::Device::InterruptMechanism::MSIX)
|
||||
{
|
||||
write32(REG_IVAR, 1 << 3);
|
||||
write32(REG_EITR, 0x1000);
|
||||
write32(REG_IMS, IMC_RxQ0);
|
||||
}
|
||||
else
|
||||
{
|
||||
write32(REG_IMS, IMC_RXT0);
|
||||
}
|
||||
|
||||
write32(REG_IMS, IMC_RxQ0);
|
||||
read32(REG_ICR);
|
||||
write32(REG_ICR, 0xFFFFFFFF);
|
||||
|
||||
TRY(m_pci_device.reserve_interrupts(1));
|
||||
m_pci_device.enable_interrupt(0, *this);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer)
|
||||
{
|
||||
ASSERT(buffer.size() + sizeof(EthernetHeader) <= E1000_TX_BUFFER_SIZE);
|
||||
|
@ -285,7 +292,7 @@ namespace Kernel
|
|||
|
||||
void E1000::handle_irq()
|
||||
{
|
||||
if (!(read32(REG_ICR) & ICR_RxQ0))
|
||||
if (!(read32(REG_ICR) & (ICR_RxQ0 | ICR_RXT0)))
|
||||
return;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
|
|
@ -129,6 +129,25 @@ namespace Kernel
|
|||
return socket;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> NetworkManager::connect_sockets(Socket::Domain domain, BAN::RefPtr<Socket> socket1, BAN::RefPtr<Socket> socket2)
|
||||
{
|
||||
switch (domain)
|
||||
{
|
||||
case Socket::Domain::UNIX:
|
||||
{
|
||||
auto* usocket1 = static_cast<UnixDomainSocket*>(socket1.ptr());
|
||||
auto* usocket2 = static_cast<UnixDomainSocket*>(socket2.ptr());
|
||||
TRY(usocket1->make_socket_pair(*usocket2));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dwarnln("TODO: connect {} domain sockets", static_cast<int>(domain));
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet)
|
||||
{
|
||||
if (packet.size() < sizeof(EthernetHeader))
|
||||
|
|
|
@ -256,6 +256,17 @@ namespace Kernel
|
|||
return to_send;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> TCPSocket::getpeername_impl(sockaddr* address, socklen_t* address_len)
|
||||
{
|
||||
if (!m_has_connected && m_state != State::Established)
|
||||
return BAN::Error::from_errno(ENOTCONN);
|
||||
ASSERT(m_connection_info.has_value());
|
||||
const size_t to_copy = BAN::Math::min(m_connection_info->address_len, *address_len);
|
||||
memcpy(address, &m_connection_info->address, to_copy);
|
||||
*address_len = to_copy;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool TCPSocket::can_read_impl() const
|
||||
{
|
||||
if (m_has_connected && !m_has_sent_zero && m_state != State::Established && m_state != State::Listen)
|
||||
|
@ -492,6 +503,8 @@ namespace Kernel
|
|||
connection_info,
|
||||
header.seq_number + 1
|
||||
));
|
||||
|
||||
epoll_notify(EPOLLIN);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -69,6 +69,20 @@ namespace Kernel
|
|||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> UnixDomainSocket::make_socket_pair(UnixDomainSocket& other)
|
||||
{
|
||||
if (!m_info.has<ConnectionInfo>() || !other.m_info.has<ConnectionInfo>())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
TRY(this->get_weak_ptr());
|
||||
TRY(other.get_weak_ptr());
|
||||
|
||||
this->m_info.get<ConnectionInfo>().connection = MUST(other.get_weak_ptr());
|
||||
other.m_info.get<ConnectionInfo>().connection = MUST(this->get_weak_ptr());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> UnixDomainSocket::accept_impl(sockaddr* address, socklen_t* address_len, int flags)
|
||||
{
|
||||
if (!m_info.has<ConnectionInfo>())
|
||||
|
@ -412,4 +426,33 @@ namespace Kernel
|
|||
return nread;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> UnixDomainSocket::getpeername_impl(sockaddr* address, socklen_t* address_len)
|
||||
{
|
||||
if (!m_info.has<ConnectionInfo>())
|
||||
return BAN::Error::from_errno(ENOTCONN);
|
||||
auto connection = m_info.get<ConnectionInfo>().connection.lock();
|
||||
if (!connection)
|
||||
return BAN::Error::from_errno(ENOTCONN);
|
||||
|
||||
sockaddr_un sa_un;
|
||||
sa_un.sun_family = AF_UNIX;
|
||||
sa_un.sun_path[0] = 0;
|
||||
|
||||
{
|
||||
SpinLockGuard _(s_bound_socket_lock);
|
||||
for (auto& [path, socket] : s_bound_sockets)
|
||||
{
|
||||
if (socket.lock() != connection)
|
||||
continue;
|
||||
strcpy(sa_un.sun_path, path.data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t to_copy = BAN::Math::min<socklen_t>(sizeof(sockaddr_un), *address_len);
|
||||
memcpy(address, &sa_un, to_copy);
|
||||
*address_len = to_copy;
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -83,50 +83,57 @@ namespace Kernel
|
|||
return open(TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags)), flags);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<int> OpenFileDescriptorSet::socket(int domain, int type, int protocol)
|
||||
struct SocketInfo
|
||||
{
|
||||
bool valid_protocol = true;
|
||||
Socket::Domain domain;
|
||||
Socket::Type type;
|
||||
int status_flags;
|
||||
int descriptor_flags;
|
||||
};
|
||||
|
||||
Socket::Domain sock_domain;
|
||||
static BAN::ErrorOr<SocketInfo> parse_socket_info(int domain, int type, int protocol)
|
||||
{
|
||||
SocketInfo info;
|
||||
|
||||
bool valid_protocol = true;
|
||||
switch (domain)
|
||||
{
|
||||
case AF_INET:
|
||||
sock_domain = Socket::Domain::INET;
|
||||
info.domain = Socket::Domain::INET;
|
||||
break;
|
||||
case AF_INET6:
|
||||
sock_domain = Socket::Domain::INET6;
|
||||
info.domain = Socket::Domain::INET6;
|
||||
break;
|
||||
case AF_UNIX:
|
||||
sock_domain = Socket::Domain::UNIX;
|
||||
info.domain = Socket::Domain::UNIX;
|
||||
valid_protocol = false;
|
||||
break;
|
||||
default:
|
||||
return BAN::Error::from_errno(EPROTOTYPE);
|
||||
}
|
||||
|
||||
int status_flags = 0;
|
||||
int descriptor_flags = 0;
|
||||
info.status_flags = 0;
|
||||
info.descriptor_flags = 0;
|
||||
if (type & SOCK_NONBLOCK)
|
||||
status_flags |= O_NONBLOCK;
|
||||
info.status_flags |= O_NONBLOCK;
|
||||
if (type & SOCK_CLOEXEC)
|
||||
descriptor_flags |= O_CLOEXEC;
|
||||
info.descriptor_flags |= O_CLOEXEC;
|
||||
type &= ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
|
||||
Socket::Type sock_type;
|
||||
switch (type)
|
||||
{
|
||||
case SOCK_STREAM:
|
||||
sock_type = Socket::Type::STREAM;
|
||||
info.type = Socket::Type::STREAM;
|
||||
if (protocol != IPPROTO_TCP)
|
||||
valid_protocol = false;
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
sock_type = Socket::Type::DGRAM;
|
||||
info.type = Socket::Type::DGRAM;
|
||||
if (protocol != IPPROTO_UDP)
|
||||
valid_protocol = false;
|
||||
break;
|
||||
case SOCK_SEQPACKET:
|
||||
sock_type = Socket::Type::SEQPACKET;
|
||||
info.type = Socket::Type::SEQPACKET;
|
||||
valid_protocol = false;
|
||||
break;
|
||||
default:
|
||||
|
@ -136,15 +143,39 @@ namespace Kernel
|
|||
if (protocol && !valid_protocol)
|
||||
return BAN::Error::from_errno(EPROTONOSUPPORT);
|
||||
|
||||
auto socket = TRY(NetworkManager::get().create_socket(sock_domain, sock_type, 0777, m_credentials.euid(), m_credentials.egid()));
|
||||
return info;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<int> OpenFileDescriptorSet::socket(int domain, int type, int protocol)
|
||||
{
|
||||
auto sock_info = TRY(parse_socket_info(domain, type, protocol));
|
||||
auto socket = TRY(NetworkManager::get().create_socket(sock_info.domain, sock_info.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;
|
||||
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, "<socket>"_sv), 0, O_RDWR | sock_info.status_flags));
|
||||
m_open_files[fd].descriptor_flags = sock_info.descriptor_flags;
|
||||
return fd;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> OpenFileDescriptorSet::socketpair(int domain, int type, int protocol, int socket_vector[2])
|
||||
{
|
||||
auto sock_info = TRY(parse_socket_info(domain, type, protocol));
|
||||
|
||||
auto socket1 = TRY(NetworkManager::get().create_socket(sock_info.domain, sock_info.type, 0600, m_credentials.euid(), m_credentials.egid()));
|
||||
auto socket2 = TRY(NetworkManager::get().create_socket(sock_info.domain, sock_info.type, 0600, m_credentials.euid(), m_credentials.egid()));
|
||||
TRY(NetworkManager::get().connect_sockets(sock_info.domain, socket1, socket2));
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
TRY(get_free_fd_pair(socket_vector));
|
||||
m_open_files[socket_vector[0]].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket1, "<socketpair>"_sv), 0, O_RDWR | sock_info.status_flags));
|
||||
m_open_files[socket_vector[0]].descriptor_flags = sock_info.descriptor_flags;
|
||||
m_open_files[socket_vector[1]].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket2, "<socketpair>"_sv), 0, O_RDWR | sock_info.status_flags));
|
||||
m_open_files[socket_vector[1]].descriptor_flags = sock_info.descriptor_flags;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> OpenFileDescriptorSet::pipe(int fds[2])
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
|
|
@ -682,9 +682,9 @@ namespace Kernel::PCI
|
|||
|
||||
auto& prt_entry_fields = prt_entry.as.package->elements;
|
||||
if (TRY(ACPI::AML::convert_node(TRY(prt_entry_fields[0].value.node->copy()), ACPI::AML::ConvInteger, -1)).as.integer.value != acpi_device_id)
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
continue;
|
||||
if (TRY(ACPI::AML::convert_node(TRY(prt_entry_fields[1].value.node->copy()), ACPI::AML::ConvInteger, -1)).as.integer.value != acpi_pin)
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
continue;
|
||||
|
||||
auto ret = route_prt_entry(prt_entry);
|
||||
if (!ret.is_error())
|
||||
|
@ -714,16 +714,14 @@ namespace Kernel::PCI
|
|||
return InterruptMechanism::NONE;
|
||||
}
|
||||
|
||||
const bool is_xhci = false && m_class_code == 0x0C && m_subclass == 0x03 && m_prog_if == 0x30;
|
||||
|
||||
if (!is_xhci && m_offset_msi_x.has_value())
|
||||
if (m_offset_msi_x.has_value())
|
||||
{
|
||||
const uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
|
||||
if (count <= (msg_ctrl & 0x7FF) + 1)
|
||||
return InterruptMechanism::MSIX;
|
||||
}
|
||||
|
||||
if (!is_xhci && m_offset_msi.has_value())
|
||||
if (m_offset_msi.has_value())
|
||||
{
|
||||
if (count == 1)
|
||||
return InterruptMechanism::MSI;
|
||||
|
|
|
@ -301,8 +301,14 @@ namespace Kernel
|
|||
);
|
||||
}
|
||||
|
||||
while (!m_threads.empty())
|
||||
m_threads.front()->on_exit();
|
||||
for (size_t i = 0; i < m_threads.size(); i++)
|
||||
{
|
||||
if (m_threads[i] == &Thread::current())
|
||||
continue;
|
||||
m_threads[i]->add_signal(SIGKILL);
|
||||
}
|
||||
|
||||
Thread::current().on_exit();
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
@ -1192,17 +1198,23 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> Process::sys_pread(int fd, void* buffer, size_t count, off_t offset)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
if (count == 0)
|
||||
{
|
||||
TRY(m_open_file_descriptors.inode_of(fd));
|
||||
return 0;
|
||||
}
|
||||
TRY(validate_pointer_access(buffer, count, true));
|
||||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
||||
return TRY(inode->read(offset, { (uint8_t*)buffer, count }));
|
||||
|
||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, true));
|
||||
BAN::ScopeGuard _([buffer_region]{ if (buffer_region) buffer_region->unpin(); });
|
||||
|
||||
return TRY(inode->read(offset, { reinterpret_cast<uint8_t*>(buffer), count }));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pwrite(int fd, const void* buffer, size_t count, off_t offset)
|
||||
{
|
||||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
||||
|
||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, false));
|
||||
BAN::ScopeGuard _([buffer_region]{ if (buffer_region) buffer_region->unpin(); });
|
||||
|
||||
return TRY(inode->write(offset, { reinterpret_cast<const uint8_t*>(buffer), count })); }
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_fchmodat(int fd, const char* path, mode_t mode, int flag)
|
||||
{
|
||||
if (mode & S_IFMASK)
|
||||
|
@ -1258,6 +1270,14 @@ namespace Kernel
|
|||
return TRY(m_open_file_descriptors.socket(domain, type, protocol));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_socketpair(int domain, int type, int protocol, int socket_vector[2])
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(socket_vector, sizeof(int) * 2, true));
|
||||
TRY(m_open_file_descriptors.socketpair(domain, type, protocol, socket_vector));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_getsockname(int socket, sockaddr* address, socklen_t* address_len)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
@ -1272,6 +1292,20 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_getpeername(int socket, sockaddr* address, socklen_t* address_len)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
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())
|
||||
return BAN::Error::from_errno(ENOTSOCK);
|
||||
|
||||
TRY(inode->getpeername(address, address_len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_getsockopt(int socket, int level, int option_name, void* option_value, socklen_t* option_len)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
@ -2304,14 +2338,10 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
TRY(m_exited_pthreads.emplace_back(Thread::current().tid(), value));
|
||||
for (auto* thread : m_threads)
|
||||
{
|
||||
if (thread != &Thread::current())
|
||||
continue;
|
||||
m_pthread_exit_blocker.unblock();
|
||||
m_process_lock.unlock();
|
||||
thread->on_exit();
|
||||
}
|
||||
|
||||
m_pthread_exit_blocker.unblock();
|
||||
m_process_lock.unlock();
|
||||
Thread::current().on_exit();
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ set(LIBC_SOURCES
|
|||
sys/stat.cpp
|
||||
sys/statvfs.cpp
|
||||
sys/time.cpp
|
||||
sys/uio.cpp
|
||||
sys/utsname.cpp
|
||||
sys/wait.cpp
|
||||
syslog.cpp
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
|
||||
uint32_t htonl(uint32_t hostlong)
|
||||
|
|
|
@ -19,7 +19,7 @@ static int malloc_environ()
|
|||
ASSERT(!s_environ_malloced);
|
||||
|
||||
size_t environ_count = 0;
|
||||
while (environ[environ_count])
|
||||
while (environ && environ[environ_count])
|
||||
environ_count++;
|
||||
|
||||
const size_t bitmap_size = (environ_count + 7) / 8;
|
||||
|
@ -111,12 +111,37 @@ static int putenv_impl(char* string, bool malloced)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int clearenv(void)
|
||||
{
|
||||
if (s_environ_malloced)
|
||||
{
|
||||
ASSERT(environ);
|
||||
|
||||
for (size_t i = 0; environ[i]; i++)
|
||||
{
|
||||
const size_t byte = i / 8;
|
||||
const size_t mask = 1 << (i % 8);
|
||||
if (s_environ_bitmap[byte] & mask)
|
||||
free(environ[i]);
|
||||
}
|
||||
|
||||
free(s_environ_bitmap);
|
||||
free(environ);
|
||||
}
|
||||
|
||||
environ = nullptr;
|
||||
s_environ_count = 0;
|
||||
s_environ_bitmap = nullptr;
|
||||
s_environ_malloced = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* getenv(const char* name)
|
||||
{
|
||||
if (environ == nullptr)
|
||||
return nullptr;
|
||||
const size_t namelen = strlen(name);
|
||||
for (int i = 0; environ[i]; i++)
|
||||
for (size_t i = 0; environ[i]; i++)
|
||||
if (strncmp(name, environ[i], namelen) == 0)
|
||||
if (environ[i][namelen] == '=')
|
||||
return environ[i] + namelen + 1;
|
||||
|
@ -154,6 +179,9 @@ int unsetenv(const char* name)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (environ == nullptr)
|
||||
return 0;
|
||||
|
||||
const size_t namelen = strlen(name);
|
||||
|
||||
size_t i = 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _INET_H
|
||||
#define _INET_H 1
|
||||
#ifndef _ARPA_INET_H
|
||||
#define _ARPA_INET_H 1
|
||||
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/arpa_inet.h.html
|
||||
|
||||
|
@ -7,13 +7,8 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
uint32_t htonl(uint32_t);
|
||||
uint16_t htons(uint16_t);
|
||||
uint32_t ntohl(uint32_t);
|
||||
uint16_t ntohs(uint16_t);
|
||||
#include <bits/inet_common.h>
|
||||
#include <bits/types/socklen_t.h>
|
||||
|
||||
in_addr_t inet_addr(const char* cp);
|
||||
char* inet_ntoa(struct in_addr in);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef _BITS_INET_COMMON_H
|
||||
#define _BITS_INET_COMMON_H 1
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define INET_ADDRSTRLEN 16
|
||||
#define INET6_ADDRSTRLEN 46
|
||||
|
||||
typedef uint16_t in_port_t;
|
||||
typedef uint32_t in_addr_t;
|
||||
|
||||
struct in_addr
|
||||
{
|
||||
in_addr_t s_addr;
|
||||
};
|
||||
|
||||
uint32_t htonl(uint32_t);
|
||||
uint16_t htons(uint16_t);
|
||||
uint32_t ntohl(uint32_t);
|
||||
uint16_t ntohs(uint16_t);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef _BITS_TYPES_SOCKLEN_T_H
|
||||
#define _BITS_TYPES_SOCKLEN_T_H 1
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
typedef long socklen_t;
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <bits/inet_common.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define IPPROTO_IP 1
|
||||
|
@ -30,9 +30,6 @@ __BEGIN_DECLS
|
|||
#define INADDR_BROADCAST 0xFFFFFFFF
|
||||
#define INADDR_LOOPBACK 0x7F000001
|
||||
|
||||
#define INET_ADDRSTRLEN 16
|
||||
#define INET6_ADDRSTRLEN 46
|
||||
|
||||
#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
|
||||
#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
|
||||
|
||||
|
@ -51,14 +48,6 @@ __BEGIN_DECLS
|
|||
#define IN6_IS_ADDR_MC_GLOBAL(addr)
|
||||
#endif
|
||||
|
||||
typedef uint16_t in_port_t;
|
||||
typedef uint32_t in_addr_t;
|
||||
|
||||
struct in_addr
|
||||
{
|
||||
in_addr_t s_addr;
|
||||
};
|
||||
|
||||
struct sockaddr_in
|
||||
{
|
||||
sa_family_t sin_family; /* AF_INET. */
|
||||
|
|
|
@ -57,8 +57,8 @@ struct uthread
|
|||
|
||||
#define PTHREAD_SPIN_INITIALIZER (pthread_spinlock_t)0
|
||||
#define PTHREAD_COND_INITIALIZER (pthread_cond_t){ { CLOCK_REALTIME, 0 }, PTHREAD_SPIN_INITIALIZER, NULL }
|
||||
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, false }, 0, 0 }
|
||||
#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t){ { false }, 0, 0 }
|
||||
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, 0 }, 0, 0 }
|
||||
#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t){ { 0 }, 0, 0 }
|
||||
|
||||
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
|
||||
int pthread_attr_destroy(pthread_attr_t* attr);
|
||||
|
|
|
@ -51,6 +51,7 @@ long atol(const char* str);
|
|||
long long atoll(const char* str);
|
||||
void* bsearch(const void* key, const void* base, size_t nel, size_t width, int (*compar)(const void*, const void*));
|
||||
void* calloc(size_t nelem, size_t elsize);
|
||||
int clearenv(void);
|
||||
div_t div(int numer, int denom);
|
||||
double drand48(void);
|
||||
double erand48(unsigned short xsubi[3]);
|
||||
|
|
|
@ -14,7 +14,7 @@ __BEGIN_DECLS
|
|||
#include <sys/uio.h>
|
||||
|
||||
#include <bits/types/sa_family_t.h>
|
||||
typedef long socklen_t;
|
||||
#include <bits/types/socklen_t.h>
|
||||
|
||||
#if !defined(FILENAME_MAX)
|
||||
#define FILENAME_MAX 256
|
||||
|
|
|
@ -60,9 +60,11 @@ __BEGIN_DECLS
|
|||
O(SYS_READLINKAT, readlinkat) \
|
||||
O(SYS_MSYNC, msync) \
|
||||
O(SYS_PREAD, pread) \
|
||||
O(SYS_PWRITE, pwrite) \
|
||||
O(SYS_FCHOWNAT, fchownat) \
|
||||
O(SYS_LOAD_KEYMAP, load_keymap) \
|
||||
O(SYS_SOCKET, socket) \
|
||||
O(SYS_SOCKETPAIR, socketpair) \
|
||||
O(SYS_BIND, bind) \
|
||||
O(SYS_SENDTO, sendto) \
|
||||
O(SYS_RECVFROM, recvfrom) \
|
||||
|
@ -77,6 +79,7 @@ __BEGIN_DECLS
|
|||
O(SYS_SMO_MAP, smo_map) \
|
||||
O(SYS_ISATTY, isatty) \
|
||||
O(SYS_GETSOCKNAME, getsockname) \
|
||||
O(SYS_GETPEERNAME, getpeername) \
|
||||
O(SYS_GETSOCKOPT, getsockopt) \
|
||||
O(SYS_SETSOCKOPT, setsockopt) \
|
||||
O(SYS_REALPATH, realpath) \
|
||||
|
|
|
@ -33,6 +33,36 @@ int gettimeofday(struct timeval* __restrict tp, void* __restrict tzp);
|
|||
int setitimer(int which, const struct itimerval* __restrict value, struct itimerval* __restrict ovalue);
|
||||
int utimes(const char* path, const struct timeval times[2]);
|
||||
|
||||
#define timeradd(a, b, res) \
|
||||
do { \
|
||||
(res)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
|
||||
(res)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
|
||||
(res)->tv_sec += (res)->tv_usec / 1000000; \
|
||||
(res)->tv_usec %= 1000000; \
|
||||
} while (0)
|
||||
|
||||
#define timersub(a, b, res) \
|
||||
do { \
|
||||
(res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
|
||||
(res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
|
||||
(res)->tv_sec += (res)->tv_usec / 1000000; \
|
||||
(res)->tv_usec %= 1000000; \
|
||||
} while (0)
|
||||
|
||||
#define timerclear(tvp) \
|
||||
do { \
|
||||
(tvp)->tv_sec = 0; \
|
||||
(tvp)->tv_usec = 0; \
|
||||
} while (0)
|
||||
|
||||
#define timerisset(tvp) \
|
||||
((tvp)->tv_sec || (tvp)->tv_usec)
|
||||
|
||||
#define timercmp(a, b, CMP) \
|
||||
(((a)->tv_sec == (b)->tv_sec) \
|
||||
? ((a)->tv_usec CMP (b)->tv_usec) \
|
||||
: ((a)->tv_sec CMP (b)->tv_sec))
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -185,6 +185,8 @@ __BEGIN_DECLS
|
|||
typedef int bits32_t;
|
||||
typedef unsigned int u_bits32_t;
|
||||
typedef char* bits64_t;
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned short u_short;
|
||||
typedef unsigned int u_int;
|
||||
typedef unsigned long u_long;
|
||||
#endif
|
||||
|
|
|
@ -70,7 +70,7 @@ int getaddrinfo(const char* __restrict nodename, const char* __restrict servname
|
|||
return EAI_SOCKTYPE;
|
||||
}
|
||||
|
||||
if (!nodename)
|
||||
if (!nodename && !servname)
|
||||
return EAI_NONAME;
|
||||
|
||||
int port = 0;
|
||||
|
@ -147,9 +147,34 @@ error_close_socket:
|
|||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
int getnameinfo(const struct sockaddr* __restrict, socklen_t, char* __restrict, socklen_t, char* __restrict, socklen_t, int)
|
||||
#include <BAN/Debug.h>
|
||||
|
||||
int getnameinfo(const struct sockaddr* __restrict sa, socklen_t salen, char* __restrict node, socklen_t nodelen, char* __restrict service, socklen_t servicelen, int flags)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
printf("getnameinfo(%p, %p, %p, 0x%X)\n", sa, node, service, flags);
|
||||
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
if (salen < static_cast<socklen_t>(sizeof(sockaddr_in)))
|
||||
return EAI_FAMILY;
|
||||
if (service && snprintf(service, servicelen, "%d", reinterpret_cast<sockaddr_in*>(service)->sin_port) < 0)
|
||||
return EAI_SYSTEM;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (salen < static_cast<socklen_t>(sizeof(sockaddr_in6)))
|
||||
return EAI_FAMILY;
|
||||
if (service && snprintf(service, servicelen, "%d", reinterpret_cast<sockaddr_in6*>(service)->sin6_port) < 0)
|
||||
return EAI_SYSTEM;
|
||||
break;
|
||||
default:
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
if (node && inet_ntop(sa->sa_family, sa, node, nodelen) == nullptr)
|
||||
return EAI_SYSTEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hostent* gethostbyname(const char* name)
|
||||
|
|
|
@ -552,6 +552,7 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
|
|||
conversion[0] = va_arg(arguments, int);
|
||||
conversion[1] = '\0';
|
||||
string = conversion;
|
||||
length = 1;
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
@ -633,7 +634,7 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
|
|||
for (int i = length; i < options.width; i++)
|
||||
BAN_PRINTF_PUTC(' ');
|
||||
|
||||
for (int i = 0; i < length && string[i]; i++)
|
||||
for (int i = 0; i < length; i++)
|
||||
BAN_PRINTF_PUTC(string[i]);
|
||||
|
||||
if (options.left_justified)
|
||||
|
|
|
@ -82,13 +82,10 @@ static void init_closed_file(FILE* file)
|
|||
|
||||
static int drop_read_buffer(FILE* file)
|
||||
{
|
||||
if (file->buffer_rd_size == 0)
|
||||
return 0;
|
||||
ASSERT(file->buffer_idx != 0);
|
||||
if (file->buffer_idx == 1)
|
||||
return 0;
|
||||
if (syscall(SYS_SEEK, file->fd, file->buffer_idx - 1, SEEK_CUR) == -1)
|
||||
return EOF;
|
||||
const off_t bytes_remaining = file->buffer_rd_size - file->buffer_idx;
|
||||
if (bytes_remaining > 0)
|
||||
if (syscall(SYS_SEEK, file->fd, -bytes_remaining, SEEK_CUR) == -1)
|
||||
return EOF;
|
||||
file->buffer_rd_size = 0;
|
||||
file->buffer_idx = 0;
|
||||
return 0;
|
||||
|
@ -452,8 +449,7 @@ int fseeko(FILE* file, off_t offset, int whence)
|
|||
ScopeLock _(file);
|
||||
if (fflush(file) == EOF)
|
||||
return -1;
|
||||
long ret = syscall(SYS_SEEK, file->fd, offset, whence);
|
||||
if (ret < 0)
|
||||
if (syscall(SYS_SEEK, file->fd, offset, whence) == -1)
|
||||
return -1;
|
||||
file->eof = false;
|
||||
return 0;
|
||||
|
@ -472,12 +468,12 @@ long ftell(FILE* file)
|
|||
off_t ftello(FILE* file)
|
||||
{
|
||||
ScopeLock _(file);
|
||||
if (fflush(file) == EOF)
|
||||
auto offset = syscall(SYS_TELL, file->fd);
|
||||
if (offset == -1)
|
||||
return -1;
|
||||
long ret = syscall(SYS_TELL, file->fd);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
return ret;
|
||||
if (file->buffer_rd_size)
|
||||
offset -= file->buffer_rd_size - file->buffer_idx;
|
||||
return offset - file->unget_buf_idx;
|
||||
}
|
||||
|
||||
int ftrylockfile(FILE* fp)
|
||||
|
@ -541,10 +537,7 @@ int getc_unlocked(FILE* file)
|
|||
if (file->unget_buf_idx)
|
||||
{
|
||||
file->unget_buf_idx--;
|
||||
unsigned char ch = file->unget_buffer[file->unget_buf_idx];
|
||||
if (fseeko(file, 1, SEEK_CUR) == -1)
|
||||
return EOF;
|
||||
return ch;
|
||||
return file->unget_buffer[file->unget_buf_idx];
|
||||
}
|
||||
|
||||
// read from unbuffered file
|
||||
|
@ -582,8 +575,6 @@ int getc_unlocked(FILE* file)
|
|||
((nread == 0) ? file->eof : file->error) = true;
|
||||
return EOF;
|
||||
}
|
||||
if (fseeko(file, 1 - nread, SEEK_CUR) == -1)
|
||||
return EOF;
|
||||
file->buffer_rd_size = nread;
|
||||
file->buffer_idx = 1;
|
||||
return file->buffer[0];
|
||||
|
@ -965,7 +956,29 @@ char* tempnam(const char*, const char*);
|
|||
|
||||
FILE* tmpfile(void)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
for (;;)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
if (tmpnam(path) == nullptr)
|
||||
return nullptr;
|
||||
|
||||
int fd = open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (fd == -1)
|
||||
{
|
||||
if (errno == EEXIST)
|
||||
continue;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
(void)unlink(path);
|
||||
|
||||
FILE* fp = fdopen(fd, "wb+");
|
||||
if (fp != nullptr)
|
||||
return fp;
|
||||
|
||||
close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
char* tmpnam(char* storage)
|
||||
|
@ -998,9 +1011,6 @@ int ungetc_unlocked(int c, FILE* stream)
|
|||
return EOF;
|
||||
}
|
||||
|
||||
if (fseeko(stream, -1, SEEK_CUR) == -1)
|
||||
return EOF;
|
||||
|
||||
stream->unget_buffer[stream->unget_buf_idx] = c;
|
||||
stream->unget_buf_idx++;
|
||||
stream->eof = false;
|
||||
|
|
|
@ -69,10 +69,8 @@ static constexpr int get_base_digit(char c, int base)
|
|||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_digit_append_overflow(bool negative, T current, int digit, int base)
|
||||
static constexpr bool will_digit_append_overflow(T current, int digit, int base)
|
||||
{
|
||||
if (BAN::is_unsigned_v<T> && negative && digit)
|
||||
return true;
|
||||
if (BAN::Math::will_multiplication_overflow<T>(current, base))
|
||||
return true;
|
||||
if (BAN::Math::will_addition_overflow<T>(current * base, current < 0 ? -digit : digit))
|
||||
|
@ -86,6 +84,8 @@ static T strtoT(const char* str, char** endp, int base, int& error)
|
|||
// validate base
|
||||
if (base != 0 && (base < 2 || base > 36))
|
||||
{
|
||||
if (endp)
|
||||
*endp = const_cast<char*>(str);
|
||||
error = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
@ -134,11 +134,18 @@ static T strtoT(const char* str, char** endp, int base, int& error)
|
|||
break;
|
||||
str++;
|
||||
|
||||
overflow = will_digit_append_overflow(negative, result, digit, base);
|
||||
overflow = will_digit_append_overflow(result, digit, base);
|
||||
if (!overflow)
|
||||
result = result * base + (negative ? -digit : digit);
|
||||
{
|
||||
if (negative && !BAN::is_unsigned_v<T>)
|
||||
digit = -digit;
|
||||
result = result * base + digit;
|
||||
}
|
||||
}
|
||||
|
||||
if (negative && BAN::is_unsigned_v<T>)
|
||||
result = -result;
|
||||
|
||||
// save endp if asked
|
||||
if (endp)
|
||||
{
|
||||
|
@ -540,6 +547,26 @@ char* ptsname(int fildes)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
int mblen(const char* s, size_t n)
|
||||
{
|
||||
if (s == nullptr)
|
||||
return 0;
|
||||
if (n == 0)
|
||||
return -1;
|
||||
switch (__getlocale(LC_CTYPE))
|
||||
{
|
||||
case LOCALE_INVALID:
|
||||
ASSERT_NOT_REACHED();
|
||||
case LOCALE_POSIX:
|
||||
return 1;
|
||||
case LOCALE_UTF8:
|
||||
if (const auto bytes = BAN::UTF8::byte_length(*s); n >= bytes)
|
||||
return bytes;
|
||||
return -1;
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n)
|
||||
{
|
||||
auto* us = reinterpret_cast<const unsigned char*>(s);
|
||||
|
|
|
@ -147,11 +147,12 @@ char* strcat(char* __restrict__ dest, const char* __restrict__ src)
|
|||
|
||||
char* strncat(char* __restrict__ dest, const char* __restrict__ src, size_t n)
|
||||
{
|
||||
char* ret = dest;
|
||||
dest += strlen(dest);
|
||||
while (*src && n--)
|
||||
*dest++ = *src++;
|
||||
*dest = '\0';
|
||||
return dest;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int strcoll(const char* s1, const char* s2)
|
||||
|
|
|
@ -68,11 +68,21 @@ int socket(int domain, int type, int protocol)
|
|||
return syscall(SYS_SOCKET, domain, type, protocol);
|
||||
}
|
||||
|
||||
int socketpair(int domain, int type, int protocol, int socket_vector[2])
|
||||
{
|
||||
return syscall(SYS_SOCKETPAIR, domain, type, protocol, socket_vector);
|
||||
}
|
||||
|
||||
int getsockname(int socket, struct sockaddr* __restrict address, socklen_t* __restrict address_len)
|
||||
{
|
||||
return syscall(SYS_GETSOCKNAME, socket, address, address_len);
|
||||
}
|
||||
|
||||
int getpeername(int socket, struct sockaddr* __restrict address, socklen_t* __restrict address_len)
|
||||
{
|
||||
return syscall(SYS_GETPEERNAME, socket, address, address_len);
|
||||
}
|
||||
|
||||
int getsockopt(int socket, int level, int option_name, void* __restrict option_value, socklen_t* __restrict option_len)
|
||||
{
|
||||
return syscall(SYS_GETSOCKOPT, socket, level, option_name, option_value, option_len);
|
||||
|
@ -87,11 +97,6 @@ int setsockopt(int socket, int level, int option_name, const void* option_value,
|
|||
|
||||
#include <BAN/Assert.h>
|
||||
|
||||
int getpeername(int, struct sockaddr* __restrict, socklen_t* __restrict)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
int shutdown(int, int)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
ssize_t readv(int fildes, const struct iovec* iov, int iovcnt)
|
||||
{
|
||||
size_t result = 0;
|
||||
for (int i = 0; i < iovcnt; i++)
|
||||
{
|
||||
uint8_t* base = static_cast<uint8_t*>(iov->iov_base);
|
||||
|
||||
size_t nread = 0;
|
||||
while (nread < iov[i].iov_len)
|
||||
{
|
||||
const ssize_t ret = read(fildes, base + nread, iov[i].iov_len - nread);
|
||||
if (ret == -1 && result == 0)
|
||||
return -1;
|
||||
if (ret <= 0)
|
||||
return result;
|
||||
nread += ret;
|
||||
}
|
||||
result += nread;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t writev(int fildes, const struct iovec* iov, int iovcnt)
|
||||
{
|
||||
size_t result = 0;
|
||||
for (int i = 0; i < iovcnt; i++)
|
||||
{
|
||||
const uint8_t* base = static_cast<const uint8_t*>(iov->iov_base);
|
||||
|
||||
size_t nwrite = 0;
|
||||
while (nwrite < iov[i].iov_len)
|
||||
{
|
||||
const ssize_t ret = write(fildes, base + nwrite, iov[i].iov_len - nwrite);
|
||||
if (ret == -1 && result == 0)
|
||||
return -1;
|
||||
if (ret <= 0)
|
||||
return result;
|
||||
nwrite += ret;
|
||||
}
|
||||
result += nwrite;
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -9,6 +9,10 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int daylight;
|
||||
long timezone;
|
||||
char* tzname[2];
|
||||
|
||||
int clock_gettime(clockid_t clock_id, struct timespec* tp)
|
||||
{
|
||||
return syscall(SYS_CLOCK_GETTIME, clock_id, tp);
|
||||
|
@ -127,8 +131,8 @@ time_t mktime(struct tm* tm)
|
|||
tm->tm_mon %= 12;
|
||||
|
||||
tm->tm_yday = tm->tm_mday - 1;
|
||||
if (tm->tm_mon > 0)
|
||||
tm->tm_yday += month_days[tm->tm_mon - 1];
|
||||
for (int i = 0; i < tm->tm_mon; i++)
|
||||
tm->tm_yday += month_days[i];
|
||||
|
||||
const time_t num_febs = (tm->tm_mon > 1) ? tm->tm_year + 1 : tm->tm_year;
|
||||
const time_t leap_years = (num_febs - 69) / 4 - (num_febs - 1) / 100 + (num_febs + 299) / 400;
|
||||
|
@ -196,6 +200,14 @@ struct tm* localtime(const time_t* timer)
|
|||
return localtime_r(timer, &tm);
|
||||
}
|
||||
|
||||
void tzset()
|
||||
{
|
||||
daylight = 0;
|
||||
timezone = 0;
|
||||
tzname[0] = const_cast<char*>("UTC");
|
||||
tzname[1] = const_cast<char*>("UTC");
|
||||
}
|
||||
|
||||
size_t strftime(char* __restrict s, size_t maxsize, const char* __restrict format, const struct tm* __restrict timeptr)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
@ -544,13 +556,3 @@ size_t strftime(char* __restrict s, size_t maxsize, const char* __restrict forma
|
|||
s[len++] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
|
||||
long timezone;
|
||||
void tzset()
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -127,6 +127,11 @@ ssize_t pread(int fildes, void* buf, size_t nbyte, off_t offset)
|
|||
return syscall(SYS_PREAD, fildes, buf, nbyte, offset);
|
||||
}
|
||||
|
||||
ssize_t pwrite(int fildes, const void* buf, size_t nbyte, off_t offset)
|
||||
{
|
||||
return syscall(SYS_PWRITE, fildes, buf, nbyte, offset);
|
||||
}
|
||||
|
||||
off_t lseek(int fildes, off_t offset, int whence)
|
||||
{
|
||||
return syscall(SYS_SEEK, fildes, offset, whence);
|
||||
|
|
Loading…
Reference in New Issue