diff options
-rw-r--r-- | lib9p/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib9p/core.c | 197 | ||||
-rw-r--r-- | lib9p/core_include/lib9p/core.h | 38 | ||||
-rw-r--r-- | lib9p/core_tables.c | 190 |
4 files changed, 203 insertions, 223 deletions
diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt index 0a5ea3e..cff07ad 100644 --- a/lib9p/CMakeLists.txt +++ b/lib9p/CMakeLists.txt @@ -8,7 +8,6 @@ target_include_directories(lib9p_core PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DI target_sources(lib9p_core INTERFACE core.c core_generated.c - core_tables.c ) target_link_libraries(lib9p_core INTERFACE libfmt diff --git a/lib9p/core.c b/lib9p/core.c index cb8ddee..adf7ecf 100644 --- a/lib9p/core.c +++ b/lib9p/core.c @@ -4,14 +4,18 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include <inttypes.h> /* for PRIu{n} */ -#include <stdarg.h> /* for va_* */ -#include <string.h> /* for strncpy() */ +#include <stdarg.h> /* for va_* */ +#include <string.h> /* for strlen(), strnlen(), strncpy(), memcmp(), memset() */ -#include <libfmt/fmt.h> /* for fmt_vsnprintf() */ +#include <libfmt/fmt.h> /* for fmt_vsnprintf() */ +#include <libmisc/assert.h> /* for assert() */ +#include <libmisc/endian.h> /* for uint32le_decode() */ +#include <libmisc/log.h> /* for const_byte_str() */ #include <lib9p/core.h> +#include "core_tables.h" + /* strings ********************************************************************/ struct lib9p_s lib9p_str(char *s) { @@ -58,10 +62,7 @@ bool lib9p_ctx_has_error(struct lib9p_ctx *ctx) { return ctx->err_msg[0]; } -#undef lib9p_error -#undef lib9p_errorf - -int lib9p_error(struct lib9p_ctx *ctx, +int _lib9p_error(struct lib9p_ctx *ctx, #if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L lib9p_errno_t linux_errno, #endif @@ -78,7 +79,7 @@ int lib9p_error(struct lib9p_ctx *ctx, return -1; } -int lib9p_errorf(struct lib9p_ctx *ctx, +int _lib9p_errorf(struct lib9p_ctx *ctx, #if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L lib9p_errno_t linux_errno, #endif @@ -100,3 +101,181 @@ int lib9p_errorf(struct lib9p_ctx *ctx, return -1; } + +/* bounds checks **************************************************************/ + +static inline void assert_ver(enum lib9p_version ver) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" + assert(0 <= ver && ver < LIB9P_VER_NUM); +#pragma GCC diagnostic pop +} + +static inline void assert_typ(enum lib9p_msg_type typ) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" + assert(0 <= typ && typ < 0xFF); +#pragma GCC diagnostic pop +} + +/* simple lookups *************************************************************/ + +const char *lib9p_version_str(enum lib9p_version ver) { + assert_ver(ver); + return _lib9p_table_ver[ver].name; +} + +uint32_t lib9p_version_min_msg_size(enum lib9p_version ver) { + assert_ver(ver); + return _lib9p_table_ver[ver].min_msg_size; +} + +const char *lib9p_msgtype_str(enum lib9p_version ver, enum lib9p_msg_type typ) { + assert_ver(ver); + assert_typ(typ); + return _lib9p_table_msg[ver][typ].name ?: const_byte_str(typ); +} + +lo_interface fmt_formatter lo_box_lib9p_msg_as_fmt_formatter(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body) { + assert(ctx); + assert_ver(ctx->version); + assert_typ(typ); + assert(_lib9p_table_msg[ctx->version][typ].box_as_fmt_formatter); + return _lib9p_table_msg[ctx->version][typ].box_as_fmt_formatter(body); +} + +/* main message functions *****************************************************/ + +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) { + assert_ver(ctx->version); + /* Inspect the first 5 bytes ourselves. */ + uint32_t net_size = uint32le_decode(net_bytes); + if (net_size < 5) + return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message is impossibly short"); + uint8_t typ = net_bytes[4]; + if (typ % 2 != xxx_low_typ_bit) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, "%s: message_type=%s", xxx_errmsg, + lib9p_msgtype_str(ctx->version, typ)); + struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; + if (!tentry.validate) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, "unknown message type: %s (protocol_version=%s)", + lib9p_msgtype_str(ctx->version, typ), lib9p_version_str(ctx->version)); + + /* Now use the message-type-specific tentry to process the whole thing. */ + return tentry.validate(ctx, net_size, net_bytes); +} + +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) { + assert_ver(ctx->version); + enum lib9p_msg_type typ = net_bytes[4]; + *ret_typ = typ; + struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; + assert(tentry.unmarshal); + + tentry.unmarshal(ctx, net_bytes, 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); +} + +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, + size_t *ret_iov_cnt, struct iovec *ret_iov, uint8_t *ret_copied) { + assert_ver(ctx->version); + assert_typ(typ); + struct _marshal_ret ret = { + .net_iov_cnt = 1, + .net_iov = ret_iov, + .net_copied_size = 0, + .net_copied = ret_copied, + }; + struct _lib9p_send_tentry tentry = xxx_table[ctx->version][typ/2]; + assert(tentry.marshal); + + bool ret_erred = tentry.marshal(ctx, body, &ret); + if (ret_iov[ret.net_iov_cnt-1].iov_len == 0) + ret.net_iov_cnt--; + *ret_iov_cnt = ret.net_iov_cnt; + return ret_erred; +} + +bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, + struct lib9p_Tmsg_send_buf *ret) { + assert(typ % 2 == 0); + memset(ret, 0, sizeof(*ret)); + return _lib9p_marshal(_lib9p_table_Tmsg_send, + ctx, typ, body, + &ret->iov_cnt, ret->iov, ret->copied); +} + +bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, + struct lib9p_Rmsg_send_buf *ret) { + assert(typ % 2 == 1); + memset(ret, 0, sizeof(*ret)); + return _lib9p_marshal(_lib9p_table_Rmsg_send, + ctx, typ, body, + &ret->iov_cnt, ret->iov, ret->copied); +} + +/* `struct lib9p_stat` helpers ************************************************/ + +#if _LIB9P_ENABLE_stat +bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, + uint32_t *ret_net_size, size_t *ret_host_size) { + ssize_t host_size = _lib9p_stat_validate(ctx, net_size, net_bytes, ret_net_size); + if (host_size < 0) + return true; + if (ret_host_size) + *ret_host_size = (size_t)host_size; + return false; +} + +void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, + struct lib9p_stat *ret) { + _lib9p_stat_unmarshal(ctx, net_bytes, ret); +} + +uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj, + uint8_t *ret_bytes) { + struct lib9p_ctx _ctx = *ctx; + _ctx.max_msg_size = max_net_size; + + struct iovec iov = {0}; + struct _marshal_ret ret = { + .net_iov_cnt = 1, + .net_iov = &iov, + .net_copied_size = 0, + .net_copied = ret_bytes, + }; + if (_lib9p_stat_marshal(&_ctx, obj, &ret)) + return 0; + return ret.net_iov[0].iov_len; +} +#endif diff --git a/lib9p/core_include/lib9p/core.h b/lib9p/core_include/lib9p/core.h index 38f3934..2dfda27 100644 --- a/lib9p/core_include/lib9p/core.h +++ b/lib9p/core_include/lib9p/core.h @@ -56,31 +56,23 @@ void lib9p_ctx_clear_error(struct lib9p_ctx *ctx); bool lib9p_ctx_has_error(struct lib9p_ctx *ctx); -/** Write an static error into ctx, return -1. */ -int lib9p_error(struct lib9p_ctx *ctx, +/* NB: This __VA_ARGS__ definition of lib9p_errorf() is handy because it + * will produce an error if .../__VA_ARGS__ is empty; which means that + * it should be lib9p_error() instead! */ #if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L - lib9p_errno_t linux_errno, -#endif - char const *msg); -/** Write a printf-style error into ctx, return -1. */ -int lib9p_errorf(struct lib9p_ctx *ctx, -#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L - lib9p_errno_t linux_errno, -#endif - char const *fmt, ...) -#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L - [[gnu::format(printf, 3, 4)]] -#else - [[gnu::format(printf, 2, 3)]] -#endif - ; - -#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L -/* Detect things that should be just lib9p_error() */ -#define lib9p_errorf(ctx, errnum, fmt, ...) lib9p_errorf(ctx, errnum, fmt, __VA_ARGS__) + int _lib9p_error(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *msg); + int _lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *fmt, ...) [[gnu::format(printf, 3, 4)]]; + /** Write an static error into ctx, return -1. */ + #define lib9p_error(ctx, errnum, errmsg) _lib9p_error(ctx, errnum, errmsg) + /** Write a printf-style error into ctx, return -1. */ + #define lib9p_errorf(ctx, errnum, fmt, ...) _lib9p_errorf(ctx, errnum, fmt, __VA_ARGS__) #else -#define lib9p_errorf(ctx, errnum, fmt, ...) lib9p_errorf(ctx, fmt, __VA_ARGS__) -#define lib9p_error(ctx, errnum, errmsg) lib9p_error(ctx, errmsg) + int _lib9p_error(struct lib9p_ctx *ctx, char const *msg); + int _lib9p_errorf(struct lib9p_ctx *ctx, char const *fmt, ...) [[gnu::format(printf, 2, 3)]]; + /** Write an static error into ctx, return -1. */ + #define lib9p_error(ctx, errnum, errmsg) _lib9p_error(ctx, errmsg) + /** Write a printf-style error into ctx, return -1. */ + #define lib9p_errorf(ctx, errnum, fmt, ...) _lib9p_errorf(ctx, fmt, __VA_ARGS__) #endif /* misc utilities *************************************************************/ diff --git a/lib9p/core_tables.c b/lib9p/core_tables.c deleted file mode 100644 index bc452c7..0000000 --- a/lib9p/core_tables.c +++ /dev/null @@ -1,190 +0,0 @@ -/* lib9p/core_tables.c - Access tables of version and message information - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#include <string.h> - -#include <libmisc/endian.h> -#include <libmisc/log.h> /* for const_byte_str() */ - -#include "core_tables.h" - -/* bounds checks **************************************************************/ - -static inline void assert_ver(enum lib9p_version ver) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" - assert(0 <= ver && ver < LIB9P_VER_NUM); -#pragma GCC diagnostic pop -} - -static inline void assert_typ(enum lib9p_msg_type typ) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" - assert(0 <= typ && typ < 0xFF); -#pragma GCC diagnostic pop -} - -/* simple lookups *************************************************************/ - -const char *lib9p_version_str(enum lib9p_version ver) { - assert_ver(ver); - return _lib9p_table_ver[ver].name; -} - -uint32_t lib9p_version_min_msg_size(enum lib9p_version ver) { - assert_ver(ver); - return _lib9p_table_ver[ver].min_msg_size; -} - -const char *lib9p_msgtype_str(enum lib9p_version ver, enum lib9p_msg_type typ) { - assert_ver(ver); - assert_typ(typ); - return _lib9p_table_msg[ver][typ].name ?: const_byte_str(typ); -} - -lo_interface fmt_formatter lo_box_lib9p_msg_as_fmt_formatter(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body) { - assert(ctx); - assert_ver(ctx->version); - assert_typ(typ); - assert(_lib9p_table_msg[ctx->version][typ].box_as_fmt_formatter); - return _lib9p_table_msg[ctx->version][typ].box_as_fmt_formatter(body); -} - -/* main message functions *****************************************************/ - -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) { - assert_ver(ctx->version); - /* Inspect the first 5 bytes ourselves. */ - uint32_t net_size = uint32le_decode(net_bytes); - if (net_size < 5) - return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message is impossibly short"); - uint8_t typ = net_bytes[4]; - if (typ % 2 != xxx_low_typ_bit) - return lib9p_errorf(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, "%s: message_type=%s", xxx_errmsg, - lib9p_msgtype_str(ctx->version, typ)); - struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; - if (!tentry.validate) - return lib9p_errorf(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, "unknown message type: %s (protocol_version=%s)", - lib9p_msgtype_str(ctx->version, typ), lib9p_version_str(ctx->version)); - - /* Now use the message-type-specific tentry to process the whole thing. */ - return tentry.validate(ctx, net_size, net_bytes); -} - -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) { - assert_ver(ctx->version); - enum lib9p_msg_type typ = net_bytes[4]; - *ret_typ = typ; - struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; - assert(tentry.unmarshal); - - tentry.unmarshal(ctx, net_bytes, 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); -} - -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, - size_t *ret_iov_cnt, struct iovec *ret_iov, uint8_t *ret_copied) { - assert_ver(ctx->version); - assert_typ(typ); - struct _marshal_ret ret = { - .net_iov_cnt = 1, - .net_iov = ret_iov, - .net_copied_size = 0, - .net_copied = ret_copied, - }; - struct _lib9p_send_tentry tentry = xxx_table[ctx->version][typ/2]; - assert(tentry.marshal); - - bool ret_erred = tentry.marshal(ctx, body, &ret); - if (ret_iov[ret.net_iov_cnt-1].iov_len == 0) - ret.net_iov_cnt--; - *ret_iov_cnt = ret.net_iov_cnt; - return ret_erred; -} - -bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, - struct lib9p_Tmsg_send_buf *ret) { - assert(typ % 2 == 0); - memset(ret, 0, sizeof(*ret)); - return _lib9p_marshal(_lib9p_table_Tmsg_send, - ctx, typ, body, - &ret->iov_cnt, ret->iov, ret->copied); -} - -bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, - struct lib9p_Rmsg_send_buf *ret) { - assert(typ % 2 == 1); - memset(ret, 0, sizeof(*ret)); - return _lib9p_marshal(_lib9p_table_Rmsg_send, - ctx, typ, body, - &ret->iov_cnt, ret->iov, ret->copied); -} - -/* `struct lib9p_stat` helpers ************************************************/ - -#if _LIB9P_ENABLE_stat -bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, - uint32_t *ret_net_size, size_t *ret_host_size) { - ssize_t host_size = _lib9p_stat_validate(ctx, net_size, net_bytes, ret_net_size); - if (host_size < 0) - return true; - if (ret_host_size) - *ret_host_size = (size_t)host_size; - return false; -} - -void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, - struct lib9p_stat *ret) { - _lib9p_stat_unmarshal(ctx, net_bytes, ret); -} - -uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj, - uint8_t *ret_bytes) { - struct lib9p_ctx _ctx = *ctx; - _ctx.max_msg_size = max_net_size; - - struct iovec iov = {0}; - struct _marshal_ret ret = { - .net_iov_cnt = 1, - .net_iov = &iov, - .net_copied_size = 0, - .net_copied = ret_bytes, - }; - if (_lib9p_stat_marshal(&_ctx, obj, &ret)) - return 0; - return ret.net_iov[0].iov_len; -} -#endif |