hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit f6edab32b290c79e655ead598ed8bb7ffe93f90b
parent 11bf1261ae1afc556cd3b65c3ddf52730cdee20b
Author: Noah Pederson <noah@packetlost.dev>
Date:   Wed,  4 May 2022 17:03:28 -0500

Add CLOEXEC, NONBLOCK flags to net::accept

Creates an enum to wrap the underlying OS flags values from rt and limit
to the allowed subset by defining a new enum type called sock_flags.

Adds a rt::accept4 method which mirrors the accept(2) from
<sys/socket.h> and switches calls to net::accept to use that. Given that
flags should default to 0 and accept4 is documented to behave
identically to accept when flags are 0, there is no reason to support
both rt::accept and rt::accept4 outside of internal api cleanliness.

Updates both FreeBSD and Linux net:: and rt:: implementations.

Signed-off-by: Noah Pederson <noah@packetlost.dev>

Diffstat:
Mnet/+freebsd.ha | 25++++++++++++++++++++++---
Mnet/+linux.ha | 25++++++++++++++++++++++---
Mnet/tcp/listener.ha | 2+-
Mnet/unix/listener.ha | 2+-
Mrt/+freebsd/syscalls.ha | 5+++++
Mrt/+linux/syscalls.ha | 5+++++
6 files changed, 56 insertions(+), 8 deletions(-)

diff --git a/net/+freebsd.ha b/net/+freebsd.ha @@ -1,6 +1,7 @@ // License: MPL-2.0 // (c) 2021 Drew DeVault <sir@cmpwn.com> // (c) 2021 Eyal Sawady <ecs@d2evs.net> +// (c) 2022 Noah Pederson <noah@packetlost.dev> use errors; use fmt; use io; @@ -9,12 +10,30 @@ use os; use rt; use strings; +// Optional flags to [[accept]] to be set on the returned [[io::file]]. +// See the O_CLOEXEC and O_NONBLOCK sections of open(2) for details. +export type sockflags = enum int { + CLOEXEC = rt::SOCK_CLOEXEC, + NONBLOCK = rt::SOCK_NONBLOCK +}; + // Accepts the next connection from a socket. Blocks until a new connection is -// available. -export fn accept(sock: io::file) (io::file | error) = { +// available. Optionally accepts CLOEXEC and NONBLOCK flags. If flags are +// supplied, the [[io::file]] returned will have the supplied flags set. +// If no flags are supplied, CLOEXEC is used by default. +export fn accept(sock: io::file, flags: sockflags...) (io::file | error) = { let sn = rt::sockaddr {...}; const sz = size(rt::sockaddr): u32; - const fd = match (rt::accept(sock, &sn, &sz)) { + // Default to CLOEXEC if no flags are supplied + if (len(flags) == 0) { + flags = [sockflags::CLOEXEC]; + }; + // Apply any supplied flags + let f = 0i; + for (let i = 0z; i < len(flags); i += 1) { + f |= flags[i]; + }; + const fd = match (rt::accept4(sock, &sn, &sz, f)) { case let err: rt::errno => return errors::errno(err); case let fd: int => diff --git a/net/+linux.ha b/net/+linux.ha @@ -1,6 +1,7 @@ // License: MPL-2.0 // (c) 2021 Drew DeVault <sir@cmpwn.com> // (c) 2021 Eyal Sawady <ecs@d2evs.net> +// (c) 2022 Noah Pederson <noah@packetlost.dev> use errors; use fmt; use io; @@ -9,12 +10,30 @@ use os; use rt; use strings; +// Optional flags to [[accept]] to be set on the returned [[io::file]]. +// See the O_CLOEXEC and O_NONBLOCK sections of open(2) for details. +export type sockflags = enum int { + CLOEXEC = rt::SOCK_CLOEXEC, + NONBLOCK = rt::SOCK_NONBLOCK +}; + // Accepts the next connection from a socket. Blocks until a new connection is -// available. -export fn accept(sock: io::file) (io::file | error) = { +// available. Optionally accepts CLOEXEC and NONBLOCK flags. If flags are +// supplied, the [[io::file]] returned will have the supplied flags set. +// If no flags are supplied, CLOEXEC is used by default. +export fn accept(sock: io::file, flags: sockflags...) (io::file | error) = { let sn = rt::sockaddr {...}; const sz = size(rt::sockaddr): u32; - const fd = match (rt::accept(sock, &sn, &sz)) { + // Default to CLOEXEC if no flags are supplied + if (len(flags) == 0) { + flags = [sockflags::CLOEXEC]; + }; + // Apply any supplied flags + let f = 0i; + for (let i = 0z; i < len(flags); i += 1) { + f |= flags[i]; + }; + const fd = match (rt::accept4(sock, &sn, &sz, f: int)) { case let err: rt::errno => return errors::errno(err); case let fd: int => diff --git a/net/tcp/listener.ha b/net/tcp/listener.ha @@ -5,7 +5,7 @@ use net; // Accepts the next connection from a socket. Blocks until a new connection is // available. This is a convenience wrapper around [[net::accept]]. -export fn accept(sock: io::file) (io::file | net::error) = net::accept(sock); +export fn accept(sock: io::file, flags: net::sockflags...) (io::file | net::error) = net::accept(sock, flags...); // Shuts down a listening socket. This is a convenience wrapper around // [[net::shutdown]]. diff --git a/net/unix/listener.ha b/net/unix/listener.ha @@ -5,7 +5,7 @@ use net; // Accepts the next connection from a socket. Blocks until a new connection is // available. This is a convenience wrapper around [[net::accept]]. -export fn accept(sock: io::file) (io::file | net::error) = net::accept(sock); +export fn accept(sock: io::file, flags: net::sockflags...) (io::file | net::error) = net::accept(sock, flags...); // Shuts down a listening socket. This is a convenience wrapper around // [[net::shutdown]]. diff --git a/rt/+freebsd/syscalls.ha b/rt/+freebsd/syscalls.ha @@ -421,6 +421,11 @@ export fn accept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; +export fn accept4(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int) (int | errno) = { + return wrap_return(syscall4(SYS_accept, + sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64, flags: u64))?: int; +}; + export fn recvfrom(sockfd: int, buf: *void, len_: size, flags: int, src_addr: nullable *sockaddr, addrlen: nullable *u32 ) (size | errno) = { diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha @@ -583,6 +583,11 @@ export fn accept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; +export fn accept4(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int) (int | errno) = { + return wrap_return(syscall4(SYS_accept, + sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64, flags: u64))?: int; +}; + export fn recvfrom(sockfd: int, buf: *void, len_: size, flags: int, src_addr: nullable *sockaddr, addrlen: nullable *u32 ) (size | errno) = {