diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/sbc_harness/CMakeLists.txt | 3 | ||||
-rw-r--r-- | cmd/sbc_harness/hw/w5500.c | 145 | ||||
-rw-r--r-- | cmd/sbc_harness/hw/w5500.h | 18 | ||||
-rw-r--r-- | cmd/sbc_harness/main.c | 30 | ||||
-rw-r--r-- | cmd/srv9p/gnet.c | 283 | ||||
-rw-r--r-- | cmd/srv9p/gnet.h | 20 | ||||
-rw-r--r-- | cmd/srv9p/main.c | 4 |
7 files changed, 371 insertions, 132 deletions
diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt index 201b378..54553f0 100644 --- a/cmd/sbc_harness/CMakeLists.txt +++ b/cmd/sbc_harness/CMakeLists.txt @@ -15,8 +15,9 @@ target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config target_include_directories(sbc_harness PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(sbc_harness pico_stdlib - hardware_spi + hardware_flash hardware_gpio + hardware_spi libmisc libusb diff --git a/cmd/sbc_harness/hw/w5500.c b/cmd/sbc_harness/hw/w5500.c index b95ad88..ab1ac19 100644 --- a/cmd/sbc_harness/hw/w5500.c +++ b/cmd/sbc_harness/hw/w5500.c @@ -122,7 +122,7 @@ static COROUTINE w5500_irq_cr(void *_chip) { for (uint8_t socknum = 0; socknum < 8; socknum++) { if (!(sockmask & (1<<socknum))) continue; - struct _w5500_listener *listener = &chip->listeners[socknum]; + struct _w5500_tcp_listener *listener = &chip->listeners[socknum]; uint8_t sockintr = w5500ll_read_sock_reg(chip->spidev, socknum, interrupt); @@ -144,19 +144,19 @@ static COROUTINE w5500_irq_cr(void *_chip) { /* init() *********************************************************************/ -static implements_net_conn *w5500_accept(implements_net_listener *_listener); -static ssize_t w5500_read(implements_net_conn *conn, void *buf, size_t count); -static ssize_t w5500_write(implements_net_conn *conn, void *buf, size_t count); -static int w5500_close(implements_net_conn *conn, bool rd, bool wr); +static implements_net_stream_conn *w5500_tcp_accept(implements_net_stream_listener *listener); +static ssize_t w5500_tcp_read(implements_net_stream_conn *conn, void *buf, size_t count); +static ssize_t w5500_tcp_write(implements_net_stream_conn *conn, void *buf, size_t count); +static int w5500_tcp_close(implements_net_stream_conn *conn, bool rd, bool wr); -static struct net_listener_vtable w5500_listener_vtable = { - .accept = w5500_accept, +static struct net_stream_listener_vtable w5500_tcp_listener_vtable = { + .accept = w5500_tcp_accept, }; -static struct net_conn_vtable w5500_conn_vtable = { - .read = w5500_read, - .write = w5500_write, - .close = w5500_close, +static struct net_stream_conn_vtable w5500_tcp_conn_vtable = { + .read = w5500_tcp_read, + .write = w5500_tcp_write, + .close = w5500_tcp_close, }; static struct w5500 *w5500_chips[CONFIG_W5500_NUM] = {0}; @@ -183,13 +183,13 @@ void _w5500_init(struct w5500 *chip, .next_local_port = CONFIG_W5500_LOCAL_PORT_MIN, }; for (uint8_t i = 0; i < 8; i++) { - chip->listeners[i] = (struct _w5500_listener){ + chip->listeners[i] = (struct _w5500_tcp_listener){ /* const-after-init */ - .vtable = &w5500_listener_vtable, + .vtable = &w5500_tcp_listener_vtable, .socknum = i, .active_conn = { /* const-after-init */ - .vtable = &w5500_conn_vtable, + .vtable = &w5500_tcp_conn_vtable, /* mutable */ .read_open = false, .write_open = false, @@ -219,24 +219,44 @@ void _w5500_init(struct w5500 *chip, /* chip methods ***************************************************************/ static inline void w5500_post_reset(struct w5500 *chip, struct net_eth_addr addr) { + /* The W5500 does not have a built-in MAC address, we must + * provide one. */ w5500ll_write_common_reg(chip->spidev, eth_addr, addr); - /* The RP2040 needs a 1/sys_clk hysteresis between interrupts for us - * to notice them. At the maximum-rated clock-rate of 133MHz, that - * means 7.5ns (but the sbc-harness overclocks the RP2040, so we - * could get away with even shorter). + /* The RP2040 needs a 1/sys_clk hysteresis between interrupts + * for us to notice them. At the maximum-rated clock-rate of + * 133MHz, that means 7.5ns (but the sbc-harness overclocks + * the RP2040, so we could get away with even shorter). * - * The hysteresis is (intlevel+1)*4/(150MHz) (if intlevel is - * non-zero), or (intlevel+1)*26.7ns; so even the shortest-possible - * hysteresis much larger than necessary for us. */ + * If intlevel is non-zero, then the hysteresis is + * (intlevel+1)*4/(150MHz), or (intlevel+1)*26.7ns; so even + * the shortest-possible hysteresis much larger than necessary + * for us. */ w5500ll_write_common_reg(chip->spidev, intlevel, uint16be_marshal(1)); - /* This implementation does not care about any of the chip-level - * interrupts. */ + /* This implementation does not care about any of the + * chip-level interrupts. */ w5500ll_write_common_reg(chip->spidev, chip_interrupt_mask, 0); - /* This implementation cares about interrupts for each socket. */ + /* This implementation cares about interrupts for each + * socket. */ w5500ll_write_common_reg(chip->spidev, sock_interrupt_mask, 0xFF); + + /* Configure retry/timeout. + * + * timeout_arp = 0.1ms * retry_time * (retry_count+1) + * + * retry_count + * timeout_tcp = 0.1ms * retry_time * Σ 2^min(n, floor(1+log_2(65535/retry_time))) + * n=0 + * + * For retry_time=2000, retry_count=3, this means + * + * timeout_arp = 0.8s + * timeout_tcp = 3.0s + */ + w5500ll_write_common_reg(chip->spidev, retry_time, uint16be_marshal(2000)); + w5500ll_write_common_reg(chip->spidev, retry_count, 3); } void w5500_hard_reset(struct w5500 *chip, struct net_eth_addr addr) { @@ -263,8 +283,8 @@ void w5500_netcfg(struct w5500 *chip, struct w5500_netcfg cfg) { w5500ll_write_common_reg(chip->spidev, ip_addr, cfg.addr); } -implements_net_listener *w5500_listen(struct w5500 *chip, uint8_t socknum, - uint16_t port) { +implements_net_stream_listener *w5500_tcp_listen(struct w5500 *chip, uint8_t socknum, + uint16_t port) { assert(chip); assert(socknum < 8); assert(port); @@ -275,13 +295,13 @@ implements_net_listener *w5500_listen(struct w5500 *chip, uint8_t socknum, return &chip->listeners[socknum]; } -/* listener methods ***********************************************************/ +/* tcp_listener methods *******************************************************/ -static struct w5500 *w5500_listener_chip(struct _w5500_listener *listener) { +static struct w5500 *w5500_tcp_listener_chip(struct _w5500_tcp_listener *listener) { assert(listener); assert(listener->socknum < 8); - struct _w5500_listener *sock0 = &listener[-listener->socknum]; + struct _w5500_tcp_listener *sock0 = &listener[-listener->socknum]; assert(sock0); struct w5500 *chip = ((void *)sock0) - offsetof(struct w5500, listeners); @@ -289,9 +309,9 @@ static struct w5500 *w5500_listener_chip(struct _w5500_listener *listener) { return chip; } -static inline void w5500_listener_cmd(struct _w5500_listener *listener, uint8_t cmd) { +static inline void w5500_tcp_listener_cmd(struct _w5500_tcp_listener *listener, uint8_t cmd) { assert(listener); - struct w5500 *chip = w5500_listener_chip(listener); + struct w5500 *chip = w5500_tcp_listener_chip(listener); uint8_t socknum = listener->socknum; cr_mutex_lock(&listener->cmd_mu); @@ -301,12 +321,12 @@ static inline void w5500_listener_cmd(struct _w5500_listener *listener, uint8_t cr_mutex_unlock(&listener->cmd_mu); } -static inline void w5500_listener_cmd_close(struct _w5500_listener *listener) { +static inline void w5500_tcp_listener_cmd_close(struct _w5500_tcp_listener *listener) { assert(listener); - struct w5500 *chip = w5500_listener_chip(listener); + struct w5500 *chip = w5500_tcp_listener_chip(listener); uint8_t socknum = listener->socknum; - w5500_listener_cmd(listener, CMD_CLOSE); + w5500_tcp_listener_cmd(listener, CMD_CLOSE); w5500ll_write_sock_reg(chip->spidev, socknum, interrupt, 0xFF); while (w5500ll_read_sock_reg(chip->spidev, socknum, state) != STATE_CLOSED) cr_yield(); @@ -314,27 +334,27 @@ static inline void w5500_listener_cmd_close(struct _w5500_listener *listener) { listener->active_conn.read_open = listener->active_conn.write_open = false; } -#define ASSERT_LISTENER() \ - struct _w5500_listener *self = \ - VCALL_SELF(struct _w5500_listener, \ - implements_net_listener, _self); \ - struct w5500 *chip = w5500_listener_chip(self); \ +#define ASSERT_LISTENER() \ + struct _w5500_tcp_listener *self = \ + VCALL_SELF(struct _w5500_tcp_listener, \ + implements_net_stream_listener, _self); \ + struct w5500 *chip = w5500_tcp_listener_chip(self); \ uint8_t socknum = self->socknum; -static implements_net_conn *w5500_accept(implements_net_listener *_self) { +static implements_net_stream_conn *w5500_tcp_accept(implements_net_stream_listener *_self) { ASSERT_LISTENER(); restart: /* Mimics socket.c:socket(). */ - w5500_listener_cmd_close(self); + w5500_tcp_listener_cmd_close(self); w5500ll_write_sock_reg(chip->spidev, socknum, mode, SOCKMODE_TCP); w5500ll_write_sock_reg(chip->spidev, socknum, local_port, uint16be_marshal(self->port)); - w5500_listener_cmd(self, CMD_OPEN); + w5500_tcp_listener_cmd(self, CMD_OPEN); while (w5500ll_read_sock_reg(chip->spidev, socknum, state) != STATE_TCP_INIT) cr_yield(); /* Mimics socket.c:listen(). */ - w5500_listener_cmd(self, CMD_LISTEN); + w5500_tcp_listener_cmd(self, CMD_LISTEN); for (;;) { uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state); switch (state) { @@ -356,31 +376,32 @@ static implements_net_conn *w5500_accept(implements_net_listener *_self) { /* conn methods ***************************************************************/ -static struct _w5500_listener *w5500_conn_listener(struct _w5500_conn *conn) { +static struct _w5500_tcp_listener *w5500_tcp_conn_listener(struct _w5500_tcp_conn *conn) { assert(conn); - struct _w5500_listener *list = - ((void *)conn) - offsetof(struct _w5500_listener, active_conn); + struct _w5500_tcp_listener *list = + ((void *)conn) - offsetof(struct _w5500_tcp_listener, active_conn); return list; } #define ASSERT_CONN() \ - struct _w5500_conn *self = \ - VCALL_SELF(struct _w5500_conn, implements_net_conn, _self); \ - struct _w5500_listener *listener = w5500_conn_listener(self); \ - struct w5500 *chip = w5500_listener_chip(listener); \ + struct _w5500_tcp_conn *self = \ + VCALL_SELF(struct _w5500_tcp_conn, implements_net_stream_conn, _self); \ + struct _w5500_tcp_listener *listener = w5500_tcp_conn_listener(self); \ + struct w5500 *chip = w5500_tcp_listener_chip(listener); \ uint8_t socknum = listener->socknum; -static ssize_t w5500_write(implements_net_conn *_self, void *buf, size_t count) { +static ssize_t w5500_tcp_write(implements_net_stream_conn *_self, void *buf, size_t count) { ASSERT_CONN(); assert(buf); assert(count); - /* What we really want is to pause until we receive an ACK - * for some data we just queued, so that we can line up some - * new data to keep the buffer full. But that's not what SEND_FINIAIUI, the - * SEND_FINISHED interrupt doesn't fire until we receive the - * *last* ACK for the data, when the buffer is entirely empty. + /* What we really want is to pause until we receive an ACK for + * some data we just queued, so that we can line up some new + * data to keep the buffer full. But that's not what + * SEND_FINIAIUI, the SEND_FINISHED interrupt doesn't fire + * until we receive the *last* ACK for the data, when the + * buffer is entirely empty. * * Which means we basically have to busy-poll for space in the * buffer becoming available. @@ -416,13 +437,13 @@ static ssize_t w5500_write(implements_net_conn *_self, void *buf, size_t count) w5500ll_write_sock_reg(chip->spidev, socknum, tx_write_pointer, uint16be_marshal(ptr+freesize)); /* Submit the queue. */ - w5500_listener_cmd(listener, CMD_SEND); + w5500_tcp_listener_cmd(listener, CMD_SEND); done += freesize; } return done; } -static ssize_t w5500_read(implements_net_conn *_self, void *buf, size_t count) { +static ssize_t w5500_tcp_read(implements_net_stream_conn *_self, void *buf, size_t count) { ASSERT_CONN(); assert(buf); assert(count); @@ -452,20 +473,20 @@ static ssize_t w5500_read(implements_net_conn *_self, void *buf, size_t count) { w5500ll_read(chip->spidev, ptr, CTL_BLOCK_SOCK(socknum, RX), &((char *)buf)[done], avail); w5500ll_write_sock_reg(chip->spidev, socknum, rx_read_pointer, uint16be_marshal(ptr+avail)); - w5500_listener_cmd(listener, CMD_RECV); + w5500_tcp_listener_cmd(listener, CMD_RECV); done += avail; } return done; } -static int w5500_close(implements_net_conn *_self, bool rd, bool wr) { +static int w5500_tcp_close(implements_net_stream_conn *_self, bool rd, bool wr) { ASSERT_CONN(); if (rd) self->read_open = false; if (wr && self->write_open) { - w5500_listener_cmd(listener, CMD_DISCON); + w5500_tcp_listener_cmd(listener, CMD_DISCON); while (self->write_open) { uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state); switch (state) { @@ -473,7 +494,7 @@ static int w5500_close(implements_net_conn *_self, bool rd, bool wr) { self->write_open = false; /* Can still read */ if (!self->read_open) - w5500_listener_cmd_close(listener); + w5500_tcp_listener_cmd_close(listener); break; case STATE_CLOSED: self->write_open = false; diff --git a/cmd/sbc_harness/hw/w5500.h b/cmd/sbc_harness/hw/w5500.h index d0c8d48..cf28579 100644 --- a/cmd/sbc_harness/hw/w5500.h +++ b/cmd/sbc_harness/hw/w5500.h @@ -13,21 +13,19 @@ #include "hw/spi.h" -struct _w5500_listener; - -struct _w5500_conn { +struct _w5500_tcp_conn { /* const-after-init */ - implements_net_conn; + implements_net_stream_conn; /* mutable */ bool read_open; bool write_open; }; -struct _w5500_listener { +struct _w5500_tcp_listener { /* const-after-init */ - implements_net_listener; + implements_net_stream_listener; uint8_t socknum; - struct _w5500_conn active_conn; + struct _w5500_tcp_conn active_conn; /* mutable */ uint16_t port; @@ -43,7 +41,7 @@ struct w5500 { /* mutable */ uint16_t next_local_port; - struct _w5500_listener listeners[8]; + struct _w5500_tcp_listener listeners[8]; cr_sema_t intr; }; @@ -91,7 +89,7 @@ struct w5500_netcfg { */ void w5500_netcfg(struct w5500 *self, struct w5500_netcfg cfg); -implements_net_listener *w5500_listen(struct w5500 *self, uint8_t socknum, - uint16_t port); +implements_net_stream_listener *w5500_listen(struct w5500 *self, uint8_t socknum, + uint16_t port); #endif /* _HW_W5500_H_ */ diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c index c6df8f5..8ecc56c 100644 --- a/cmd/sbc_harness/main.c +++ b/cmd/sbc_harness/main.c @@ -7,9 +7,11 @@ #include <string.h> /* for strlen() */ #include <stdio.h> /* for printf() */ #include "pico/stdlib.h" +#include "hardware/flash.h" #include <libcr/coroutine.h> #include <libusb/usb_common.h> +#include <libmisc/hash.h> #include "hw/rp2040_hwspi.h" #include "hw/w5500.h" @@ -32,9 +34,23 @@ COROUTINE hello_world_cr(void *_chan) { } int main() { - /* initialization */ + /* initialization *****************************************************/ stdio_uart_init(); + /* NOR flash chips have a (bog-?)standard "RUID" "Read Unique + * ID" instruction; use our flash chip's unique ID as the + * basis for our serial numbers. */ + uint64_t flash_id64; + static_assert(sizeof(flash_id64) == FLASH_UNIQUE_ID_SIZE_BYTES); + flash_get_unique_id((uint8_t *)&flash_id64); + uint32_t flash_id32 = hash(&flash_id64, sizeof(flash_id64)); + static_assert(sizeof(flash_id32) == sizeof(hash(NULL, 0))); + uint8_t flash_id24[3] = { + (uint8_t)((flash_id32 >> 16) & 0xFF), + (uint8_t)((flash_id32 >> 8) & 0xFF), + (uint8_t)((flash_id32 >> 0) & 0xFF), + }; + struct rp2040_hwspi dev_spi; struct w5500 dev_w5500; rp2040_hwspi_init(&dev_spi, "W5500", RP2040_HWSPI_0, @@ -47,18 +63,24 @@ int main() { w5500_init(&dev_w5500, "W5500", &dev_spi, 21, /* PIN_INTR */ 20, /* PIN_RESET */ - ((struct net_eth_addr){{0xDE,0xAD,0xBE,0xEF,0x01,0x02}})); + ((struct net_eth_addr){{ + /* vendor ID: "Wiznet" */ + 0x00, 0x08, 0xDC, + /* serial number */ + flash_id24[0], flash_id24[1], flash_id24[2], + }})); usb_common_earlyinit(); usb_keyboard_init(); usb_common_lateinit(); - /* set up coroutines */ + /* set up coroutines **************************************************/ coroutine_add(usb_common_cr, NULL); usb_keyboard_rpc_t keyboard_chan = {0}; coroutine_add(usb_keyboard_cr, &keyboard_chan); //coroutine_add(hello_world_cr, &keyboard_chan); + //coroutine_add(dhcp_client_cr, NULL); - /* Event loop. */ + /* event loop *********************************************************/ coroutine_main(); } diff --git a/cmd/srv9p/gnet.c b/cmd/srv9p/gnet.c index d7e8717..5dd4a93 100644 --- a/cmd/srv9p/gnet.c +++ b/cmd/srv9p/gnet.c @@ -70,24 +70,35 @@ static inline bool RUN_PTHREAD(void *(*fn)(void *), void *args) { return false; } -/* init() ( AKA socket(3) + listen(3) )****************************************/ +static inline ssize_t gnet_map_errno(ssize_t v) { + if (v >= 0) + return v; + switch (v) { + case ETIMEDOUT: + return NET_ETIMEDOUT; + default: + return NET_EOTHER; + } +} + +/* TCP init() ( AKA socket(3) + listen(3) )************************************/ -static implements_net_conn *gnet_accept(implements_net_listener *_listener); -static ssize_t gnet_read(implements_net_conn *conn, void *buf, size_t count); -static ssize_t gnet_write(implements_net_conn *conn, void *buf, size_t count); -static int gnet_close(implements_net_conn *conn, bool rd, bool wr); +static implements_net_stream_conn *gnet_tcp_accept(implements_net_stream_listener *_listener); +static ssize_t gnet_tcp_read(implements_net_stream_conn *conn, void *buf, size_t count); +static ssize_t gnet_tcp_write(implements_net_stream_conn *conn, void *buf, size_t count); +static int gnet_tcp_close(implements_net_stream_conn *conn, bool rd, bool wr); -static struct net_listener_vtable gnet_listener_vtable = { - .accept = gnet_accept, +static struct net_stream_listener_vtable gnet_tcp_listener_vtable = { + .accept = gnet_tcp_accept, }; -static struct net_conn_vtable gnet_conn_vtable = { - .read = gnet_read, - .write = gnet_write, - .close = gnet_close, +static struct net_stream_conn_vtable gnet_tcp_conn_vtable = { + .read = gnet_tcp_read, + .write = gnet_tcp_write, + .close = gnet_tcp_close, }; -void gnet_listener_init(struct gnet_listener *self, uint16_t port) { +void gnet_tcp_listener_init(struct gnet_tcp_listener *self, uint16_t port) { int listenerfd; union { struct sockaddr_in in; @@ -108,13 +119,13 @@ void gnet_listener_init(struct gnet_listener *self, uint16_t port) { if (listen(listenerfd, 0) < 0) error(1, errno, "listen"); - self->vtable = &gnet_listener_vtable; + self->vtable = &gnet_tcp_listener_vtable; self->fd = listenerfd; } -/* accept() *******************************************************************/ +/* TCP accept() ***************************************************************/ -struct _pthread_accept_args { +struct gnet_pthread_accept_args { pthread_t cr_thread; cid_t cr_coroutine; @@ -123,8 +134,8 @@ struct _pthread_accept_args { int *ret_connfd; }; -static void *_pthread_accept(void *_args) { - struct _pthread_accept_args *args = _args; +static void *gnet_pthread_accept(void *_args) { + struct gnet_pthread_accept_args *args = _args; *(args->ret_connfd) = accept(args->listenerfd, NULL, NULL); if (*(args->ret_connfd) < 0) *(args->ret_connfd) = -errno; @@ -132,28 +143,29 @@ static void *_pthread_accept(void *_args) { return NULL; }; -static implements_net_conn *gnet_accept(implements_net_listener *_listener) { - struct gnet_listener *listener = VCALL_SELF(struct gnet_listener, implements_net_listener, _listener); +static implements_net_stream_conn *gnet_tcp_accept(implements_net_stream_listener *_listener) { + struct gnet_tcp_listener *listener = + VCALL_SELF(struct gnet_tcp_listener, implements_net_stream_listener, _listener); assert(listener); int ret_connfd; - struct _pthread_accept_args args = { + struct gnet_pthread_accept_args args = { .cr_thread = pthread_self(), .cr_coroutine = cr_getcid(), .listenerfd = listener->fd, .ret_connfd = &ret_connfd, }; - if (RUN_PTHREAD(_pthread_accept, &args)) + if (RUN_PTHREAD(gnet_pthread_accept, &args)) return NULL; - listener->active_conn.vtable = &gnet_conn_vtable; + listener->active_conn.vtable = &gnet_tcp_conn_vtable; listener->active_conn.fd = ret_connfd; return &listener->active_conn; } -/* read() *********************************************************************/ +/* TCP read() *****************************************************************/ -struct _pthread_read_args { +struct gnet_pthread_read_args { pthread_t cr_thread; cid_t cr_coroutine; @@ -164,21 +176,22 @@ struct _pthread_read_args { ssize_t *ret; }; -static void *_pthread_read(void *_args) { - struct _pthread_read_args *args = _args; +static void *gnet_pthread_read(void *_args) { + struct gnet_pthread_read_args *args = _args; *(args->ret) = read(args->connfd, args->buf, args->count); if (*(args->ret) < 0) - *(args->ret) = -errno; + *(args->ret) = gnet_map_errno(-errno); WAKE_COROUTINE(args); return NULL; }; -static ssize_t gnet_read(implements_net_conn *_conn, void *buf, size_t count) { - struct _gnet_conn *conn = VCALL_SELF(struct _gnet_conn, implements_net_conn, _conn); +static ssize_t gnet_tcp_read(implements_net_stream_conn *_conn, void *buf, size_t count) { + struct _gnet_tcp_conn *conn = + VCALL_SELF(struct _gnet_tcp_conn, implements_net_stream_conn, _conn); assert(conn); ssize_t ret; - struct _pthread_read_args args = { + struct gnet_pthread_read_args args = { .cr_thread = pthread_self(), .cr_coroutine = cr_getcid(), @@ -188,14 +201,14 @@ static ssize_t gnet_read(implements_net_conn *_conn, void *buf, size_t count) { .ret = &ret, }; - if (RUN_PTHREAD(_pthread_read, &args)) - return -1; + if (RUN_PTHREAD(gnet_pthread_read, &args)) + return -NET_ETHREAD; return ret; } -/* write() ********************************************************************/ +/* TCP write() ****************************************************************/ -struct _pthread_write_args { +struct gnet_pthread_write_args { pthread_t cr_thread; cid_t cr_coroutine; @@ -206,13 +219,13 @@ struct _pthread_write_args { ssize_t *ret; }; -static void *_pthread_write(void *_args) { - struct _pthread_read_args *args = _args; +static void *gnet_pthread_write(void *_args) { + struct gnet_pthread_read_args *args = _args; size_t done = 0; while (done < args->count) { ssize_t r = write(args->connfd, args->buf, args->count); if (r < 0) { - *(args->ret) = -errno; + gnet_map_errno(-errno); break; } done += r; @@ -223,12 +236,13 @@ static void *_pthread_write(void *_args) { return NULL; }; -static ssize_t gnet_write(implements_net_conn *_conn, void *buf, size_t count) { - struct _gnet_conn *conn = VCALL_SELF(struct _gnet_conn, implements_net_conn, _conn); +static ssize_t gnet_tcp_write(implements_net_stream_conn *_conn, void *buf, size_t count) { + struct _gnet_tcp_conn *conn = + VCALL_SELF(struct _gnet_tcp_conn, implements_net_stream_conn, _conn); assert(conn); ssize_t ret; - struct _pthread_write_args args = { + struct gnet_pthread_write_args args = { .cr_thread = pthread_self(), .cr_coroutine = cr_getcid(), @@ -238,15 +252,16 @@ static ssize_t gnet_write(implements_net_conn *_conn, void *buf, size_t count) { .ret = &ret, }; - if (RUN_PTHREAD(_pthread_write, &args)) - return -1; + if (RUN_PTHREAD(gnet_pthread_write, &args)) + return -NET_ETHREAD; return ret; } -/* close() ********************************************************************/ +/* TCP close() ****************************************************************/ -static int gnet_close(implements_net_conn *_conn, bool rd, bool wr) { - struct _gnet_conn *conn = VCALL_SELF(struct _gnet_conn, implements_net_conn, _conn); +static int gnet_tcp_close(implements_net_stream_conn *_conn, bool rd, bool wr) { + struct _gnet_tcp_conn *conn = + VCALL_SELF(struct _gnet_tcp_conn, implements_net_stream_conn, _conn); assert(conn); int how; @@ -257,6 +272,180 @@ static int gnet_close(implements_net_conn *_conn, bool rd, bool wr) { else if (!rd && wr) how = SHUT_WR; else - return -EINVAL; - return shutdown(conn->fd, how) ? -errno : 0; + assert(false); + return gnet_map_errno(shutdown(conn->fd, how) ? -errno : 0); +} + +/* UDP init() *****************************************************************/ + +static ssize_t gnet_udp_sendto(struct net_packet_conn *self, void *buf, size_t len, + struct net_ip4_addr addr, uint16_t port); +static ssize_t gnet_udp_recvfrom(struct net_packet_conn *self, void *buf, size_t len, + struct net_ip4_addr *ret_addr, uint16_t *ret_port); +static int gnet_udp_close(struct net_packet_conn *self); + +static struct net_packet_conn_vtable gnet_udp_conn_vtable = { + .sendto = gnet_udp_sendto, + .recvfrom = gnet_udp_recvfrom, + .close = gnet_udp_close, +}; + +void gnet_udp_conn_init(struct gnet_udp_conn *self, uint16_t port) { + int fd; + union { + struct sockaddr_in in; + struct sockaddr gen; + struct sockaddr_storage stor; + } addr = { 0 }; + + gnet_init(); + + addr.in.sin_family = AF_INET; + addr.in.sin_port = htons(port); + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) + error(1, errno, "socket"); + if (bind(fd, &addr.gen, sizeof addr) < 0) + error(1, errno, "bind"); + + self->vtable = &gnet_udp_conn_vtable; + self->fd = fd; +} + +/* UDP sendto() ***************************************************************/ + +struct gnet_pthread_sendto_args { + pthread_t cr_thread; + cid_t cr_coroutine; + + int connfd; + void *buf; + size_t count; + struct net_ip4_addr node; + uint16_t port; + + ssize_t *ret; +}; + +static void *gnet_pthread_sendto(void *_args) { + struct gnet_pthread_sendto_args *args = _args; + union { + struct sockaddr_in in; + struct sockaddr gen; + struct sockaddr_storage stor; + } addr = { 0 }; + + addr.in.sin_family = AF_INET; + addr.in.sin_addr.s_addr = + (((uint32_t)args->node.octets[0])<<24) | + (((uint32_t)args->node.octets[1])<<16) | + (((uint32_t)args->node.octets[2])<< 8) | + (((uint32_t)args->node.octets[3])<< 0) ; + 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) = gnet_map_errno(-errno); + WAKE_COROUTINE(args); + return NULL; +} + +static ssize_t gnet_udp_sendto(struct net_packet_conn *_conn, void *buf, size_t count, + struct net_ip4_addr node, uint16_t port) { + struct gnet_udp_conn *conn = + VCALL_SELF(struct gnet_udp_conn, implements_net_packet_conn, _conn); + assert(conn); + + ssize_t ret; + struct gnet_pthread_sendto_args args = { + .cr_thread = pthread_self(), + .cr_coroutine = cr_getcid(), + + .connfd = conn->fd, + .buf = buf, + .count = count, + .node = node, + .port = port, + + .ret = &ret, + }; + if (RUN_PTHREAD(gnet_pthread_sendto, &args)) + return -NET_ETHREAD; + return ret; +} + +/* UDP recvfrom() *************************************************************/ + +struct gnet_pthread_recvfrom_args { + pthread_t cr_thread; + cid_t cr_coroutine; + + int connfd; + void *buf; + size_t count; + + ssize_t *ret_size; + struct net_ip4_addr *ret_node; + uint16_t *ret_port; +}; + +static void *gnet_pthread_recvfrom(void *_args) { + struct gnet_pthread_recvfrom_args *args = _args; + + union { + struct sockaddr_in in; + struct sockaddr gen; + struct sockaddr_storage stor; + } addr = { 0 }; + socklen_t addr_size; + + *(args->ret_size) = recvfrom(args->connfd, args->buf, args->count, 0, &addr.gen, &addr_size); + if (*(args->ret_size) < 0) + *(args->ret_size) = gnet_map_errno(-errno); + else { + assert(addr.in.sin_family == AF_INET); + if (args->ret_node) { + args->ret_node->octets[0] = (addr.in.sin_addr.s_addr >> 24) & 0xFF; + args->ret_node->octets[1] = (addr.in.sin_addr.s_addr >> 16) & 0xFF; + args->ret_node->octets[2] = (addr.in.sin_addr.s_addr >> 8) & 0xFF; + args->ret_node->octets[3] = (addr.in.sin_addr.s_addr >> 0) & 0xFF; + } + if (args->ret_port) + (*args->ret_port) = ntohs(addr.in.sin_port); + } + WAKE_COROUTINE(args); + return NULL; +} + +static ssize_t gnet_udp_recvfrom(struct net_packet_conn *_conn, void *buf, size_t count, + struct net_ip4_addr *ret_node, uint16_t *ret_port) { + struct gnet_udp_conn *conn = + VCALL_SELF(struct gnet_udp_conn, implements_net_packet_conn, _conn); + assert(conn); + + ssize_t ret; + struct gnet_pthread_recvfrom_args args = { + .cr_thread = pthread_self(), + .cr_coroutine = cr_getcid(), + + .connfd = conn->fd, + .buf = buf, + .count = count, + + .ret_size = &ret, + .ret_node = ret_node, + .ret_port = ret_port, + }; + if (RUN_PTHREAD(gnet_pthread_recvfrom, &args)) + return -NET_ETHREAD; + return ret; +} + +/* UDP close() ****************************************************************/ + +static int gnet_udp_close(struct net_packet_conn *_conn) { + struct gnet_udp_conn *conn = + VCALL_SELF(struct gnet_udp_conn, implements_net_packet_conn, _conn); + assert(conn); + + return gnet_map_errno(close(conn->fd) ? -errno : 0); } diff --git a/cmd/srv9p/gnet.h b/cmd/srv9p/gnet.h index 01f2d40..4380c1d 100644 --- a/cmd/srv9p/gnet.h +++ b/cmd/srv9p/gnet.h @@ -11,19 +11,27 @@ #include <libmisc/net.h> -struct _gnet_conn { - implements_net_conn; +struct _gnet_tcp_conn { + implements_net_stream_conn; int fd; }; -struct gnet_listener { - implements_net_listener; +struct gnet_tcp_listener { + implements_net_stream_listener; int fd; - struct _gnet_conn active_conn; + struct _gnet_tcp_conn active_conn; }; -void gnet_listener_init(struct gnet_listener *self, uint16_t port); +void gnet_tcp_listener_init(struct gnet_tcp_listener *self, uint16_t port); + +struct gnet_udp_conn { + implements_net_packet_conn; + + int fd; +}; + +void gnet_udp_conn_init(struct gnet_udp_conn *self, uint16_t port); #endif /* _GNET_H_ */ diff --git a/cmd/srv9p/main.c b/cmd/srv9p/main.c index d83fac4..7ed985f 100644 --- a/cmd/srv9p/main.c +++ b/cmd/srv9p/main.c @@ -91,8 +91,8 @@ static COROUTINE read_cr(void *_srv) { cr_begin(); - struct gnet_listener listener; - gnet_listener_init(&listener, 9000); + struct gnet_tcp_listener listener; + gnet_tcp_listener_init(&listener, 9000); lib9p_srv_read_cr(srv, &listener); |