summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-10-04 19:38:42 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-10-04 19:38:42 -0600
commit4f7cf6b416ccede492ace64533ab35a9a289f463 (patch)
treedb28d138f8b6d4c9bf71f2790881ea04f68b3ece
parent860a9e995b8e7076ce4e5c231e844184bef9b95e (diff)
wip
-rw-r--r--lib9p/9p.c4
-rw-r--r--lib9p/include/lib9p/srv.h15
-rw-r--r--lib9p/map.h3
-rw-r--r--lib9p/srv.c189
4 files changed, 125 insertions, 86 deletions
diff --git a/lib9p/9p.c b/lib9p/9p.c
index 0ab940c..8633a44 100644
--- a/lib9p/9p.c
+++ b/lib9p/9p.c
@@ -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) {