summaryrefslogtreecommitdiff
path: root/libhw/host_net.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhw/host_net.c')
-rw-r--r--libhw/host_net.c149
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);
}