Net: Add a basic sys$shutdown() implementation

Calling shutdown prevents further reads and/or writes on a socket.
We should do a few more things based on the type of socket, but this
initial implementation just puts the basic mechanism in place.

Work towards #428.
This commit is contained in:
Andreas Kling 2020-02-08 00:52:33 +01:00
parent a3f39fe789
commit 2b0b7cc5a4
Notes: sideshowbarker 2024-07-19 09:32:27 +09:00
8 changed files with 60 additions and 2 deletions

View file

@ -149,10 +149,23 @@ KResult Socket::getsockopt(FileDescription&, int level, int option, void* value,
ssize_t Socket::read(FileDescription& description, u8* buffer, ssize_t size)
{
if (is_shut_down_for_reading())
return 0;
return recvfrom(description, buffer, size, 0, nullptr, 0);
}
ssize_t Socket::write(FileDescription& description, const u8* data, ssize_t size)
{
if (is_shut_down_for_writing())
return -EPIPE;
return sendto(description, data, size, 0, nullptr, 0);
}
KResult Socket::shutdown(int how)
{
if (type() == SOCK_STREAM && !is_connected())
return KResult(-ENOTCONN);
m_shut_down_for_reading |= how & SHUT_RD;
m_shut_down_for_writing |= how & SHUT_WR;
return KSuccess;
}

View file

@ -51,6 +51,9 @@ public:
int type() const { return m_type; }
int protocol() const { return m_protocol; }
bool is_shut_down_for_writing() const { return m_shut_down_for_writing; }
bool is_shut_down_for_reading() const { return m_shut_down_for_reading; }
enum class SetupState {
Unstarted, // we haven't tried to set the socket up yet
InProgress, // we're in the process of setting things up - for TCP maybe we've sent a SYN packet
@ -90,6 +93,8 @@ public:
bool can_accept() const { return !m_pending.is_empty(); }
RefPtr<Socket> accept();
KResult shutdown(int how);
virtual KResult bind(const sockaddr*, socklen_t) = 0;
virtual KResult connect(FileDescription&, const sockaddr*, socklen_t, ShouldBlock) = 0;
virtual KResult listen(int) = 0;
@ -153,6 +158,8 @@ private:
int m_backlog { 0 };
SetupState m_setup_state { SetupState::Unstarted };
bool m_connected { false };
bool m_shut_down_for_reading { false };
bool m_shut_down_for_writing { false };
timeval m_receive_timeout { 0, 0 };
timeval m_send_timeout { 0, 0 };

View file

@ -3221,6 +3221,22 @@ int Process::sys$connect(int sockfd, const sockaddr* address, socklen_t address_
return socket.connect(*description, address, address_size, description->is_blocking() ? ShouldBlock::Yes : ShouldBlock::No);
}
int Process::sys$shutdown(int sockfd, int how)
{
REQUIRE_PROMISE(stdio);
if (how & ~SHUT_RDWR)
return -EINVAL;
auto description = file_description(sockfd);
if (!description)
return -EBADF;
if (!description->is_socket())
return -ENOTSOCK;
auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
return socket.shutdown(how);
}
ssize_t Process::sys$sendto(const Syscall::SC_sendto_params* user_params)
{
REQUIRE_PROMISE(stdio);
@ -3241,8 +3257,10 @@ ssize_t Process::sys$sendto(const Syscall::SC_sendto_params* user_params)
return -EBADF;
if (!description->is_socket())
return -ENOTSOCK;
SmapDisabler disabler;
auto& socket = *description->socket();
if (socket.is_shut_down_for_writing())
return -EPIPE;
SmapDisabler disabler;
return socket.sendto(*description, params.data.data, params.data.size, flags, addr, addr_length);
}
@ -3276,6 +3294,9 @@ ssize_t Process::sys$recvfrom(const Syscall::SC_recvfrom_params* user_params)
return -ENOTSOCK;
auto& socket = *description->socket();
if (socket.is_shut_down_for_reading())
return 0;
bool original_blocking = description->is_blocking();
if (flags & MSG_DONTWAIT)
description->set_blocking(false);

View file

@ -260,6 +260,7 @@ public:
int sys$listen(int sockfd, int backlog);
int sys$accept(int sockfd, sockaddr*, socklen_t*);
int sys$connect(int sockfd, const sockaddr*, socklen_t);
int sys$shutdown(int sockfd, int how);
ssize_t sys$sendto(const Syscall::SC_sendto_params*);
ssize_t sys$recvfrom(const Syscall::SC_recvfrom_params*);
int sys$getsockopt(const Syscall::SC_getsockopt_params*);

View file

@ -177,7 +177,8 @@ typedef u32 socklen_t;
__ENUMERATE_SYSCALL(chroot) \
__ENUMERATE_SYSCALL(pledge) \
__ENUMERATE_SYSCALL(unveil) \
__ENUMERATE_SYSCALL(perf_event)
__ENUMERATE_SYSCALL(perf_event) \
__ENUMERATE_SYSCALL(shutdown)
namespace Syscall {

View file

@ -387,6 +387,10 @@ struct pollfd {
#define SOCK_NONBLOCK 04000
#define SOCK_CLOEXEC 02000000
#define SHUT_RD 1
#define SHUT_WR 2
#define SHUT_RDWR 3
#define MSG_DONTWAIT 0x40
#define SOL_SOCKET 1

View file

@ -62,6 +62,12 @@ int connect(int sockfd, const sockaddr* addr, socklen_t addrlen)
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int shutdown(int sockfd, int how)
{
int rc = syscall(SC_shutdown, sockfd, how);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
ssize_t sendto(int sockfd, const void* data, size_t data_length, int flags, const struct sockaddr* addr, socklen_t addr_length)
{
Syscall::SC_sendto_params params { sockfd, { data, data_length }, flags, addr, addr_length };

View file

@ -49,6 +49,10 @@ __BEGIN_DECLS
#define SOCK_NONBLOCK 04000
#define SOCK_CLOEXEC 02000000
#define SHUT_RD 1
#define SHUT_WR 2
#define SHUT_RDWR 3
#define IPPROTO_IP 0
#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
@ -81,6 +85,7 @@ int bind(int sockfd, const struct sockaddr* addr, socklen_t);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr*, socklen_t*);
int connect(int sockfd, const struct sockaddr*, socklen_t);
int shutdown(int sockfd, int how);
ssize_t send(int sockfd, const void*, size_t, int flags);
ssize_t sendto(int sockfd, const void*, size_t, int flags, const struct sockaddr*, socklen_t);
ssize_t recv(int sockfd, void*, size_t, int flags);