mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 01:47:36 +00:00
Kernel: Add so_error to keep track of the socket's error state
This sets the m_so_error variable every time the socket returns an error.
This commit is contained in:
parent
f424485193
commit
0095c7cb7d
6 changed files with 88 additions and 78 deletions
|
@ -108,20 +108,20 @@ KResult IPv4Socket::bind(Userspace<const sockaddr*> user_address, socklen_t addr
|
||||||
{
|
{
|
||||||
VERIFY(setup_state() == SetupState::Unstarted);
|
VERIFY(setup_state() == SetupState::Unstarted);
|
||||||
if (address_size != sizeof(sockaddr_in))
|
if (address_size != sizeof(sockaddr_in))
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
|
|
||||||
sockaddr_in address;
|
sockaddr_in address;
|
||||||
if (!copy_from_user(&address, user_address, sizeof(sockaddr_in)))
|
if (!copy_from_user(&address, user_address, sizeof(sockaddr_in)))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
|
|
||||||
if (address.sin_family != AF_INET)
|
if (address.sin_family != AF_INET)
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
|
|
||||||
auto requested_local_port = ntohs(address.sin_port);
|
auto requested_local_port = ntohs(address.sin_port);
|
||||||
if (!Process::current()->is_superuser()) {
|
if (!Process::current()->is_superuser()) {
|
||||||
if (requested_local_port > 0 && requested_local_port < 1024) {
|
if (requested_local_port > 0 && requested_local_port < 1024) {
|
||||||
dbgln("UID {} attempted to bind {} to port {}", Process::current()->uid(), class_name(), requested_local_port);
|
dbgln("UID {} attempted to bind {} to port {}", Process::current()->uid(), class_name(), requested_local_port);
|
||||||
return EACCES;
|
return set_so_error(EACCES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,19 +152,19 @@ KResult IPv4Socket::listen(size_t backlog)
|
||||||
KResult IPv4Socket::connect(FileDescription& description, Userspace<const sockaddr*> address, socklen_t address_size, ShouldBlock should_block)
|
KResult IPv4Socket::connect(FileDescription& description, Userspace<const sockaddr*> address, socklen_t address_size, ShouldBlock should_block)
|
||||||
{
|
{
|
||||||
if (address_size != sizeof(sockaddr_in))
|
if (address_size != sizeof(sockaddr_in))
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
u16 sa_family_copy;
|
u16 sa_family_copy;
|
||||||
auto* user_address = reinterpret_cast<const sockaddr*>(address.unsafe_userspace_ptr());
|
auto* user_address = reinterpret_cast<const sockaddr*>(address.unsafe_userspace_ptr());
|
||||||
if (!copy_from_user(&sa_family_copy, &user_address->sa_family, sizeof(u16)))
|
if (!copy_from_user(&sa_family_copy, &user_address->sa_family, sizeof(u16)))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
if (sa_family_copy != AF_INET)
|
if (sa_family_copy != AF_INET)
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
if (m_role == Role::Connected)
|
if (m_role == Role::Connected)
|
||||||
return EISCONN;
|
return set_so_error(EISCONN);
|
||||||
|
|
||||||
sockaddr_in safe_address;
|
sockaddr_in safe_address;
|
||||||
if (!copy_from_user(&safe_address, (const sockaddr_in*)user_address, sizeof(sockaddr_in)))
|
if (!copy_from_user(&safe_address, (const sockaddr_in*)user_address, sizeof(sockaddr_in)))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
|
|
||||||
m_peer_address = IPv4Address((const u8*)&safe_address.sin_addr.s_addr);
|
m_peer_address = IPv4Address((const u8*)&safe_address.sin_addr.s_addr);
|
||||||
if (m_peer_address == IPv4Address { 0, 0, 0, 0 })
|
if (m_peer_address == IPv4Address { 0, 0, 0, 0 })
|
||||||
|
@ -205,16 +205,16 @@ KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const UserOrKernelBuffer&
|
||||||
MutexLocker locker(lock());
|
MutexLocker locker(lock());
|
||||||
|
|
||||||
if (addr && addr_length != sizeof(sockaddr_in))
|
if (addr && addr_length != sizeof(sockaddr_in))
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
|
|
||||||
if (addr) {
|
if (addr) {
|
||||||
sockaddr_in ia;
|
sockaddr_in ia;
|
||||||
if (!copy_from_user(&ia, Userspace<const sockaddr_in*>(addr.ptr())))
|
if (!copy_from_user(&ia, Userspace<const sockaddr_in*>(addr.ptr())))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
|
|
||||||
if (ia.sin_family != AF_INET) {
|
if (ia.sin_family != AF_INET) {
|
||||||
dmesgln("sendto: Bad address family: {} is not AF_INET", ia.sin_family);
|
dmesgln("sendto: Bad address family: {} is not AF_INET", ia.sin_family);
|
||||||
return EAFNOSUPPORT;
|
return set_so_error(EAFNOSUPPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_peer_address = IPv4Address((const u8*)&ia.sin_addr.s_addr);
|
m_peer_address = IPv4Address((const u8*)&ia.sin_addr.s_addr);
|
||||||
|
@ -222,11 +222,11 @@ KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const UserOrKernelBuffer&
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_connected() && m_peer_address.is_zero())
|
if (!is_connected() && m_peer_address.is_zero())
|
||||||
return EPIPE;
|
return set_so_error(EPIPE);
|
||||||
|
|
||||||
auto routing_decision = route_to(m_peer_address, m_local_address, bound_interface());
|
auto routing_decision = route_to(m_peer_address, m_local_address, bound_interface());
|
||||||
if (routing_decision.is_zero())
|
if (routing_decision.is_zero())
|
||||||
return EHOSTUNREACH;
|
return set_so_error(EHOSTUNREACH);
|
||||||
|
|
||||||
if (m_local_address.to_u32() == 0)
|
if (m_local_address.to_u32() == 0)
|
||||||
m_local_address = routing_decision.adapter->ipv4_address();
|
m_local_address = routing_decision.adapter->ipv4_address();
|
||||||
|
@ -241,12 +241,12 @@ KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const UserOrKernelBuffer&
|
||||||
data_length = min(data_length, routing_decision.adapter->mtu() - ipv4_payload_offset);
|
data_length = min(data_length, routing_decision.adapter->mtu() - ipv4_payload_offset);
|
||||||
auto packet = routing_decision.adapter->acquire_packet_buffer(ipv4_payload_offset + data_length);
|
auto packet = routing_decision.adapter->acquire_packet_buffer(ipv4_payload_offset + data_length);
|
||||||
if (!packet)
|
if (!packet)
|
||||||
return ENOMEM;
|
return set_so_error(ENOMEM);
|
||||||
routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), routing_decision.next_hop,
|
routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), routing_decision.next_hop,
|
||||||
m_peer_address, (IPv4Protocol)protocol(), data_length, m_ttl);
|
m_peer_address, (IPv4Protocol)protocol(), data_length, m_ttl);
|
||||||
if (!data.read(packet->buffer->data() + ipv4_payload_offset, data_length)) {
|
if (!data.read(packet->buffer->data() + ipv4_payload_offset, data_length)) {
|
||||||
routing_decision.adapter->release_packet_buffer(*packet);
|
routing_decision.adapter->release_packet_buffer(*packet);
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
}
|
}
|
||||||
routing_decision.adapter->send_packet(packet->bytes());
|
routing_decision.adapter->send_packet(packet->bytes());
|
||||||
routing_decision.adapter->release_packet_buffer(*packet);
|
routing_decision.adapter->release_packet_buffer(*packet);
|
||||||
|
@ -266,7 +266,7 @@ KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description
|
||||||
if (protocol_is_disconnected())
|
if (protocol_is_disconnected())
|
||||||
return 0;
|
return 0;
|
||||||
if (!description.is_blocking())
|
if (!description.is_blocking())
|
||||||
return EAGAIN;
|
return set_so_error(EAGAIN);
|
||||||
|
|
||||||
locker.unlock();
|
locker.unlock();
|
||||||
auto unblocked_flags = BlockFlags::None;
|
auto unblocked_flags = BlockFlags::None;
|
||||||
|
@ -275,10 +275,10 @@ KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description
|
||||||
|
|
||||||
if (!has_flag(unblocked_flags, BlockFlags::Read)) {
|
if (!has_flag(unblocked_flags, BlockFlags::Read)) {
|
||||||
if (res.was_interrupted())
|
if (res.was_interrupted())
|
||||||
return EINTR;
|
return set_so_error(EINTR);
|
||||||
|
|
||||||
// Unblocked due to timeout.
|
// Unblocked due to timeout.
|
||||||
return EAGAIN;
|
return set_so_error(EAGAIN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ KResultOr<size_t> IPv4Socket::receive_packet_buffered(FileDescription& descripti
|
||||||
if (protocol_is_disconnected())
|
if (protocol_is_disconnected())
|
||||||
return 0;
|
return 0;
|
||||||
if (!description.is_blocking())
|
if (!description.is_blocking())
|
||||||
return EAGAIN;
|
return set_so_error(EAGAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_receive_queue.is_empty()) {
|
if (!m_receive_queue.is_empty()) {
|
||||||
|
@ -336,10 +336,10 @@ KResultOr<size_t> IPv4Socket::receive_packet_buffered(FileDescription& descripti
|
||||||
|
|
||||||
if (!has_flag(unblocked_flags, BlockFlags::Read)) {
|
if (!has_flag(unblocked_flags, BlockFlags::Read)) {
|
||||||
if (res.was_interrupted())
|
if (res.was_interrupted())
|
||||||
return EINTR;
|
return set_so_error(EINTR);
|
||||||
|
|
||||||
// Unblocked due to timeout.
|
// Unblocked due to timeout.
|
||||||
return EAGAIN;
|
return set_so_error(EAGAIN);
|
||||||
}
|
}
|
||||||
VERIFY(m_can_read);
|
VERIFY(m_can_read);
|
||||||
VERIFY(!m_receive_queue.is_empty());
|
VERIFY(!m_receive_queue.is_empty());
|
||||||
|
@ -369,18 +369,18 @@ KResultOr<size_t> IPv4Socket::receive_packet_buffered(FileDescription& descripti
|
||||||
out_addr.sin_family = AF_INET;
|
out_addr.sin_family = AF_INET;
|
||||||
Userspace<sockaddr_in*> dest_addr = addr.ptr();
|
Userspace<sockaddr_in*> dest_addr = addr.ptr();
|
||||||
if (!copy_to_user(dest_addr, &out_addr))
|
if (!copy_to_user(dest_addr, &out_addr))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
|
|
||||||
socklen_t out_length = sizeof(sockaddr_in);
|
socklen_t out_length = sizeof(sockaddr_in);
|
||||||
VERIFY(addr_length);
|
VERIFY(addr_length);
|
||||||
if (!copy_to_user(addr_length, &out_length))
|
if (!copy_to_user(addr_length, &out_length))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type() == SOCK_RAW) {
|
if (type() == SOCK_RAW) {
|
||||||
size_t bytes_written = min(packet.data.value().size(), buffer_length);
|
size_t bytes_written = min(packet.data.value().size(), buffer_length);
|
||||||
if (!buffer.write(packet.data.value().data(), bytes_written))
|
if (!buffer.write(packet.data.value().data(), bytes_written))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
return bytes_written;
|
return bytes_written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,9 +392,9 @@ KResultOr<size_t> IPv4Socket::recvfrom(FileDescription& description, UserOrKerne
|
||||||
if (user_addr_length) {
|
if (user_addr_length) {
|
||||||
socklen_t addr_length;
|
socklen_t addr_length;
|
||||||
if (!copy_from_user(&addr_length, user_addr_length.unsafe_userspace_ptr()))
|
if (!copy_from_user(&addr_length, user_addr_length.unsafe_userspace_ptr()))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
if (addr_length < sizeof(sockaddr_in))
|
if (addr_length < sizeof(sockaddr_in))
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbgln_if(IPV4_SOCKET_DEBUG, "recvfrom: type={}, local_port={}", type(), local_port());
|
dbgln_if(IPV4_SOCKET_DEBUG, "recvfrom: type={}, local_port={}", type(), local_port());
|
||||||
|
|
|
@ -122,14 +122,14 @@ KResult LocalSocket::bind(Userspace<const sockaddr*> user_address, socklen_t add
|
||||||
{
|
{
|
||||||
VERIFY(setup_state() == SetupState::Unstarted);
|
VERIFY(setup_state() == SetupState::Unstarted);
|
||||||
if (address_size != sizeof(sockaddr_un))
|
if (address_size != sizeof(sockaddr_un))
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
|
|
||||||
sockaddr_un address;
|
sockaddr_un address;
|
||||||
if (!copy_from_user(&address, user_address, sizeof(sockaddr_un)))
|
if (!copy_from_user(&address, user_address, sizeof(sockaddr_un)))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
|
|
||||||
if (address.sun_family != AF_LOCAL)
|
if (address.sun_family != AF_LOCAL)
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
|
|
||||||
auto path = String(address.sun_path, strnlen(address.sun_path, sizeof(address.sun_path)));
|
auto path = String(address.sun_path, strnlen(address.sun_path, sizeof(address.sun_path)));
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ KResult LocalSocket::bind(Userspace<const sockaddr*> user_address, socklen_t add
|
||||||
auto result = VirtualFileSystem::the().open(path, O_CREAT | O_EXCL | O_NOFOLLOW_NOERROR, mode, Process::current()->current_directory(), owner);
|
auto result = VirtualFileSystem::the().open(path, O_CREAT | O_EXCL | O_NOFOLLOW_NOERROR, mode, Process::current()->current_directory(), owner);
|
||||||
if (result.is_error()) {
|
if (result.is_error()) {
|
||||||
if (result.error() == -EEXIST)
|
if (result.error() == -EEXIST)
|
||||||
return EADDRINUSE;
|
return set_so_error(EADDRINUSE);
|
||||||
return result.error();
|
return result.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ KResult LocalSocket::bind(Userspace<const sockaddr*> user_address, socklen_t add
|
||||||
|
|
||||||
VERIFY(file->inode());
|
VERIFY(file->inode());
|
||||||
if (!file->inode()->bind_socket(*this))
|
if (!file->inode()->bind_socket(*this))
|
||||||
return EADDRINUSE;
|
return set_so_error(EADDRINUSE);
|
||||||
|
|
||||||
m_file = move(file);
|
m_file = move(file);
|
||||||
|
|
||||||
|
@ -161,33 +161,33 @@ KResult LocalSocket::connect(FileDescription& description, Userspace<const socka
|
||||||
{
|
{
|
||||||
VERIFY(!m_bound);
|
VERIFY(!m_bound);
|
||||||
if (address_size != sizeof(sockaddr_un))
|
if (address_size != sizeof(sockaddr_un))
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
u16 sa_family_copy;
|
u16 sa_family_copy;
|
||||||
auto* user_address = reinterpret_cast<const sockaddr*>(address.unsafe_userspace_ptr());
|
auto* user_address = reinterpret_cast<const sockaddr*>(address.unsafe_userspace_ptr());
|
||||||
if (!copy_from_user(&sa_family_copy, &user_address->sa_family, sizeof(u16)))
|
if (!copy_from_user(&sa_family_copy, &user_address->sa_family, sizeof(u16)))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
if (sa_family_copy != AF_LOCAL)
|
if (sa_family_copy != AF_LOCAL)
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
if (is_connected())
|
if (is_connected())
|
||||||
return EISCONN;
|
return set_so_error(EISCONN);
|
||||||
|
|
||||||
const auto& local_address = *reinterpret_cast<const sockaddr_un*>(user_address);
|
const auto& local_address = *reinterpret_cast<const sockaddr_un*>(user_address);
|
||||||
char safe_address[sizeof(local_address.sun_path) + 1] = { 0 };
|
char safe_address[sizeof(local_address.sun_path) + 1] = { 0 };
|
||||||
if (!copy_from_user(&safe_address[0], &local_address.sun_path[0], sizeof(safe_address) - 1))
|
if (!copy_from_user(&safe_address[0], &local_address.sun_path[0], sizeof(safe_address) - 1))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
safe_address[sizeof(safe_address) - 1] = '\0';
|
safe_address[sizeof(safe_address) - 1] = '\0';
|
||||||
|
|
||||||
dbgln_if(LOCAL_SOCKET_DEBUG, "LocalSocket({}) connect({})", this, safe_address);
|
dbgln_if(LOCAL_SOCKET_DEBUG, "LocalSocket({}) connect({})", this, safe_address);
|
||||||
|
|
||||||
auto description_or_error = VirtualFileSystem::the().open(safe_address, O_RDWR, 0, Process::current()->current_directory());
|
auto description_or_error = VirtualFileSystem::the().open(safe_address, O_RDWR, 0, Process::current()->current_directory());
|
||||||
if (description_or_error.is_error())
|
if (description_or_error.is_error())
|
||||||
return ECONNREFUSED;
|
return set_so_error(ECONNREFUSED);
|
||||||
|
|
||||||
m_file = move(description_or_error.value());
|
m_file = move(description_or_error.value());
|
||||||
|
|
||||||
VERIFY(m_file->inode());
|
VERIFY(m_file->inode());
|
||||||
if (!m_file->inode()->socket())
|
if (!m_file->inode()->socket())
|
||||||
return ECONNREFUSED;
|
return set_so_error(ECONNREFUSED);
|
||||||
|
|
||||||
m_address.sun_family = sa_family_copy;
|
m_address.sun_family = sa_family_copy;
|
||||||
memcpy(m_address.sun_path, safe_address, sizeof(m_address.sun_path));
|
memcpy(m_address.sun_path, safe_address, sizeof(m_address.sun_path));
|
||||||
|
@ -210,14 +210,14 @@ KResult LocalSocket::connect(FileDescription& description, Userspace<const socka
|
||||||
auto unblock_flags = Thread::FileDescriptionBlocker::BlockFlags::None;
|
auto unblock_flags = Thread::FileDescriptionBlocker::BlockFlags::None;
|
||||||
if (Thread::current()->block<Thread::ConnectBlocker>({}, description, unblock_flags).was_interrupted()) {
|
if (Thread::current()->block<Thread::ConnectBlocker>({}, description, unblock_flags).was_interrupted()) {
|
||||||
set_connect_side_role(Role::None);
|
set_connect_side_role(Role::None);
|
||||||
return EINTR;
|
return set_so_error(EINTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbgln_if(LOCAL_SOCKET_DEBUG, "LocalSocket({}) connect({}) status is {}", this, safe_address, to_string(setup_state()));
|
dbgln_if(LOCAL_SOCKET_DEBUG, "LocalSocket({}) connect({}) status is {}", this, safe_address, to_string(setup_state()));
|
||||||
|
|
||||||
if (!has_flag(unblock_flags, Thread::FileDescriptionBlocker::BlockFlags::Connect)) {
|
if (!has_flag(unblock_flags, Thread::FileDescriptionBlocker::BlockFlags::Connect)) {
|
||||||
set_connect_side_role(Role::None);
|
set_connect_side_role(Role::None);
|
||||||
return ECONNREFUSED;
|
return set_so_error(ECONNREFUSED);
|
||||||
}
|
}
|
||||||
set_connect_side_role(Role::Connected);
|
set_connect_side_role(Role::Connected);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
|
@ -227,7 +227,7 @@ KResult LocalSocket::listen(size_t backlog)
|
||||||
{
|
{
|
||||||
MutexLocker locker(lock());
|
MutexLocker locker(lock());
|
||||||
if (type() != SOCK_STREAM)
|
if (type() != SOCK_STREAM)
|
||||||
return EOPNOTSUPP;
|
return set_so_error(EOPNOTSUPP);
|
||||||
set_backlog(backlog);
|
set_backlog(backlog);
|
||||||
auto previous_role = m_role;
|
auto previous_role = m_role;
|
||||||
m_role = Role::Listener;
|
m_role = Role::Listener;
|
||||||
|
@ -300,10 +300,10 @@ bool LocalSocket::can_write(const FileDescription& description, size_t) const
|
||||||
KResultOr<size_t> LocalSocket::sendto(FileDescription& description, const UserOrKernelBuffer& data, size_t data_size, int, Userspace<const sockaddr*>, socklen_t)
|
KResultOr<size_t> LocalSocket::sendto(FileDescription& description, const UserOrKernelBuffer& data, size_t data_size, int, Userspace<const sockaddr*>, socklen_t)
|
||||||
{
|
{
|
||||||
if (!has_attached_peer(description))
|
if (!has_attached_peer(description))
|
||||||
return EPIPE;
|
return set_so_error(EPIPE);
|
||||||
auto* socket_buffer = send_buffer_for(description);
|
auto* socket_buffer = send_buffer_for(description);
|
||||||
if (!socket_buffer)
|
if (!socket_buffer)
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
auto nwritten_or_error = socket_buffer->write(data, data_size);
|
auto nwritten_or_error = socket_buffer->write(data, data_size);
|
||||||
if (!nwritten_or_error.is_error() && nwritten_or_error.value() > 0)
|
if (!nwritten_or_error.is_error() && nwritten_or_error.value() > 0)
|
||||||
Thread::current()->did_unix_socket_write(nwritten_or_error.value());
|
Thread::current()->did_unix_socket_write(nwritten_or_error.value());
|
||||||
|
@ -334,17 +334,18 @@ KResultOr<size_t> LocalSocket::recvfrom(FileDescription& description, UserOrKern
|
||||||
{
|
{
|
||||||
auto* socket_buffer = receive_buffer_for(description);
|
auto* socket_buffer = receive_buffer_for(description);
|
||||||
if (!socket_buffer)
|
if (!socket_buffer)
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
if (!description.is_blocking()) {
|
if (!description.is_blocking()) {
|
||||||
if (socket_buffer->is_empty()) {
|
if (socket_buffer->is_empty()) {
|
||||||
if (!has_attached_peer(description))
|
if (!has_attached_peer(description))
|
||||||
return 0;
|
return 0;
|
||||||
return EAGAIN;
|
return set_so_error(EAGAIN);
|
||||||
}
|
}
|
||||||
} else if (!can_read(description, 0)) {
|
} else if (!can_read(description, 0)) {
|
||||||
auto unblock_flags = Thread::FileDescriptionBlocker::BlockFlags::None;
|
auto unblock_flags = Thread::FileDescriptionBlocker::BlockFlags::None;
|
||||||
if (Thread::current()->block<Thread::ReadBlocker>({}, description, unblock_flags).was_interrupted())
|
if (Thread::current()->block<Thread::ReadBlocker>({}, description, unblock_flags).was_interrupted()) {
|
||||||
return EINTR;
|
return set_so_error(EINTR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!has_attached_peer(description) && socket_buffer->is_empty())
|
if (!has_attached_peer(description) && socket_buffer->is_empty())
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -447,7 +448,7 @@ KResult LocalSocket::chown(FileDescription&, uid_t uid, gid_t gid)
|
||||||
|
|
||||||
auto current_process = Process::current();
|
auto current_process = Process::current();
|
||||||
if (!current_process->is_superuser() && (current_process->euid() != uid || !current_process->in_group(gid)))
|
if (!current_process->is_superuser() && (current_process->euid() != uid || !current_process->in_group(gid)))
|
||||||
return EPERM;
|
return set_so_error(EPERM);
|
||||||
|
|
||||||
m_prebind_uid = uid;
|
m_prebind_uid = uid;
|
||||||
m_prebind_gid = gid;
|
m_prebind_gid = gid;
|
||||||
|
@ -479,13 +480,13 @@ KResult LocalSocket::sendfd(const FileDescription& socket_description, FileDescr
|
||||||
MutexLocker locker(lock());
|
MutexLocker locker(lock());
|
||||||
auto role = this->role(socket_description);
|
auto role = this->role(socket_description);
|
||||||
if (role != Role::Connected && role != Role::Accepted)
|
if (role != Role::Connected && role != Role::Accepted)
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
auto& queue = sendfd_queue_for(socket_description);
|
auto& queue = sendfd_queue_for(socket_description);
|
||||||
// FIXME: Figure out how we should limit this properly.
|
// FIXME: Figure out how we should limit this properly.
|
||||||
if (queue.size() > 128)
|
if (queue.size() > 128)
|
||||||
return EBUSY;
|
return set_so_error(EBUSY);
|
||||||
if (!queue.try_append(move(passing_description)))
|
if (!queue.try_append(move(passing_description)))
|
||||||
return ENOMEM;
|
return set_so_error(ENOMEM);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,11 +495,11 @@ KResultOr<NonnullRefPtr<FileDescription>> LocalSocket::recvfd(const FileDescript
|
||||||
MutexLocker locker(lock());
|
MutexLocker locker(lock());
|
||||||
auto role = this->role(socket_description);
|
auto role = this->role(socket_description);
|
||||||
if (role != Role::Connected && role != Role::Accepted)
|
if (role != Role::Connected && role != Role::Accepted)
|
||||||
return EINVAL;
|
return set_so_error(EINVAL);
|
||||||
auto& queue = recvfd_queue_for(socket_description);
|
auto& queue = recvfd_queue_for(socket_description);
|
||||||
if (queue.is_empty()) {
|
if (queue.is_empty()) {
|
||||||
// FIXME: Figure out the perfect error code for this.
|
// FIXME: Figure out the perfect error code for this.
|
||||||
return EAGAIN;
|
return set_so_error(EAGAIN);
|
||||||
}
|
}
|
||||||
return queue.take_first();
|
return queue.take_first();
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,9 +71,9 @@ KResult Socket::queue_connection_from(NonnullRefPtr<Socket> peer)
|
||||||
dbgln_if(SOCKET_DEBUG, "Socket({}) queueing connection", this);
|
dbgln_if(SOCKET_DEBUG, "Socket({}) queueing connection", this);
|
||||||
MutexLocker locker(m_lock);
|
MutexLocker locker(m_lock);
|
||||||
if (m_pending.size() >= m_backlog)
|
if (m_pending.size() >= m_backlog)
|
||||||
return ECONNREFUSED;
|
return set_so_error(ECONNREFUSED);
|
||||||
if (!m_pending.try_append(peer))
|
if (!m_pending.try_append(peer))
|
||||||
return ENOMEM;
|
return set_so_error(ENOMEM);
|
||||||
evaluate_block_conditions();
|
evaluate_block_conditions();
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ KResultOr<size_t> Socket::read(FileDescription& description, u64, UserOrKernelBu
|
||||||
KResultOr<size_t> Socket::write(FileDescription& description, u64, const UserOrKernelBuffer& data, size_t size)
|
KResultOr<size_t> Socket::write(FileDescription& description, u64, const UserOrKernelBuffer& data, size_t size)
|
||||||
{
|
{
|
||||||
if (is_shut_down_for_writing())
|
if (is_shut_down_for_writing())
|
||||||
return EPIPE;
|
return set_so_error(EPIPE);
|
||||||
return sendto(description, data, size, 0, {}, 0);
|
return sendto(description, data, size, 0, {}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,9 +243,9 @@ KResult Socket::shutdown(int how)
|
||||||
{
|
{
|
||||||
MutexLocker locker(lock());
|
MutexLocker locker(lock());
|
||||||
if (type() == SOCK_STREAM && !is_connected())
|
if (type() == SOCK_STREAM && !is_connected())
|
||||||
return ENOTCONN;
|
return set_so_error(ENOTCONN);
|
||||||
if (m_role == Role::Listener)
|
if (m_role == Role::Listener)
|
||||||
return ENOTCONN;
|
return set_so_error(ENOTCONN);
|
||||||
if (!m_shut_down_for_writing && (how & SHUT_WR))
|
if (!m_shut_down_for_writing && (how & SHUT_WR))
|
||||||
shut_down_for_writing();
|
shut_down_for_writing();
|
||||||
if (!m_shut_down_for_reading && (how & SHUT_RD))
|
if (!m_shut_down_for_reading && (how & SHUT_RD))
|
||||||
|
|
|
@ -130,6 +130,13 @@ protected:
|
||||||
|
|
||||||
Role m_role { Role::None };
|
Role m_role { Role::None };
|
||||||
|
|
||||||
|
KResult so_error() const { return m_so_error; }
|
||||||
|
KResult set_so_error(KResult error)
|
||||||
|
{
|
||||||
|
m_so_error = error;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ucred m_origin { 0, 0, 0 };
|
ucred m_origin { 0, 0, 0 };
|
||||||
ucred m_acceptor { 0, 0, 0 };
|
ucred m_acceptor { 0, 0, 0 };
|
||||||
|
@ -154,6 +161,8 @@ private:
|
||||||
Time m_send_timeout {};
|
Time m_send_timeout {};
|
||||||
int m_timestamp { 0 };
|
int m_timestamp { 0 };
|
||||||
|
|
||||||
|
KResult m_so_error { KSuccess };
|
||||||
|
|
||||||
NonnullRefPtrVector<Socket> m_pending;
|
NonnullRefPtrVector<Socket> m_pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,7 @@ KResultOr<size_t> TCPSocket::protocol_receive(ReadonlyBytes raw_ipv4_packet, Use
|
||||||
dbgln_if(TCP_SOCKET_DEBUG, "payload_size {}, will it fit in {}?", payload_size, buffer_size);
|
dbgln_if(TCP_SOCKET_DEBUG, "payload_size {}, will it fit in {}?", payload_size, buffer_size);
|
||||||
VERIFY(buffer_size >= payload_size);
|
VERIFY(buffer_size >= payload_size);
|
||||||
if (!buffer.write(tcp_packet.payload(), payload_size))
|
if (!buffer.write(tcp_packet.payload(), payload_size))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
return payload_size;
|
return payload_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ KResultOr<size_t> TCPSocket::protocol_send(const UserOrKernelBuffer& data, size_
|
||||||
{
|
{
|
||||||
RoutingDecision routing_decision = route_to(peer_address(), local_address(), bound_interface());
|
RoutingDecision routing_decision = route_to(peer_address(), local_address(), bound_interface());
|
||||||
if (routing_decision.is_zero())
|
if (routing_decision.is_zero())
|
||||||
return EHOSTUNREACH;
|
return set_so_error(EHOSTUNREACH);
|
||||||
size_t mss = routing_decision.adapter->mtu() - sizeof(IPv4Packet) - sizeof(TCPPacket);
|
size_t mss = routing_decision.adapter->mtu() - sizeof(IPv4Packet) - sizeof(TCPPacket);
|
||||||
data_length = min(data_length, mss);
|
data_length = min(data_length, mss);
|
||||||
int err = send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, &data, data_length, &routing_decision);
|
int err = send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, &data, data_length, &routing_decision);
|
||||||
|
@ -199,7 +199,7 @@ KResult TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload,
|
||||||
{
|
{
|
||||||
RoutingDecision routing_decision = user_routing_decision ? *user_routing_decision : route_to(peer_address(), local_address(), bound_interface());
|
RoutingDecision routing_decision = user_routing_decision ? *user_routing_decision : route_to(peer_address(), local_address(), bound_interface());
|
||||||
if (routing_decision.is_zero())
|
if (routing_decision.is_zero())
|
||||||
return EHOSTUNREACH;
|
return set_so_error(EHOSTUNREACH);
|
||||||
|
|
||||||
auto ipv4_payload_offset = routing_decision.adapter->ipv4_payload_offset();
|
auto ipv4_payload_offset = routing_decision.adapter->ipv4_payload_offset();
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ KResult TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload,
|
||||||
const size_t buffer_size = ipv4_payload_offset + tcp_header_size + payload_size;
|
const size_t buffer_size = ipv4_payload_offset + tcp_header_size + payload_size;
|
||||||
auto packet = routing_decision.adapter->acquire_packet_buffer(buffer_size);
|
auto packet = routing_decision.adapter->acquire_packet_buffer(buffer_size);
|
||||||
if (!packet)
|
if (!packet)
|
||||||
return ENOMEM;
|
return set_so_error(ENOMEM);
|
||||||
routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(),
|
routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(),
|
||||||
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
|
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
|
||||||
buffer_size - ipv4_payload_offset, ttl());
|
buffer_size - ipv4_payload_offset, ttl());
|
||||||
|
@ -231,7 +231,7 @@ KResult TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload,
|
||||||
|
|
||||||
if (payload && !payload->read(tcp_packet.payload(), payload_size)) {
|
if (payload && !payload->read(tcp_packet.payload(), payload_size)) {
|
||||||
routing_decision.adapter->release_packet_buffer(*packet);
|
routing_decision.adapter->release_packet_buffer(*packet);
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & TCPFlags::SYN) {
|
if (flags & TCPFlags::SYN) {
|
||||||
|
@ -370,7 +370,7 @@ KResult TCPSocket::protocol_bind()
|
||||||
if (has_specific_local_address() && !m_adapter) {
|
if (has_specific_local_address() && !m_adapter) {
|
||||||
m_adapter = NetworkingManagement::the().from_ipv4_address(local_address());
|
m_adapter = NetworkingManagement::the().from_ipv4_address(local_address());
|
||||||
if (!m_adapter)
|
if (!m_adapter)
|
||||||
return EADDRNOTAVAIL;
|
return set_so_error(EADDRNOTAVAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
|
@ -386,7 +386,7 @@ KResult TCPSocket::protocol_listen(bool did_allocate_port)
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return EADDRINUSE;
|
return set_so_error(EADDRINUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_direction(Direction::Passive);
|
set_direction(Direction::Passive);
|
||||||
|
@ -401,7 +401,7 @@ KResult TCPSocket::protocol_connect(FileDescription& description, ShouldBlock sh
|
||||||
|
|
||||||
auto routing_decision = route_to(peer_address(), local_address());
|
auto routing_decision = route_to(peer_address(), local_address());
|
||||||
if (routing_decision.is_zero())
|
if (routing_decision.is_zero())
|
||||||
return EHOSTUNREACH;
|
return set_so_error(EHOSTUNREACH);
|
||||||
if (!has_specific_local_address())
|
if (!has_specific_local_address())
|
||||||
set_local_address(routing_decision.adapter->ipv4_address());
|
set_local_address(routing_decision.adapter->ipv4_address());
|
||||||
|
|
||||||
|
@ -425,20 +425,20 @@ KResult TCPSocket::protocol_connect(FileDescription& description, ShouldBlock sh
|
||||||
locker.unlock();
|
locker.unlock();
|
||||||
auto unblock_flags = Thread::FileBlocker::BlockFlags::None;
|
auto unblock_flags = Thread::FileBlocker::BlockFlags::None;
|
||||||
if (Thread::current()->block<Thread::ConnectBlocker>({}, description, unblock_flags).was_interrupted())
|
if (Thread::current()->block<Thread::ConnectBlocker>({}, description, unblock_flags).was_interrupted())
|
||||||
return EINTR;
|
return set_so_error(EINTR);
|
||||||
locker.lock();
|
locker.lock();
|
||||||
VERIFY(setup_state() == SetupState::Completed);
|
VERIFY(setup_state() == SetupState::Completed);
|
||||||
if (has_error()) { // TODO: check unblock_flags
|
if (has_error()) { // TODO: check unblock_flags
|
||||||
m_role = Role::None;
|
m_role = Role::None;
|
||||||
if (error() == TCPSocket::Error::RetransmitTimeout)
|
if (error() == TCPSocket::Error::RetransmitTimeout)
|
||||||
return ETIMEDOUT;
|
return set_so_error(ETIMEDOUT);
|
||||||
else
|
else
|
||||||
return ECONNREFUSED;
|
return set_so_error(ECONNREFUSED);
|
||||||
}
|
}
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EINPROGRESS;
|
return set_so_error(EINPROGRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<u16> TCPSocket::protocol_allocate_local_port()
|
KResultOr<u16> TCPSocket::protocol_allocate_local_port()
|
||||||
|
@ -464,7 +464,7 @@ KResultOr<u16> TCPSocket::protocol_allocate_local_port()
|
||||||
if (port == first_scan_port)
|
if (port == first_scan_port)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return EADDRINUSE;
|
return set_so_error(EADDRINUSE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ KResultOr<size_t> UDPSocket::protocol_receive(ReadonlyBytes raw_ipv4_packet, Use
|
||||||
VERIFY(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier.
|
VERIFY(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier.
|
||||||
size_t read_size = min(buffer_size, udp_packet.length() - sizeof(UDPPacket));
|
size_t read_size = min(buffer_size, udp_packet.length() - sizeof(UDPPacket));
|
||||||
if (!buffer.write(udp_packet.payload(), read_size))
|
if (!buffer.write(udp_packet.payload(), read_size))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
return read_size;
|
return read_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,20 +77,20 @@ KResultOr<size_t> UDPSocket::protocol_send(const UserOrKernelBuffer& data, size_
|
||||||
{
|
{
|
||||||
auto routing_decision = route_to(peer_address(), local_address(), bound_interface());
|
auto routing_decision = route_to(peer_address(), local_address(), bound_interface());
|
||||||
if (routing_decision.is_zero())
|
if (routing_decision.is_zero())
|
||||||
return EHOSTUNREACH;
|
return set_so_error(EHOSTUNREACH);
|
||||||
auto ipv4_payload_offset = routing_decision.adapter->ipv4_payload_offset();
|
auto ipv4_payload_offset = routing_decision.adapter->ipv4_payload_offset();
|
||||||
data_length = min(data_length, routing_decision.adapter->mtu() - ipv4_payload_offset - sizeof(UDPPacket));
|
data_length = min(data_length, routing_decision.adapter->mtu() - ipv4_payload_offset - sizeof(UDPPacket));
|
||||||
const size_t udp_buffer_size = sizeof(UDPPacket) + data_length;
|
const size_t udp_buffer_size = sizeof(UDPPacket) + data_length;
|
||||||
auto packet = routing_decision.adapter->acquire_packet_buffer(ipv4_payload_offset + udp_buffer_size);
|
auto packet = routing_decision.adapter->acquire_packet_buffer(ipv4_payload_offset + udp_buffer_size);
|
||||||
if (!packet)
|
if (!packet)
|
||||||
return ENOMEM;
|
return set_so_error(ENOMEM);
|
||||||
memset(packet->buffer->data() + ipv4_payload_offset, 0, sizeof(UDPPacket));
|
memset(packet->buffer->data() + ipv4_payload_offset, 0, sizeof(UDPPacket));
|
||||||
auto& udp_packet = *reinterpret_cast<UDPPacket*>(packet->buffer->data() + ipv4_payload_offset);
|
auto& udp_packet = *reinterpret_cast<UDPPacket*>(packet->buffer->data() + ipv4_payload_offset);
|
||||||
udp_packet.set_source_port(local_port());
|
udp_packet.set_source_port(local_port());
|
||||||
udp_packet.set_destination_port(peer_port());
|
udp_packet.set_destination_port(peer_port());
|
||||||
udp_packet.set_length(udp_buffer_size);
|
udp_packet.set_length(udp_buffer_size);
|
||||||
if (!data.read(udp_packet.payload(), data_length))
|
if (!data.read(udp_packet.payload(), data_length))
|
||||||
return EFAULT;
|
return set_so_error(EFAULT);
|
||||||
|
|
||||||
routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), routing_decision.next_hop,
|
routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), routing_decision.next_hop,
|
||||||
peer_address(), IPv4Protocol::UDP, udp_buffer_size, ttl());
|
peer_address(), IPv4Protocol::UDP, udp_buffer_size, ttl());
|
||||||
|
@ -126,7 +126,7 @@ KResultOr<u16> UDPSocket::protocol_allocate_local_port()
|
||||||
if (port == first_scan_port)
|
if (port == first_scan_port)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return EADDRINUSE;
|
return set_so_error(EADDRINUSE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ KResult UDPSocket::protocol_bind()
|
||||||
{
|
{
|
||||||
return sockets_by_port().with_exclusive([&](auto& table) -> KResult {
|
return sockets_by_port().with_exclusive([&](auto& table) -> KResult {
|
||||||
if (table.contains(local_port()))
|
if (table.contains(local_port()))
|
||||||
return EADDRINUSE;
|
return set_so_error(EADDRINUSE);
|
||||||
table.set(local_port(), this);
|
table.set(local_port(), this);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue