Hi, On Fri, Oct 5, 2018 at 12:00 PM Luiz Augusto von Dentz <luiz.dentz@xxxxxxxxx> wrote: > > From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> > > This adds option -m/--monitor that can be used toguether with > tester_monitor to send protocol data to be decoded by btmon. > > In addition to that this also logs the tester output into btmon since > that has support to store its output on file this can be quite > convenient for reporting. > --- > src/shared/tester.c | 237 ++++++++++++++++++++++++++++++++++++++++---- > src/shared/tester.h | 4 + > 2 files changed, 220 insertions(+), 21 deletions(-) > > diff --git a/src/shared/tester.c b/src/shared/tester.c > index 80d65110b..05c81a66d 100644 > --- a/src/shared/tester.c > +++ b/src/shared/tester.c > @@ -27,14 +27,19 @@ > > #include <stdio.h> > #include <errno.h> > +#include <syslog.h> > #include <unistd.h> > #include <stdlib.h> > #include <string.h> > #include <signal.h> > #include <sys/signalfd.h> > +#include <sys/socket.h> > > #include <glib.h> > > +#include "lib/bluetooth.h" > +#include "lib/hci.h" > + > #ifdef HAVE_VALGRIND_MEMCHECK_H > #include <valgrind/memcheck.h> > #endif > @@ -54,15 +59,15 @@ > #define COLOR_HIGHLIGHT "\x1B[1;39m" > > #define print_text(color, fmt, args...) \ > - printf(color fmt COLOR_OFF "\n", ## args) > + tester_log(color fmt COLOR_OFF, ## args) > > #define print_summary(label, color, value, fmt, args...) \ > - printf("%-52s " color "%-10s" COLOR_OFF fmt "\n", \ > + tester_log("%-52s " color "%-10s" COLOR_OFF fmt, \ > label, value, ## args) > > #define print_progress(name, color, fmt, args...) \ > - printf(COLOR_HIGHLIGHT "%s" COLOR_OFF " - " \ > - color fmt COLOR_OFF "\n", name, ## args) > + tester_log(COLOR_HIGHLIGHT "%s" COLOR_OFF " - " \ > + color fmt COLOR_OFF, name, ## args) > > enum test_result { > TEST_RESULT_NOT_RUN, > @@ -100,6 +105,7 @@ struct test_case { > }; > > static GMainLoop *main_loop; > +static char *tester_name; > > static GList *test_list; > static GList *test_current; > @@ -108,9 +114,25 @@ static GTimer *test_timer; > static gboolean option_version = FALSE; > static gboolean option_quiet = FALSE; > static gboolean option_debug = FALSE; > +static gboolean option_monitor = FALSE; > static gboolean option_list = FALSE; > static const char *option_prefix = NULL; > > +struct monitor_hdr { > + uint16_t opcode; > + uint16_t index; > + uint16_t len; > + uint8_t priority; > + uint8_t ident_len; > +} __attribute__((packed)); > + > +struct monitor_l2cap_hdr { > + uint16_t cid; > + uint16_t psm; > +} __attribute__((packed)); > + > +static int monitor_fd = -1; > + > static void test_destroy(gpointer data) > { > struct test_case *test = data; > @@ -128,43 +150,208 @@ static void test_destroy(gpointer data) > free(test); > } > > -void tester_print(const char *format, ...) > +static int monitor_open(void) > { > - va_list ap; > + struct sockaddr_hci addr; > + int fd; > + > + if (!option_monitor) > + return -1; > + > + if (monitor_fd >= 0) > + return monitor_fd; > + > + fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); > + if (fd < 0) > + return fd; > + > + memset(&addr, 0, sizeof(addr)); > + addr.hci_family = AF_BLUETOOTH; > + addr.hci_dev = HCI_DEV_NONE; > + addr.hci_channel = HCI_CHANNEL_LOGGING; > + > + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { > + option_monitor = FALSE; > + tester_debug("Failed to open monitor socket: %s", > + strerror(errno)); > + close(fd); > + return -1; > + } > + > + monitor_fd = fd; > + > + return fd; > +} > + > +static void monitor_sendmsg(const char *label, int level, struct iovec *io, > + size_t io_len) > +{ > + struct monitor_hdr hdr; > + struct msghdr msg; > + struct iovec iov[5]; > + size_t i; > + > + monitor_fd = monitor_open(); > + if (monitor_fd < 0 || io_len > 3) > + return; > + > + hdr.opcode = cpu_to_le16(0x0000); > + hdr.index = cpu_to_le16(0xffff); > + hdr.ident_len = strlen(label) + 1; > + hdr.len = cpu_to_le16(2 + hdr.ident_len); > + hdr.priority = level; > + > + iov[0].iov_base = &hdr; > + iov[0].iov_len = sizeof(hdr); > + > + iov[1].iov_base = (void *) label; > + iov[1].iov_len = hdr.ident_len; > + > + memset(&msg, 0, sizeof(msg)); > + msg.msg_iov = iov; > + msg.msg_iovlen = 2; > + > + for (i = 0; i < io_len; i++) { > + iov[i + 2] = io[i]; > + hdr.len += io[i].iov_len; > + msg.msg_iovlen++; > + } > > + if (sendmsg(monitor_fd, &msg, 0) < 0) { > + /* Disable monitor */ > + option_monitor = FALSE; > + tester_debug("Failed to send to monitor: %s", strerror(errno)); > + close(monitor_fd); > + monitor_fd = -1; > + } > +} > + > +static void monitor_vprintf(const char *id, int level, const char *format, > + va_list ap) > +{ > + struct iovec iov; > + char *str; > + > + if (!option_monitor) > + return; > + > + if (vasprintf(&str, format, ap) < 0) > + return; > + > + iov.iov_base = str; > + iov.iov_len = strlen(str) + 1; > + > + monitor_sendmsg(id, level, &iov, 1); > + > + free(str); > +} > + > +static void tester_vprintf(const char *format, va_list ap) > +{ > if (tester_use_quiet()) > return; > > printf(" %s", COLOR_WHITE); > + vprintf(format, ap); > + printf("%s\n", COLOR_OFF); > +} > + > +static void tester_log(const char *format, ...) > +{ > + va_list ap; > + > va_start(ap, format); > vprintf(format, ap); > + printf("\n"); > + va_end(ap); > + > + va_start(ap, format); > + monitor_vprintf(tester_name, LOG_INFO, format, ap); > + va_end(ap); > +} > + > +void tester_print(const char *format, ...) > +{ > + va_list ap; > + > + va_start(ap, format); > + tester_vprintf(format, ap); > + va_end(ap); > + > + va_start(ap, format); > + monitor_vprintf(tester_name, LOG_INFO, format, ap); > va_end(ap); > - printf("%s\n", COLOR_OFF); > } > > void tester_debug(const char *format, ...) > { > va_list ap; > > - if (!tester_use_debug()) > - return; > + va_start(ap, format); > + tester_vprintf(format, ap); > + va_end(ap); > > - printf(" %s", COLOR_WHITE); > va_start(ap, format); > - vprintf(format, ap); > + monitor_vprintf(tester_name, LOG_DEBUG, format, ap); > va_end(ap); > - printf("%s\n", COLOR_OFF); > } > > void tester_warn(const char *format, ...) > { > va_list ap; > > - printf(" %s", COLOR_WHITE); > va_start(ap, format); > - vprintf(format, ap); > + tester_vprintf(format, ap); > + va_end(ap); > + > + va_start(ap, format); > + monitor_vprintf(tester_name, LOG_WARNING, format, ap); > va_end(ap); > - printf("%s\n", COLOR_OFF); > +} > + > +static void monitor_debug(const char *str, void *user_data) > +{ > + const char *label = user_data; > + > + tester_debug("%s: %s", label, str); > +} > + > +static void monitor_log(char dir, uint16_t cid, uint16_t psm, const void *data, > + size_t len) > +{ > + struct iovec iov[3]; > + struct monitor_l2cap_hdr hdr; > + uint8_t term = 0x00; > + char label[16]; > + > + if (snprintf(label, sizeof(label), "%c %s", dir, tester_name) < 0) > + return; > + > + hdr.cid = cpu_to_le16(cid); > + hdr.psm = cpu_to_le16(psm); > + > + iov[0].iov_base = &hdr; > + iov[0].iov_len = sizeof(hdr); > + > + iov[1].iov_base = (void *) data; > + iov[1].iov_len = len; > + > + /* Kernel won't forward if data is no NULL terminated */ > + iov[2].iov_base = &term; > + iov[2].iov_len = sizeof(term); > + > + monitor_sendmsg(label, LOG_INFO, iov, 3); > +} > + > +void tester_monitor(char dir, uint16_t cid, uint16_t psm, const void *data, > + size_t len) > +{ > + monitor_log(dir, cid, psm, data, len); > + > + if (!tester_use_debug()) > + return; > + > + util_hexdump(dir, data, len, monitor_debug, (void *) tester_name); > } > > static void default_pre_setup(const void *test_data) > @@ -208,7 +395,7 @@ void tester_add_full(const char *name, const void *test_data, > } > > if (option_list) { > - printf("%s\n", name); > + tester_log("%s", name); > if (destroy) > destroy(user_data); > return; > @@ -278,7 +465,7 @@ static int tester_summarize(void) > gdouble execution_time; > GList *list; > > - printf("\n"); > + tester_log(""); > print_text(COLOR_HIGHLIGHT, ""); > print_text(COLOR_HIGHLIGHT, "Test Summary"); > print_text(COLOR_HIGHLIGHT, "------------"); > @@ -312,17 +499,17 @@ static int tester_summarize(void) > } > } > > - printf("\nTotal: %d, " > + tester_log("Total: %d, " > COLOR_GREEN "Passed: %d (%.1f%%)" COLOR_OFF ", " > COLOR_RED "Failed: %d" COLOR_OFF ", " > - COLOR_YELLOW "Not Run: %d" COLOR_OFF "\n", > + COLOR_YELLOW "Not Run: %d" COLOR_OFF, > not_run + passed + failed, passed, > (not_run + passed + failed) ? > (float) passed * 100 / (not_run + passed + failed) : 0, > failed, not_run); > > execution_time = g_timer_elapsed(test_timer, NULL); > - printf("Overall execution time: %.3g seconds\n", execution_time); > + tester_log("Overall execution time: %.3g seconds", execution_time); > > return failed; > } > @@ -379,7 +566,7 @@ static void next_test_case(void) > > test = test_current->data; > > - printf("\n"); > + tester_log(""); > print_progress(test->name, COLOR_BLACK, "init"); > > test->start_time = g_timer_elapsed(test_timer, NULL); > @@ -774,6 +961,8 @@ static GOptionEntry options[] = { > "Run tests without logging" }, > { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, > "Run tests with debug output" }, > + { "monitor", 'm', 0, G_OPTION_ARG_NONE, &option_monitor, > + "Enable monitor output" }, > { "list", 'l', 0, G_OPTION_ARG_NONE, &option_list, > "Only list the tests to be run" }, > { "prefix", 'p', 0, G_OPTION_ARG_STRING, &option_prefix, > @@ -807,6 +996,12 @@ void tester_init(int *argc, char ***argv) > > main_loop = g_main_loop_new(NULL, FALSE); > > + tester_name = strrchr(*argv[0], '/'); > + if (!tester_name) > + tester_name = strdup(*argv[0]); > + else > + tester_name = strdup(++tester_name); > + > test_list = NULL; > test_current = NULL; > } > diff --git a/src/shared/tester.h b/src/shared/tester.h > index 83ef5de7a..96e8dc901 100644 > --- a/src/shared/tester.h > +++ b/src/shared/tester.h > @@ -22,6 +22,8 @@ > */ > > #include <stdbool.h> > +#include <stddef.h> > +#include <stdint.h> > > void tester_init(int *argc, char ***argv); > int tester_run(void); > @@ -35,6 +37,8 @@ void tester_warn(const char *format, ...) > __attribute__((format(printf, 1, 2))); > void tester_debug(const char *format, ...) > __attribute__((format(printf, 1, 2))); > +void tester_monitor(char dir, uint16_t cid, uint16_t psm, const void *data, > + size_t len); > > typedef void (*tester_destroy_func_t)(void *user_data); > typedef void (*tester_data_func_t)(const void *test_data); > -- > 2.17.1 Applied. -- Luiz Augusto von Dentz