brei: add a brei context object

Having debugging in the brei code is useful, the only way we can do this
is by passing the log handler down.
This commit is contained in:
Peter Hutterer 2023-02-08 11:13:43 +10:00
parent 6721802059
commit da51bc095f
6 changed files with 159 additions and 21 deletions

View file

@ -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;
}

View file

@ -31,11 +31,32 @@
#include <stdarg.h>
#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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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 */