summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-12-16 14:51:10 -0500
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-01-11 23:34:14 -0700
commitc3b9d7e802d7d2e31131692d621515ac88178ebb (patch)
treeada9990fb897eb95e4fa5dbc11d332326480aab3
parentcd64085694c7c4aa96312e88905015eea4d8b63d (diff)
lib9p: Split lib9p_{validate,unmarshal,marshal} into _Tmsg and _Rmsg variants
-rwxr-xr-xbuild-aux/stack.c.gen2
-rw-r--r--lib9p/9p.c75
-rw-r--r--lib9p/include/lib9p/9p.h40
-rw-r--r--lib9p/srv.c28
4 files changed, 98 insertions, 47 deletions
diff --git a/build-aux/stack.c.gen b/build-aux/stack.c.gen
index a3288b0..6602bdc 100755
--- a/build-aux/stack.c.gen
+++ b/build-aux/stack.c.gen
@@ -412,7 +412,7 @@ def main(
return sorted(tmessage_handlers)
if lib9p_msgs and "/9p.c:" in loc:
for meth in ["validate", "unmarshal", "marshal"]:
- if line.startswith(f"table.{meth}("):
+ if line.startswith(f"tentry.{meth}("):
return sorted(f"{meth}_{msg}" for msg in lib9p_msgs)
return None
diff --git a/lib9p/9p.c b/lib9p/9p.c
index b464f63..8f3ae78 100644
--- a/lib9p/9p.c
+++ b/lib9p/9p.c
@@ -77,7 +77,11 @@ const char *lib9p_msg_type_str(struct lib9p_ctx *ctx, enum lib9p_msg_type typ) {
/* main message functions *****************************************************/
-ssize_t lib9p_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
+static
+ssize_t _lib9p_validate(uint8_t xxx_low_typ_bit,
+ const char *xxx_errmsg,
+ const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0x80],
+ struct lib9p_ctx *ctx, uint8_t *net_bytes) {
/* Inspect the first 5 bytes ourselves. */
struct _validate_ctx subctx = {
.ctx = ctx,
@@ -90,13 +94,16 @@ ssize_t lib9p_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
if (subctx.net_size < 5)
return lib9p_error(ctx, LINUX_EBADMSG, "message is impossibly short");
uint8_t typ = net_bytes[4];
- struct _lib9p_recv_tentry table = ((typ % 2 == 0) ? _lib9p_table_Tmsg_recv : _lib9p_table_Rmsg_recv)[ctx->version][typ/2];
- if (!table.validate)
+ if (typ % 2 != xxx_low_typ_bit)
+ return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "%s: message_type=%s", xxx_errmsg,
+ lib9p_msg_type_str(ctx, typ));
+ struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2];
+ if (!tentry.validate)
return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type: %s (protocol_version=%s)",
lib9p_msg_type_str(ctx, typ), lib9p_version_str(ctx->version));
- /* Now use the message-type-specific table to process the whole thing. */
- if (table.validate(&subctx))
+ /* Now use the message-type-specific tentry to process the whole thing. */
+ if (tentry.validate(&subctx))
return -1;
assert(subctx.net_offset <= subctx.net_size);
if (subctx.net_offset < subctx.net_size)
@@ -105,13 +112,25 @@ ssize_t lib9p_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
/* Return. */
ssize_t ret;
- if (__builtin_add_overflow(table.basesize, subctx.host_extra, &ret))
+ if (__builtin_add_overflow(tentry.basesize, subctx.host_extra, &ret))
return lib9p_error(ctx, LINUX_EMSGSIZE, "unmarshalled payload overflows SSIZE_MAX");
return ret;
}
-void lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
- enum lib9p_msg_type *ret_typ, void *ret_body) {
+ssize_t lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
+ return _lib9p_validate(0, "expected a T-message but got an R-message", _lib9p_table_Tmsg_recv,
+ ctx, net_bytes);
+}
+
+ssize_t lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
+ return _lib9p_validate(1, "expected an R-message but got a T-message", _lib9p_table_Rmsg_recv,
+ ctx, net_bytes);
+}
+
+static
+void _lib9p_unmarshal(const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0x80],
+ struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body) {
struct _unmarshal_ctx subctx = {
.ctx = ctx,
.net_bytes = net_bytes,
@@ -121,21 +140,47 @@ void lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
enum lib9p_msg_type typ = net_bytes[4];
*ret_typ = typ;
- struct _lib9p_recv_tentry table = ((typ % 2 == 0) ? _lib9p_table_Tmsg_recv : _lib9p_table_Rmsg_recv)[ctx->version][typ/2];
- subctx.extra = ret_body + table.basesize;
- table.unmarshal(&subctx, ret_body);
+ struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2];
+ subctx.extra = ret_body + tentry.basesize;
+ tentry.unmarshal(&subctx, ret_body);
+}
+
+void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body) {
+ _lib9p_unmarshal(_lib9p_table_Tmsg_recv,
+ ctx, net_bytes, ret_typ, ret_body);
}
-bool lib9p_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
- uint8_t *ret_bytes) {
+void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body) {
+ _lib9p_unmarshal(_lib9p_table_Rmsg_recv,
+ ctx, net_bytes, ret_typ, ret_body);
+}
+
+static
+bool _lib9p_marshal(const struct _lib9p_send_tentry xxx_table[LIB9P_VER_NUM][0x80],
+ struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ uint8_t *ret_bytes) {
struct _marshal_ctx subctx = {
.ctx = ctx,
.net_bytes = ret_bytes,
.net_offset = 0,
};
- struct _lib9p_send_tentry table = ((typ % 2 == 0) ? _lib9p_table_Tmsg_send : _lib9p_table_Rmsg_send)[ctx->version][typ/2];
- return table.marshal(&subctx, body);
+ struct _lib9p_send_tentry tentry = xxx_table[ctx->version][typ/2];
+ return tentry.marshal(&subctx, body);
+}
+
+bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ uint8_t *ret_bytes) {
+ assert(typ % 2 == 0);
+ return _lib9p_marshal(_lib9p_table_Tmsg_send, ctx, typ, body, ret_bytes);
+}
+
+bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ uint8_t *ret_bytes) {
+ assert(typ % 2 == 1);
+ return _lib9p_marshal(_lib9p_table_Rmsg_send, ctx, typ, body, ret_bytes);
}
/* `struct lib9p_stat` helpers ************************************************/
diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h
index fb1f97d..3d89370 100644
--- a/lib9p/include/lib9p/9p.h
+++ b/lib9p/include/lib9p/9p.h
@@ -1,6 +1,6 @@
/* lib9p/9p.h - Base 9P protocol definitions for both clients and servers
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -49,7 +49,7 @@ int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, .
const char *lib9p_msg_type_str(struct lib9p_ctx *, enum lib9p_msg_type);
-/* main message functions *****************************************************/
+/* main T-message functions ***************************************************/
/**
* Validate a message's structure; it's size, string encodings, enums,
@@ -68,13 +68,14 @@ const char *lib9p_msg_type_str(struct lib9p_ctx *, enum lib9p_msg_type);
*
* @return required size, or -1 on error
*
+ * @errno LINUX_EOPNOTSUPP: message is an R-message
* @errno LINUX_EOPNOTSUPP: message has unknown type
* @errno LINUX_EBADMSG: message is wrong size for content
* @errno LINUX_EBADMSG: message contains invalid UTF-8
* @errno LINUX_EBADMSG: message contains a bitfield with unknown bits
* @errno LINUX_EMSGSIZE: would-be return value overflows SSIZE_MAX
*/
-ssize_t lib9p_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
+ssize_t lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
/**
* Unmarshal the 9P message `net_bytes` into the C struct `ret_body`.
@@ -82,25 +83,25 @@ ssize_t lib9p_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
* Emits an error (return 0, set ctx->err_num and ctx->err_msg) if a
* string contains invalid UTF-8 or a nul-byte.
*
- * lib9p_unmarshal does no validation; you must run lib9p_validate()
- * first.
+ * lib9p_unmarshal does no validation; you must run
+ * lib9p_Tmsg_validate() first.
*
* @param ctx : negotiated protocol parameters, where to record errors
* @param net_bytes : the complete message, starting with the "size[4]"
*
* @return ret_typ : the mesage type
- * @return ret_body : the message body, must be at least lib9p_validate() bytes
+ * @return ret_body : the message body, must be at least lib9p_Tmsg_validate() bytes
*/
-void lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
- enum lib9p_msg_type *ret_typ, void *ret_body);
+void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body);
/**
* Marshal a `struct lib9p_msg_{typ}` structure into a byte-array.
*
- * lib9p_marshal does no validation; it trusts that the programmer
- * won't give it garbage input. However, just as it doesn't marshal
- * struct fields that aren't in ctx->version, it won't marshal
- * bitfield bits that aren't in ctx->version; it applies a
+ * lib9p_Tmsg_marshal does no validation; it trusts that the
+ * programmer won't give it garbage input. However, just as it
+ * doesn't marshal struct fields that aren't in ctx->version, it won't
+ * marshal bitfield bits that aren't in ctx->version; it applies a
* version-specific mask to bitfields.
*
* @param ctx : negotiated protocol parameters, where to record errors
@@ -112,8 +113,19 @@ void lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
*
* @errno LINUX_ERANGE: reply does not fit in ctx->max_msg_size
*/
-bool lib9p_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
- uint8_t *ret_bytes);
+bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ uint8_t *ret_bytes);
+
+/* main R-message functions ***************************************************/
+
+/** Same as above, but for R-messages instead of T-messages. */
+
+ssize_t lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
+void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body);
+bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ uint8_t *ret_bytes);
+
/* `struct lib9p_stat` helpers ************************************************/
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 3535f9a..f98db67 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -1,6 +1,6 @@
/* lib9p/srv.c - 9P server
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -116,9 +116,9 @@ static uint32_t rerror_overhead_for_version(enum lib9p_version version,
struct lib9p_msg_Rerror empty_error = { 0 };
bool e;
- e = lib9p_marshal(&empty_ctx, LIB9P_TYP_Rerror,
- &empty_error, /* host_body */
- scratch); /* net_bytes */
+ e = lib9p_Rmsg_marshal(&empty_ctx, LIB9P_TYP_Rerror,
+ &empty_error, /* host_body */
+ scratch); /* net_bytes */
assert(!e);
uint32_t min_msg_size = decode_u32le(scratch);
@@ -162,8 +162,8 @@ static void respond_error(struct _lib9p_srv_req *req) {
if (((uint32_t)host.ename.len) + sess->rerror_overhead > sess->max_msg_size)
host.ename.len = sess->max_msg_size - sess->rerror_overhead;
- lib9p_marshal(&req->ctx.basectx, LIB9P_TYP_Rerror,
- &host, req->net_bytes);
+ lib9p_Rmsg_marshal(&req->ctx.basectx, LIB9P_TYP_Rerror,
+ &host, req->net_bytes);
cr_mutex_lock(&sess->parent_conn->writelock);
r = VCALL(sess->parent_conn->fd, write,
@@ -369,14 +369,7 @@ static void handle_message(struct _lib9p_srv_req *ctx) {
uint8_t host_resp[CONFIG_9P_MAX_HOSTMSG_SIZE];
/* Unmarshal it. */
- enum lib9p_msg_type typ = ctx->net_bytes[4];
- if (typ % 2 != 0) {
- lib9p_errorf(&ctx->ctx.basectx,
- LINUX_EOPNOTSUPP, "expected a T-message but got an R-message: message_type=%s",
- lib9p_msg_type_str(&ctx->ctx.basectx, typ));
- goto write;
- }
- ssize_t host_size = lib9p_validate(&ctx->ctx.basectx, ctx->net_bytes);
+ ssize_t host_size = lib9p_Tmsg_validate(&ctx->ctx.basectx, ctx->net_bytes);
if (host_size < 0)
goto write;
if ((size_t)host_size > sizeof(host_req)) {
@@ -385,7 +378,8 @@ static void handle_message(struct _lib9p_srv_req *ctx) {
host_size, sizeof(host_req));
goto write;
}
- lib9p_unmarshal(&ctx->ctx.basectx, ctx->net_bytes,
+ enum lib9p_msg_type typ;
+ lib9p_Tmsg_unmarshal(&ctx->ctx.basectx, ctx->net_bytes,
&typ, host_req);
/* Handle it. */
@@ -395,8 +389,8 @@ static void handle_message(struct _lib9p_srv_req *ctx) {
if (lib9p_ctx_has_error(&ctx->ctx.basectx))
respond_error(ctx);
else {
- if (lib9p_marshal(&ctx->ctx.basectx, typ+1, host_resp,
- ctx->net_bytes))
+ if (lib9p_Rmsg_marshal(&ctx->ctx.basectx, typ+1, host_resp,
+ ctx->net_bytes))
goto write;
cr_mutex_lock(&ctx->parent_sess->parent_conn->writelock);