diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-10-04 19:38:42 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-10-04 19:38:42 -0600 |
commit | 4f7cf6b416ccede492ace64533ab35a9a289f463 (patch) | |
tree | db28d138f8b6d4c9bf71f2790881ea04f68b3ece | |
parent | 860a9e995b8e7076ce4e5c231e844184bef9b95e (diff) |
wip
-rw-r--r-- | lib9p/9p.c | 4 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 15 | ||||
-rw-r--r-- | lib9p/map.h | 3 | ||||
-rw-r--r-- | lib9p/srv.c | 189 |
4 files changed, 125 insertions, 86 deletions
@@ -52,8 +52,8 @@ ssize_t lib9p_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) { /* Body */ struct _vtable_msg vtable = _lib9p_vtables[ctx->version].msgs[typ]; if (!vtable.validate) - return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %s", - lib9p_msg_type_str(typ)); + return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type: %s (protocol_version=%s)", + lib9p_msg_type_str(typ), lib9p_version_str(ctx->version)); if (vtable.validate(&subctx)) return -1; assert(subctx.net_offset <= subctx.net_size); diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h index 0211260..d2ada62 100644 --- a/lib9p/include/lib9p/srv.h +++ b/lib9p/include/lib9p/srv.h @@ -10,8 +10,23 @@ struct lib9p_srv_reqctx { struct lib9p_ctx *base; uint32_t uid; char *uname; + + cr_chan_t(bool) _flushch; }; +static inline bool flush_requested(struct lib9p_srv_reqctx *ctx) { + assert(ctx); + return cr_chan_can_write(&ctx->_flushch); +} + +static inline int acknowledge_flush(struct lib9p_srv_reqctx *ctx) { + assert(ctx); + assert(cr_chan_can_send(&ctx->_flushch)); + lib9p_error(ctx->base, LINUX_ECANCELED, "request canceled by flush"); + cr_chan_send(&ctx->_flushch, true); + return -1; +} + /* vtables you must implement *************************************************/ struct lib9p_srv_file_vtable { diff --git a/lib9p/map.h b/lib9p/map.h index 9df9be7..ea9cdb6 100644 --- a/lib9p/map.h +++ b/lib9p/map.h @@ -27,6 +27,9 @@ #ifndef MAP_KEY #define MAP_KV(TNAME) CAT3(_,TNAME,_kv) #define MAP_METHOD(TNAME, MNAME) CAT3(TNAME,_,MNAME) +#define MAP_FOREACH(m, k, v) \ + for (size_t i = 0, typeof(m->items[0].key) k, typeof(&m->items[0].val) v; i < ARRAY_LEN(m->items); i++) \ + if ( ({ k = m->items[i].key; v = &m->items[i].val; m->items[i].set; }) ) #endif /* This implementation is just an array that we brute-force search diff --git a/lib9p/srv.c b/lib9p/srv.c index 534d70a..3d990aa 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -19,6 +19,12 @@ #define CAP CONFIG_9P_MAX_FIDS #include "map.h" +#define NAME reqmap +#define KEY_T uint32_t +#define VAL_T struct lib9p_reqctx +#define CAP CONFIG_9P_MAX_REQS +#include "map.h" + /* The hierarchy of concepts is: * * server -> connection -> session -> request @@ -44,7 +50,7 @@ struct lib9p_sess { uint32_t rerror_overhead; /* mutable */ bool initialized; - unsigned int refcount; + struct reqmap reqs; struct fidmap fids; }; @@ -123,6 +129,8 @@ static bool read_at_least(int fd, uint8_t *buf, size_t goal, size_t *done) { return false; } +static bool handle_Tmessage(struct lib9p_req *); + COROUTINE lib9p_srv_read_cr(void *_srv) { uint8_t buf[CONFIG_9P_MAX_MSG_SIZE]; @@ -219,8 +227,6 @@ static void handle_Tswrite(struct lib9p_req *ctx, struct lib9p_msg_Tswrite *req, COROUTINE lib9p_srv_write_cr(void *_srv) { uint8_t net[CONFIG_9P_MAX_MSG_SIZE]; - uint8_t host_req[CONFIG_9P_MAX_HOSTMSG_SIZE]; - uint8_t host_resp[CONFIG_9P_MAX_HOSTMSG_SIZE]; struct lib9p_srv *srv = _srv; assert(srv); @@ -236,87 +242,8 @@ COROUTINE lib9p_srv_write_cr(void *_srv) { req.net_bytes = net; cr_unpause(req.parent_sess->parent_conn->reader); /* notify that we've copied req */ - /* Unmarshal it. */ - enum lib9p_msg_type typ = net[4]; - if (typ % 2 != 0) { - lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "expected a T-message but got an R-message: message_type=%s", - lib9p_msg_type_str(typ)); - goto write; - } - ssize_t host_size = lib9p_validate(&req.ctx, net); - if (host_size < 0) - goto write; - if ((size_t)host_size > sizeof(host_req)) { - lib9p_errorf(&req.ctx, LINUX_EMSGSIZE, "unmarshalled payload larger than server limit (%zu > %zu)", - host_size, sizeof(host_req)); - goto write; - } - lib9p_unmarshal(&req.ctx, net, &typ, &req.tag, host_req); - - /* Handle it. */ - switch (typ) { - case LIB9P_TYP_Tversion: - handle_Tversion(&req, (struct lib9p_msg_Tversion *)host_req, (struct lib9p_msg_Rversion *)host_resp); - break; - case LIB9P_TYP_Tauth: - handle_Tauth(&req, (struct lib9p_msg_Tauth *)host_req, (struct lib9p_msg_Rauth *)host_resp); - break; - case LIB9P_TYP_Tattach: - handle_Tattach(&req, (struct lib9p_msg_Tattach *)host_req, (struct lib9p_msg_Rattach *)host_resp); - break; - case LIB9P_TYP_Tflush: - handle_Tflush(&req, (struct lib9p_msg_Tflush *)host_req, (struct lib9p_msg_Rflush *)host_resp); - break; - case LIB9P_TYP_Twalk: - handle_Twalk(&req, (struct lib9p_msg_Twalk *)host_req, (struct lib9p_msg_Rwalk *)host_resp); - break; - case LIB9P_TYP_Topen: - handle_Topen(&req, (struct lib9p_msg_Topen *)host_req, (struct lib9p_msg_Ropen *)host_resp); - break; - case LIB9P_TYP_Tcreate: - handle_Tcreate(&req, (struct lib9p_msg_Tcreate *)host_req, (struct lib9p_msg_Rcreate *)host_resp); - break; - case LIB9P_TYP_Tread: - handle_Tread(&req, (struct lib9p_msg_Tread *)host_req, (struct lib9p_msg_Rread *)host_resp); - break; - case LIB9P_TYP_Twrite: - handle_Twrite(&req, (struct lib9p_msg_Twrite *)host_req, (struct lib9p_msg_Rwrite *)host_resp); - break; - case LIB9P_TYP_Tclunk: - handle_Tclunk(&req, (struct lib9p_msg_Tclunk *)host_req, (struct lib9p_msg_Rclunk *)host_resp); - break; - case LIB9P_TYP_Tremove: - handle_Tremove(&req, (struct lib9p_msg_Tremove *)host_req, (struct lib9p_msg_Rremove *)host_resp); - break; - case LIB9P_TYP_Tstat: - handle_Tstat(&req, (struct lib9p_msg_Tstat *)host_req, (struct lib9p_msg_Rstat *)host_resp); - break; - case LIB9P_TYP_Twstat: - handle_Twstat(&req, (struct lib9p_msg_Twstat *)host_req, (struct lib9p_msg_Rwstat *)host_resp); - break; - case LIB9P_TYP_Tsession: /* 9P2000.e */ - handle_Tsession(&req, (struct lib9p_msg_Tsession *)host_req, (struct lib9p_msg_Rsession *)host_resp); - break; - case LIB9P_TYP_Tsread: /* 9P2000.e */ - handle_Tsread(&req, (struct lib9p_msg_Tsread *)host_req, (struct lib9p_msg_Rsread *)host_resp); - break; - case LIB9P_TYP_Tswrite: /* 9P2000.e */ - handle_Tswrite(&req, (struct lib9p_msg_Tswrite *)host_req, (struct lib9p_msg_Rswrite *)host_resp); - break; - default: - assert(false); - } + handle_Tmessage(&req); - write: - if (lib9p_ctx_has_error(&req.ctx)) - respond_error(&req); - else { - if (lib9p_marshal(&req.ctx, typ+1, req.tag, host_resp, net)) - goto write; - cr_mutex_lock(&req.parent_sess->parent_conn->writelock); - netio_write(req.parent_sess->parent_conn->fd, net, decode_u32le(net)); - cr_mutex_unlock(&req.parent_sess->parent_conn->writelock); - } if ((--req.parent_sess->refcount) == 0) cr_unpause(req.parent_sess->parent_conn->reader); } @@ -324,6 +251,93 @@ COROUTINE lib9p_srv_write_cr(void *_srv) { cr_end(); } +static bool handle_Tmessage(struct lib9p_req *req) { + uint8_t host_req[CONFIG_9P_MAX_HOSTMSG_SIZE]; + uint8_t host_resp[CONFIG_9P_MAX_HOSTMSG_SIZE]; + + /* Unmarshal it. */ + enum lib9p_msg_type typ = req->net_bytes[4]; + if (typ % 2 != 0) { + lib9p_errorf(&req->ctx, LINUX_EOPNOTSUPP, "expected a T-message but got an R-message: message_type=%s", + lib9p_msg_type_str(typ)); + goto write; + } + ssize_t host_size = lib9p_validate(&req->ctx, req->net_bytes); + if (host_size < 0) + goto write; + if ((size_t)host_size > sizeof(host_req)) { + lib9p_errorf(&req->ctx, LINUX_EMSGSIZE, "unmarshalled payload larger than server limit (%zu > %zu)", + host_size, sizeof(host_req)); + goto write; + } + lib9p_unmarshal(&req->ctx, req->net_bytes, &typ, &req->tag, host_req); + + /* Handle it. */ + switch (typ) { + case LIB9P_TYP_Tversion: + handle_Tversion(req, (struct lib9p_msg_Tversion *)host_req, (struct lib9p_msg_Rversion *)host_resp); + break; + case LIB9P_TYP_Tauth: + handle_Tauth(req, (struct lib9p_msg_Tauth *)host_req, (struct lib9p_msg_Rauth *)host_resp); + break; + case LIB9P_TYP_Tattach: + handle_Tattach(req, (struct lib9p_msg_Tattach *)host_req, (struct lib9p_msg_Rattach *)host_resp); + break; + case LIB9P_TYP_Tflush: + handle_Tflush(req, (struct lib9p_msg_Tflush *)host_req, (struct lib9p_msg_Rflush *)host_resp); + break; + case LIB9P_TYP_Twalk: + handle_Twalk(req, (struct lib9p_msg_Twalk *)host_req, (struct lib9p_msg_Rwalk *)host_resp); + break; + case LIB9P_TYP_Topen: + handle_Topen(req, (struct lib9p_msg_Topen *)host_req, (struct lib9p_msg_Ropen *)host_resp); + break; + case LIB9P_TYP_Tcreate: + handle_Tcreate(req, (struct lib9p_msg_Tcreate *)host_req, (struct lib9p_msg_Rcreate *)host_resp); + break; + case LIB9P_TYP_Tread: + handle_Tread(req, (struct lib9p_msg_Tread *)host_req, (struct lib9p_msg_Rread *)host_resp); + break; + case LIB9P_TYP_Twrite: + handle_Twrite(req, (struct lib9p_msg_Twrite *)host_req, (struct lib9p_msg_Rwrite *)host_resp); + break; + case LIB9P_TYP_Tclunk: + handle_Tclunk(req, (struct lib9p_msg_Tclunk *)host_req, (struct lib9p_msg_Rclunk *)host_resp); + break; + case LIB9P_TYP_Tremove: + handle_Tremove(req, (struct lib9p_msg_Tremove *)host_req, (struct lib9p_msg_Rremove *)host_resp); + break; + case LIB9P_TYP_Tstat: + handle_Tstat(req, (struct lib9p_msg_Tstat *)host_req, (struct lib9p_msg_Rstat *)host_resp); + break; + case LIB9P_TYP_Twstat: + handle_Twstat(req, (struct lib9p_msg_Twstat *)host_req, (struct lib9p_msg_Rwstat *)host_resp); + break; + case LIB9P_TYP_Tsession: /* 9P2000.e */ + handle_Tsession(req, (struct lib9p_msg_Tsession *)host_req, (struct lib9p_msg_Rsession *)host_resp); + break; + case LIB9P_TYP_Tsread: /* 9P2000.e */ + handle_Tsread(req, (struct lib9p_msg_Tsread *)host_req, (struct lib9p_msg_Rsread *)host_resp); + break; + case LIB9P_TYP_Tswrite: /* 9P2000.e */ + handle_Tswrite(req, (struct lib9p_msg_Tswrite *)host_req, (struct lib9p_msg_Rswrite *)host_resp); + break; + default: + assert(false); + } + + write: + if (lib9p_ctx_has_error(&req->ctx)) + respond_error(req); + else { + if (lib9p_marshal(&req->ctx, typ+1, req->tag, host_resp, req->net_bytes)) + goto write; + cr_mutex_lock(&req->parent_sess->parent_conn->writelock); + netio_write(req->parent_sess->parent_conn->fd, req->net_bytes, decode_u32le(req->net_bytes)); + cr_mutex_unlock(&req->parent_sess->parent_conn->writelock); + } +} + static void handle_Tversion(struct lib9p_req *ctx, struct lib9p_msg_Tversion *req, struct lib9p_msg_Rversion *resp) { enum lib9p_version version = LIB9P_VER_unknown; @@ -350,6 +364,14 @@ static void handle_Tversion(struct lib9p_req *ctx, struct lib9p_msg_Tversion *re return; } + + ctx->parent_sess--; + MAP_FOREACH(&ctx->parent_sess->fids, fid, fptr) { + fptr->vtable.free(subctx, fptr->impldata); + fidmap_del(&ctx->parent_sess->fids, fid); + } +} + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" resp->version.utf8 = lib9p_version_str(version); @@ -372,7 +394,6 @@ static void handle_Tauth(struct lib9p_req *ctx, struct lib9p_msg_Tauth *req, str }; ctx->parent_sess->parent_conn->parent_srv->auth(&subctx, req->aname.utf8); lib9p_error(&ctx->ctx, LINUX_EOPNOTSUPP, "TODO: auth not implemented"); - return; } static void handle_Tattach(struct lib9p_req *ctx, struct lib9p_msg_Tattach *req, struct lib9p_msg_Rattach *resp) { |