hare

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

commit 7e363afbd6cecfcb97299a9114bf4b1f49dd27cd
parent f55f1cf85c5935a3bbf972f6ca97e1c3a0f241e0
Author: Lorenz (xha) <me@xha.li>
Date:   Sat, 25 Nov 2023 15:18:21 +0100

OpenBSD: add net

Signed-off-by: Lorenz (xha) <me@xha.li>

Diffstat:
Anet/+openbsd.ha | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 98 insertions(+), 0 deletions(-)

diff --git a/net/+openbsd.ha b/net/+openbsd.ha @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use rt; + +// A network socket. +export type socket = io::file; + +// Optional flags to [[accept]] to be set on the returned [[socket]]. +// See the O_CLOEXEC and O_NONBLOCK sections of open(2) for details. +// Note that CLOEXEC is on by default, and NOCLOEXEC flag disables it. +export type sockflag = enum int { + NOCLOEXEC = rt::SOCK_CLOEXEC, + NONBLOCK = rt::SOCK_NONBLOCK +}; + +// Accepts the next connection from a socket. Blocks until a new connection is +// available. Optionally accepts NOCLOEXEC and NONBLOCK flags. If flags are +// supplied, the [[io::file]] returned will have the supplied flags set. +export fn accept(sock: socket, flags: sockflag...) (socket | error) = { + // Apply any supplied flags + let f = 0i; + for (let i = 0z; i < len(flags); i += 1) { + f |= flags[i]; + }; + f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC + const fd = match (rt::accept4(sock, null, null, f: int)) { + case let err: rt::errno => + return errors::errno(err); + case let fd: int => + yield fd; + }; + return io::fdopen(fd); +}; + +fn msg_to_native(msg: *msghdr) *rt::msghdr = { + let native = &msg.native; + if (len(msg.vectors) != 0) { + native.msg_iov = msg.vectors: *[*]rt::iovec; + // XXX: size -> uint could overflow here. + native.msg_iovlen = len(msg.vectors): uint; + }; + if (len(msg.control) != 0) { + native.msg_control = msg.control: *[*]u8; + // XXX: size -> uint could overflow here. + native.msg_controllen = len(msg.control): uint; + }; + return native; +}; + +// Sends a message to a socket. See [[newmsg]] for details. +export fn sendmsg(sock: socket, msg: *msghdr) (size | error) = { + // TODO: Flags + match (rt::sendmsg(sock, msg_to_native(msg), 0)) { + case let n: int => + return n: size; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Receives a message from a socket. See [[newmsg]] for details. +export fn recvmsg(sock: socket, msg: *msghdr) (size | error) = { + // TODO: Flags + match (rt::recvmsg(sock, msg_to_native(msg), 0)) { + case let n: int => + return n: size; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Closes a [[socket]]. No further operations against this socket are permitted +// after calling this function. Closing a socket can fail only under certain +// conditions (for example, closing a socket twice, or an interrupted syscall). +// However, the user should not attempt to close the file again on failure - at +// best the user should print a diagnostic message and move on. See close(2) for +// details. +// +// On OpenBSD, this function is an alias for [[io::close]]. +export fn close(sock: socket) (void | error) = match (io::close(sock)) { +case void => void; +case io::underread => abort(); +case io::mode => abort(); +case let err: errors::error => + yield err; +}; + +// Shuts down part of a full-duplex connection. +export fn shutdown(sock: socket, how: shut) (void | error) = { + match (rt::shutdown(sock, how)) { + case void => void; + case let err: rt::errno => + return errors::errno(err); + }; +};