diff options
-rw-r--r-- | cmd/sbc_harness/main.c | 22 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 2 | ||||
-rw-r--r-- | lib9p/srv.c | 24 | ||||
-rw-r--r-- | lib9p/tests/test_server/main.c | 4 | ||||
-rw-r--r-- | libdhcp/dhcp_client.c | 45 | ||||
-rw-r--r-- | libdhcp/include/libdhcp/client.h | 4 | ||||
-rw-r--r-- | libhw/host_include/libhw/host_net.h | 11 | ||||
-rw-r--r-- | libhw/host_net.c | 89 | ||||
-rw-r--r-- | libhw/rp2040_include/libhw/w5500.h | 12 | ||||
-rw-r--r-- | libhw/w5500.c | 136 | ||||
-rw-r--r-- | libhw/w5500_ll.h | 1 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/net.h | 188 |
12 files changed, 198 insertions, 340 deletions
diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c index 7b1d5c5..ce80711 100644 --- a/cmd/sbc_harness/main.c +++ b/cmd/sbc_harness/main.c @@ -15,7 +15,6 @@ #include <libhw/rp2040_hwtimer.h> #include <libhw/w5500.h> #include <libmisc/hash.h> -#include <libmisc/vcall.h> #include <libusb/usb_common.h> #include <libdhcp/client.h> #include <lib9p/srv.h> @@ -43,15 +42,6 @@ static COROUTINE hello_world_cr(void *_chan) { cr_end(); } -static COROUTINE dhcp_cr(void *_chip) { - struct w5500 *chip = _chip; - cr_begin(); - - dhcp_client_main(chip, "harness"); - - cr_end(); -} - struct { struct rp2040_hwspi dev_spi; struct w5500 dev_w5500; @@ -60,11 +50,19 @@ struct { struct lib9p_srv srv; } globals; +static COROUTINE dhcp_cr(void *) { + cr_begin(); + + dhcp_client_main(lo_box_w5500_if_as_net_iface(&globals.dev_w5500), "harness"); + + cr_end(); +} + static COROUTINE read9p_cr(void *) { cr_begin(); lib9p_srv_read_cr(&globals.srv, - VCALL(&globals.dev_w5500, tcp_listen, CONFIG_9P_PORT)); + LO_CALL(lo_box_w5500_if_as_net_iface(&globals.dev_w5500), tcp_listen, CONFIG_9P_PORT)); cr_end(); } @@ -120,7 +118,7 @@ COROUTINE init_cr(void *) { coroutine_add("usb_common", usb_common_cr, NULL); coroutine_add("usb_keyboard", usb_keyboard_cr, &globals.keyboard_chan); coroutine_add("hello_world", hello_world_cr, &globals.keyboard_chan); - coroutine_add_with_stack_size(4*1024, "dhcp", dhcp_cr, &globals.dev_w5500); + coroutine_add_with_stack_size(4*1024, "dhcp", dhcp_cr, NULL); for (int i = 0; i < _CONFIG_9P_NUM_SOCKS; i++) { char name[] = {'r', 'e', 'a', 'd', '-', hexdig[i], '\0'}; coroutine_add(name, read9p_cr, NULL); diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h index e9d2d7b..0fc9011 100644 --- a/lib9p/include/lib9p/srv.h +++ b/lib9p/include/lib9p/srv.h @@ -105,7 +105,7 @@ struct lib9p_srv { * @errno LINUX_ERANGE R-message does not fit into max_msg_size */ -[[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, implements_net_stream_listener *listener); +[[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, lo_interface net_stream_listener listener); COROUTINE lib9p_srv_write_cr(void *_srv); #endif /* _LIB9P_SRV_H_ */ diff --git a/lib9p/srv.c b/lib9p/srv.c index 47dd78d..0bfe5da 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -108,7 +108,7 @@ struct _srv_fidinfo { struct _srv_conn { /* immutable */ struct lib9p_srv *parent_srv; - implements_net_stream_conn *fd; + lo_interface net_stream_conn fd; cid_t reader; /* the lib9p_srv_read_cr() coroutine */ /* mutable */ cr_mutex_t writelock; @@ -197,7 +197,7 @@ static void respond_error(struct _lib9p_srv_req *req) { &host, req->net_bytes); cr_mutex_lock(&sess->parent_conn->writelock); - r = VCALL(sess->parent_conn->fd, write, + r = LO_CALL(sess->parent_conn->fd, write, req->net_bytes, uint32le_decode(req->net_bytes)); cr_mutex_unlock(&sess->parent_conn->writelock); if (r < 0) @@ -206,12 +206,12 @@ static void respond_error(struct _lib9p_srv_req *req) { /* read coroutine *************************************************************/ -static bool read_at_least(implements_net_stream_conn *fd, uint8_t *buf, size_t goal, size_t *done) { +static bool read_at_least(lo_interface net_stream_conn fd, uint8_t *buf, size_t goal, size_t *done) { assert(buf); assert(goal); assert(done); while (*done < goal) { - ssize_t r = VCALL(fd, read, &buf[*done], CONFIG_9P_MAX_MSG_SIZE - *done); + ssize_t r = LO_CALL(fd, read, &buf[*done], CONFIG_9P_MAX_MSG_SIZE - *done); if (r < 0) { nonrespond_errorf("read: %s", net_strerror(-r)); return true; @@ -227,12 +227,12 @@ static bool read_at_least(implements_net_stream_conn *fd, uint8_t *buf, size_t g static void handle_message(struct _lib9p_srv_req *ctx); -[[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, implements_net_stream_listener *listener) { +[[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, lo_interface net_stream_listener listener) { uint8_t buf[CONFIG_9P_MAX_MSG_SIZE]; assert(srv); assert(srv->rootdir); - assert(listener); + assert(!LO_IS_NULL(listener)); srv->readers++; @@ -241,10 +241,10 @@ static void handle_message(struct _lib9p_srv_req *ctx); for (;;) { struct _srv_conn conn = { .parent_srv = srv, - .fd = VCALL(listener, accept), + .fd = LO_CALL(listener, accept), .reader = cr_getcid(), }; - if (!conn.fd) { + if (LO_IS_NULL(conn.fd)) { nonrespond_errorf("accept: error"); srv->readers--; if (srv->readers == 0) @@ -305,12 +305,12 @@ static void handle_message(struct _lib9p_srv_req *ctx); _lib9p_srv_reqch_send_req(&srv->_reqch, &req); } close: - VCALL(conn.fd, close, true, sess.reqs.len == 0); + LO_CALL(conn.fd, close, true, sess.reqs.len == 0); if (sess.reqs.len) { sess.closing = true; cr_pause_and_yield(); assert(sess.reqs.len == 0); - VCALL(conn.fd, close, true, true); + LO_CALL(conn.fd, close, true, true); } } } @@ -438,8 +438,8 @@ static void handle_message(struct _lib9p_srv_req *ctx) { goto write; cr_mutex_lock(&ctx->parent_sess->parent_conn->writelock); - VCALL(ctx->parent_sess->parent_conn->fd, write, - ctx->net_bytes, uint32le_decode(ctx->net_bytes)); + LO_CALL(ctx->parent_sess->parent_conn->fd, write, + ctx->net_bytes, uint32le_decode(ctx->net_bytes)); cr_mutex_unlock(&ctx->parent_sess->parent_conn->writelock); } } diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c index 8df3da0..6655f67 100644 --- a/lib9p/tests/test_server/main.c +++ b/lib9p/tests/test_server/main.c @@ -91,7 +91,7 @@ static uint32_t api_pwrite(implements_lib9p_srv_file *, struct lib9p_srv_ctx *, if (byte_count == 0) return 0; for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) - VCALL(&globals.listeners[i], close); + LO_CALL(lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i]), close); return byte_count; } @@ -170,7 +170,7 @@ static COROUTINE read_cr(void *_i) { hostnet_tcp_listener_init(&globals.listeners[i], 9000); - lib9p_srv_read_cr(&globals.srv, &globals.listeners[i]); + lib9p_srv_read_cr(&globals.srv, lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i])); cr_end(); } diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c index d6b2f19..e50c5f3 100644 --- a/libdhcp/dhcp_client.c +++ b/libdhcp/dhcp_client.c @@ -87,7 +87,6 @@ #include <string.h> /* for strlen(), memcpy(), memset() */ #include <libmisc/rand.h> -#include <libmisc/vcall.h> #include <libhw/generic/alarmclock.h> #define LOG_NAME DHCP @@ -125,8 +124,8 @@ enum requirement { struct dhcp_client { /* Static. */ - implements_net_iface *iface; - implements_net_packet_conn *sock; + lo_interface net_iface iface; + lo_interface net_packet_conn sock; struct net_eth_addr self_eth_addr; char *self_hostname; size_t self_id_len; @@ -462,7 +461,7 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c * Send * \**********************************************************************/ debugf("state %s: sending DHCP %s", state_strs[client->state], dhcp_msgtyp_str(msgtyp)); - ssize_t r = VCALL(client->sock, sendto, scratch_msg, DHCP_MSG_BASE_SIZE + optlen, + ssize_t r = LO_CALL(client->sock, sendto, scratch_msg, DHCP_MSG_BASE_SIZE + optlen, client_broadcasts ? net_ip4_addr_broadcast : client->lease_server_id, DHCP_PORT_SERVER); if (r < 0) { debugf("error: sendto: %zd", r); @@ -579,7 +578,7 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg assert(client); ignore: - msg_len = VCALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port); + msg_len = LO_CALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port); if (msg_len < 0) /* msg_len is -errno */ return msg_len; @@ -702,9 +701,9 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg } /** @return true if there's a conflict, false if the addr appears to be unused */ -static bool dhcp_check_conflict(implements_net_packet_conn *sock, struct net_ip4_addr addr) { - assert(sock); - ssize_t v = VCALL(sock, sendto, "CHECK_IP_CONFLICT", 17, addr, 5000); +static bool dhcp_check_conflict(lo_interface net_packet_conn sock, struct net_ip4_addr addr) { + assert(!LO_IS_NULL(sock)); + ssize_t v = LO_CALL(sock, sendto, "CHECK_IP_CONFLICT", 17, addr, 5000); debugf("check_ip_conflict => %zd", v); return v != -NET_EARP_TIMEOUT; } @@ -745,7 +744,7 @@ static void dhcp_client_take_lease(struct dhcp_client *client, struct dhcp_recv_ infof(":: addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(client->lease_client_addr)); infof(":: gateway_addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(client->lease_auxdata.gateway_addr)); infof(":: subnet_mask = "PRI_net_ip4_addr, ARG_net_ip4_addr(client->lease_auxdata.subnet_mask)); - VCALL(client->iface, ifup, (struct net_iface_config){ + LO_CALL(client->iface, ifup, (struct net_iface_config){ .addr = client->lease_client_addr, .gateway_addr = client->lease_auxdata.gateway_addr, .subnet_mask = client->lease_auxdata.subnet_mask, @@ -776,7 +775,7 @@ static void dhcp_client_setstate(struct dhcp_client *client, dhcp_client_setstate(client, STATE_SELECTING, DHCP_MSGTYP_DISCOVER, NULL, scratch_msg); break; case STATE_SELECTING: - VCALL(client->sock, set_read_deadline, client->time_ns_init+CONFIG_DHCP_SELECTING_NS); + LO_CALL(client->sock, set_read_deadline, client->time_ns_init+CONFIG_DHCP_SELECTING_NS); switch ((r = dhcp_client_recv(client, scratch_msg))) { case 0: switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) { @@ -798,7 +797,7 @@ static void dhcp_client_setstate(struct dhcp_client *client, } break; case STATE_REQUESTING: - VCALL(client->sock, set_read_deadline, 0); + LO_CALL(client->sock, set_read_deadline, 0); switch ((r = dhcp_client_recv(client, scratch_msg))) { case 0: switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) { @@ -825,7 +824,7 @@ static void dhcp_client_setstate(struct dhcp_client *client, } break; case STATE_BOUND: - VCALL(client->sock, set_read_deadline, client->lease_time_ns_t1); + LO_CALL(client->sock, set_read_deadline, client->lease_time_ns_t1); switch ((r = dhcp_client_recv(client, scratch_msg))) { case 0: /* discard */ @@ -842,12 +841,12 @@ static void dhcp_client_setstate(struct dhcp_client *client, client->xid = rand_uint63n(UINT32_MAX); client->time_ns_init = LO_CALL(bootclock, get_time_ns); - VCALL(client->sock, set_read_deadline, client->lease_time_ns_t2); + LO_CALL(client->sock, set_read_deadline, client->lease_time_ns_t2); switch ((r = dhcp_client_recv(client, scratch_msg))) { case 0: switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) { case DHCP_MSGTYP_NAK: - VCALL(client->iface, ifdown); + LO_CALL(client->iface, ifdown); dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); break; case DHCP_MSGTYP_ACK: @@ -868,12 +867,12 @@ static void dhcp_client_setstate(struct dhcp_client *client, } break; case STATE_REBINDING: - VCALL(client->sock, set_read_deadline, client->lease_time_ns_end); + LO_CALL(client->sock, set_read_deadline, client->lease_time_ns_end); switch ((r = dhcp_client_recv(client, scratch_msg))) { case 0: switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) { case DHCP_MSGTYP_NAK: - VCALL(client->iface, ifdown); + LO_CALL(client->iface, ifdown); dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg); break; case DHCP_MSGTYP_ACK: @@ -885,7 +884,7 @@ static void dhcp_client_setstate(struct dhcp_client *client, } break; case -NET_ERECV_TIMEOUT: - VCALL(client->iface, ifdown); + LO_CALL(client->iface, ifdown); dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg); break; default: @@ -902,9 +901,9 @@ static void dhcp_client_setstate(struct dhcp_client *client, } } -[[noreturn]] void dhcp_client_main(implements_net_iface *iface, +[[noreturn]] void dhcp_client_main(lo_interface net_iface iface, char *self_hostname) { - assert(iface); + assert(!LO_IS_NULL(iface)); /* Even though a client ID is optional and not meaningful for * us (the best we can do is to duplicate .chaddr), systemd's @@ -912,14 +911,14 @@ static void dhcp_client_setstate(struct dhcp_client *client, * require it to be set. */ struct {uint8_t typ; struct net_eth_addr dat;} client_id = { DHCP_HTYPE_ETHERNET, - VCALL(iface, hwaddr), + LO_CALL(iface, hwaddr), }; struct dhcp_client client = { /* Static. */ .iface = iface, - .sock = VCALL(iface, udp_conn, DHCP_PORT_CLIENT), - .self_eth_addr = VCALL(iface, hwaddr), + .sock = LO_CALL(iface, udp_conn, DHCP_PORT_CLIENT), + .self_eth_addr = LO_CALL(iface, hwaddr), .self_hostname = self_hostname, .self_id_len = sizeof(client_id), .self_id_dat = &client_id, @@ -927,7 +926,7 @@ static void dhcp_client_setstate(struct dhcp_client *client, /* Mutable. */ .state = STATE_INIT, }; - assert(client.sock); + assert(!LO_IS_NULL(client.sock)); struct dhcp_recv_msg scratch; diff --git a/libdhcp/include/libdhcp/client.h b/libdhcp/include/libdhcp/client.h index c3cb76f..f81e9b1 100644 --- a/libdhcp/include/libdhcp/client.h +++ b/libdhcp/include/libdhcp/client.h @@ -1,6 +1,6 @@ /* libdhcp/client.h - A DHCP client * - * 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 * * ----------------------------------------------------------------------------- @@ -69,7 +69,7 @@ #include <libhw/generic/net.h> -[[noreturn]] void dhcp_client_main(implements_net_iface *iface, +[[noreturn]] void dhcp_client_main(lo_interface net_iface iface, char *self_hostname); #endif /* _LIBDHCP_CLIENT_H_ */ diff --git a/libhw/host_include/libhw/host_net.h b/libhw/host_include/libhw/host_net.h index bfef5c9..fced229 100644 --- a/libhw/host_include/libhw/host_net.h +++ b/libhw/host_include/libhw/host_net.h @@ -1,6 +1,6 @@ /* libhw/host_net.h - <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 */ @@ -14,33 +14,30 @@ #include <libhw/generic/net.h> struct _hostnet_tcp_conn { - implements_net_stream_conn; - BEGIN_PRIVATE(LIBHW_HOST_NET_H) int fd; uint64_t read_deadline_ns; END_PRIVATE(LIBHW_HOST_NET_H) }; +LO_IMPLEMENTATION_H(net_stream_conn, struct _hostnet_tcp_conn, hostnet_tcp) struct hostnet_tcp_listener { - implements_net_stream_listener; - BEGIN_PRIVATE(LIBHW_HOST_NET_H) int fd; struct _hostnet_tcp_conn active_conn; END_PRIVATE(LIBHW_HOST_NET_H) }; +LO_IMPLEMENTATION_H(net_stream_listener, struct hostnet_tcp_listener, hostnet_tcplist) void hostnet_tcp_listener_init(struct hostnet_tcp_listener *self, uint16_t port); struct hostnet_udp_conn { - implements_net_packet_conn; - BEGIN_PRIVATE(LIBHW_HOST_NET_H) int fd; uint64_t read_deadline_ns; END_PRIVATE(LIBHW_HOST_NET_H) }; +LO_IMPLEMENTATION_H(net_packet_conn, struct hostnet_udp_conn, hostnet_udp) void hostnet_udp_conn_init(struct hostnet_udp_conn *self, uint16_t port); diff --git a/libhw/host_net.c b/libhw/host_net.c index 3352b87..505c7dc 100644 --- a/libhw/host_net.c +++ b/libhw/host_net.c @@ -21,7 +21,7 @@ #include <libcr/coroutine.h> #include <libmisc/assert.h> #include <libmisc/macro.h> -#include <libmisc/vcall.h> +#include <libobj/obj.h> #include <libhw/generic/alarmclock.h> @@ -30,6 +30,10 @@ #include "host_util.h" /* for host_sigrt_alloc(), ns_to_host_us_time() */ +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) + /* common *********************************************************************/ static int hostnet_sig_io = 0; @@ -109,25 +113,6 @@ static inline ssize_t hostnet_map_negerrno(ssize_t v, enum hostnet_timeout_op op /* 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 { @@ -151,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; } @@ -175,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; @@ -188,22 +170,19 @@ 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 NULL; + return LO_NULL(net_stream_conn); - listener->active_conn.vtable = &hostnet_tcp_conn_vtable; listener->active_conn.fd = ret_connfd; listener->active_conn.read_deadline_ns = 0; - return &listener->active_conn; + 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(shutdown(listener->fd, SHUT_RDWR) ? -errno : 0, OP_NONE); @@ -211,9 +190,7 @@ static int hostnet_tcplist_close(implements_net_stream_listener *_listener) { /* 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; @@ -250,9 +227,7 @@ static void *hostnet_pthread_read(void *_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; @@ -310,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; @@ -333,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; @@ -352,21 +323,6 @@ static int hostnet_tcp_close(implements_net_stream_conn *_conn, bool rd, bool wr /* 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 { @@ -385,7 +341,6 @@ 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; } @@ -427,10 +382,8 @@ static void *hostnet_pthread_sendto(void *_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; @@ -453,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; @@ -514,10 +465,8 @@ static void *hostnet_pthread_recvfrom(void *_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; @@ -549,9 +498,7 @@ 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, OP_NONE); diff --git a/libhw/rp2040_include/libhw/w5500.h b/libhw/rp2040_include/libhw/w5500.h index 87d333a..ab9f50e 100644 --- a/libhw/rp2040_include/libhw/w5500.h +++ b/libhw/rp2040_include/libhw/w5500.h @@ -20,11 +20,8 @@ CR_CHAN_DECLARE(_w5500_sockintr_ch, uint8_t) struct _w5500_socket { - /* const-after-init */ - implements_net_stream_listener implements_net_stream_listener; - implements_net_stream_conn implements_net_stream_conn; - implements_net_packet_conn implements_net_packet_conn; BEGIN_PRIVATE(LIBHW_W5500_H) + /* const-after-init */ uint8_t socknum; /* mutable */ @@ -43,11 +40,13 @@ struct _w5500_socket { END_PRIVATE(LIBHW_W5500_H) }; +LO_IMPLEMENTATION_H(net_stream_listener, struct _w5500_socket, w5500_tcplist) +LO_IMPLEMENTATION_H(net_stream_conn, struct _w5500_socket, w5500_tcp) +LO_IMPLEMENTATION_H(net_packet_conn, struct _w5500_socket, w5500_udp) struct w5500 { - /* const-after-init */ - implements_net_iface; BEGIN_PRIVATE(LIBHW_W5500_H) + /* const-after-init */ lo_interface spi spidev; uint pin_intr; uint pin_reset; @@ -61,6 +60,7 @@ struct w5500 { cr_mutex_t mu; END_PRIVATE(LIBHW_W5500_H) }; +LO_IMPLEMENTATION_H(net_iface, struct w5500, w5500_if) /** * Initialize a WIZnet W5500 Ethernet-and-TCP/IP-offload chip. diff --git a/libhw/w5500.c b/libhw/w5500.c index 2c130f5..dfe169f 100644 --- a/libhw/w5500.c +++ b/libhw/w5500.c @@ -74,7 +74,6 @@ #include <hardware/gpio.h> /* pico-sdk:hardware_gpio */ #include <libcr/coroutine.h> /* for cr_yield() */ -#include <libmisc/vcall.h> /* for VCALL_SELF() */ #include <libhw/generic/alarmclock.h> /* for sleep_*() */ @@ -124,61 +123,12 @@ static const char *w5500_state_str(uint8_t state) { } } -/* vtables ********************************************************************/ - -/* iface */ -static struct net_eth_addr w5500_if_hwaddr (implements_net_iface *); -static void w5500_if_up (implements_net_iface *, struct net_iface_config); -static void w5500_if_down (implements_net_iface *); -static implements_net_stream_listener *w5500_if_tcp_listen (implements_net_iface *, uint16_t local_port); -static implements_net_stream_conn *w5500_if_tcp_dial (implements_net_iface *, struct net_ip4_addr, uint16_t remote_port); -static implements_net_packet_conn *w5500_if_udp_conn (implements_net_iface *, uint16_t local_port); - -/* stream_listener */ -static implements_net_stream_conn *w5500_tcplist_accept(implements_net_stream_listener *); -static int w5500_tcplist_close (implements_net_stream_listener *); - -/* stream_conn */ -static void w5500_tcp_set_read_deadline (implements_net_stream_conn *, uint64_t ns); -static ssize_t w5500_tcp_read (implements_net_stream_conn *, void *, size_t); -static ssize_t w5500_tcp_write (implements_net_stream_conn *, void *, size_t); -static int w5500_tcp_close (implements_net_stream_conn *, bool rd, bool wr); - -/* packet_conn */ -static void w5500_udp_set_read_deadline (implements_net_packet_conn *, uint64_t ns); -static ssize_t w5500_udp_recvfrom (implements_net_packet_conn *, void *, size_t, struct net_ip4_addr *, uint16_t *); -static ssize_t w5500_udp_sendto (implements_net_packet_conn *, void *, size_t, struct net_ip4_addr, uint16_t); -static int w5500_udp_close (implements_net_packet_conn *); - -/* tables */ - -static struct net_iface_vtable w5500_iface_vtable = { - .hwaddr = w5500_if_hwaddr, - .ifup = w5500_if_up, - .ifdown = w5500_if_down, - .tcp_listen = w5500_if_tcp_listen, - .tcp_dial = w5500_if_tcp_dial, - .udp_conn = w5500_if_udp_conn, -}; - -static struct net_stream_listener_vtable w5500_tcp_listener_vtable = { - .accept = w5500_tcplist_accept, - .close = w5500_tcplist_close, -}; - -static struct net_stream_conn_vtable w5500_tcp_conn_vtable = { - .set_read_deadline = w5500_tcp_set_read_deadline, - .read = w5500_tcp_read, - .write = w5500_tcp_write, - .close = w5500_tcp_close, -}; - -static struct net_packet_conn_vtable w5500_udp_conn_vtable = { - .set_read_deadline = w5500_udp_set_read_deadline, - .recvfrom = w5500_udp_recvfrom, - .sendto = w5500_udp_sendto, - .close = w5500_udp_close, -}; +/* libobj *********************************************************************/ + +LO_IMPLEMENTATION_C(net_stream_listener, struct _w5500_socket, w5500_tcplist, static) +LO_IMPLEMENTATION_C(net_stream_conn, struct _w5500_socket, w5500_tcp, static) +LO_IMPLEMENTATION_C(net_packet_conn, struct _w5500_socket, w5500_udp, static) +LO_IMPLEMENTATION_C(net_iface, struct w5500, w5500_if, static) /* mid-level utilities ********************************************************/ @@ -311,9 +261,6 @@ static inline void w5500_socket_close(struct _w5500_socket *socket) { } #define ASSERT_SELF(_iface, _mode) \ - struct _w5500_socket *socket = \ - VCALL_SELF(struct _w5500_socket, \ - implements_net_##_iface, _socket); \ assert(socket); \ uint8_t socknum = socket->socknum; \ assert(socknum < 8); \ @@ -341,7 +288,6 @@ void _w5500_init(struct w5500 *chip, /* Initialize the data structures. */ *chip = (struct w5500){ /* const-after-init */ - .implements_net_iface = { .vtable = &w5500_iface_vtable }, .spidev = spi, .pin_intr = pin_intr, .pin_reset = pin_reset, @@ -353,9 +299,6 @@ void _w5500_init(struct w5500 *chip, for (uint8_t i = 0; i < 8; i++) { chip->sockets[i] = (struct _w5500_socket){ /* const-after-init */ - .implements_net_stream_listener = { .vtable = &w5500_tcp_listener_vtable }, - .implements_net_stream_conn = { .vtable = &w5500_tcp_conn_vtable }, - .implements_net_packet_conn = { .vtable = &w5500_udp_conn_vtable }, .socknum = i, /* mutable */ .next_free = (i + 1 < 8) ? &chip->sockets[i+1] : NULL, @@ -449,15 +392,13 @@ void w5500_soft_reset(struct w5500 *chip) { cr_mutex_unlock(&chip->mu); } -static struct net_eth_addr w5500_if_hwaddr(implements_net_iface *_chip) { - struct w5500 *chip = VCALL_SELF(struct w5500, implements_net_iface, _chip); +static struct net_eth_addr w5500_if_hwaddr(struct w5500 *chip) { assert(chip); return chip->hwaddr; } -static void _w5500_if_up(implements_net_iface *_chip, struct net_iface_config cfg) { - struct w5500 *chip = VCALL_SELF(struct w5500, implements_net_iface, _chip); +static void _w5500_if_up(struct w5500 *chip, struct net_iface_config cfg) { assert(chip); cr_mutex_lock(&chip->mu); @@ -469,27 +410,26 @@ static void _w5500_if_up(implements_net_iface *_chip, struct net_iface_config cf cr_mutex_unlock(&chip->mu); } -static void w5500_if_up(implements_net_iface *_chip, struct net_iface_config cfg) { +static void w5500_if_ifup(struct w5500 *chip, struct net_iface_config cfg) { debugf("if_up()"); debugf(":: addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(cfg.addr)); debugf(":: gateway_addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(cfg.gateway_addr)); debugf(":: subnet_mask = "PRI_net_ip4_addr, ARG_net_ip4_addr(cfg.subnet_mask)); - _w5500_if_up(_chip, cfg); + _w5500_if_up(chip, cfg); } -static void w5500_if_down(implements_net_iface *_chip) { +static void w5500_if_ifdown(struct w5500 *chip) { debugf("if_down()"); - _w5500_if_up(_chip, (struct net_iface_config){0}); + _w5500_if_up(chip, (struct net_iface_config){0}); } -static implements_net_stream_listener *w5500_if_tcp_listen(implements_net_iface *_chip, uint16_t local_port) { - struct w5500 *chip = VCALL_SELF(struct w5500, implements_net_iface, _chip); +static lo_interface net_stream_listener w5500_if_tcp_listen(struct w5500 *chip, uint16_t local_port) { assert(chip); struct _w5500_socket *sock = w5500_alloc_socket(chip); if (!sock) { debugf("tcp_listen() => no sock"); - return NULL; + return LO_NULL(net_stream_listener); } debugf("tcp_listen() => sock[%"PRIu8"]", sock->socknum); @@ -502,12 +442,11 @@ static implements_net_stream_listener *w5500_if_tcp_listen(implements_net_iface sock->read_deadline_ns = 0; sock->list_open = true; - return &sock->implements_net_stream_listener; + return lo_box_w5500_tcplist_as_net_stream_listener(sock); } -static implements_net_stream_conn *w5500_if_tcp_dial(implements_net_iface *_chip, - struct net_ip4_addr node, uint16_t port) { - struct w5500 *chip = VCALL_SELF(struct w5500, implements_net_iface, _chip); +static lo_interface net_stream_conn w5500_if_tcp_dial(struct w5500 *chip, + struct net_ip4_addr node, uint16_t port) { assert(chip); assert(memcmp(node.octets, net_ip4_addr_zero.octets, 4)); assert(memcmp(node.octets, net_ip4_addr_broadcast.octets, 4)); @@ -516,7 +455,7 @@ static implements_net_stream_conn *w5500_if_tcp_dial(implements_net_iface *_chip struct _w5500_socket *socket = w5500_alloc_socket(chip); if (!socket) { debugf("tcp_dial() => no sock"); - return NULL; + return LO_NULL(net_stream_conn); } uint8_t socknum = socket->socknum; debugf("tcp_dial() => sock[%"PRIu8"]", socknum); @@ -553,21 +492,20 @@ static implements_net_stream_conn *w5500_if_tcp_dial(implements_net_iface *_chip cr_yield(); break; case STATE_TCP_ESTABLISHED: - return &socket->implements_net_stream_conn; + return lo_box_w5500_tcp_as_net_stream_conn(socket); default: goto restart; } } } -static implements_net_packet_conn *w5500_if_udp_conn(implements_net_iface *_chip, uint16_t local_port) { - struct w5500 *chip = VCALL_SELF(struct w5500, implements_net_iface, _chip); +static lo_interface net_packet_conn w5500_if_udp_conn(struct w5500 *chip, uint16_t local_port) { assert(chip); struct _w5500_socket *socket = w5500_alloc_socket(chip); if (!socket) { debugf("udp_conn() => no sock"); - return NULL; + return LO_NULL(net_packet_conn); } uint8_t socknum = socket->socknum; debugf("udp_conn() => sock[%"PRIu8"]", socknum); @@ -590,18 +528,18 @@ static implements_net_packet_conn *w5500_if_udp_conn(implements_net_iface *_chip cr_yield(); cr_mutex_unlock(&chip->mu); - return &socket->implements_net_packet_conn; + return lo_box_w5500_udp_as_net_packet_conn(socket); } /* tcp_listener methods *******************************************************/ -static implements_net_stream_conn *w5500_tcplist_accept(implements_net_stream_listener *_socket) { +static lo_interface net_stream_conn w5500_tcplist_accept(struct _w5500_socket *socket) { ASSERT_SELF(stream_listener, TCP); restart: if (!socket->list_open) { debugf("tcp_listener.accept() => already closed"); - return NULL; + return LO_NULL(net_stream_conn); } cr_mutex_lock(&chip->mu); @@ -630,14 +568,14 @@ static implements_net_stream_conn *w5500_tcplist_accept(implements_net_stream_li /* fall-through */ case STATE_TCP_CLOSE_WAIT: socket->write_open = true; - return &socket->implements_net_stream_conn; + return lo_box_w5500_tcp_as_net_stream_conn(socket); default: goto restart; } } } -static int w5500_tcplist_close(implements_net_stream_listener *_socket) { +static int w5500_tcplist_close(struct _w5500_socket *socket) { debugf("tcp_listener.close()"); ASSERT_SELF(stream_listener, TCP); @@ -648,7 +586,7 @@ static int w5500_tcplist_close(implements_net_stream_listener *_socket) { /* tcp_conn methods ***********************************************************/ -static ssize_t w5500_tcp_write(implements_net_stream_conn *_socket, void *buf, size_t count) { +static ssize_t w5500_tcp_write(struct _w5500_socket *socket, void *buf, size_t count) { debugf("tcp_conn.write(%zu)", count); ASSERT_SELF(stream_conn, TCP); assert(buf); @@ -725,7 +663,7 @@ static ssize_t w5500_tcp_write(implements_net_stream_conn *_socket, void *buf, s return done; } -static void w5500_tcp_set_read_deadline(implements_net_stream_conn *_socket, uint64_t ns) { +static void w5500_tcp_set_read_deadline(struct _w5500_socket *socket, uint64_t ns) { debugf("tcp_conn.set_read_deadline(%"PRIu64")", ns); ASSERT_SELF(stream_conn, TCP); socket->read_deadline_ns = ns; @@ -736,7 +674,7 @@ static void w5500_tcp_alarm_handler(void *_arg) { cr_sema_signal_from_intrhandler(&socket->read_sema); } -static ssize_t w5500_tcp_read(implements_net_stream_conn *_socket, void *buf, size_t count) { +static ssize_t w5500_tcp_read(struct _w5500_socket *socket, void *buf, size_t count) { debugf("tcp_conn.read()"); ASSERT_SELF(stream_conn, TCP); assert(buf); @@ -745,9 +683,9 @@ static ssize_t w5500_tcp_read(implements_net_stream_conn *_socket, void *buf, si struct alarmclock_trigger trigger = {0}; if (socket->read_deadline_ns) LO_CALL(bootclock, add_trigger, &trigger, - socket->read_deadline_ns, - w5500_tcp_alarm_handler, - socket); + socket->read_deadline_ns, + w5500_tcp_alarm_handler, + socket); /* Wait until there is data to read. */ uint16_t avail = 0; @@ -806,7 +744,7 @@ static ssize_t w5500_tcp_read(implements_net_stream_conn *_socket, void *buf, si return avail; } -static int w5500_tcp_close(implements_net_stream_conn *_socket, bool rd, bool wr) { +static int w5500_tcp_close(struct _w5500_socket *socket, bool rd, bool wr) { debugf("tcp_conn.close(rd=%s, wr=%s)", rd ? "true" : "false", wr ? "true" : "false"); ASSERT_SELF(stream_conn, TCP); @@ -839,7 +777,7 @@ static int w5500_tcp_close(implements_net_stream_conn *_socket, bool rd, bool wr /* udp_conn methods ***********************************************************/ -static ssize_t w5500_udp_sendto(implements_net_packet_conn *_socket, void *buf, size_t count, +static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t count, struct net_ip4_addr node, uint16_t port) { debugf("udp_conn.sendto()"); ASSERT_SELF(packet_conn, UDP); @@ -896,7 +834,7 @@ static ssize_t w5500_udp_sendto(implements_net_packet_conn *_socket, void *buf, } } -static void w5500_udp_set_read_deadline(implements_net_packet_conn *_socket, uint64_t ns) { +static void w5500_udp_set_read_deadline(struct _w5500_socket *socket, uint64_t ns) { debugf("udp_conn.set_read_deadline(%"PRIu64")", ns); ASSERT_SELF(packet_conn, UDP); socket->read_deadline_ns = ns; @@ -907,7 +845,7 @@ static void w5500_udp_alarm_handler(void *_arg) { cr_sema_signal_from_intrhandler(&socket->read_sema); } -static ssize_t w5500_udp_recvfrom(implements_net_packet_conn *_socket, void *buf, size_t count, +static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_t count, struct net_ip4_addr *ret_node, uint16_t *ret_port) { debugf("udp_conn.recvfrom()"); ASSERT_SELF(packet_conn, UDP); @@ -975,7 +913,7 @@ static ssize_t w5500_udp_recvfrom(implements_net_packet_conn *_socket, void *buf return len; } -static int w5500_udp_close(implements_net_packet_conn *_socket) { +static int w5500_udp_close(struct _w5500_socket *socket) { debugf("udp_conn.close()"); ASSERT_SELF(packet_conn, UDP); diff --git a/libhw/w5500_ll.h b/libhw/w5500_ll.h index c05a04f..92d9f14 100644 --- a/libhw/w5500_ll.h +++ b/libhw/w5500_ll.h @@ -15,7 +15,6 @@ #include <libmisc/assert.h> /* for assert(), static_assert() */ #include <libmisc/endian.h> /* for uint16be_t */ -#include <libmisc/vcall.h> /* for VCALL() */ #include <libhw/generic/net.h> /* for struct net_eth_addr, struct net_ip4_addr */ #include <libhw/generic/spi.h> /* for lo_interface spi */ diff --git a/libhw_generic/include/libhw/generic/net.h b/libhw_generic/include/libhw/generic/net.h index 0f9872e..c888735 100644 --- a/libhw_generic/include/libhw/generic/net.h +++ b/libhw_generic/include/libhw/generic/net.h @@ -1,6 +1,6 @@ /* libhw/generic/net.h - Device-independent network definitions * - * 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 */ @@ -13,6 +13,8 @@ #include <stdint.h> /* for uint{n}_t} */ #include <sys/types.h> /* for ssize_t */ +#include <libobj/obj.h> + /* Errnos *********************************************************************/ #define NET_EOTHER 1 @@ -54,97 +56,81 @@ struct net_eth_addr { /* Streams (e.g. TCP) *********************************************************/ -struct net_stream_listener_vtable; -struct net_stream_conn_vtable; - -typedef struct { - struct net_stream_listener_vtable *vtable; -} implements_net_stream_listener; - -typedef struct { - struct net_stream_conn_vtable *vtable; -} implements_net_stream_conn; - -struct net_stream_listener_vtable { - /** - * It is invalid to accept() a new connection if an existing - * connection is still open. - */ - implements_net_stream_conn *(*accept)(implements_net_stream_listener *self); - - /** - * The net_stream_conn returned from accept() may still be - * valid after the listener is closed. - * - * Return 0 on success, -errno on error. - */ - int (*close)(implements_net_stream_listener *self); -}; - -struct net_stream_conn_vtable { - /** - * Return bytes-read on success, 0 on EOF, -errno on error; a - * short read is *not* an error. - */ - ssize_t (*read)(implements_net_stream_conn *self, - void *buf, size_t count); - - /** - * Set a timestamp after which calls to read() will return - * NET_ETIMEDOUT. The timestamp is in nanoseconds on the - * system monotonic clock, which is usually (on pico-sdk and - * on the Linux kernel) nanoseconds-since-boot. - * - * A zero value disables the deadline. - * - * (2⁶⁴-1 nanoseconds is more than 500 years; there is little - * risk of this overflowing) - */ - void (*set_read_deadline)(implements_net_stream_conn *self, - uint64_t ns_since_boot); - - /** - * Return `count` on success, -errno on error; a short write *is* an - * error. - * - * Writes are *not* guaranteed to be atomic (as this would be - * expensive to implement), so if you have concurrent writers then you - * should arrange for a mutex to protect the connection. - */ - ssize_t (*write)(implements_net_stream_conn *self, - void *buf, size_t count); - - /** - * Return 0 on success, -errno on error. - */ - int (*close)(implements_net_stream_conn *self, - bool rd, bool wr); -}; +lo_interface net_stream_conn; + +#define net_stream_listener_LO_IFACE \ + /** \ + * It is invalid to accept() a new connection if an existing \ + * connection is still open. \ + */ \ + LO_FUNC(lo_interface net_stream_conn, accept) \ + \ + /** \ + * The net_stream_conn returned from accept() may still be \ + * valid after the listener is closed. \ + * \ + * Return 0 on success, -errno on error. \ + */ \ + LO_FUNC(int, close) +LO_INTERFACE(net_stream_listener) + +#define net_stream_conn_LO_IFACE \ + /** \ + * Return bytes-read on success, 0 on EOF, -errno on error; a \ + * short read is *not* an error. \ + */ \ + LO_FUNC(ssize_t, read, void *buf, size_t count) \ + \ + /** \ + * Set a timestamp after which calls to read() will return \ + * NET_ETIMEDOUT. The timestamp is in nanoseconds on the \ + * system monotonic clock, which is usually (on pico-sdk and \ + * on the Linux kernel) nanoseconds-since-boot. \ + * \ + * A zero value disables the deadline. \ + * \ + * (2⁶⁴-1 nanoseconds is more than 500 years; there is little \ + * risk of this overflowing) \ + */ \ + LO_FUNC(void, set_read_deadline, uint64_t ns_since_boot) \ + \ + /** \ + * Return `count` on success, -errno on error; a short write *is* an \ + * error. \ + * \ + * Writes are *not* guaranteed to be atomic (as this would be \ + * expensive to implement), so if you have concurrent writers then you \ + * should arrange for a mutex to protect the connection. \ + */ \ + LO_FUNC(ssize_t, write, void *buf, size_t count) \ + \ + /** \ + * Return 0 on success, -errno on error. \ + */ \ + LO_FUNC(int, close, bool rd, bool wr) +LO_INTERFACE(net_stream_conn) /* Packets (e.g. UDP) *********************************************************/ -struct net_packet_conn_vtable; - -typedef struct { - struct net_packet_conn_vtable *vtable; -} implements_net_packet_conn; - -struct net_packet_conn_vtable { - ssize_t (*sendto )(implements_net_packet_conn *self, - void *buf, size_t len, - struct net_ip4_addr node, uint16_t port); - /** - * @return The full length of the message, which may be more - * than the given `len` (as if the Linux MSG_TRUNC flag were - * given). - */ - ssize_t (*recvfrom)(implements_net_packet_conn *self, - void *buf, size_t len, - struct net_ip4_addr *ret_node, uint16_t *ret_port); - void (*set_read_deadline)(implements_net_packet_conn *self, - uint64_t ns_since_boot); - int (*close )(implements_net_packet_conn *self); -}; +#define net_packet_conn_LO_IFACE \ + LO_FUNC(ssize_t, sendto, \ + void *buf, size_t len, \ + struct net_ip4_addr node, uint16_t port) \ + \ + /** \ + * @return The full length of the message, which may be more \ + * than the given `len` (as if the Linux MSG_TRUNC flag were \ + * given). \ + */ \ + LO_FUNC(ssize_t, recvfrom, \ + void *buf, size_t len, \ + struct net_ip4_addr *ret_node, uint16_t *ret_port) \ + \ + LO_FUNC(void, set_read_deadline, \ + uint64_t ns_since_boot) \ + \ + LO_FUNC(int, close) +LO_INTERFACE(net_packet_conn) /* Interfaces *****************************************************************/ @@ -154,20 +140,14 @@ struct net_iface_config { struct net_ip4_addr subnet_mask; }; -struct net_iface_vtable; - -typedef struct { - struct net_iface_vtable *vtable; -} implements_net_iface; - -struct net_iface_vtable { - struct net_eth_addr (*hwaddr )(implements_net_iface *); - void (*ifup )(implements_net_iface *, struct net_iface_config); - void (*ifdown )(implements_net_iface *); - - implements_net_stream_listener *(*tcp_listen)(implements_net_iface *, uint16_t local_port); - implements_net_stream_conn *(*tcp_dial )(implements_net_iface *, struct net_ip4_addr remote_node, uint16_t remote_port); - implements_net_packet_conn *(*udp_conn )(implements_net_iface *, uint16_t local_port); -}; +#define net_iface_LO_IFACE \ + LO_FUNC(struct net_eth_addr , hwaddr ) \ + LO_FUNC(void , ifup , struct net_iface_config) \ + LO_FUNC(void , ifdown ) \ + \ + LO_FUNC(lo_interface net_stream_listener, tcp_listen, uint16_t local_port) \ + LO_FUNC(lo_interface net_stream_conn , tcp_dial , struct net_ip4_addr remote_node, uint16_t remote_port) \ + LO_FUNC(lo_interface net_packet_conn , udp_conn , uint16_t local_port) +LO_INTERFACE(net_iface) #endif /* _LIBHW_GENERIC_NET_H_ */ |