diff options
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r-- | lib9p/srv.c | 162 |
1 files changed, 82 insertions, 80 deletions
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) \ |