diff options
-rw-r--r-- | lib9p/srv.c | 66 | ||||
-rw-r--r-- | libdhcp/dhcp_client.c | 91 | ||||
-rw-r--r-- | libdhcp/tests/test_client.c | 20 | ||||
-rw-r--r-- | libhw_cr/host_net.c | 239 | ||||
-rw-r--r-- | libhw_cr/host_util.c | 92 | ||||
-rw-r--r-- | libhw_cr/host_util.h | 6 | ||||
-rw-r--r-- | libhw_cr/rp2040_hwspi.c | 3 | ||||
-rw-r--r-- | libhw_cr/w5500.c | 82 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/io.h | 34 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/net.h | 52 |
10 files changed, 413 insertions, 272 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c index 32e9a9a..7785e4d 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -366,23 +366,23 @@ static void srv_msglog(struct srv_req *req, enum lib9p_msg_type typ, void *hostm log_infoln(typ % 2 ? "< " : "> ", (lib9p_msg, &req->basectx, typ, hostmsg)); } -static ssize_t srv_write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *resp) { - ssize_t r; +#define srv_nonrespond_error log_errorln + +static void srv_write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *resp) { + size_t_and_error r; cr_mutex_lock(&req->parent_sess->parent_conn->writelock); r = io_writev(req->parent_sess->parent_conn->fd, resp->iov, resp->iov_cnt); cr_mutex_unlock(&req->parent_sess->parent_conn->writelock); - return r; + if (!ERROR_IS_NULL(r.err)) + srv_nonrespond_error("write: (", r.size_t, ", ", (error, r.err), ")"); } -#define srv_nonrespond_error log_errorln - static void srv_respond_error(struct srv_req *req) { #if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L assert(req->basectx.err_num); #endif assert(req->basectx.err_msg[0]); - ssize_t r; struct lib9p_msg_Rerror host = { .tag = req->tag, .errstr = lib9p_strn(req->basectx.err_msg, @@ -408,28 +408,29 @@ static void srv_respond_error(struct srv_req *req) { &net); srv_msglog(req, LIB9P_TYP_Rerror, &host); - r = srv_write_Rmsg(req, &net); - if (r < 0) - srv_nonrespond_error("write: ", net_strerror(-r)); + srv_write_Rmsg(req, &net); } /* read coroutine *************************************************************/ +/** Return whether to `break`. */ static inline bool srv_read_exactly(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 = io_read(fd, &buf[*done], goal - *done); - if (r < 0) { - srv_nonrespond_error("read: ", net_strerror(-r)); - return true; - } else if (r == 0) { - if (*done != 0) - srv_nonrespond_error("read: unexpected EOF"); + size_t_or_error r = io_read(fd, &buf[*done], goal - *done); + if (r.is_err) { + if (r.err.num == E_EOF) { + if (*done != 0) + srv_nonrespond_error("read: unexpected EOF"); + } else { + srv_nonrespond_error("read: ", (error, r.err)); + } + error_cleanup(&r.err); return true; } - *done += r; + *done += r.size_t; } return false; } @@ -442,16 +443,17 @@ void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stre srv->readers++; for (;;) { - lo_interface net_stream_conn conn = LO_CALL(listener, accept); - if (LO_IS_NULL(conn)) { - srv_nonrespond_error("accept: error"); + net_stream_conn_or_error r = LO_CALL(listener, accept); + if (r.is_err) { + srv_nonrespond_error("accept: ", (error, r.err)); + error_cleanup(&r.err); srv->readers--; if (srv->readers == 0) while (srv->writers > 0) cr_rpc_send_req(&srv->_reqch, NULL); return; } - lib9p_srv_read(srv, conn); + lib9p_srv_read(srv, r.net_stream_conn); } } @@ -517,14 +519,26 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { /* ...but usually in another coroutine. */ cr_rpc_send_req(&srv->_reqch, &req); } - if (map_len(&sess.reqs) == 0) - io_close(conn.fd); - else { - io_close_read(conn.fd); + if (map_len(&sess.reqs) == 0) { + error err = io_close(conn.fd); + if (!ERROR_IS_NULL(err)) { + srv_nonrespond_error("conn close: ", (error, err)); + error_cleanup(&err); + } + } else { + error err = io_close_read(conn.fd); + if (!ERROR_IS_NULL(err)) { + srv_nonrespond_error("conn close: ", (error, err)); + error_cleanup(&err); + } sess.closing = true; cr_pause_and_yield(); assert(map_len(&sess.reqs) == 0); - io_close_write(conn.fd); + err = io_close_write(conn.fd); + if (!ERROR_IS_NULL(err)) { + srv_nonrespond_error("conn close: ", (error, err)); + error_cleanup(&err); + } } assert(map_len(&sess.reqs) == 0); diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c index 57a2f60..1164355 100644 --- a/libdhcp/dhcp_client.c +++ b/libdhcp/dhcp_client.c @@ -252,11 +252,8 @@ static inline enum requirement dhcp_table5(typeof((struct dhcp_client){}.state) * @param client->lease_client_addr (sometimes) * @param client->lease_server_id (sometimes) * @param client->sock - * - * @return client->last_sent_msgtyp - * @return whether there was an error */ -static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const char *errstr, struct dhcp_msg *scratch_msg) { +static error dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const char *errstr, struct dhcp_msg *scratch_msg) { /**********************************************************************\ * Preconditions * \**********************************************************************/ @@ -462,14 +459,14 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c * Send * \**********************************************************************/ log_debugln("state ", state_strs[client->state], ": sending DHCP ", dhcp_msgtyp_str(msgtyp)); - 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) { - log_debugln("error: sendto: ", r); - return true; + error err = 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 (!ERROR_IS_NULL(err)) { + log_debugln("error: sendto: ", (error, err)); + return err; } client->last_sent_msgtyp = msgtyp; - return false; + return ERROR_NULL; } struct dhcp_recv_msg { @@ -565,24 +562,20 @@ static inline enum requirement dhcp_table3(uint8_t req_msgtyp, uint8_t resp_msgt * @param client->self_eth_addr * @param client->xid * @param client->lease_server_id - * - * @return - * - <0: -errno - * - 0: success - * - >0: should not happen */ -static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg *ret) { +static error dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg *ret) { struct net_ip4_addr srv_addr; uint16_t srv_port; - ssize_t msg_len; + size_t msg_len; assert(client); ignore: - msg_len = LO_CALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port); - if (msg_len < 0) + size_t_or_error r = LO_CALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port); + if (r.is_err) /* msg_len is -errno */ - return msg_len; + return r.err; + msg_len = r.size_t; /* Validate L3: IP */ /* Don't validate that srv_addr matches client->server_id @@ -595,10 +588,10 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg goto ignore; /* Validate L5: DHCP. */ - if ((size_t)msg_len < DHCP_MSG_BASE_SIZE + sizeof(dhcp_magic_cookie)) + if (msg_len < DHCP_MSG_BASE_SIZE + sizeof(dhcp_magic_cookie)) /* ignore impossibly short message */ goto ignore; - if ((size_t)msg_len > sizeof(ret->raw)) + if (msg_len > sizeof(ret->raw)) /* ignore message that is larger than the specified * DHCP_OPT_DHCP_MAX_MSG_SIZE */ goto ignore; @@ -698,7 +691,7 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg goto ignore; } - return 0; + return ERROR_NULL; } static void dhcp_client_take_lease(struct dhcp_client *client, struct dhcp_recv_msg *msg, bool ifup) { @@ -748,18 +741,19 @@ static void dhcp_client_take_lease(struct dhcp_client *client, struct dhcp_recv_ static void dhcp_client_setstate(struct dhcp_client *client, typeof((struct dhcp_client){}.state) newstate, uint8_t send_msgtyp, const char *errstr, struct dhcp_recv_msg *scratch_msg) { - if (send_msgtyp) - (void)dhcp_client_send(client, send_msgtyp, errstr, &scratch_msg->raw); + if (send_msgtyp) { + error err = dhcp_client_send(client, send_msgtyp, errstr, &scratch_msg->raw); + error_cleanup(&err); + } client->state = newstate; } [[noreturn]] static void dhcp_client_run(struct dhcp_client *client, struct dhcp_recv_msg *scratch_msg) { assert(client); - ssize_t r; - /* State transition diagram: https://datatracker.ietf.org/doc/html/rfc2131#page-35 */ for (;;) { + [[gnu::cleanup(error_cleanup)]] error err = {}; log_debugln("loop: state=", state_strs[client->state]); switch (client->state) { case STATE_INIT: @@ -769,8 +763,8 @@ static void dhcp_client_setstate(struct dhcp_client *client, break; case STATE_SELECTING: LO_CALL(client->sock, set_recv_deadline, client->time_ns_init+CONFIG_DHCP_SELECTING_NS); - switch ((r = dhcp_client_recv(client, scratch_msg))) { - case 0: + LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) { + case E_NOERROR: switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) { case DHCP_MSGTYP_OFFER: /* Accept the first offer. */ @@ -781,18 +775,17 @@ static void dhcp_client_setstate(struct dhcp_client *client, /* ignore */ } break; - case -NET_ERECV_TIMEOUT: + case E_NET_ERECV_TIMEOUT: dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); break; default: - assert(r < 0); - log_debugln("error: recvfrom: ", r); + log_debugln("error: recvfrom: ", (error, err)); } break; case STATE_REQUESTING: LO_CALL(client->sock, set_recv_deadline, 0); - switch ((r = dhcp_client_recv(client, scratch_msg))) { - case 0: + LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) { + case E_NOERROR: switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) { case DHCP_MSGTYP_NAK: dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); @@ -811,22 +804,20 @@ static void dhcp_client_setstate(struct dhcp_client *client, } break; default: - assert(r < 0); - log_debugln("error: recvfrom: ", r); + log_debugln("error: recvfrom: ", (error, err)); } break; case STATE_BOUND: LO_CALL(client->sock, set_recv_deadline, client->lease_time_ns_t1); - switch ((r = dhcp_client_recv(client, scratch_msg))) { - case 0: + LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) { + case E_NOERROR: /* discard */ break; - case -NET_ERECV_TIMEOUT: + case E_NET_ERECV_TIMEOUT: dhcp_client_setstate(client, STATE_RENEWING, DHCP_MSGTYP_REQUEST, NULL, scratch_msg); break; default: - assert(r < 0); - log_debugln("error: recvfrom: ", r); + log_debugln("error: recvfrom: ", (error, err)); } break; case STATE_RENEWING: @@ -834,8 +825,8 @@ static void dhcp_client_setstate(struct dhcp_client *client, client->time_ns_init = LO_CALL(bootclock, get_time_ns); LO_CALL(client->sock, set_recv_deadline, client->lease_time_ns_t2); - switch ((r = dhcp_client_recv(client, scratch_msg))) { - case 0: + LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) { + case E_NOERROR: switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) { case DHCP_MSGTYP_NAK: LO_CALL(client->iface, ifdown); @@ -849,19 +840,18 @@ static void dhcp_client_setstate(struct dhcp_client *client, /* ignore */ } break; - case -NET_ERECV_TIMEOUT: + case E_NET_ERECV_TIMEOUT: client->lease_server_id = net_ip4_addr_zero; dhcp_client_setstate(client, STATE_REBINDING, DHCP_MSGTYP_REQUEST, NULL, scratch_msg); break; default: - assert(r < 0); - log_debugln("error: recvfrom: ", r); + log_debugln("error: recvfrom: ", (error, err)); } break; case STATE_REBINDING: LO_CALL(client->sock, set_recv_deadline, client->lease_time_ns_end); - switch ((r = dhcp_client_recv(client, scratch_msg))) { - case 0: + LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) { + case E_NOERROR: switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) { case DHCP_MSGTYP_NAK: LO_CALL(client->iface, ifdown); @@ -875,13 +865,12 @@ static void dhcp_client_setstate(struct dhcp_client *client, /* ignore */ } break; - case -NET_ERECV_TIMEOUT: + case E_NET_ERECV_TIMEOUT: LO_CALL(client->iface, ifdown); dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg); break; default: - assert(r < 0); - log_debugln("error: recvfrom: ", r); + log_debugln("error: recvfrom: ", (error, err)); } break; case STATE_INIT_REBOOT: diff --git a/libdhcp/tests/test_client.c b/libdhcp/tests/test_client.c index 09557e5..cf76653 100644 --- a/libdhcp/tests/test_client.c +++ b/libdhcp/tests/test_client.c @@ -23,14 +23,14 @@ LO_IMPLEMENTATION_C(io_closer, struct test_udp, test_udp, static); LO_IMPLEMENTATION_H(net_packet_conn, struct test_udp, test_udp); LO_IMPLEMENTATION_C(net_packet_conn, struct test_udp, test_udp, static); -static ssize_t test_udp_sendto(struct test_udp *LM_UNUSED(self), void *LM_UNUSED(buf), size_t len, struct net_ip4_addr LM_UNUSED(node), uint16_t LM_UNUSED(port)) { +static error test_udp_sendto(struct test_udp *LM_UNUSED(self), void *LM_UNUSED(buf), size_t LM_UNUSED(len), struct net_ip4_addr LM_UNUSED(node), uint16_t LM_UNUSED(port)) { static unsigned cnt = 0; if (cnt++ % 2 == 0) - return -NET_EOTHER; - return len; + return error_new(E_EUNKNOWN); + return ERROR_NULL; } -static ssize_t test_udp_recvfrom(struct test_udp *LM_UNUSED(self), void *buf, size_t len, struct net_ip4_addr *ret_node, uint16_t *ret_port) { +static size_t_or_error test_udp_recvfrom(struct test_udp *LM_UNUSED(self), void *buf, size_t len, struct net_ip4_addr *ret_node, uint16_t *ret_port) { static const uint8_t resp_offer[] = {0x02,0x01,0x06,0x00,0xE8,0x40,0xC6,0x79,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0xC0,0xA8,0x0A,0x78,0xC0,0xA8,0x0A,0x01,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x82,0x53,0x63,0x35,0x01,0x02,0x36,0x04,0xC0,0xA8,0x0A,0x01,0x33,0x04,0x00,0x00,0xA8,0xC0,0x3A,0x04,0x00,0x00,0x54,0x60,0x3B,0x04,0x00,0x00,0x93,0xA8,0x01,0x04,0xFF,0xFF,0xFF,0x00,0x1C,0x04,0xC0,0xA8,0x0A,0xFF,0x03,0x04,0xC0,0xA8,0x0A,0x01,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; static const uint8_t resp_ack[] = {0x02,0x01,0x06,0x00,0xE8,0x40,0xC6,0x79,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0xC0,0xA8,0x0A,0x78,0xC0,0xA8,0x0A,0x01,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x82,0x53,0x63,0x35,0x01,0x05,0x36,0x04,0xC0,0xA8,0x0A,0x01,0x33,0x04,0x00,0x00,0xA8,0xC0,0x3A,0x04,0x00,0x00,0x54,0x60,0x3B,0x04,0x00,0x00,0x93,0xA8,0x01,0x04,0xFF,0xFF,0xFF,0x00,0x1C,0x04,0xC0,0xA8,0x0A,0xFF,0x03,0x04,0xC0,0xA8,0x0A,0x01,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; @@ -38,24 +38,24 @@ static ssize_t test_udp_recvfrom(struct test_udp *LM_UNUSED(self), void *buf, si const void *resp; size_t resp_len; switch (cnt++) { - case 0: return -NET_EOTHER; + case 0: return ERROR_NEW_ERR(size_t, error_new(E_EUNKNOWN)); case 1: resp = resp_offer; resp_len = sizeof(resp_offer); break; - case 2: return -NET_EOTHER; + case 2: return ERROR_NEW_ERR(size_t, error_new(E_EUNKNOWN)); case 3: resp = resp_ack; resp_len = sizeof(resp_ack); break; - default: return -NET_ERECV_TIMEOUT; + default: return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT)); } test_assert(len >= resp_len); memcpy(buf, resp, resp_len); *ret_node = ((struct net_ip4_addr){{192,168,10,1}}); *ret_port = 67; - return resp_len; + return ERROR_NEW_VAL(size_t, resp_len); } static void test_udp_set_recv_deadline(struct test_udp *LM_UNUSED(self), uint64_t LM_UNUSED(ns_since_boot)) { /* Do nothing? */ } -static int test_udp_close(struct test_udp *LM_UNUSED(self)) { +static error test_udp_close(struct test_udp *LM_UNUSED(self)) { assert_notreached("not implemented"); } @@ -90,7 +90,7 @@ static lo_interface net_stream_listener test_tcp_listen(struct test_iface *LM_UN assert_notreached("not implemented"); } -static lo_interface net_stream_conn test_tcp_dial(struct test_iface *LM_UNUSED(self), struct net_ip4_addr LM_UNUSED(remote_node), uint16_t LM_UNUSED(remote_port)) { +static net_stream_conn_or_error test_tcp_dial(struct test_iface *LM_UNUSED(self), struct net_ip4_addr LM_UNUSED(remote_node), uint16_t LM_UNUSED(remote_port)) { assert_notreached("not implemented"); } diff --git a/libhw_cr/host_net.c b/libhw_cr/host_net.c index 6093792..39bfd46 100644 --- a/libhw_cr/host_net.c +++ b/libhw_cr/host_net.c @@ -80,46 +80,47 @@ static void hostnet_init(void) { } while (r == EAGAIN); \ } while (0) -static inline bool RUN_PTHREAD(void *(*fn)(void *), void *args) { +static inline host_errno_t RUN_PTHREAD(void *(*fn)(void *), void *args) { pthread_t thread; + host_errno_t r; bool saved = cr_save_and_disable_interrupts(); - if (pthread_create(&thread, NULL, fn, args)) - return true; + r = pthread_create(&thread, NULL, fn, args); + if (r) { + cr_restore_interrupts(saved); + return r; + } cr_pause_and_yield(); cr_restore_interrupts(saved); - if (pthread_join(thread, NULL)) - return true; - return false; + return pthread_join(thread, NULL); } enum hostnet_timeout_op { - OP_NONE, + OP_CLOSE, 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: +static inline error hostnet_error(host_errno_t errnum, enum hostnet_timeout_op op) { + assert(errnum > 0); + switch (errnum) { + case EHOSTUNREACH: + return error_new(E_NET_EARP_TIMEOUT); + case ETIMEDOUT: switch (op) { - case OP_NONE: + case OP_CLOSE: assert_notreached("impossible ETIMEDOUT"); case OP_SEND: - return -NET_EACK_TIMEOUT; + return error_new(E_NET_EACK_TIMEOUT); case OP_RECV: - return -NET_ERECV_TIMEOUT; + return error_new(E_NET_ERECV_TIMEOUT); } assert_notreached("invalid timeout op"); - case -EBADF: - return -NET_ECLOSED; - case -EMSGSIZE: - return -NET_EMSGSIZE; + case EBADF: + return error_new(E_NET_ECLOSED); + case EMSGSIZE: + return error_new(E_POSIX_EMSGSIZE); default: - return -NET_EOTHER; + return errno2lm(errnum); } } @@ -160,44 +161,48 @@ struct hostnet_pthread_accept_args { int listenerfd; int *ret_connfd; + host_errno_t *ret_errno; }; static void *hostnet_pthread_accept(void *_args) { struct hostnet_pthread_accept_args *args = _args; *(args->ret_connfd) = accept(args->listenerfd, NULL, NULL); - if (*(args->ret_connfd) < 0) - *(args->ret_connfd) = -errno; + *(args->ret_errno) = errno; WAKE_COROUTINE(args); return NULL; } -static lo_interface net_stream_conn hostnet_tcplist_accept(struct hostnet_tcp_listener *listener) { +static net_stream_conn_or_error hostnet_tcplist_accept(struct hostnet_tcp_listener *listener) { assert(listener); int ret_connfd; + host_errno_t ret_errno; struct hostnet_pthread_accept_args args = { .cr_thread = pthread_self(), .cr_coroutine = cr_getcid(), .listenerfd = listener->fd, .ret_connfd = &ret_connfd, + .ret_errno = &ret_errno, }; - if (RUN_PTHREAD(hostnet_pthread_accept, &args)) - return LO_NULL(net_stream_conn); - + host_errno_t thread_errno = RUN_PTHREAD(hostnet_pthread_accept, &args); + if (thread_errno) + return ERROR_NEW_ERR(net_stream_conn, errno2lm(thread_errno)); if (ret_connfd < 0) - return LO_NULL(net_stream_conn); + return ERROR_NEW_ERR(net_stream_conn, hostnet_error(ret_errno, OP_RECV)); listener->active_conn.fd = ret_connfd; listener->active_conn.read_deadline_ns = 0; - return LO_BOX(net_stream_conn, &listener->active_conn); + return ERROR_NEW_VAL(net_stream_conn, LO_BOX(net_stream_conn, &listener->active_conn)); } /* TCP listener close() *******************************************************/ -static int hostnet_tcplist_close(struct hostnet_tcp_listener *listener) { +static error hostnet_tcplist_close(struct hostnet_tcp_listener *listener) { assert(listener); - return hostnet_map_negerrno(shutdown(listener->fd, SHUT_RDWR) ? -errno : 0, OP_NONE); + if (shutdown(listener->fd, SHUT_RDWR)) + return hostnet_error(errno, OP_CLOSE); + return ERROR_NULL; } /* TCP read() *****************************************************************/ @@ -217,29 +222,36 @@ struct hostnet_pthread_readv_args { const struct iovec *iov; int iovcnt; - ssize_t *ret; + size_t *ret_size; + host_errno_t *ret_errno; }; static void *hostnet_pthread_readv(void *_args) { struct hostnet_pthread_readv_args *args = _args; - *(args->ret) = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO, - &args->timeout, sizeof(args->timeout)); - if (*(args->ret) < 0) + int r_i = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO, + &args->timeout, sizeof(args->timeout)); + if (r_i) { + *args->ret_size = 0; + *args->ret_errno = errno; goto end; + } - *(args->ret) = readv(args->connfd, args->iov, args->iovcnt); - if (*(args->ret) < 0) + ssize_t r_ss = readv(args->connfd, args->iov, args->iovcnt); + if (r_ss < 0) { + *args->ret_size = 0; + *args->ret_errno = errno; goto end; + } + *args->ret_size = r_ss; + *args->ret_errno = 0; end: - if (*(args->ret) < 0) - *(args->ret) = hostnet_map_negerrno(-errno, OP_SEND); WAKE_COROUTINE(args); return NULL; } -static ssize_t hostnet_tcp_readv(struct _hostnet_tcp_conn *conn, const struct iovec *iov, int iovcnt) { +static size_t_or_error hostnet_tcp_readv(struct _hostnet_tcp_conn *conn, const struct iovec *iov, int iovcnt) { assert(conn); assert(iov); assert(iovcnt > 0); @@ -248,7 +260,8 @@ static ssize_t hostnet_tcp_readv(struct _hostnet_tcp_conn *conn, const struct io count += iov[i].iov_len; assert(count); - ssize_t ret; + size_t ret_size; + host_errno_t ret_errno; struct hostnet_pthread_readv_args args = { .cr_thread = pthread_self(), .cr_coroutine = cr_getcid(), @@ -257,20 +270,26 @@ static ssize_t hostnet_tcp_readv(struct _hostnet_tcp_conn *conn, const struct io .iov = iov, .iovcnt = iovcnt, - .ret = &ret, + .ret_size = &ret_size, + .ret_errno = &ret_errno, }; if (conn->read_deadline_ns) { uint64_t now_ns = LO_CALL(bootclock, get_time_ns); if (conn->read_deadline_ns < now_ns) - return -NET_ERECV_TIMEOUT; + return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT)); args.timeout = ns_to_host_us_time(conn->read_deadline_ns-now_ns); } else { args.timeout = (host_us_time_t){}; } - if (RUN_PTHREAD(hostnet_pthread_readv, &args)) - return -NET_ETHREAD; - return ret; + host_errno_t thread_errno = RUN_PTHREAD(hostnet_pthread_readv, &args); + if (thread_errno) + return ERROR_NEW_ERR(size_t, errno2lm(thread_errno)); + if (ret_errno) + return ERROR_NEW_ERR(size_t, hostnet_error(ret_errno, OP_RECV)); + if (!ret_size) + return ERROR_NEW_ERR(size_t, error_new(E_EOF)); + return ERROR_NEW_VAL(size_t, ret_size); } /* TCP write() ****************************************************************/ @@ -283,7 +302,8 @@ struct hostnet_pthread_writev_args { const struct iovec *iov; int iovcnt; - ssize_t *ret; + size_t *ret_size; + host_errno_t *ret_errno; }; static void *hostnet_pthread_writev(void *_args) { @@ -301,7 +321,7 @@ static void *hostnet_pthread_writev(void *_args) { while (done < count) { ssize_t r = writev(args->connfd, iov, iovcnt); if (r < 0) { - hostnet_map_negerrno(-errno, OP_RECV); + *args->ret_errno = errno; break; } done += r; @@ -316,12 +336,13 @@ static void *hostnet_pthread_writev(void *_args) { } } if (done == count) - *(args->ret) = done; + *args->ret_errno = 0; + *args->ret_size = done; WAKE_COROUTINE(args); return NULL; } -static ssize_t hostnet_tcp_writev(struct _hostnet_tcp_conn *conn, const struct iovec *iov, int iovcnt) { +static size_t_and_error hostnet_tcp_writev(struct _hostnet_tcp_conn *conn, const struct iovec *iov, int iovcnt) { assert(conn); assert(iov); assert(iovcnt > 0); @@ -330,7 +351,8 @@ static ssize_t hostnet_tcp_writev(struct _hostnet_tcp_conn *conn, const struct i count += iov[i].iov_len; assert(count); - ssize_t ret; + size_t ret_size; + host_errno_t ret_errno; struct hostnet_pthread_writev_args args = { .cr_thread = pthread_self(), .cr_coroutine = cr_getcid(), @@ -339,26 +361,34 @@ static ssize_t hostnet_tcp_writev(struct _hostnet_tcp_conn *conn, const struct i .iov = iov, .iovcnt = iovcnt, - .ret = &ret, + .ret_size = &ret_size, + .ret_errno = &ret_errno, }; - if (RUN_PTHREAD(hostnet_pthread_writev, &args)) - return -NET_ETHREAD; - return ret; + int thread_errno = RUN_PTHREAD(hostnet_pthread_writev, &args); + if (thread_errno) + return ERROR_AND(size_t, 0, errno2lm(thread_errno)); + return ERROR_AND(size_t, ret_size, ret_errno ? hostnet_error(ret_errno, OP_SEND) : ERROR_NULL); } /* TCP close() ****************************************************************/ -static int hostnet_tcp_close(struct _hostnet_tcp_conn *conn) { +static error hostnet_tcp_close(struct _hostnet_tcp_conn *conn) { assert(conn); - return hostnet_map_negerrno(shutdown(conn->fd, SHUT_RDWR) ? -errno : 0, OP_NONE); + if (shutdown(conn->fd, SHUT_RDWR)) + return hostnet_error(errno, OP_CLOSE); + return ERROR_NULL; } -static int hostnet_tcp_close_read(struct _hostnet_tcp_conn *conn) { +static error hostnet_tcp_close_read(struct _hostnet_tcp_conn *conn) { assert(conn); - return hostnet_map_negerrno(shutdown(conn->fd, SHUT_RD) ? -errno : 0, OP_NONE); + if (shutdown(conn->fd, SHUT_RD)) + return hostnet_error(errno, OP_CLOSE); + return ERROR_NULL; } -static int hostnet_tcp_close_write(struct _hostnet_tcp_conn *conn) { +static error hostnet_tcp_close_write(struct _hostnet_tcp_conn *conn) { assert(conn); - return hostnet_map_negerrno(shutdown(conn->fd, SHUT_WR) ? -errno : 0, OP_NONE); + if (shutdown(conn->fd, SHUT_WR)) + return hostnet_error(errno, OP_CLOSE); + return ERROR_NULL; } /* UDP init() *****************************************************************/ @@ -399,7 +429,8 @@ struct hostnet_pthread_sendto_args { struct net_ip4_addr node; uint16_t port; - ssize_t *ret; + size_t *ret_size; + host_errno_t *ret_errno; }; static void *hostnet_pthread_sendto(void *_args) { @@ -417,18 +448,24 @@ static void *hostnet_pthread_sendto(void *_args) { (((uint32_t)args->node.octets[1])<< 8) | (((uint32_t)args->node.octets[0])<< 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) = hostnet_map_negerrno(-errno, OP_SEND); + ssize_t r = sendto(args->connfd, args->buf, args->count, 0, &addr.gen, sizeof(addr)); + if (r < 0) { + *args->ret_size = 0; + *args->ret_errno = errno; + } else { + *args->ret_size = r; + *args->ret_errno = 0; + } WAKE_COROUTINE(args); return NULL; } -static ssize_t hostnet_udp_sendto(struct hostnet_udp_conn *conn, void *buf, size_t count, - struct net_ip4_addr node, uint16_t port) { +static error hostnet_udp_sendto(struct hostnet_udp_conn *conn, void *buf, size_t count, + struct net_ip4_addr node, uint16_t port) { assert(conn); - ssize_t ret; + size_t ret_size; + host_errno_t ret_errno; struct hostnet_pthread_sendto_args args = { .cr_thread = pthread_self(), .cr_coroutine = cr_getcid(), @@ -439,11 +476,15 @@ static ssize_t hostnet_udp_sendto(struct hostnet_udp_conn *conn, void *buf, size .node = node, .port = port, - .ret = &ret, + .ret_size = &ret_size, + .ret_errno = &ret_errno, }; - if (RUN_PTHREAD(hostnet_pthread_sendto, &args)) - return -NET_ETHREAD; - return ret; + int thread_errno = RUN_PTHREAD(hostnet_pthread_sendto, &args); + if (thread_errno) + return errno2lm(thread_errno); + if (ret_errno) + return hostnet_error(ret_errno, OP_SEND); + return ERROR_NULL; } /* UDP recvfrom() *************************************************************/ @@ -464,7 +505,8 @@ struct hostnet_pthread_recvfrom_args { void *buf; size_t count; - ssize_t *ret_size; + size_t *ret_size; + host_errno_t *ret_errno; struct net_ip4_addr *ret_node; uint16_t *ret_port; }; @@ -479,15 +521,23 @@ static void *hostnet_pthread_recvfrom(void *_args) { } addr = {}; socklen_t addr_size = sizeof(addr); - *(args->ret_size) = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO, - &args->timeout, sizeof(args->timeout)); - if (*(args->ret_size) < 0) + int r_i = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO, + &args->timeout, sizeof(args->timeout)); + if (r_i) { + *args->ret_size = 0; + *args->ret_errno = errno; goto end; + } - *(args->ret_size) = recvfrom(args->connfd, args->buf, args->count, - MSG_TRUNC, &addr.gen, &addr_size); - if (*(args->ret_size) < 0) + ssize_t r_ss = recvfrom(args->connfd, args->buf, args->count, + MSG_TRUNC, &addr.gen, &addr_size); + if (r_ss < 0) { + *args->ret_size = 0; + *args->ret_errno = errno; goto end; + } + *args->ret_size = r_ss; + *args->ret_errno = 0; assert(addr.in.sin_family == AF_INET); if (args->ret_node) { @@ -501,17 +551,16 @@ static void *hostnet_pthread_recvfrom(void *_args) { } end: - if (*(args->ret_size) < 0) - *(args->ret_size) = hostnet_map_negerrno(-errno, OP_RECV); WAKE_COROUTINE(args); return NULL; } -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) { +static size_t_or_error hostnet_udp_recvfrom(struct hostnet_udp_conn *conn, void *buf, size_t count, + struct net_ip4_addr *ret_node, uint16_t *ret_port) { assert(conn); - ssize_t ret; + size_t ret_size; + host_errno_t ret_errno; struct hostnet_pthread_recvfrom_args args = { .cr_thread = pthread_self(), .cr_coroutine = cr_getcid(), @@ -520,28 +569,34 @@ static ssize_t hostnet_udp_recvfrom(struct hostnet_udp_conn *conn, void *buf, si .buf = buf, .count = count, - .ret_size = &ret, + .ret_size = &ret_size, + .ret_errno = &ret_errno, .ret_node = ret_node, .ret_port = ret_port, }; if (conn->read_deadline_ns) { uint64_t now_ns = LO_CALL(bootclock, get_time_ns); if (conn->read_deadline_ns < now_ns) - return -NET_ERECV_TIMEOUT; + return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT)); args.timeout = ns_to_host_us_time(conn->read_deadline_ns-now_ns); } else { args.timeout = (host_us_time_t){}; } - if (RUN_PTHREAD(hostnet_pthread_recvfrom, &args)) - return -NET_ETHREAD; - return ret; + host_errno_t thread_errno = RUN_PTHREAD(hostnet_pthread_recvfrom, &args); + if (thread_errno) + return ERROR_NEW_ERR(size_t, errno2lm(thread_errno)); + if (ret_errno) + return ERROR_NEW_ERR(size_t, hostnet_error(ret_errno, OP_RECV)); + return ERROR_NEW_VAL(size_t, ret_size); } /* UDP close() ****************************************************************/ -static int hostnet_udp_close(struct hostnet_udp_conn *conn) { +static error hostnet_udp_close(struct hostnet_udp_conn *conn) { assert(conn); - return hostnet_map_negerrno(close(conn->fd) ? -errno : 0, OP_NONE); + if (close(conn->fd)) + return hostnet_error(errno, OP_CLOSE); + return ERROR_NULL; } diff --git a/libhw_cr/host_util.c b/libhw_cr/host_util.c index d0f01d7..2d45490 100644 --- a/libhw_cr/host_util.c +++ b/libhw_cr/host_util.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +#include <errno.h> /* for E* */ #include <signal.h> /* for SIGRTMIN, SIGRTMAX */ #define error __error @@ -51,3 +52,94 @@ uint64_t ns_from_host_ns_time(host_ns_time_t host_time) { return (((uint64_t)host_time.tv_sec) * NS_PER_S) + ((uint64_t)host_time.tv_nsec); } + +_errnum errno_host2lm(host_errno_t host) { + switch (host) { + case E2BIG: return E_POSIX_E2BIG; + case EACCES: return E_POSIX_EACCES; + case EADDRINUSE: return E_POSIX_EADDRINUSE; + case EADDRNOTAVAIL: return E_POSIX_EADDRNOTAVAIL; + case EAFNOSUPPORT: return E_POSIX_EAFNOSUPPORT; + case EAGAIN: return E_POSIX_EAGAIN; + case EALREADY: return E_POSIX_EALREADY; + case EBADF: return E_POSIX_EBADF; + case EBADMSG: return E_POSIX_EBADMSG; + case EBUSY: return E_POSIX_EBUSY; + case ECANCELED: return E_POSIX_ECANCELED; + case ECHILD: return E_POSIX_ECHILD; + case ECONNABORTED: return E_POSIX_ECONNABORTED; + case ECONNREFUSED: return E_POSIX_ECONNREFUSED; + case ECONNRESET: return E_POSIX_ECONNRESET; + case EDEADLK: return E_POSIX_EDEADLK; + case EDESTADDRREQ: return E_POSIX_EDESTADDRREQ; + case EDOM: return E_POSIX_EDOM; + case EDQUOT: return E_POSIX_EDQUOT; + case EEXIST: return E_POSIX_EEXIST; + case EFAULT: return E_POSIX_EFAULT; + case EFBIG: return E_POSIX_EFBIG; + case EHOSTUNREACH: return E_POSIX_EHOSTUNREACH; + case EIDRM: return E_POSIX_EIDRM; + case EILSEQ: return E_POSIX_EILSEQ; + case EINPROGRESS: return E_POSIX_EINPROGRESS; + case EINTR: return E_POSIX_EINTR; + case EINVAL: return E_POSIX_EINVAL; + case EIO: return E_POSIX_EIO; + case EISCONN: return E_POSIX_EISCONN; + case EISDIR: return E_POSIX_EISDIR; + case ELOOP: return E_POSIX_ELOOP; + case EMFILE: return E_POSIX_EMFILE; + case EMLINK: return E_POSIX_EMLINK; + case EMSGSIZE: return E_POSIX_EMSGSIZE; + case EMULTIHOP: return E_POSIX_EMULTIHOP; + case ENAMETOOLONG: return E_POSIX_ENAMETOOLONG; + case ENETDOWN: return E_POSIX_ENETDOWN; + case ENETRESET: return E_POSIX_ENETRESET; + case ENETUNREACH: return E_POSIX_ENETUNREACH; + case ENFILE: return E_POSIX_ENFILE; + case ENOBUFS: return E_POSIX_ENOBUFS; + case ENODEV: return E_POSIX_ENODEV; + case ENOENT: return E_POSIX_ENOENT; + case ENOEXEC: return E_POSIX_ENOEXEC; + case ENOLCK: return E_POSIX_ENOLCK; + case ENOLINK: return E_POSIX_ENOLINK; + case ENOMEM: return E_POSIX_ENOMEM; + case ENOMSG: return E_POSIX_ENOMSG; + case ENOPROTOOPT: return E_POSIX_ENOPROTOOPT; + case ENOSPC: return E_POSIX_ENOSPC; + case ENOSYS: return E_POSIX_ENOSYS; + case ENOTCONN: return E_POSIX_ENOTCONN; + case ENOTDIR: return E_POSIX_ENOTDIR; + case ENOTEMPTY: return E_POSIX_ENOTEMPTY; + case ENOTRECOVERABLE: return E_POSIX_ENOTRECOVERABLE; + case ENOTSOCK: return E_POSIX_ENOTSOCK; + case ENOTSUP: return E_POSIX_ENOTSUP; + case ENOTTY: return E_POSIX_ENOTTY; + case ENXIO: return E_POSIX_ENXIO; + case EOVERFLOW: return E_POSIX_EOVERFLOW; + case EOWNERDEAD: return E_POSIX_EOWNERDEAD; + case EPERM: return E_POSIX_EPERM; + case EPIPE: return E_POSIX_EPIPE; + case EPROTO: return E_POSIX_EPROTO; + case EPROTONOSUPPORT: return E_POSIX_EPROTONOSUPPORT; + case EPROTOTYPE: return E_POSIX_EPROTOTYPE; + case ERANGE: return E_POSIX_ERANGE; + case EROFS: return E_POSIX_EROFS; + case ESOCKTNOSUPPORT: return E_POSIX_ESOCKTNOSUPPORT; + case ESPIPE: return E_POSIX_ESPIPE; + case ESRCH: return E_POSIX_ESRCH; + case ESTALE: return E_POSIX_ESTALE; + case ETIMEDOUT: return E_POSIX_ETIMEDOUT; + case ETXTBSY: return E_POSIX_ETXTBSY; + case EXDEV: return E_POSIX_EXDEV; + default: + switch (host) { + case EOPNOTSUPP: return E_POSIX_EOPNOTSUPP; + case EWOULDBLOCK: return E_POSIX_EWOULDBLOCK; + default: return E_EUNKNOWN; + } + } +} + +error errno2lm(host_errno_t host) { + return error_new(errno_host2lm(host)); +} diff --git a/libhw_cr/host_util.h b/libhw_cr/host_util.h index 4adb94e..7e559ef 100644 --- a/libhw_cr/host_util.h +++ b/libhw_cr/host_util.h @@ -11,6 +11,8 @@ #include <sys/time.h> /* for struct timeval */ #include <time.h> /* for struct timespec */ +#include <libmisc/error.h> /* for _errnum, error */ + int host_sigrt_alloc(void); typedef struct timeval host_us_time_t; @@ -21,4 +23,8 @@ host_ns_time_t ns_to_host_ns_time(uint64_t time_ns); uint64_t ns_from_host_us_time(host_us_time_t host_time); uint64_t ns_from_host_ns_time(host_ns_time_t host_time); +#define host_errno_t int +_errnum errno_host2lm(host_errno_t host); +error errno2lm(host_errno_t host); + #endif /* _LIBHW_CR_HOST_UTIL_H_ */ diff --git a/libhw_cr/rp2040_hwspi.c b/libhw_cr/rp2040_hwspi.c index a7840e8..d717a79 100644 --- a/libhw_cr/rp2040_hwspi.c +++ b/libhw_cr/rp2040_hwspi.c @@ -136,7 +136,7 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self, dmairq_set_and_enable_exclusive_handler(DMAIRQ_0, self->dma_rx_data, rp2040_hwspi_intrhandler, self); } -static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct duplex_iovec *iov, int iovcnt) { +static size_t_and_error rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct duplex_iovec *iov, int iovcnt) { assert(self); assert(self->inst); assert(iov); @@ -268,4 +268,5 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl cr_restore_interrupts(saved); cr_sema_wait(&self->sema); self->dead_until_ns = LO_CALL(bootclock, get_time_ns) + self->min_delay_ns; + return ERROR_AND(size_t, count, ERROR_NULL); } diff --git a/libhw_cr/w5500.c b/libhw_cr/w5500.c index 58715c9..594b391 100644 --- a/libhw_cr/w5500.c +++ b/libhw_cr/w5500.c @@ -462,8 +462,8 @@ static lo_interface net_stream_listener w5500_if_tcp_listen(struct w5500 *chip, return LO_BOX(net_stream_listener, sock); } -static lo_interface net_stream_conn w5500_if_tcp_dial(struct w5500 *chip, - struct net_ip4_addr node, uint16_t port) { +static net_stream_conn_or_error 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)); @@ -472,7 +472,7 @@ static lo_interface net_stream_conn w5500_if_tcp_dial(struct w5500 *chip, struct _w5500_socket *socket = w5500_alloc_socket(chip); if (!socket) { log_debugln("tcp_dial() => no sock"); - return LO_NULL(net_stream_conn); + return ERROR_NEW_ERR(net_stream_conn, error_new(E_POSIX_ENOTSOCK)); } uint8_t socknum = socket->socknum; log_debugln("tcp_dial() => sock[", socknum, "]"); @@ -509,7 +509,7 @@ static lo_interface net_stream_conn w5500_if_tcp_dial(struct w5500 *chip, cr_yield(); break; case STATE_TCP_ESTABLISHED: - return LO_BOX(net_stream_conn, socket); + return ERROR_NEW_VAL(net_stream_conn, LO_BOX(net_stream_conn, socket)); default: goto restart; } @@ -559,20 +559,20 @@ static bool w5500_if_arp_ping(struct w5500 *chip, struct net_ip4_addr addr) { sock = &chip->sockets[i]; } assert(sock); - ssize_t v = w5500_udp_sendto(sock, "BOGUS_PACKET_TO_TRIGGER_AN_ARP", 17, addr, 5000); - log_debugln("arp_ping => ", v); - return v != -NET_EARP_TIMEOUT; + error err = w5500_udp_sendto(sock, "BOGUS_PACKET_TO_TRIGGER_AN_ARP", 17, addr, 5000); + log_debugln("arp_ping => ", (error, err)); + return err.num != E_NET_EARP_TIMEOUT; } /* tcp_listener methods *******************************************************/ -static lo_interface net_stream_conn w5500_tcplist_accept(struct _w5500_socket *socket) { +static net_stream_conn_or_error w5500_tcplist_accept(struct _w5500_socket *socket) { ASSERT_SELF(stream_listener, TCP); restart: if (!socket->list_open) { log_debugln("tcp_listener.accept() => already closed"); - return LO_NULL(net_stream_conn); + return ERROR_NEW_ERR(net_stream_conn, error_new(E_NET_ECLOSED)); } cr_mutex_lock(&chip->mu); @@ -601,25 +601,25 @@ static lo_interface net_stream_conn w5500_tcplist_accept(struct _w5500_socket *s [[fallthrough]]; case STATE_TCP_CLOSE_WAIT: socket->write_open = true; - return LO_BOX(net_stream_conn, socket); + return ERROR_NEW_VAL(net_stream_conn, LO_BOX(net_stream_conn, socket)); default: goto restart; } } } -static int w5500_tcplist_close(struct _w5500_socket *socket) { +static error w5500_tcplist_close(struct _w5500_socket *socket) { log_debugln("tcp_listener.close()"); ASSERT_SELF(stream_listener, TCP); socket->list_open = false; w5500_tcp_maybe_free(chip, socket); - return 0; + return ERROR_NULL; } /* tcp_conn methods ***********************************************************/ -static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec *iov, int iovcnt) { +static size_t_and_error w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec *iov, int iovcnt) { assert(iov); assert(iovcnt > 0); size_t count = 0; @@ -653,14 +653,14 @@ static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec while (done < count) { if (!socket->write_open) { log_debugln(" => soft closed"); - return -NET_ECLOSED; + return ERROR_AND(size_t, done, error_new(E_NET_ECLOSED)); } cr_mutex_lock(&chip->mu); uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state); if (state != STATE_TCP_ESTABLISHED && state != STATE_TCP_CLOSE_WAIT) { cr_mutex_unlock(&chip->mu); log_debugln(" => hard closed"); - return -NET_ECLOSED; + return ERROR_AND(size_t, done, error_new(E_NET_ECLOSED)); } uint16_t freesize = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, tx_free_size)); @@ -689,7 +689,7 @@ static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec break; case SOCKINTR_SEND_TIMEOUT: log_debugln(" => ACK timeout"); - return -NET_EACK_TIMEOUT; + return ERROR_AND(size_t, done, error_new(E_NET_EACK_TIMEOUT)); case SOCKINTR_SEND_OK|SOCKINTR_SEND_TIMEOUT: assert_notreached("send both OK and timed out?"); default: @@ -697,7 +697,7 @@ static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec } } log_debugln(" => send finished"); - return done; + return ERROR_AND(size_t, done, ERROR_NULL); } static void w5500_tcp_set_read_deadline(struct _w5500_socket *socket, uint64_t ns) { @@ -711,7 +711,7 @@ static void w5500_tcp_alarm_handler(void *_arg) { cr_sema_signal_from_intrhandler(&socket->read_sema); } -static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec *iov, int iovcnt) { +static size_t_or_error w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec *iov, int iovcnt) { assert(iov); assert(iovcnt > 0); size_t count = 0; @@ -734,12 +734,12 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec if (!socket->read_open) { LO_CALL(bootclock, del_trigger, &trigger); log_debugln(" => soft closed"); - return -NET_ECLOSED; + return ERROR_NEW_ERR(size_t, error_new(E_NET_ECLOSED)); } if (socket->read_deadline_ns && socket->read_deadline_ns <= LO_CALL(bootclock, get_time_ns)) { LO_CALL(bootclock, del_trigger, &trigger); log_debugln(" => recv timeout"); - return -NET_ERECV_TIMEOUT; + return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT)); } cr_mutex_lock(&chip->mu); uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state); @@ -752,7 +752,7 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec LO_CALL(bootclock, del_trigger, &trigger); cr_mutex_unlock(&chip->mu); log_debugln(" => hard closed"); - return -NET_ECLOSED; + return ERROR_NEW_ERR(size_t, error_new(E_NET_ECLOSED)); } avail = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, rx_size)); @@ -763,7 +763,7 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec LO_CALL(bootclock, del_trigger, &trigger); cr_mutex_unlock(&chip->mu); log_debugln(" => EOF"); - return 0; + return ERROR_NEW_ERR(size_t, error_new(E_EOF)); } cr_mutex_unlock(&chip->mu); @@ -782,10 +782,10 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec /* Return. */ LO_CALL(bootclock, del_trigger, &trigger); cr_mutex_unlock(&chip->mu); - return avail; + return ERROR_NEW_VAL(size_t, avail); } -static int w5500_tcp_close_inner(struct _w5500_socket *socket, bool rd, bool wr) { +static error w5500_tcp_close_inner(struct _w5500_socket *socket, bool rd, bool wr) { log_debugln("tcp_conn.close(rd=", rd, ", wr=", wr, ")"); ASSERT_SELF(stream_conn, TCP); @@ -813,17 +813,17 @@ static int w5500_tcp_close_inner(struct _w5500_socket *socket, bool rd, bool wr) } w5500_tcp_maybe_free(chip, socket); - return 0; + return ERROR_NULL; } -static int w5500_tcp_close(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, true, true); } -static int w5500_tcp_close_read(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, true, false); } -static int w5500_tcp_close_write(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, false, true); } +static error w5500_tcp_close(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, true, true); } +static error w5500_tcp_close_read(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, true, false); } +static error w5500_tcp_close_write(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, false, true); } /* udp_conn methods ***********************************************************/ -static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t count, - struct net_ip4_addr node, uint16_t port) { +static error w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t count, + struct net_ip4_addr node, uint16_t port) { log_debugln("udp_conn.sendto()"); ASSERT_SELF(packet_conn, UDP); assert(buf); @@ -832,7 +832,7 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t uint16_t bufsize = ((uint16_t)w5500ll_read_sock_reg(chip->spidev, socknum, tx_buf_size))*1024; if (count > bufsize) { log_debugln(" => msg too large"); - return -NET_EMSGSIZE; + return error_new(E_POSIX_EMSGSIZE); } for (;;) { @@ -841,7 +841,7 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t if (state != STATE_UDP) { cr_mutex_unlock(&chip->mu); log_debugln(" => closed"); - return -NET_ECLOSED; + return error_new(E_NET_ECLOSED); } uint16_t freesize = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, tx_free_size)); @@ -871,10 +871,10 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t switch (cr_chan_recv(&socket->write_ch)) { case SOCKINTR_SEND_OK: log_debugln(" => sent"); - return count; + return ERROR_NULL; case SOCKINTR_SEND_TIMEOUT: log_debugln(" => ARP timeout"); - return -NET_EARP_TIMEOUT; + return error_new(E_NET_EARP_TIMEOUT); case SOCKINTR_SEND_OK|SOCKINTR_SEND_TIMEOUT: assert_notreached("send both OK and timed out?"); default: @@ -893,8 +893,8 @@ static void w5500_udp_alarm_handler(void *_arg) { cr_sema_signal_from_intrhandler(&socket->read_sema); } -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) { +static size_t_or_error w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_t count, + struct net_ip4_addr *ret_node, uint16_t *ret_port) { log_debugln("udp_conn.recvfrom()"); ASSERT_SELF(packet_conn, UDP); assert(buf); @@ -913,14 +913,14 @@ static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_ if (socket->read_deadline_ns && socket->read_deadline_ns <= LO_CALL(bootclock, get_time_ns)) { LO_CALL(bootclock, del_trigger, &trigger); log_debugln(" => recv timeout"); - return -NET_ERECV_TIMEOUT; + return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT)); } cr_mutex_lock(&chip->mu); uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state); if (state != STATE_UDP) { LO_CALL(bootclock, del_trigger, &trigger); log_debugln(" => hard closed"); - return -NET_ECLOSED; + return ERROR_NEW_ERR(size_t, error_new(E_NET_ECLOSED)); } avail = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, rx_size)); @@ -964,14 +964,14 @@ static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_ /* Return. */ LO_CALL(bootclock, del_trigger, &trigger); cr_mutex_unlock(&chip->mu); - return len; + return ERROR_NEW_VAL(size_t, len); } -static int w5500_udp_close(struct _w5500_socket *socket) { +static error w5500_udp_close(struct _w5500_socket *socket) { log_debugln("udp_conn.close()"); ASSERT_SELF(packet_conn, UDP); w5500_socket_close(socket); w5500_free_socket(chip, socket); - return 0; + return ERROR_NULL; } diff --git a/libhw_generic/include/libhw/generic/io.h b/libhw_generic/include/libhw/generic/io.h index 8b3fb9c..ebbd6cb 100644 --- a/libhw_generic/include/libhw/generic/io.h +++ b/libhw_generic/include/libhw/generic/io.h @@ -9,8 +9,8 @@ #include <stddef.h> /* for size_t */ #include <stdint.h> /* for uintptr_t */ -#include <sys/types.h> /* for ssize_t */ +#include <libmisc/error.h> #include <libmisc/obj.h> /* structs ********************************************************************/ @@ -58,20 +58,19 @@ void io_slice_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, in /* basic interfaces ***********************************************************/ /** - * Return bytes-read on success, 0 on EOF, -errno on error; a short - * read is *not* an error. + * Return bytes-read on success. A short read is *not* an error + * (unlike writev). * * It is invalid to call readv when the sum length of iovecs is 0. */ #define io_reader_LO_IFACE \ - LO_FUNC(ssize_t, readv, const struct iovec *iov, int iovcnt) + LO_FUNC(size_t_or_error, readv, const struct iovec *iov, int iovcnt) LO_INTERFACE(io_reader); #define io_readv(r, iov, iovcnt) LO_CALL(r, readv, iov, iovcnt) #define io_read(r, buf, count) LO_CALL(r, readv, &((struct iovec){.iov_base = buf, .iov_len = count}), 1) /** - * Return `count` on success, -errno on error; a short write *is* an - * error. + * Return bytes-written. A short write *is* an error (unlike readv) * * Writes are *not* guaranteed to be atomic, so if you have concurrent * writers then you should arrange for a mutex to protect the writer. @@ -79,38 +78,35 @@ LO_INTERFACE(io_reader); * It is invalid to call writev when the sum length of iovecs is 0. */ #define io_writer_LO_IFACE \ - LO_FUNC(ssize_t, writev, const struct iovec *iov, int iovcnt) + LO_FUNC(size_t_and_error, writev, const struct iovec *iov, int iovcnt) LO_INTERFACE(io_writer); #define io_writev(w, iov, iovcnt) LO_CALL(w, writev, iov, iovcnt) #define io_write(w, buf, count) LO_CALL(w, writev, &((struct iovec){.iov_base = buf, .iov_len = count}), 1) -/** - * Return 0 on success, -errno on error. - */ #define io_closer_LO_IFACE \ - LO_FUNC(int, close) + LO_FUNC(error, close) LO_INTERFACE(io_closer); #define io_close(c) LO_CALL(c, close) -/** - * All methods return 0 on success, -errno on error. - */ #define io_bidi_closer_LO_IFACE \ LO_NEST(io_closer) \ - LO_FUNC(int, close_read) \ - LO_FUNC(int, close_write) + LO_FUNC(error, close_read) \ + LO_FUNC(error, close_write) LO_INTERFACE(io_bidi_closer); #define io_close_read(c) LO_CALL(c, close_read) #define io_close_write(c) LO_CALL(c, close_write) /** - * Return bytes-read and bytes-written on success, -errno on error; a - * short read/write *is* an error. + * A short read/write *is* an error (like writev and unlike readv). + * + * Reads/writes are *not* guaranteed to be atomic, so if you have + * concurrent readers/writers then you should arrange for a mutex to + * protect the duplex_readwriter. * * It is invalid to call readwritev when the sum length of iovecs is 0. */ #define io_duplex_readwriter_LO_IFACE \ - LO_FUNC(void, readwritev, const struct duplex_iovec *iov, int iovcnt) + LO_FUNC(size_t_and_error, readwritev, const struct duplex_iovec *iov, int iovcnt) LO_INTERFACE(io_duplex_readwriter); #define io_readwritev(rw, iov, iovcnt) \ diff --git a/libhw_generic/include/libhw/generic/net.h b/libhw_generic/include/libhw/generic/net.h index 55e4a6f..d1d4194 100644 --- a/libhw_generic/include/libhw/generic/net.h +++ b/libhw_generic/include/libhw/generic/net.h @@ -9,23 +9,10 @@ #include <stddef.h> /* for size_t */ #include <stdint.h> /* for uint{n}_t} */ -#include <sys/types.h> /* for ssize_t */ #include <libhw/generic/io.h> #include <libmisc/fmt.h> -/* Errnos *********************************************************************/ - -#define NET_EOTHER 1 -#define NET_EARP_TIMEOUT 2 -#define NET_EACK_TIMEOUT 3 -#define NET_ERECV_TIMEOUT 4 -#define NET_ETHREAD 5 -#define NET_ECLOSED 6 -#define NET_EMSGSIZE 7 - -const char *net_strerror(int net_errno); - /* Address types **************************************************************/ struct net_ip4_addr { @@ -44,22 +31,6 @@ void fmt_print_net_eth_addr(lo_interface fmt_dest, struct net_eth_addr); /* Streams (e.g. TCP) *********************************************************/ -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. \ - */ \ - LO_NEST(io_closer) -LO_INTERFACE(net_stream_listener); - #define net_stream_conn_LO_IFACE \ LO_NEST(io_readwriter) \ LO_NEST(io_bidi_closer) \ @@ -78,10 +49,27 @@ LO_INTERFACE(net_stream_listener); LO_FUNC(void, set_read_deadline, uint64_t ns_since_boot) LO_INTERFACE(net_stream_conn); +typedef lo_interface net_stream_conn net_stream_conn; +DECLARE_ERROR_OR(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(net_stream_conn_or_error, accept) \ + \ + /** \ + * The net_stream_conn returned from accept() may still be \ + * valid after the listener is closed. \ + */ \ + LO_NEST(io_closer) +LO_INTERFACE(net_stream_listener); + /* Packets (e.g. UDP) *********************************************************/ #define net_packet_conn_LO_IFACE \ - LO_FUNC(ssize_t, sendto, \ + LO_FUNC(error, sendto, \ void *buf, size_t len, \ struct net_ip4_addr node, uint16_t port) \ \ @@ -90,7 +78,7 @@ LO_INTERFACE(net_stream_conn); * than the given `len` (as if the Linux MSG_TRUNC flag were \ * given). \ */ \ - LO_FUNC(ssize_t, recvfrom, \ + LO_FUNC(size_t_or_error, recvfrom, \ void *buf, size_t len, \ struct net_ip4_addr *ret_node, uint16_t *ret_port) \ \ @@ -125,7 +113,7 @@ 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(net_stream_conn_or_error , 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) \ \ /** FIXME: arp_ping should probably have an explicit timeout or something. */ \ |