diff options
Diffstat (limited to 'libhw/host_net.c')
-rw-r--r-- | libhw/host_net.c | 149 |
1 files changed, 59 insertions, 90 deletions
diff --git a/libhw/host_net.c b/libhw/host_net.c index 88bda49..505c7dc 100644 --- a/libhw/host_net.c +++ b/libhw/host_net.c @@ -1,12 +1,11 @@ /* libhw/host_net.c - <libhw/generic/net.h> implementation for hosted glibc * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ #define _GNU_SOURCE /* for pthread_sigqueue(3gnu) */ /* misc */ -#include <assert.h> /* for assert() */ #include <errno.h> /* for errno, EAGAIN, EINVAL */ #include <error.h> /* for error(3gnu) */ #include <stdlib.h> /* for abs(), shutdown(), SHUT_RD, SHUT_WR, SHUT_RDWR */ @@ -20,7 +19,9 @@ #include <signal.h> /* for siginfo_t, struct sigaction, enum sigval, sigaction(), SA_SIGINFO */ #include <libcr/coroutine.h> -#include <libmisc/vcall.h> +#include <libmisc/assert.h> +#include <libmisc/macro.h> +#include <libobj/obj.h> #include <libhw/generic/alarmclock.h> @@ -29,13 +30,15 @@ #include "host_util.h" /* for host_sigrt_alloc(), ns_to_host_us_time() */ -/* common *********************************************************************/ +LO_IMPLEMENTATION_C(net_stream_conn, struct _hostnet_tcp_conn, hostnet_tcp, static) +LO_IMPLEMENTATION_C(net_stream_listener, struct hostnet_tcp_listener, hostnet_tcplist, static) +LO_IMPLEMENTATION_C(net_packet_conn, struct hostnet_udp_conn, hostnet_udp, static) -#define UNUSED(name) /* name __attribute__ ((unused)) */ +/* common *********************************************************************/ static int hostnet_sig_io = 0; -static void hostnet_handle_sig_io(int UNUSED(sig), siginfo_t *info, void *UNUSED(ucontext)) { +static void hostnet_handle_sig_io(int LM_UNUSED(sig), siginfo_t *info, void *LM_UNUSED(ucontext)) { cr_unpause_from_intrhandler((cid_t)info->si_value.sival_int); } @@ -67,20 +70,38 @@ static void hostnet_init(void) { static inline bool RUN_PTHREAD(void *(*fn)(void *), void *args) { pthread_t thread; + bool saved = cr_save_and_disable_interrupts(); if (pthread_create(&thread, NULL, fn, args)) return true; cr_pause_and_yield(); + cr_restore_interrupts(saved); if (pthread_join(thread, NULL)) return true; return false; } -static inline ssize_t hostnet_map_negerrno(ssize_t v) { +enum hostnet_timeout_op { + OP_NONE, + OP_SEND, + OP_RECV, +}; + +static inline ssize_t hostnet_map_negerrno(ssize_t v, enum hostnet_timeout_op op) { if (v >= 0) return v; switch (v) { + case -EHOSTUNREACH: + return -NET_EARP_TIMEOUT; case -ETIMEDOUT: - return -NET_ETIMEDOUT; + switch (op) { + case OP_NONE: + assert_notreached("impossible ETIMEDOUT"); + case OP_SEND: + return -NET_EACK_TIMEOUT; + case OP_RECV: + return -NET_ERECV_TIMEOUT; + } + assert_notreached("invalid timeout op"); case -EBADF: return -NET_ECLOSED; case -EMSGSIZE: @@ -92,25 +113,6 @@ static inline ssize_t hostnet_map_negerrno(ssize_t v) { /* TCP init() ( AKA socket(3) + listen(3) )************************************/ -static implements_net_stream_conn *hostnet_tcplist_accept(implements_net_stream_listener *); -static int hostnet_tcplist_close(implements_net_stream_listener *); -static void hostnet_tcp_set_read_deadline(implements_net_stream_conn *conn, uint64_t ts_ns); -static ssize_t hostnet_tcp_read(implements_net_stream_conn *conn, void *buf, size_t count); -static ssize_t hostnet_tcp_write(implements_net_stream_conn *conn, void *buf, size_t count); -static int hostnet_tcp_close(implements_net_stream_conn *conn, bool rd, bool wr); - -static struct net_stream_listener_vtable hostnet_tcp_listener_vtable = { - .accept = hostnet_tcplist_accept, - .close = hostnet_tcplist_close, -}; - -static struct net_stream_conn_vtable hostnet_tcp_conn_vtable = { - .set_read_deadline = hostnet_tcp_set_read_deadline, - .read = hostnet_tcp_read, - .write = hostnet_tcp_write, - .close = hostnet_tcp_close, -}; - void hostnet_tcp_listener_init(struct hostnet_tcp_listener *self, uint16_t port) { int listenerfd; union { @@ -134,7 +136,6 @@ void hostnet_tcp_listener_init(struct hostnet_tcp_listener *self, uint16_t port) if (listen(listenerfd, 0) < 0) error(1, errno, "listen(fd=%d)", listenerfd); - self->vtable = &hostnet_tcp_listener_vtable; self->fd = listenerfd; } @@ -158,9 +159,7 @@ static void *hostnet_pthread_accept(void *_args) { return NULL; } -static implements_net_stream_conn *hostnet_tcplist_accept(implements_net_stream_listener *_listener) { - struct hostnet_tcp_listener *listener = - VCALL_SELF(struct hostnet_tcp_listener, implements_net_stream_listener, _listener); +static lo_interface net_stream_conn hostnet_tcplist_accept(struct hostnet_tcp_listener *listener) { assert(listener); int ret_connfd; @@ -171,28 +170,27 @@ static implements_net_stream_conn *hostnet_tcplist_accept(implements_net_stream_ .ret_connfd = &ret_connfd, }; if (RUN_PTHREAD(hostnet_pthread_accept, &args)) - return NULL; + return LO_NULL(net_stream_conn); + + if (ret_connfd < 0) + return LO_NULL(net_stream_conn); - listener->active_conn.vtable = &hostnet_tcp_conn_vtable; listener->active_conn.fd = ret_connfd; - return &listener->active_conn; + listener->active_conn.read_deadline_ns = 0; + return lo_box_hostnet_tcp_as_net_stream_conn(&listener->active_conn); } /* TCP listener close() *******************************************************/ -static int hostnet_tcplist_close(implements_net_stream_listener *_listener) { - struct hostnet_tcp_listener *listener = - VCALL_SELF(struct hostnet_tcp_listener, implements_net_stream_listener, _listener); +static int hostnet_tcplist_close(struct hostnet_tcp_listener *listener) { assert(listener); - return hostnet_map_negerrno(close(listener->fd) ? -errno : 0); + return hostnet_map_negerrno(shutdown(listener->fd, SHUT_RDWR) ? -errno : 0, OP_NONE); } /* TCP read() *****************************************************************/ -static void hostnet_tcp_set_read_deadline(implements_net_stream_conn *_conn, uint64_t ts_ns) { - struct _hostnet_tcp_conn *conn = - VCALL_SELF(struct _hostnet_tcp_conn, implements_net_stream_conn, _conn); +static void hostnet_tcp_set_read_deadline(struct _hostnet_tcp_conn *conn, uint64_t ts_ns) { assert(conn); conn->read_deadline_ns = ts_ns; @@ -224,14 +222,12 @@ static void *hostnet_pthread_read(void *_args) { end: if (*(args->ret) < 0) - *(args->ret) = hostnet_map_negerrno(-errno); + *(args->ret) = hostnet_map_negerrno(-errno, OP_SEND); WAKE_COROUTINE(args); return NULL; } -static ssize_t hostnet_tcp_read(implements_net_stream_conn *_conn, void *buf, size_t count) { - struct _hostnet_tcp_conn *conn = - VCALL_SELF(struct _hostnet_tcp_conn, implements_net_stream_conn, _conn); +static ssize_t hostnet_tcp_read(struct _hostnet_tcp_conn *conn, void *buf, size_t count) { assert(conn); ssize_t ret; @@ -246,9 +242,9 @@ static ssize_t hostnet_tcp_read(implements_net_stream_conn *_conn, void *buf, si .ret = &ret, }; if (conn->read_deadline_ns) { - uint64_t now_ns = VCALL(bootclock, get_time_ns); + uint64_t now_ns = LO_CALL(bootclock, get_time_ns); if (conn->read_deadline_ns < now_ns) - return -NET_ETIMEDOUT; + return -NET_ERECV_TIMEOUT; args.timeout = ns_to_host_us_time(conn->read_deadline_ns-now_ns); } else { args.timeout = (host_us_time_t){0}; @@ -273,12 +269,12 @@ struct hostnet_pthread_write_args { }; static void *hostnet_pthread_write(void *_args) { - struct hostnet_pthread_read_args *args = _args; + struct hostnet_pthread_write_args *args = _args; size_t done = 0; while (done < args->count) { ssize_t r = write(args->connfd, args->buf, args->count); if (r < 0) { - hostnet_map_negerrno(-errno); + hostnet_map_negerrno(-errno, OP_RECV); break; } done += r; @@ -289,9 +285,7 @@ static void *hostnet_pthread_write(void *_args) { return NULL; } -static ssize_t hostnet_tcp_write(implements_net_stream_conn *_conn, void *buf, size_t count) { - struct _hostnet_tcp_conn *conn = - VCALL_SELF(struct _hostnet_tcp_conn, implements_net_stream_conn, _conn); +static ssize_t hostnet_tcp_write(struct _hostnet_tcp_conn *conn, void *buf, size_t count) { assert(conn); ssize_t ret; @@ -312,9 +306,7 @@ static ssize_t hostnet_tcp_write(implements_net_stream_conn *_conn, void *buf, s /* TCP close() ****************************************************************/ -static int hostnet_tcp_close(implements_net_stream_conn *_conn, bool rd, bool wr) { - struct _hostnet_tcp_conn *conn = - VCALL_SELF(struct _hostnet_tcp_conn, implements_net_stream_conn, _conn); +static int hostnet_tcp_close(struct _hostnet_tcp_conn *conn, bool rd, bool wr) { assert(conn); int how; @@ -325,27 +317,12 @@ static int hostnet_tcp_close(implements_net_stream_conn *_conn, bool rd, bool wr else if (!rd && wr) how = SHUT_WR; else - assert(false); - return hostnet_map_negerrno(shutdown(conn->fd, how) ? -errno : 0); + assert_notreached("invalid arguments to stream_conn.close()"); + return hostnet_map_negerrno(shutdown(conn->fd, how) ? -errno : 0, OP_NONE); } /* UDP init() *****************************************************************/ -static void hostnet_udp_set_read_deadline(implements_net_packet_conn *self, - uint64_t ts_ns); -static ssize_t hostnet_udp_sendto(implements_net_packet_conn *self, void *buf, size_t len, - struct net_ip4_addr addr, uint16_t port); -static ssize_t hostnet_udp_recvfrom(implements_net_packet_conn *self, void *buf, size_t len, - struct net_ip4_addr *ret_addr, uint16_t *ret_port); -static int hostnet_udp_close(implements_net_packet_conn *self); - -static struct net_packet_conn_vtable hostnet_udp_conn_vtable = { - .set_read_deadline = hostnet_udp_set_read_deadline, - .sendto = hostnet_udp_sendto, - .recvfrom = hostnet_udp_recvfrom, - .close = hostnet_udp_close, -}; - void hostnet_udp_conn_init(struct hostnet_udp_conn *self, uint16_t port) { int fd; union { @@ -364,8 +341,8 @@ void hostnet_udp_conn_init(struct hostnet_udp_conn *self, uint16_t port) { if (bind(fd, &addr.gen, sizeof addr) < 0) error(1, errno, "bind"); - self->vtable = &hostnet_udp_conn_vtable; self->fd = fd; + self->read_deadline_ns = 0; } /* UDP sendto() ***************************************************************/ @@ -400,15 +377,13 @@ static void *hostnet_pthread_sendto(void *_args) { addr.in.sin_port = htons(args->port); *(args->ret) = sendto(args->connfd, args->buf, args->count, 0, &addr.gen, sizeof(addr)); if (*(args->ret) < 0) - *(args->ret) = hostnet_map_negerrno(-errno); + *(args->ret) = hostnet_map_negerrno(-errno, OP_SEND); WAKE_COROUTINE(args); return NULL; } -static ssize_t hostnet_udp_sendto(implements_net_packet_conn *_conn, void *buf, size_t count, +static ssize_t hostnet_udp_sendto(struct hostnet_udp_conn *conn, void *buf, size_t count, struct net_ip4_addr node, uint16_t port) { - struct hostnet_udp_conn *conn = - VCALL_SELF(struct hostnet_udp_conn, implements_net_packet_conn, _conn); assert(conn); ssize_t ret; @@ -431,10 +406,8 @@ static ssize_t hostnet_udp_sendto(implements_net_packet_conn *_conn, void *buf, /* UDP recvfrom() *************************************************************/ -static void hostnet_udp_set_read_deadline(implements_net_packet_conn *_conn, +static void hostnet_udp_set_read_deadline(struct hostnet_udp_conn *conn, uint64_t ts_ns) { - struct hostnet_udp_conn *conn = - VCALL_SELF(struct hostnet_udp_conn, implements_net_packet_conn, _conn); assert(conn); conn->read_deadline_ns = ts_ns; @@ -487,15 +460,13 @@ static void *hostnet_pthread_recvfrom(void *_args) { end: if (*(args->ret_size) < 0) - *(args->ret_size) = hostnet_map_negerrno(-errno); + *(args->ret_size) = hostnet_map_negerrno(-errno, OP_RECV); WAKE_COROUTINE(args); return NULL; } -static ssize_t hostnet_udp_recvfrom(implements_net_packet_conn *_conn, void *buf, size_t count, +static ssize_t hostnet_udp_recvfrom(struct hostnet_udp_conn *conn, void *buf, size_t count, struct net_ip4_addr *ret_node, uint16_t *ret_port) { - struct hostnet_udp_conn *conn = - VCALL_SELF(struct hostnet_udp_conn, implements_net_packet_conn, _conn); assert(conn); ssize_t ret; @@ -512,9 +483,9 @@ static ssize_t hostnet_udp_recvfrom(implements_net_packet_conn *_conn, void *buf .ret_port = ret_port, }; if (conn->read_deadline_ns) { - uint64_t now_ns = VCALL(bootclock, get_time_ns); + uint64_t now_ns = LO_CALL(bootclock, get_time_ns); if (conn->read_deadline_ns < now_ns) - return -NET_ETIMEDOUT; + return -NET_ERECV_TIMEOUT; args.timeout = ns_to_host_us_time(conn->read_deadline_ns-now_ns); } else { args.timeout = (host_us_time_t){0}; @@ -527,10 +498,8 @@ static ssize_t hostnet_udp_recvfrom(implements_net_packet_conn *_conn, void *buf /* UDP close() ****************************************************************/ -static int hostnet_udp_close(implements_net_packet_conn *_conn) { - struct hostnet_udp_conn *conn = - VCALL_SELF(struct hostnet_udp_conn, implements_net_packet_conn, _conn); +static int hostnet_udp_close(struct hostnet_udp_conn *conn) { assert(conn); - return hostnet_map_negerrno(close(conn->fd) ? -errno : 0); + return hostnet_map_negerrno(close(conn->fd) ? -errno : 0, OP_NONE); } |