diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-12-16 14:51:10 -0500 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-01-11 23:34:14 -0700 |
commit | c3b9d7e802d7d2e31131692d621515ac88178ebb (patch) | |
tree | ada9990fb897eb95e4fa5dbc11d332326480aab3 | |
parent | cd64085694c7c4aa96312e88905015eea4d8b63d (diff) |
lib9p: Split lib9p_{validate,unmarshal,marshal} into _Tmsg and _Rmsg variants
-rwxr-xr-x | build-aux/stack.c.gen | 2 | ||||
-rw-r--r-- | lib9p/9p.c | 75 | ||||
-rw-r--r-- | lib9p/include/lib9p/9p.h | 40 | ||||
-rw-r--r-- | lib9p/srv.c | 28 |
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 @@ -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); |