diff --git a/src/brei-shared.c b/src/brei-shared.c index 9325619..10aad0c 100644 --- a/src/brei-shared.c +++ b/src/brei-shared.c @@ -31,6 +31,73 @@ #include "brei-shared.h" +struct brei_context { + struct object object; + void *parent_context; + + brei_logfunc_t log_func; + void *log_context; +}; + +static void +brei_context_destroy(struct brei_context *ctx) +{ +} + +static +OBJECT_IMPLEMENT_CREATE(brei_context); +OBJECT_IMPLEMENT_REF(brei_context); +OBJECT_IMPLEMENT_UNREF_CLEANUP(brei_context); +OBJECT_IMPLEMENT_SETTER(brei_context, log_func, brei_logfunc_t); +OBJECT_IMPLEMENT_SETTER(brei_context, log_context, void *); + +struct brei_context * +brei_context_new(void *parent_context) +{ + struct brei_context *brei = brei_context_create(NULL); + + brei->parent_context = parent_context; + + return brei; +} + +#define log_debug(T_, ...) \ + brei_log_msg((T_), BREI_LOG_PRIORITY_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define log_info(T_, ...) \ + brei_log_msg((T_), BREI_LOG_PRIORITY_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define log_warn(T_, ...) \ + brei_log_msg((T_), BREI_LOG_PRIORITY_WARNING, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define log_error(T_, ...) \ + brei_log_msg((T_), BREI_LOG_PRIORITY_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define log_bug(T_, ...) \ + brei_log_msg((T_), BREI_LOG_PRIORITY_ERROR, __FILE__, __LINE__, __func__, "🪳 brei bug: " __VA_ARGS__) +#define log_bug_client(T_, ...) \ + brei_log_msg((T_), BREI_LOG_PRIORITY_ERROR, __FILE__, __LINE__, __func__, "🪲 Bug: " __VA_ARGS__) + +_printf_(6, 0) static void +brei_log_msg_va(struct brei_context *brei, + enum brei_log_priority priority, + const char *file, int lineno, const char *func, + const char *format, + va_list ap) +{ + if (brei->log_func && brei->log_context) + brei->log_func(brei->log_context, priority, file, lineno, func, format, ap); +} + + +_printf_(6, 7) static void +brei_log_msg(struct brei_context *brei, + enum brei_log_priority priority, + const char *file, int lineno, const char *func, + const char *format, ...) +{ + va_list args; + va_start(args, format); + brei_log_msg_va(brei, priority, file, lineno, func, format, args); + va_end(args); +} + /** * Return the number of int32s required to store count bytes. */ @@ -41,11 +108,13 @@ bytes_to_int32(uint32_t count) } static int -brei_demarshal(struct iobuf *buf, const char *signature, union brei_arg **args_out) +brei_demarshal(struct brei_context *brei, struct iobuf *buf, const char *signature, union brei_arg **args_out) { size_t nargs = strlen(signature); - if (nargs > 256) + if (nargs > 256) { + log_bug(brei, "Too many arguments in signature (%zu)", nargs); return -EPROTO; + } /* This over-allocates if we have more than one char per type but meh */ _cleanup_free_ union brei_arg *args = xalloc(nargs * sizeof(*args)); @@ -77,19 +146,25 @@ brei_demarshal(struct iobuf *buf, const char *signature, union brei_arg **args_o uint32_t slen32 = bytes_to_int32(slen); if (end - p < slen32) { + log_bug_client(brei, "Invalid string length %zu, only %li bytes remaining", slen, (end - p) * 4); return -EINVAL; } const char *str = (char*)p; /* strings must be null-terminated */ - if (slen && str[slen - 1] != '\0') + if (slen && str[slen - 1] != '\0') { + log_bug_client(brei, "Message string not zero-terminated"); return -EINVAL; + } arg->str = str; p += slen32; break; } + default: + log_bug(brei, "Invalid signature '%c'", *s); + return -EBADMSG; } arg++; s++; @@ -102,7 +177,7 @@ brei_demarshal(struct iobuf *buf, const char *signature, union brei_arg **args_o } static int -brei_marshal(struct iobuf *buf, const char *signature, size_t nargs, va_list args) +brei_marshal(struct brei_context *brei, struct iobuf *buf, const char *signature, size_t nargs, va_list args) { const char *s = signature; int32_t i; @@ -144,6 +219,9 @@ brei_marshal(struct iobuf *buf, const char *signature, size_t nargs, va_list arg } break; } + default: + log_bug(brei, "Invalid signature '%c'", *s); + return -EBADMSG; } s++; } @@ -152,7 +230,8 @@ brei_marshal(struct iobuf *buf, const char *signature, size_t nargs, va_list arg } int -brei_send_message(int fd, +brei_send_message(struct brei_context *brei, + int fd, uint32_t id, uint32_t opcode, const char *signature, @@ -166,7 +245,7 @@ brei_send_message(int fd, iobuf_append(buf, (const char *)&id, 4); iobuf_append(buf, (const char *)&opcode, 4); - int rc = brei_marshal(buf, signature, nargs, args); + int rc = brei_marshal(brei, buf, signature, nargs, args); if (rc == 0) { /* now write the actual message length, including header */ @@ -178,7 +257,8 @@ brei_send_message(int fd, } int -brei_dispatch(int fd, +brei_dispatch(struct brei_context *brei, + int fd, int (*lookup_object)(uint32_t object_id, struct brei_object **object, void *user_data), void *user_data) { @@ -222,6 +302,8 @@ brei_dispatch(int fd, assert(interface); if (opcode >= interface->nincoming) { + log_bug_client(brei, "opcode %u exceeds interface %s method count %u", + opcode, interface->name, interface->nincoming); rc = -EINVAL; goto error; } @@ -231,17 +313,21 @@ brei_dispatch(int fd, /* Demarshal the protocol into a set of arguments */ _cleanup_free_ union brei_arg * args = NULL; const char *signature = interface->incoming[opcode].signature; - int nargs = brei_demarshal(buf, signature, &args); + int nargs = brei_demarshal(brei, buf, signature, &args); if (nargs < 0) { rc = nargs; goto error; } + log_debug(brei, "dispatching %s.%s() on object %#x", interface->name, interface->incoming[opcode].name, object_id); + /* Success! Let's pass this on to the * context to process */ rc = interface->dispatcher(object->implementation, opcode, nargs, args); - if (rc < 0) + if (rc < 0) { + log_error(brei, "dispatch failed with %d (%s)", -rc, strerror(-rc)); goto error; + } iobuf_pop(buf, msglen - headersize); } @@ -266,26 +352,27 @@ brei_drain_fd(int fd) #include "util-munit.h" static int -brei_marshal_va(struct iobuf *buf, const char *signature, size_t nargs, ...) +brei_marshal_va(struct brei_context *brei, struct iobuf *buf, const char *signature, size_t nargs, ...) { va_list args; va_start(args, nargs); - int rc = brei_marshal(buf, signature, nargs, args); + int rc = brei_marshal(brei, buf, signature, nargs, args); va_end(args); return rc; } MUNIT_TEST(test_brei_marshal) { + _unref_(brei_context) *brei = brei_context_new(NULL); _cleanup_iobuf_ struct iobuf *buf = iobuf_new(64); const char *str = "eierspeise"; - int rc = brei_marshal_va(buf, "noiusf", 5, 0xab, 0xcd, -13, 0xfffd, str, 1.45); + int rc = brei_marshal_va(brei, buf, "noiusf", 5, 0xab, 0xcd, -13, 0xfffd, str, 1.45); munit_assert_int(rc, ==, 0); - _cleanup_free_ union brei_arg *args; - rc = brei_demarshal(buf, "noiusf", &args); + _cleanup_free_ union brei_arg *args = NULL; + rc = brei_demarshal(brei, buf, "noiusf", &args); munit_assert_int(rc, ==, 6); munit_assert_int(args[0].obj, ==, 0xab); @@ -298,13 +385,30 @@ MUNIT_TEST(test_brei_marshal) return MUNIT_OK; } +MUNIT_TEST(test_brei_marshal_bad_sig) +{ + _unref_(brei_context) *brei = brei_context_new(NULL); + _cleanup_iobuf_ struct iobuf *buf = iobuf_new(64); + const char *str = "eierspeise"; + + int rc = brei_marshal_va(brei, buf, "noiusf", 5, 0xab, 0xcd, -13, 0xfffd, str, 1.45); + munit_assert_int(rc, ==, 0); + + _cleanup_free_ union brei_arg *args = NULL; + rc = brei_demarshal(brei, buf, "nxoiusf", &args); + munit_assert_int(rc, ==, -EBADMSG); + + return MUNIT_OK; +} + static int brei_send_message_va(int fd, uint32_t id, uint32_t opcode, const char *signature, size_t nargs, ...) { + _unref_(brei_context) *brei = brei_context_new(NULL); va_list args; va_start(args, nargs); - int rc = brei_send_message(fd, id, opcode, signature, nargs, args); + int rc = brei_send_message(brei, fd, id, opcode, signature, nargs, args); va_end(args); return rc; } diff --git a/src/brei-shared.h b/src/brei-shared.h index abd5072..9a59352 100644 --- a/src/brei-shared.h +++ b/src/brei-shared.h @@ -31,11 +31,32 @@ #include #include "util-list.h" +#include "util-object.h" struct brei_interface; struct brei_message; struct brei_object; +struct brei_context; + +enum brei_log_priority { + BREI_LOG_PRIORITY_DEBUG = 10, + BREI_LOG_PRIORITY_INFO = 20, + BREI_LOG_PRIORITY_WARNING = 30, + BREI_LOG_PRIORITY_ERROR = 40, +}; + +typedef void (*brei_logfunc_t)(void *context, enum brei_log_priority priority, + const char *file, int lineno, const char *func, + const char *format, va_list args); + +struct brei_context *brei_context_new(void *user_data); + +OBJECT_DECLARE_SETTER(brei_context, log_func, brei_logfunc_t); +OBJECT_DECLARE_SETTER(brei_context, log_context, void *); +OBJECT_DECLARE_REF(brei_context); +OBJECT_DECLARE_UNREF(brei_context); + union brei_arg { uint32_t u32; int32_t i32; @@ -77,7 +98,8 @@ struct brei_object { }; int -brei_send_message(int fd, +brei_send_message(struct brei_context *brei, + int fd, uint32_t id, uint32_t opcode, const char *signature, @@ -95,7 +117,8 @@ brei_send_message(int fd, * @return zero on success or a negative errno otherwise */ int -brei_dispatch(int fd, +brei_dispatch(struct brei_context *brei, + int fd, int (*lookup_object)(uint32_t object_id, struct brei_object **object, void *user_data), void *user_data); diff --git a/src/libei-private.h b/src/libei-private.h index f633b5a..3a7ad53 100644 --- a/src/libei-private.h +++ b/src/libei-private.h @@ -68,6 +68,7 @@ struct ei { uint32_t next_object_id; void *user_data; + struct brei_context *brei; struct sink *sink; struct source *source; struct ei_backend_interface backend_interface; diff --git a/src/libei.c b/src/libei.c index 41a1755..a83b5c8 100644 --- a/src/libei.c +++ b/src/libei.c @@ -64,6 +64,7 @@ ei_destroy(struct ei *ei) ei->backend = NULL; ei_connection_setup_unref(ei->connection_setup); ei_connection_unref(ei->connection); + brei_context_unref(ei->brei); sink_unref(ei->sink); free(ei->name); } @@ -101,6 +102,9 @@ ei_create_context(bool is_sender, void *user_data) ei->connection_setup = ei_connection_setup_new(ei, VERSION_V(1)); ei->next_object_id = 1; + ei->brei = brei_context_new(ei); + brei_context_set_log_context(ei->brei, ei); + brei_context_set_log_func(ei->brei, (brei_logfunc_t)ei_log_msg_va); ei_log_set_handler(ei, NULL); ei_log_set_priority(ei, EI_LOG_PRIORITY_INFO); @@ -697,7 +701,7 @@ connection_dispatch(struct source *source, void *userdata) struct ei *ei = userdata; enum ei_state old_state = ei->state; - int rc = brei_dispatch(source_get_fd(source), lookup_object, ei); + int rc = brei_dispatch(ei->brei, source_get_fd(source), lookup_object, ei); if (rc < 0) { brei_drain_fd(source_get_fd(source)); ei_disconnect(ei); @@ -738,7 +742,7 @@ ei_send_message(struct ei *ei, const struct brei_object *object, va_list args; va_start(args, nargs); - int rc = brei_send_message(fd, object->id, opcode, signature, nargs, args); + int rc = brei_send_message(ei->brei, fd, object->id, opcode, signature, nargs, args); va_end(args); return rc < 0 ? rc : 0; } diff --git a/src/libeis-client.c b/src/libeis-client.c index 827332e..d263e05 100644 --- a/src/libeis-client.c +++ b/src/libeis-client.c @@ -53,6 +53,7 @@ eis_client_destroy(struct eis_client *client) eis_connection_setup_unref(client->setup); eis_connection_unref(client->connection); free(client->name); + brei_context_unref(client->brei); source_remove(client->source); source_unref(client->source); list_remove(&client->link); @@ -158,7 +159,7 @@ eis_client_send_message(struct eis_client *client, const struct brei_object *obj va_list args; va_start(args, nargs); - int rc = brei_send_message(fd, object->id, opcode, signature, nargs, args); + int rc = brei_send_message(client->brei, fd, object->id, opcode, signature, nargs, args); va_end(args); return rc < 0 ? rc : 0; } @@ -325,7 +326,7 @@ client_dispatch(struct source *source, void *userdata) _unref_(eis_client) *client = eis_client_ref(userdata); enum eis_client_state old_state = client->state; - int rc = brei_dispatch(source_get_fd(source), lookup_object, client); + int rc = brei_dispatch(client->brei, source_get_fd(source), lookup_object, client); if (rc < 0) { brei_drain_fd(source_get_fd(source)); client_disconnect(client, strerror(-rc)); @@ -358,6 +359,10 @@ eis_client_new(struct eis *eis, int fd) static uint32_t client_id; struct eis_client *client = eis_client_create(&eis->object); + client->brei = brei_context_new(client); + brei_context_set_log_context(client->brei, eis); + brei_context_set_log_func(client->brei, (brei_logfunc_t)eis_log_msg_va); + client->is_sender = true; client->id = ++client_id; list_init(&client->seats); diff --git a/src/libeis-client.h b/src/libeis-client.h index 62df1d3..a7890ad 100644 --- a/src/libeis-client.h +++ b/src/libeis-client.h @@ -50,6 +50,7 @@ struct eis_client_interface_versions { struct eis_client { struct object object; + struct brei_context *brei; struct eis_connection *connection; struct list proto_objects; /* struct brei_objects list */