diff options
Diffstat (limited to '9p/srv.c')
-rw-r--r-- | 9p/srv.c | 194 |
1 files changed, 0 insertions, 194 deletions
diff --git a/9p/srv.c b/9p/srv.c deleted file mode 100644 index 59326c9..0000000 --- a/9p/srv.c +++ /dev/null @@ -1,194 +0,0 @@ -#include <assert.h> - -#include "coroutine.h" -#include "netio.h" -#include "9p/9p.h" - -#include "9p/internal.h" - -struct p9_srvconn { - /* immutable */ - p9_srv *srv; - cid_t reader; - int fd; - /* mutable */ - uint32_t max_msg_size; - enum p9_version version; - unsigned int refcount; -}; - -struct p9_srvreq { - p9_srvconn *conn; - uint8_t *msg; -}; - -COROUTINE p9_srv_read_cr(void *_srv) { - uint8_t buf[CONFIG_9P_MAX_MSG_SIZE]; - - p9_srv *srv = _srv; - assert(srv); - cr_begin(); - - for (;;) { - struct p9_srvconn conn = { - .srv = srv, - .reader = cr_getcid(); - - .max_msg_size = CONFIG_9P_MAX_MSG_SIZE; - .version = P9_VER_UNINITIALIZED; - .refcount = 1, - }; - conn.fd = netio_accept(srv->sockfd); - if (conn.fd < 0) { - fprintf(stderr, "error: accept: %m", -conn.fd); - continue; - } - - for (;;) { - /* Read the message size. */ - size_t goal = 4, done = 0; - while (done < goal) { - ssize_t r = netio_read(conn.fd, &buf[done], sizeof(buf)-done); - if (r < 0) { - fprintf(stderr, "error: read: %m", -r); - goto close; - } else if (r == 0) { - if (done != 0) - fprintf(stderr, "error: read: unexpected EOF"); - goto close; - } - done += r; - } - goal = decode_u32le(buf); - if (goal < 7) { - /* We can't respond with an Rerror becuase we wouldn't know what tag to use! */ - fprintf(stderr, "error: T-message is impossibly small"); - goto close; - } - if (goal > conn.max_msg_size) { - struct p9_ctx ctx = { - .version = conn.version, - .max_msg_size = conn.max_msg_size, - }; - if (initialized) - p9_errorf(&ctx, LINUX_EMSGSIZE, "T-message larger than negotiated limit (%zu > %zu)", goal, conn.max_msg_size); - else - p9_errorf(&ctx, LINUX_EMSGSIZE, "T-message larger than server limit (%zu > %zu)", goal, conn.max_msg_size); - marshal_error(&ctx, buf); - netio_write(conn.fd, buf, decode_u32le(buf)); - continue; - } - /* Read the rest of the message. */ - while (done < goal) { - ssize_t r = netio_read(conn.fd, &buf[done], sizeof(buf)-done); - if (r < 0) { - fprintf(stderr, "error: read: %m", -r); - goto close; - } else if (r == 0) { - fprintf(stderr, "error: read: unexpected EOF"); - goto close; - } - done += r; - } - - /* Handle the message... */ - if (conn.version == P9_VER_UNINITIALIZED) { - /* ...synchronously if we haven't negotiated the protocol yet, ... */ - handle_message(&conn, buf); - } else { - /* ...asynchronously if we have. */ - cr_chan_send(&srv->reqch, buf); - cr_pause_and_yield(); - } - } - close: - netio_close(conn.fd, true, (--conn.refcount) == 0); - if (conn.refcount) { - cr_pause_and_yield(); - assert(conn.refcount == 0); - netio_close(conn.fd, false, true); - } - } - - cr_end(); -} - -COROUTINE p9_srv_write_cr(void *_srv) { - uint8_t net[CONFIG_9P_MAX_MSG_SIZE]; - - p9_srv *srv = _srv; - assert(srv); - cr_begin(); - - for (;;) { - struct p9_srvreq req; - cr_chan_recv(&srv->reqch, &req); - memcpy(net, req.msg, decode_u32le(req.msg)); - req.conn->refcount++; - cr_unpause(req.conn->reader); - - handle_message(&req.conn, net); - - if ((--req.conn->refcount) == 0) - cr_unpause(req.conn->reader); - } - - cr_end(); -} - -void handle_message(p9_srvconn *conn, uint8_t *net) { - uint8_t host[CONFIG_9P_MAX_MSG_SIZE]; - - struct p9_ctx ctx = { - .version = req.conn->version, - .max_msg_size = req.conn->max_msg_size, - }; - - size_t host_size = p9_unmarshal_size(&ctx, net); - if (host_size == (size_t)-1) - goto write; - if (host_size > sizeof(host)) { - p9_errorf(&ctx, LINUX_EMSGSIZE, "unmarshalled payload larger than server limit (%zu > %zu)", host_size, sizeof(host)); - goto write; - } - - uint16_t tag; - uint8_t typ = p9_unmarshal(&ctx, net, &tag, host); - if (typ == (uint8_t)-1) - goto write; - if (typ % 2 != 0) { - p9_errorf(&ctx, LINUX_EOPNOTSUPP, "expected a T-message but got an R-message"); - goto write; - } - - TODO; - - write: - if (ctx.err_num || ctx.err_msg[0]) - marshal_error(&ctx, net); - else - TODO; - netio_write(req.conn->fd, net, decode_u32le(net)); -} - -static inline uint16_t min_u16(uint16_t a, b) { - return (a < b) ? a : b; -} - -/* We have special code for marshaling Rerror because we don't ever - * want to produce an error because the err_msg is too long for the - * `ctx->max_msg_size`! */ -void marshal_error(struct p9_ctx *ctx, uint16_t tag, uint8_t *net) { - struct p9_msg_Rerror host = { - .ename = { - .len = strnlen(ctx->err_msg, CONFIG_9P_MAX_ERR_SIZE), - .utf8 = ctx->err_msg, - }, - }; - if (host.ename.len + ctx->Rerror_overhead > ctx->max_msg_size) - host.ename.len = ctx->max_msg_size - overhead; - p9_marshal(ctx, tag, host, net); -} - -ERANGE for reply too large -EPROTONOSUPPORT for version errors |