diff options
-rw-r--r-- | cmd/sbc_harness/config/config.h | 2 | ||||
-rw-r--r-- | cmd/sbc_harness/main.c | 12 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 58 | ||||
-rw-r--r-- | lib9p/srv.c | 162 | ||||
-rw-r--r-- | lib9p/tests/test_server/main.c | 14 |
5 files changed, 145 insertions, 103 deletions
diff --git a/cmd/sbc_harness/config/config.h b/cmd/sbc_harness/config/config.h index 5e7bc06..14c2f03 100644 --- a/cmd/sbc_harness/config/config.h +++ b/cmd/sbc_harness/config/config.h @@ -92,8 +92,8 @@ extern const size_t CONFIG_COROUTINE_STACK_SIZE_dhcp_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_init_cr; -extern const size_t CONFIG_COROUTINE_STACK_SIZE_lib9p_srv_write_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_read9p_cr; +extern const size_t CONFIG_COROUTINE_STACK_SIZE_write9p_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_usb_common_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_usb_keyboard_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_w5500_irq_cr; diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c index 7765ca8..20cf5b1 100644 --- a/cmd/sbc_harness/main.c +++ b/cmd/sbc_harness/main.c @@ -153,7 +153,15 @@ static COROUTINE read9p_cr(void *) { lo_interface net_iface iface = lo_box_w5500_if_as_net_iface(&globals.dev_w5500); lo_interface net_stream_listener listener = LO_CALL(iface, tcp_listen, LIB9P_DEFAULT_PORT_9FS); - lib9p_srv_read_cr(&globals.srv, listener); + lib9p_srv_accept_and_read_loop(&globals.srv, listener); + + cr_end(); +} + +static COROUTINE write9p_cr(void *) { + cr_begin(); + + lib9p_srv_worker_loop(&globals.srv); cr_end(); } @@ -221,7 +229,7 @@ COROUTINE init_cr(void *) { } for (int i = 0; i < CONFIG_9P_SRV_MAX_REQS*_CONFIG_9P_NUM_SOCKS; i++) { char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'}; - coroutine_add(name, lib9p_srv_write_cr, &globals.srv); + coroutine_add(name, write9p_cr, NULL); } cr_exit(); diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h index 85fc6bd..7f2711c 100644 --- a/lib9p/include/lib9p/srv.h +++ b/lib9p/include/lib9p/srv.h @@ -149,32 +149,56 @@ struct lib9p_srv { }; /** - * In an infinite loop, accept a connection and read messages from it until - * close; dispatching requests to a pool of lib9p_srv_write_cr() coroutines - * with the same `srv`. + * In a loop loop, accept a connection call lib9p_srv_read() on it. + * If LO_CALL(listener, accept) fails, then the function returns. * - * Will just close the connection if a T-message has a size[4] <7. + * When the last lib9p_srv_accept_and_read_loop() instance for a given + * `srv` returns, it will signal all lib9p_srv_worker_loop() calls to + * return. + * + * @param srv: The server configuration and state; has an associated + * pool of lib9p_srv_worker_loop() coroutines. * - * @param srv: The server configuration and state; has an associated pool of - * lib9p_srv_write_cr() coroutines. * @param listener: The listener object to accept connections from. + */ +void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stream_listener listener); + +/** + * You should probably not call this directly; you should probably use + * lib9p_srv_accept_and_read_loop(). + * + * Given an already-established stream connection (i.e. a TCP + * connection), service that connection; return once the connection is + * closed. Requests are dispatched to a pool of + * lib9p_srv_worker_loop() coroutines with the same `srv`. * - * @errno LINUX_EMSGSIZE T-message has size[4] bigger than max_msg_size - * @errno LINUX_EDOM Tversion specified an impossibly small max_msg_size + * Will just close the connection if a T-message has a size[4] <7. + * + * @param srv: The server configuration and state; has an associated + * pool of lib9p_srv_worker_loop() coroutines. + * + * @param conn: The listener object to accept connections from. + * + * Errors that this function itself may send to clients: + * + * @errno LINUX_EMSGSIZE T-message has size[4] bigger than max_msg_size + * @errno LINUX_EDOM Tversion specified an impossibly small max_msg_size * @errno LINUX_EOPNOTSUPP T-message has an R-message type, or an unrecognized T-message type - * @errno LINUX_EBADMSG T-message has wrong size[4] for its content, or has invalid UTF-8 - * @errno LINUX_ERANGE R-message does not fit into max_msg_size + * @errno LINUX_EBADMSG T-message has wrong size[4] for its content, or has invalid UTF-8 + * @errno LINUX_ERANGE R-message does not fit into max_msg_size */ -[[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, lo_interface net_stream_listener listener); +void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn conn); + + /** - * Service requests to the `struct lib9p_srv *srv` argument that have been - * read by lib9p_srv_read_cr(). + * In a loop, service requests to the `struct lib9p_srv *srv` argument + * that have been read by lib9p_srv_accept_and_read_loop() / + * lib9p_srv_read(). A "NULL" request causes the function to return. * - * @param struct lib9p_srv *srv: The server configuration and state; has an - * associated pool of lib9p_srv_read_cr() - * coroutines. + * @param srv: The server configuration and state; has an associated + * pool of lib9p_srv_accept_and_read_loop() coroutines. */ -COROUTINE lib9p_srv_write_cr(void *_srv); +void lib9p_srv_worker_loop(struct lib9p_srv *srv); #endif /* _LIB9P_SRV_H_ */ diff --git a/lib9p/srv.c b/lib9p/srv.c index ea8b932..0a561d3 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -243,110 +243,114 @@ static bool read_exactly(lo_interface 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, lo_interface net_stream_listener listener) { +void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stream_listener listener) { assert(srv); assert(srv->rootdir); assert(!LO_IS_NULL(listener)); srv->readers++; - uint32_t initial_rerror_overhead = lib9p_version_min_msg_size(LIB9P_VER_unknown); - for (;;) { - struct _srv_conn conn = { - .parent_srv = srv, - .fd = LO_CALL(listener, accept), - .reader = cr_getcid(), - }; - if (LO_IS_NULL(conn.fd)) { + lo_interface net_stream_conn conn = LO_CALL(listener, accept); + if (LO_IS_NULL(conn)) { nonrespond_errorf("accept: error"); srv->readers--; if (srv->readers == 0) while (srv->writers > 0) _lib9p_srv_reqch_send_req(&srv->_reqch, NULL); - cr_exit(); + return; } + lib9p_srv_read(srv, conn); + } +} - struct _srv_sess sess = { - .parent_conn = &conn, - .version = LIB9P_VER_unknown, - .max_msg_size = CONFIG_9P_SRV_MAX_MSG_SIZE, - .rerror_overhead = initial_rerror_overhead, - .initialized = false, - }; - for (;;) { - nextmsg: - /* Read the message. */ - size_t done = 0; - uint8_t buf[7]; - if (read_exactly(conn.fd, buf, 4, &done)) - goto close; - size_t goal = uint32le_decode(buf); - if (goal < 7) { - nonrespond_errorf("T-message is impossibly small"); - goto close; - } - if (read_exactly(conn.fd, buf, 7, &done)) - goto close; - struct _lib9p_srv_req req = { - .parent_sess = &sess, - .tag = uint16le_decode(&buf[5]), - .net_bytes = buf, - .ctx = { - .basectx = { - .version = sess.version, - .max_msg_size = sess.max_msg_size, - }, - }, - }; - if (goal > sess.max_msg_size) { - lib9p_errorf(&req.ctx.basectx, - LINUX_EMSGSIZE, "T-message larger than %s limit (%zu > %"PRIu32")", - sess.initialized ? "negotiated" : "server", - goal, - sess.max_msg_size); - respond_error(&req); - goto nextmsg; - } - req.net_bytes = malloc(goal); - assert(req.net_bytes); - memcpy(req.net_bytes, buf, done); - if (read_exactly(conn.fd, req.net_bytes, goal, &done)) { - free(req.net_bytes); - goto close; - } +void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { + assert(srv); + assert(srv->rootdir); + assert(!LO_IS_NULL(_conn)); - /* Handle the message... */ - if (req.net_bytes[4] == LIB9P_TYP_Tversion) - /* ...in this coroutine for Tversion, */ - handle_message(&req); - else - /* ...but usually in another coroutine. */ - _lib9p_srv_reqch_send_req(&srv->_reqch, &req); + struct _srv_conn conn = { + .parent_srv = srv, + .fd = _conn, + .reader = cr_getcid(), + }; + struct _srv_sess sess = { + .parent_conn = &conn, + .version = LIB9P_VER_unknown, + .max_msg_size = CONFIG_9P_SRV_MAX_MSG_SIZE, + .rerror_overhead = lib9p_version_min_msg_size(LIB9P_VER_unknown), + .initialized = false, + }; + for (;;) { + nextmsg: + /* Read the message. */ + size_t done = 0; + uint8_t buf[7]; + if (read_exactly(conn.fd, buf, 4, &done)) + goto close; + size_t goal = uint32le_decode(buf); + if (goal < 7) { + nonrespond_errorf("T-message is impossibly small"); + goto close; } - close: - if (sess.reqs.len == 0) - io_close(conn.fd); - else { - io_close_read(conn.fd); - sess.closing = true; - cr_pause_and_yield(); - assert(sess.reqs.len == 0); - io_close_write(conn.fd); + if (read_exactly(conn.fd, buf, 7, &done)) + goto close; + struct _lib9p_srv_req req = { + .parent_sess = &sess, + .tag = uint16le_decode(&buf[5]), + .net_bytes = buf, + .ctx = { + .basectx = { + .version = sess.version, + .max_msg_size = sess.max_msg_size, + }, + }, + }; + if (goal > sess.max_msg_size) { + lib9p_errorf(&req.ctx.basectx, + LINUX_EMSGSIZE, "T-message larger than %s limit (%zu > %"PRIu32")", + sess.initialized ? "negotiated" : "server", + goal, + sess.max_msg_size); + respond_error(&req); + goto nextmsg; + } + req.net_bytes = malloc(goal); + assert(req.net_bytes); + memcpy(req.net_bytes, buf, done); + if (read_exactly(conn.fd, req.net_bytes, goal, &done)) { + free(req.net_bytes); + goto close; } + + /* Handle the message... */ + if (req.net_bytes[4] == LIB9P_TYP_Tversion) + /* ...in this coroutine for Tversion, */ + handle_message(&req); + else + /* ...but usually in another coroutine. */ + _lib9p_srv_reqch_send_req(&srv->_reqch, &req); + } + close: + if (sess.reqs.len == 0) + io_close(conn.fd); + else { + io_close_read(conn.fd); + sess.closing = true; + cr_pause_and_yield(); + assert(sess.reqs.len == 0); + io_close_write(conn.fd); } } /* write coroutine ************************************************************/ -COROUTINE lib9p_srv_write_cr(void *_srv) { +void lib9p_srv_worker_loop(struct lib9p_srv *srv) { struct _lib9p_srv_req req; _lib9p_srv_reqch_req_t rpc_handle; - struct lib9p_srv *srv = _srv; assert(srv); assert(srv->rootdir); - cr_begin(); srv->writers++; @@ -356,7 +360,7 @@ COROUTINE lib9p_srv_write_cr(void *_srv) { if (!rpc_handle.req) { srv->writers--; _lib9p_srv_reqch_send_resp(rpc_handle, 0); - cr_exit(); + return; } /* Copy the request from the reader coroutine's * stack to our stack. */ @@ -377,8 +381,6 @@ COROUTINE lib9p_srv_write_cr(void *_srv) { if (req.parent_sess->closing && !req.parent_sess->reqs.len) cr_unpause(req.parent_sess->parent_conn->reader); } - - cr_end(); } #define _HANDLER_PROTO(typ) \ diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c index 2743629..b543892 100644 --- a/lib9p/tests/test_server/main.c +++ b/lib9p/tests/test_server/main.c @@ -90,7 +90,15 @@ static COROUTINE read_cr(void *_i) { hostnet_tcp_listener_init(&globals.listeners[i], globals.port); - lib9p_srv_read_cr(&globals.srv, lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i])); + lib9p_srv_accept_and_read_loop(&globals.srv, lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i])); + + cr_end(); +} + +static COROUTINE write_cr(void *) { + cr_begin(); + + lib9p_srv_worker_loop(&globals.srv); cr_end(); } @@ -107,8 +115,8 @@ static COROUTINE init_cr(void *) { } for (int i = 0; i < 2*CONFIG_SRV9P_NUM_CONNS; i++) { char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'}; - if (!coroutine_add(name, lib9p_srv_write_cr, &globals.srv)) - error(1, 0, "coroutine_add(lib9p_srv_write_cr, &globals.srv)"); + if (!coroutine_add(name, write_cr, NULL)) + error(1, 0, "coroutine_add(write_cr, NULL)"); } cr_exit(); |