From ecf07e3805849cfd42435d4ea31bcba7cbdded68 Mon Sep 17 00:00:00 2001 From: Cedric Roux <cedric.roux@eurecom.fr> Date: Tue, 22 Oct 2013 13:42:39 +0000 Subject: [PATCH] - itti_analyzer v0.2: * Moved all GUI calls to main thread * Refine socket interface * Added origin/destination task id on message display list git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4258 818b1a75-f10b-46b9-bf7c-635c3b92a50f --- common/utils/itti_analyzer/configure.ac | 4 +- common/utils/itti_analyzer/itti_analyzer.c | 6 - .../utils/itti_analyzer/libbuffers/socket.c | 534 +++++++++++------- .../utils/itti_analyzer/libbuffers/socket.h | 18 +- .../utils/itti_analyzer/libparser/enum_type.c | 15 + .../utils/itti_analyzer/libparser/enum_type.h | 2 + .../utils/itti_analyzer/libparser/xml_parse.c | 79 ++- .../utils/itti_analyzer/libparser/xml_parse.h | 4 +- .../itti_analyzer/libresolver/locate_root.c | 56 +- .../itti_analyzer/libresolver/locate_root.h | 10 + common/utils/itti_analyzer/libui/Makefile.am | 18 +- .../utils/itti_analyzer/libui/ui_callbacks.c | 188 +++++- .../utils/itti_analyzer/libui/ui_callbacks.h | 2 + .../utils/itti_analyzer/libui/ui_interface.c | 100 +++- .../utils/itti_analyzer/libui/ui_interface.h | 94 +-- .../itti_analyzer/libui/ui_main_screen.h | 2 + .../utils/itti_analyzer/libui/ui_notif_dlg.c | 24 + .../utils/itti_analyzer/libui/ui_notif_dlg.h | 17 + .../itti_analyzer/libui/ui_notifications.c | 32 +- .../itti_analyzer/libui/ui_notifications.h | 2 - .../utils/itti_analyzer/libui/ui_tree_view.c | 56 +- .../utils/itti_analyzer/libui/ui_tree_view.h | 13 +- 22 files changed, 873 insertions(+), 403 deletions(-) create mode 100644 common/utils/itti_analyzer/libui/ui_notif_dlg.c create mode 100644 common/utils/itti_analyzer/libui/ui_notif_dlg.h diff --git a/common/utils/itti_analyzer/configure.ac b/common/utils/itti_analyzer/configure.ac index 72f542f82d..a4b19b26c3 100644 --- a/common/utils/itti_analyzer/configure.ac +++ b/common/utils/itti_analyzer/configure.ac @@ -4,7 +4,7 @@ define([svnversion], esyscmd([sh -c "svnversion ..|tr -d '\n'"])) AC_DEFINE(SVN_REVISION, "svnversion", [SVN Revision]) -AC_INIT([itti_debugger], [0.1.svnversion], [openair_admin@eurecom.fr]) +AC_INIT([itti_debugger], [0.2.svnversion], [openair_admin@eurecom.fr]) AC_CANONICAL_BUILD AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([1.11 silent-rules]) @@ -90,4 +90,4 @@ AC_CONFIG_FILES( libui/Makefile \ Makefile \ ) -AC_OUTPUT \ No newline at end of file +AC_OUTPUT diff --git a/common/utils/itti_analyzer/itti_analyzer.c b/common/utils/itti_analyzer/itti_analyzer.c index bd9d80f16c..2a61e57824 100644 --- a/common/utils/itti_analyzer/itti_analyzer.c +++ b/common/utils/itti_analyzer/itti_analyzer.c @@ -75,12 +75,6 @@ int main(int argc, char *argv[]) G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION); - if (!g_thread_supported()) - g_thread_init(NULL); - - /* Secure gtk */ - gdk_threads_init(); - /* Initialize the widget set */ gtk_init(&argc, &argv); diff --git a/common/utils/itti_analyzer/libbuffers/socket.c b/common/utils/itti_analyzer/libbuffers/socket.c index 18f76295e8..fb8a6ee553 100644 --- a/common/utils/itti_analyzer/libbuffers/socket.c +++ b/common/utils/itti_analyzer/libbuffers/socket.c @@ -5,6 +5,7 @@ #include <string.h> #include <unistd.h> #include <errno.h> +#include <fcntl.h> #include <gtk/gtk.h> @@ -12,21 +13,15 @@ #include "ui_interface.h" #include "ui_notifications.h" +#include "ui_notif_dlg.h" #include "socket.h" #include "buffers.h" #include "xml_parse.h" -#define BUFFER_SIZE 3000 -#define MAX_ATTEMPTS 10 - -socket_data_t socket_data; - -typedef struct { - char ip_address[16]; - uint16_t port; -} socket_arg_t; +#define SOCKET_NB_SIGNALS_BEFORE_SIGNALLING 10 +#define SOCKET_MS_BEFORE_SIGNALLING 100 /* Message header is the common part that should never change between * remote process and this one. @@ -40,241 +35,380 @@ typedef struct { typedef struct { uint32_t message_number; char signal_name[50]; -} itti_dump_message_t; +} itti_signal_header_t; -void *socket_read_data(void *arg); +void *socket_thread_fct(void *arg); -void *socket_read_data(void *arg) +static ssize_t socket_read_data(socket_data_t *socket_data, void *buffer, size_t size, int flags) { - int ret; - int attempts = MAX_ATTEMPTS; - int *sd = &socket_data.sd; - struct sockaddr_in *si_me = &socket_data.si_me; - socket_arg_t *socket_arg; + ssize_t recv_ret; + + recv_ret = recv(socket_data->sd, buffer, size, flags); + if (recv_ret == -1) { + /* Failure case */ + switch (errno) { +// case EWOULDBLOCK: + case EAGAIN: + return -1; + default: + g_debug("recv failed: %s", g_strerror(errno)); + pthread_exit(NULL); + break; + } + } else if (recv_ret == 0) { + /* We lost the connection with other peer or shutdown asked */ + ui_pipe_write_message(socket_data->pipe_fd, + UI_PIPE_CONNECTION_LOST, NULL, 0); + free(socket_data->ip_address); + free(socket_data); + pthread_exit(NULL); + } - socket_arg = (socket_arg_t *)arg; + return recv_ret; +} - memset(&socket_data, 0, sizeof(socket_data_t)); +static void socket_notify_gui_update(socket_data_t *socket_data) +{ + pipe_new_signals_list_message_t pipe_signal_list_message; - /* Enable the cancel attribute for the thread. - * Set the cancel type to asynchronous. The thread termination is requested - * to happen now. - */ - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pipe_signal_list_message.signal_list = socket_data->signal_list; - *sd = -1; + socket_data->signal_list = NULL; + socket_data->nb_signals_since_last_update = 0; - if ((*sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - fprintf(stderr, "socket failed\n"); - goto fail; - } - memset((void *)si_me, 0, sizeof(si_me)); + /* Send an update notification */ + ui_pipe_write_message(socket_data->pipe_fd, + UI_PIPE_UPDATE_SIGNAL_LIST, &pipe_signal_list_message, + sizeof(pipe_signal_list_message)); + + /* Acquire the last data notification */ + socket_data->last_data_notification = g_get_monotonic_time(); +} - si_me->sin_family = AF_INET; - si_me->sin_port = htons(socket_arg->port); - if (inet_aton(socket_arg->ip_address, &si_me->sin_addr) == 0) { - fprintf(stderr, "inet_aton() failed\n"); - goto fail; +static int socket_read_itti_message(socket_data_t *socket_data, + itti_socket_header_t *message_header) +{ + itti_signal_header_t itti_signal_header; + buffer_t *buffer; + uint8_t *data; + size_t data_length; + ssize_t data_read = 0; + ssize_t total_data_read = 0; + + g_assert(message_header != NULL); + + g_debug("Attempting to read signal header from socket"); + + /* Read the sub-header of signal */ + while (data_read != sizeof(itti_signal_header_t)) { + data_read = socket_read_data(socket_data, &itti_signal_header, + sizeof(itti_signal_header_t), 0); } - do { - ret = connect(*sd, (struct sockaddr *)si_me, sizeof(struct sockaddr_in)); - if (ret == 0) { - break; + data_length = message_header->message_size - sizeof(itti_socket_header_t) - sizeof(itti_signal_header_t); + data = malloc(sizeof(uint8_t) * data_length); + + while (total_data_read != data_length) { + data_read = socket_read_data(socket_data, &data[total_data_read], + data_length - total_data_read, 0); + /* We are waiting for data */ + if (data_read < 0) { + usleep(10); + } else { + total_data_read += data_read; } - attempts --; - sleep(1); - if (attempts == 0) { - printf("Cannot connect to %s with port %u:\n" - "Reached maximum retry count\nEnsure host is alive", - socket_arg->ip_address, socket_arg->port); - /* ????? */ - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Cannot connect to %s with port %u:\n" - "Reached maximum retry count\nEnsure host is alive", - socket_arg->ip_address, socket_arg->port); - ui_interface.ui_enable_connect_button(); + } - pthread_exit(NULL); - } - } while(ret != 0); - - while(1) { - uint8_t *data; - size_t data_length; - itti_socket_header_t message_header; - int recv_ret; - buffer_t *buffer; - - memset(&message_header, 0, sizeof(itti_socket_header_t)); - - /* First run acquire message header - * TODO: check for remote endianness when retrieving the structure... - */ - recv_ret = recvfrom(socket_data.sd, &message_header, sizeof(itti_socket_header_t), MSG_WAITALL, NULL, 0); - if (recv_ret == -1) { - /* Failure case */ - fprintf(stderr, "recvfrom failed\n"); - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Unexpected error while reading from socket\n%d:%s", - errno, strerror(errno)); - ui_interface.ui_enable_connect_button(); - pthread_exit(NULL); - } else if (recv_ret == 0) { - /* We lost the connection with other peer or shutdown asked */ - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Connection with remote host has been lost"); - ui_interface.ui_enable_connect_button(); - pthread_exit(NULL); + /* Create the new buffer */ + if (buffer_new_from_data(&buffer, data, data_length, 1) != RC_OK) { + g_error("Failed to create new buffer"); + g_assert_not_reached(); + } + + buffer->message_number = itti_signal_header.message_number; + buffer_dump(buffer, stdout); + + /* Update the number of signals received since last GUI update */ + socket_data->nb_signals_since_last_update++; + + socket_data->signal_list = g_list_append(socket_data->signal_list, (gpointer)buffer); + + if (socket_data->nb_signals_since_last_update >= SOCKET_NB_SIGNALS_BEFORE_SIGNALLING) { + socket_notify_gui_update(socket_data); + } + +// CHECK_FCT_DO(buffer_add_to_list(buffer), pthread_exit(NULL)); + + + g_debug("Successfully read new signal %u from socket", itti_signal_header.message_number); + + return total_data_read + sizeof(itti_signal_header); +} + +static int socket_read_xml_definition(socket_data_t *socket_data, + itti_socket_header_t *message_header) +{ + ssize_t data_read; + ssize_t total_data_read = 0; + char *xml_definition; + size_t xml_definition_length; + pipe_xml_definition_message_t pipe_xml_definition_message; + + xml_definition_length = message_header->message_size - sizeof(*message_header); + xml_definition = malloc(xml_definition_length * sizeof(char)); + + g_debug("Attempting to read XML definition of size %zu from socket", + xml_definition_length); + + /* XML definition is a long message... so function may take some time */ + + do { + data_read = socket_read_data(socket_data, &xml_definition[total_data_read], + xml_definition_length - total_data_read, 0); + + /* We are waiting for data */ + if (data_read < 0) { + usleep(10); + } else { + total_data_read += data_read; } + } while (total_data_read != xml_definition_length); - switch(message_header.message_type) { - case 1: { - itti_dump_message_t itti_dump_header; - - memset(&itti_dump_header, 0, sizeof(itti_dump_message_t)); - - /* second run: acquire the sub-header for itti dump message type */ - recv_ret = recvfrom(socket_data.sd, &itti_dump_header, sizeof(itti_dump_message_t), MSG_WAITALL, NULL, 0); - if (recv_ret == -1) { - /* Failure case */ - fprintf(stderr, "recvfrom failed\n"); - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Unexpected error while reading from socket\n%d:%s", - errno, strerror(errno)); - ui_interface.ui_enable_connect_button(); - pthread_exit(NULL); - } else if (recv_ret == 0) { - /* We lost the connection with other peer or shutdown asked */ - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Connection with remote host has been lost"); - ui_interface.ui_enable_connect_button(); - pthread_exit(NULL); - } + pipe_xml_definition_message.xml_definition = xml_definition; + pipe_xml_definition_message.xml_definition_length = xml_definition_length; - data_length = message_header.message_size - sizeof(itti_socket_header_t) - sizeof(itti_dump_message_t); - data = malloc(sizeof(uint8_t) * data_length); - - /* third run: acquire the MessageDef part */ - recv_ret = recvfrom(socket_data.sd, data, data_length, MSG_WAITALL, NULL, 0); - if (recv_ret == -1) { - /* Failure case */ - fprintf(stderr, "recvfrom failed\n"); - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Unexpected error while reading from socket\n%d:%s", - errno, strerror(errno)); - ui_interface.ui_enable_connect_button(); - pthread_exit(NULL); - } else if (recv_ret == 0) { - /* We lost the connection with other peer or shutdown asked */ - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Connection with remote host has been lost"); - ui_interface.ui_enable_connect_button(); - pthread_exit(NULL); - } + g_debug("Received XML definition of size %zu, effectively read %zu bytes", + xml_definition_length, total_data_read); - /* Create the new buffer */ - if (buffer_new_from_data(&buffer, data, data_length, 1) != RC_OK) { - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Cannot connect to %s with port %u", - socket_arg->ip_address, socket_arg->port); - ui_interface.ui_enable_connect_button(); - pthread_exit(NULL); - } + ui_pipe_write_message(socket_data->pipe_fd, UI_PIPE_XML_DEFINITION, + &pipe_xml_definition_message, sizeof(pipe_xml_definition_message)); - buffer->message_number = itti_dump_header.message_number; - buffer_dump(buffer, stdout); + return total_data_read; +} - CHECK_FCT_DO(buffer_add_to_list(buffer), pthread_exit(NULL)); +static int socket_read(socket_data_t *socket_data) +{ + int ret = 0; + itti_socket_header_t message_header; - ui_interface.ui_tree_view_new_signal_ind(itti_dump_header.message_number, - itti_dump_header.signal_name); - } break; - case 2: - /* The received message is a statistic signal */ - break; - case 3: { - char *xml_definition; - uint32_t xml_definition_length; - - xml_definition_length = message_header.message_size - sizeof(message_header); - - xml_definition = malloc(xml_definition_length); - - recv_ret = recvfrom(socket_data.sd, xml_definition, xml_definition_length, MSG_WAITALL, NULL, 0); - if (recv_ret == -1) { - /* Failure case */ - fprintf(stderr, "recvfrom failed\n"); - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Unexpected error while reading from socket\n%d:%s", - errno, strerror(errno)); - ui_interface.ui_enable_connect_button(); - pthread_exit(NULL); - } else if (recv_ret == 0) { - /* We lost the connection with other peer or shutdown asked */ - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Connection with remote host has been lost"); - ui_interface.ui_enable_connect_button(); - pthread_exit(NULL); - } + while (ret >= 0) { + ret = socket_read_data(socket_data, &message_header, sizeof(message_header), 0); - fprintf(stdout, "Received XML definition of length %u\n", - xml_definition_length); + if (ret == -1) { + break; + } - xml_parse_buffer(xml_definition, xml_definition_length); - } break; + switch(message_header.message_type) { + case 1: + socket_read_itti_message(socket_data, &message_header); + break; + case 3: + socket_read_xml_definition(socket_data, &message_header); + break; + case 2: default: - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Received unknown message type\n"); + g_debug("Received unknow (or not implemented) message from socket type: %d", + message_header.message_type); break; } } - return NULL; + return 0; +} + +static int socket_handle_disconnect_evt(socket_data_t *socket_data) +{ + /* Send shutdown to remote host */ + CHECK_FCT_POSIX(shutdown(socket_data->sd, SHUT_RDWR)); + /* Close file descriptor */ + CHECK_FCT_POSIX(close(socket_data->sd)); -fail: - ui_interface.ui_notification_dialog( - DIALOG_ERROR, "Cannot connect to %s with port %u", - socket_arg->ip_address, socket_arg->port); - ui_interface.ui_enable_connect_button(); + socket_data->sd = -1; + + /* Close pipe */ + close(socket_data->pipe_fd); + + /* Leaving the thread */ pthread_exit(NULL); + + return 0; } -int socket_disconnect_from_remote_host(void) +static int pipe_read_message(socket_data_t *socket_data) { - void *ret_val; + pipe_input_header_t input_header; + uint8_t *input_data = NULL; + size_t input_data_length = 0; + + /* Read the header */ + if (read(socket_data->pipe_fd, &input_header, sizeof(input_header)) < 0) { + g_warning("Failed to read from pipe %d: %s", socket_data->pipe_fd, + g_strerror(errno)); + return -1; + } - printf("Closing socket %d\n", socket_data.sd); + input_data_length = input_header.message_size - sizeof(input_header); - /* Cancel the thread */ - pthread_cancel(socket_data.thread); - pthread_join(socket_data.thread, &ret_val); + /* Checking for non-header part */ + if (input_data_length > 0) { + input_data = malloc(sizeof(uint8_t) * input_data_length); - /* Send shutdown to remote host */ - CHECK_FCT_POSIX(shutdown(socket_data.sd, SHUT_RDWR)); - CHECK_FCT_POSIX(close(socket_data.sd)); + if (read(socket_data->pipe_fd, input_data, input_data_length) < 0) { + g_warning("Failed to read from pipe %d: %s", socket_data->pipe_fd, + g_strerror(errno)); + return -1; + } + } - socket_data.sd = -1; - ui_interface.ui_enable_connect_button(); + switch (input_header.message_type) { + case UI_PIPE_DISCONNECT_EVT: + return socket_handle_disconnect_evt(socket_data); + default: + g_debug("[socket] Unhandled message type %u", input_header.message_type); + g_assert_not_reached(); + } + return 0; +} - return RC_OK; +void *socket_thread_fct(void *arg) +{ + int ret; + struct sockaddr_in si_me; + socket_data_t *socket_data; + + /* master file descriptor list */ + fd_set master_fds; + /* temp file descriptor list for select() */ + fd_set read_fds; + int fd_max = 0; + struct timeval tv; + + socket_data = (socket_data_t *)arg; + + g_assert(socket_data != NULL); + + /* Preparing the socket */ + if ((socket_data->sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + g_debug("socket failed: %s", g_strerror(errno)); + free(socket_data->ip_address); + free(socket_data); + pthread_exit(NULL); + } + memset((void *)&si_me, 0, sizeof(si_me)); + + si_me.sin_family = AF_INET; + si_me.sin_port = htons(socket_data->port); + if (inet_aton(socket_data->ip_address, &si_me.sin_addr) == 0) { + g_debug("inet_aton() failed\n"); + free(socket_data->ip_address); + free(socket_data); + pthread_exit(NULL); + } + + /* clear the master and temp sets */ + FD_ZERO(&master_fds); + FD_ZERO(&read_fds); + + /* Add the GUI pipe to the list of sockets to monitor */ + FD_SET(socket_data->pipe_fd, &master_fds); + + /* Add the client socket to the list of sockets to monitor */ + FD_SET(socket_data->sd, &master_fds); + + /* Update the fd_max with the MAX of socket/pipe */ + fd_max = MAX(socket_data->pipe_fd, socket_data->sd); + + /* Setup the timeout for select. + * When a timeout is caught, check for new notifications to send to GUI. + */ + tv.tv_sec = 0; + tv.tv_usec = 1000 * SOCKET_MS_BEFORE_SIGNALLING; + + /* Connecting to remote peer */ + ret = connect(socket_data->sd, (struct sockaddr *)&si_me, sizeof(struct sockaddr_in)); + if (ret < 0) { + g_debug("Failed to connect to peer %s:%d", + socket_data->ip_address, socket_data->port); + ui_pipe_write_message(socket_data->pipe_fd, + UI_PIPE_CONNECTION_FAILED, NULL, 0); + free(socket_data->ip_address); + free(socket_data); + /* Quit the thread */ + pthread_exit(NULL); + } + + /* Set the socket as non-blocking */ + fcntl(socket_data->sd, F_SETFL, O_NONBLOCK); + + while (1) { + memcpy(&read_fds, &master_fds, sizeof(master_fds)); + + ret = select(fd_max + 1, &read_fds, NULL, NULL, &tv); + if (ret < 0) { + g_debug("Error in select: %s", g_strerror(errno)); + free(socket_data->ip_address); + free(socket_data); + /* Quit the thread */ + pthread_exit(NULL); + } else if (ret == 0) { + /* Timeout for select: check if there is new incoming messages since last update of GUI + */ + if (socket_data->nb_signals_since_last_update > 0) { + socket_notify_gui_update(socket_data); + } + + /* Reset the timeval to the max value */ + tv.tv_usec = 1000 * SOCKET_MS_BEFORE_SIGNALLING; + } + + /* Checking if there is data to read from the pipe */ + if (FD_ISSET(socket_data->pipe_fd, &read_fds)) { + pipe_read_message(socket_data); + FD_CLR(socket_data->pipe_fd, &master_fds); + } + + /* Checking if there is data to read from the socket */ + if (FD_ISSET(socket_data->sd, &read_fds)) { + socket_read(socket_data); + FD_CLR(socket_data->sd, &master_fds); + + /* Update the timeout of select if there is data not notify to GUI */ + if (socket_data->nb_signals_since_last_update > 0) { + gint64 current_time; + + current_time = g_get_monotonic_time(); + + if ((current_time - socket_data->last_data_notification) > SOCKET_MS_BEFORE_SIGNALLING) { + socket_notify_gui_update(socket_data); + tv.tv_usec = 1000 * SOCKET_MS_BEFORE_SIGNALLING; + } else { + /* Update tv */ + tv.tv_usec = SOCKET_MS_BEFORE_SIGNALLING - (current_time - socket_data->last_data_notification); + } + } + } + } + + return NULL; } -int socket_connect_to_remote_host(const char *remote_ip, const uint16_t port) +int socket_connect_to_remote_host(const char *remote_ip, const uint16_t port, + int pipe_fd) { - socket_arg_t *socket_arg; + socket_data_t *socket_data; - socket_arg = malloc(sizeof(socket_arg_t)); + socket_data = calloc(1, sizeof(*socket_data)); - ui_interface.ui_disable_connect_button(); + socket_data->ip_address = strdup(remote_ip); - memcpy(socket_arg->ip_address, remote_ip, strlen(remote_ip) + 1); - socket_arg->port = port; + socket_data->pipe_fd = pipe_fd; + socket_data->port = port; + socket_data->sd = -1; - if (pthread_create(&socket_data.thread, NULL, socket_read_data, socket_arg) != 0) { - fprintf(stderr, "pthread_create failed\n"); - ui_interface.ui_enable_connect_button(); + if (pthread_create(&socket_data->thread, NULL, socket_thread_fct, socket_data) != 0) { + g_warning("Failed to create thread %d:%s", errno, strerror(errno)); + free(socket_data->ip_address); + free(socket_data); return RC_FAIL; } diff --git a/common/utils/itti_analyzer/libbuffers/socket.h b/common/utils/itti_analyzer/libbuffers/socket.h index 05a14491c4..d5396660da 100644 --- a/common/utils/itti_analyzer/libbuffers/socket.h +++ b/common/utils/itti_analyzer/libbuffers/socket.h @@ -6,13 +6,23 @@ typedef struct { pthread_t thread; - uint16_t port; - char *remote_ip; int sd; - struct sockaddr_in si_me; + char *ip_address; + uint16_t port; + + /* The pipe used between main thread (running GTK) and the socket thread */ + int pipe_fd; + + /* Time used to avoid refreshing UI every time a new signal is incoming */ + gint64 last_data_notification; + uint8_t nb_signals_since_last_update; + + /* The last signals received which are not yet been updated in GUI */ + GList *signal_list; } socket_data_t; -int socket_connect_to_remote_host(const char *remote_ip, const uint16_t port); +int socket_connect_to_remote_host(const char *remote_ip, const uint16_t port, + int pipe_fd); int socket_disconnect_from_remote_host(void); diff --git a/common/utils/itti_analyzer/libparser/enum_type.c b/common/utils/itti_analyzer/libparser/enum_type.c index 2ea2bf7832..dbaca92f18 100644 --- a/common/utils/itti_analyzer/libparser/enum_type.c +++ b/common/utils/itti_analyzer/libparser/enum_type.c @@ -6,6 +6,21 @@ #include "enum_type.h" #include "ui_interface.h" +char *enum_type_get_name_from_value(struct types_s *type, uint32_t value) +{ + char *enum_name = "UNKNOWN"; + types_t *enum_value; + + /* Loop on eache enumeration values */ + for (enum_value = type->child; enum_value; enum_value = enum_value->next) { + if (value == enum_value->init_value) { + enum_name = enum_value->name; + break; + } + } + return enum_name; +} + int enum_type_dissect_from_buffer( struct types_s *type, buffer_t *buffer, uint32_t offset, uint32_t parent_offset, int indent) diff --git a/common/utils/itti_analyzer/libparser/enum_type.h b/common/utils/itti_analyzer/libparser/enum_type.h index 7544d78660..1c153a0ccb 100644 --- a/common/utils/itti_analyzer/libparser/enum_type.h +++ b/common/utils/itti_analyzer/libparser/enum_type.h @@ -3,6 +3,8 @@ #ifndef ENUM_TYPE_H_ #define ENUM_TYPE_H_ +char *enum_type_get_name_from_value(struct types_s *type, uint32_t value); + int enum_type_dissect_from_buffer( struct types_s *type, buffer_t *buffer, uint32_t offset, uint32_t parent_offset, int indent); diff --git a/common/utils/itti_analyzer/libparser/xml_parse.c b/common/utils/itti_analyzer/libparser/xml_parse.c index b5366af091..2ec4b8ece7 100644 --- a/common/utils/itti_analyzer/libparser/xml_parse.c +++ b/common/utils/itti_analyzer/libparser/xml_parse.c @@ -9,6 +9,7 @@ #include "union_type.h" #include "ui_interface.h" +#include "ui_notif_dlg.h" #include "../libresolver/locate_root.h" #include "../libresolver/resolvers.h" @@ -21,15 +22,15 @@ extern int debug_parser; # define INDENT_START 0 #endif -#define PARSER_DEBUG(fmt, args...) \ -do { \ - if (debug_parser) \ - fprintf(stdout, "WARNING: "fmt, ##args); \ +#define PARSER_DEBUG(fmt, args...) \ +do { \ + if (debug_parser) \ + g_debug("WARNING: "fmt, ##args); \ } while(0) #define PARSER_ERROR(fmt, args...) \ do { \ - fprintf(stderr, "FATAL: "fmt, ##args); \ + g_error("FATAL: "fmt, ##args); \ } while(0) types_t *root = NULL; @@ -582,66 +583,54 @@ static int parse_pointer_type(xmlNode *node, types_t **head) { static int parse_elements(xmlNode * a_node, types_t **head) { xmlNode *cur_node = NULL; xmlNode *child_node = NULL; - unsigned long nb_nodes; - unsigned long node_count = 0; - - nb_nodes = xmlChildElementCount (a_node); for (cur_node = a_node; cur_node; cur_node = cur_node->next) { - node_count++; - sleep (1); - ui_interface.ui_progress_bar_set_fraction ((double) node_count / nb_nodes); for (child_node = cur_node->children; child_node; child_node = child_node->next) { if (child_node->type == XML_ELEMENT_NODE) { if (strcmp ((char *) child_node->name, "Enumeration") == 0) { - CHECK_FCT_DO(parse_enumeration(child_node, head), goto fail); + CHECK_FCT_DO(parse_enumeration(child_node, head), return RC_FAIL); } else if (strcmp ((char *) child_node->name, "FundamentalType") == 0) { - CHECK_FCT_DO(parse_fundamental(child_node, head), goto fail); + CHECK_FCT_DO(parse_fundamental(child_node, head), return RC_FAIL); } else if (strcmp ((char *) child_node->name, "Struct") == 0) { - CHECK_FCT_DO(parse_struct(child_node, head), goto fail); + CHECK_FCT_DO(parse_struct(child_node, head), return RC_FAIL); } else if (strcmp ((char *) child_node->name, "Union") == 0) { - CHECK_FCT_DO(parse_union(child_node, head), goto fail); + CHECK_FCT_DO(parse_union(child_node, head), return RC_FAIL); } else if (strcmp ((char *) child_node->name, "Typedef") == 0) { - CHECK_FCT_DO(parse_typedef(child_node, head), goto fail); + CHECK_FCT_DO(parse_typedef(child_node, head), return RC_FAIL); } else if (strcmp ((char *) child_node->name, "File") == 0) { - CHECK_FCT_DO(parse_file(child_node, head), goto fail); + CHECK_FCT_DO(parse_file(child_node, head), return RC_FAIL); } else if (strcmp ((char *) child_node->name, "Field") == 0) { - CHECK_FCT_DO(parse_field(child_node, head), goto fail); + CHECK_FCT_DO(parse_field(child_node, head), return RC_FAIL); } else if (strcmp ((char *) child_node->name, "ReferenceType") == 0) { - CHECK_FCT_DO(parse_reference_type(child_node, head), goto fail); + CHECK_FCT_DO(parse_reference_type(child_node, head), return RC_FAIL); } else if (strcmp ((char *) child_node->name, "ArrayType") == 0) { - CHECK_FCT_DO(parse_array_type(child_node, head), goto fail); + CHECK_FCT_DO(parse_array_type(child_node, head), return RC_FAIL); } else if (strcmp ((char *) child_node->name, "PointerType") == 0) { - CHECK_FCT_DO(parse_pointer_type(child_node, head), goto fail); + CHECK_FCT_DO(parse_pointer_type(child_node, head), return RC_FAIL); } } } } - ui_interface.ui_progress_bar_terminate (); - return RC_OK; - - fail: ui_interface.ui_progress_bar_terminate (); - return RC_FAIL; } int xml_parse_buffer(const char *xml_buffer, const int size) { @@ -651,7 +640,7 @@ int xml_parse_buffer(const char *xml_buffer, const int size) { return -1; } - fprintf(stdout, "Parsing XML definition from buffer\n"); + g_debug("Parsing XML definition from buffer"); /* This initialize the library and check potential ABI mismatches * between the version it was compiled for and the actual shared @@ -662,8 +651,8 @@ int xml_parse_buffer(const char *xml_buffer, const int size) { doc = xmlReadMemory(xml_buffer, size, NULL, NULL, 0); if (doc == NULL) { - fprintf (stderr, "Failed to parse buffer: %s\n", xml_buffer); - ui_interface.ui_notification_dialog (DIALOG_WARNING, "Fail to parse XML buffer"); + g_warning("Failed to parse buffer: %s", xml_buffer); +// ui_notification_dialog(DIALOG_WARNING, "Fail to parse XML buffer"); return RC_FAIL; } @@ -686,8 +675,8 @@ int xml_parse_file(const char *filename) { doc = xmlReadFile (filename, NULL, 0); if (doc == NULL) { - fprintf (stderr, "Failed to parse %s\n", filename); - ui_interface.ui_notification_dialog (DIALOG_WARNING, "Failed to parse file %s", filename); + g_warning("Failed to parse %s\n", filename); +// ui_notification_dialog(DIALOG_WARNING, "Failed to parse file %s", filename); return RC_FAIL; } @@ -703,17 +692,17 @@ static int xml_parse_doc(xmlDocPtr doc) { dissect_file = fopen ("./dissect.xml", "w"); /* Get the root element node */ - root_element = xmlDocGetRootElement (doc); + root_element = xmlDocGetRootElement(doc); - ret = parse_elements (root_element, &head); + ret = parse_elements(root_element, &head); /* Free the document */ - xmlFreeDoc (doc); + xmlFreeDoc(doc); /* Free the global variables that may * have been allocated by the parser. */ - xmlCleanupParser (); + xmlCleanupParser(); if (ret == RC_OK) { resolve_typedefs (&head); @@ -724,34 +713,38 @@ static int xml_parse_doc(xmlDocPtr doc) { resolve_struct (&head); resolve_file (&head); resolve_union (&head); + /* Locate the root element which corresponds to the MessageDef struct */ CHECK_FCT(locate_root("MessageDef", head, &root)); + /* Locate the message id enumeration */ + CHECK_FCT(locate_type("MessagesIds", head, &messages_id_enum)); + CHECK_FCT(locate_type("originTaskId", head, &origin_task_id_type)); + CHECK_FCT(locate_type("destinationTaskId", head, &destination_task_id_type)); // root->type_hr_display(root, 0); if (dissect_file != NULL) { root->type_file_print (root, 0, dissect_file); } - ui_interface.dissector_ready = 1; } fclose (dissect_file); return ret; } -int dissect_signal(const uint32_t message_number) { - buffer_t *buffer; +int dissect_signal(buffer_t *buffer) { +// buffer_t *buffer; if (root == NULL) { - ui_interface.ui_notification_dialog (DIALOG_ERROR, "No message XML file provided"); +// ui_notification_dialog(DIALOG_ERROR, "No message XML file provided"); return RC_FAIL; } - CHECK_FCT(buffer_get_from_mn(message_number, &buffer)); +// CHECK_FCT(buffer_get_from_mn(message_number, &buffer)); if (buffer == NULL) { - fprintf (stderr, "Failed buffer %u in list\n", message_number); + g_error("Failed buffer is NULL\n"); return RC_FAIL; } - root->type_dissect_from_buffer (root, buffer, 0, 0, INDENT_START); + root->type_dissect_from_buffer(root, buffer, 0, 0, INDENT_START); return RC_OK; } diff --git a/common/utils/itti_analyzer/libparser/xml_parse.h b/common/utils/itti_analyzer/libparser/xml_parse.h index b1df13ea89..5bc56dd9aa 100644 --- a/common/utils/itti_analyzer/libparser/xml_parse.h +++ b/common/utils/itti_analyzer/libparser/xml_parse.h @@ -4,10 +4,12 @@ #ifndef XML_PARSE_H_ #define XML_PARSE_H_ +extern types_t *root; + int xml_parse_file(const char *filename); int xml_parse_buffer(const char *xml_buffer, const int size); -int dissect_signal(const uint32_t message_number); +int dissect_signal(buffer_t *buffer); #endif /* XML_PARSE_H_ */ diff --git a/common/utils/itti_analyzer/libresolver/locate_root.c b/common/utils/itti_analyzer/libresolver/locate_root.c index e0eaadfdff..8a6ff94877 100644 --- a/common/utils/itti_analyzer/libresolver/locate_root.c +++ b/common/utils/itti_analyzer/libresolver/locate_root.c @@ -6,9 +6,15 @@ #include "rc.h" #include "types.h" +#include "enum_type.h" #include "locate_root.h" +#include "xml_parse.h" -int locate_root(const char *root_name, types_t *head, types_t **root) { +types_t *messages_id_enum = NULL; +types_t *origin_task_id_type = NULL; +types_t *destination_task_id_type = NULL; + +int locate_root(const char *root_name, types_t *head, types_t **root_elm) { types_t *next_type; /* The root element is for example : MessageDef. @@ -22,7 +28,7 @@ int locate_root(const char *root_name, types_t *head, types_t **root) { g_warning("Empty list detected"); return -1; } - if (!root) { + if (!root_elm) { g_warning("NULL root reference"); return -1; } @@ -35,7 +41,7 @@ int locate_root(const char *root_name, types_t *head, types_t **root) { break; } } - *root = next_type; + *root_elm = next_type; return (next_type == NULL) ? -2 : 0; } @@ -46,7 +52,7 @@ int locate_type(const char *type_name, types_t *head, types_t **type) { * This element is the entry for other sub-types. */ if (!type_name) { - g_warning("FATAL: no root element name provided"); + g_warning("FATAL: no element name provided"); return RC_BAD_PARAM; } if (!head) { @@ -69,16 +75,46 @@ int locate_type(const char *type_name, types_t *head, types_t **type) { int get_message_id(types_t *head, buffer_t *buffer, uint32_t *message_id) { uint32_t value; - types_t *type_message_id; - - if (!head || !message_id || !buffer) - return RC_BAD_PARAM; - CHECK_FCT(locate_type("messageId", head, &type_message_id)); + g_assert(message_id != NULL); + g_assert(buffer != NULL); /* MessageId is an offset from start of buffer */ - value = buffer_get_uint32_t (buffer, type_message_id->offset); + value = buffer_get_uint32_t(buffer, messages_id_enum->offset); *message_id = value; return RC_OK; } + +char *get_origin_task_id(buffer_t *buffer) { + char *origin_task_id = "UNKNOWN"; + uint32_t origin_task_id_value; + + /* Fetch task id value */ + if (buffer_fetch_bits(buffer, origin_task_id_type->offset, + origin_task_id_type->child->size, &origin_task_id_value) == RC_OK) { + origin_task_id = enum_type_get_name_from_value(origin_task_id_type->child, + origin_task_id_value); + } + + return origin_task_id; +} + +char *get_destination_task_id(buffer_t *buffer) { + char *destination_task_id = "UNKNOWN"; + uint32_t destination_task_id_value; + + /* Fetch task id value */ + if (buffer_fetch_bits(buffer, destination_task_id_type->offset, + destination_task_id_type->child->size, &destination_task_id_value) == RC_OK) { + destination_task_id = enum_type_get_name_from_value(destination_task_id_type->child, + destination_task_id_value); + } + + return destination_task_id; +} + +char *message_id_to_string(uint32_t message_id) +{ + return enum_type_get_name_from_value(messages_id_enum, message_id); +} diff --git a/common/utils/itti_analyzer/libresolver/locate_root.h b/common/utils/itti_analyzer/libresolver/locate_root.h index 0cfab65fe2..96b489e0dc 100644 --- a/common/utils/itti_analyzer/libresolver/locate_root.h +++ b/common/utils/itti_analyzer/libresolver/locate_root.h @@ -1,10 +1,20 @@ #ifndef LOCATE_ROOT_H_ #define LOCATE_ROOT_H_ +extern types_t *messages_id_enum; +extern types_t *origin_task_id_type; +extern types_t *destination_task_id_type; + int locate_root(const char *root_name, types_t *head, types_t **root); int locate_type(const char *type_name, types_t *head, types_t **type); int get_message_id(types_t *head, buffer_t *buffer, uint32_t *message_id); +char *message_id_to_string(uint32_t message_id); + +char *get_origin_task_id(buffer_t *buffer); + +char *get_destination_task_id(buffer_t *buffer); + #endif /* LOCATE_ROOT_H_ */ diff --git a/common/utils/itti_analyzer/libui/Makefile.am b/common/utils/itti_analyzer/libui/Makefile.am index 4c42ead836..8a74c0b2cf 100644 --- a/common/utils/itti_analyzer/libui/Makefile.am +++ b/common/utils/itti_analyzer/libui/Makefile.am @@ -2,17 +2,19 @@ AM_CFLAGS = \ @ADD_CFLAGS@ \ -I$(top_srcdir)/common \ -I$(top_srcdir)/libbuffers \ - -I$(top_srcdir)/libparser + -I$(top_srcdir)/libparser \ + -I$(top_srcdir)/libresolver noinst_LTLIBRARIES = libui.la libui_la_LDFLAGS = -all-static libui_la_SOURCES = \ - ui_main_screen.c ui_main_screen.h \ - ui_menu_bar.c ui_menu_bar.h \ - ui_callbacks.c ui_callbacks.h \ - ui_tree_view.c ui_tree_view.h \ + ui_main_screen.c ui_main_screen.h \ + ui_menu_bar.c ui_menu_bar.h \ + ui_callbacks.c ui_callbacks.h \ + ui_tree_view.c ui_tree_view.h \ ui_signal_dissect_view.c ui_signal_dissect_view.h \ - ui_notifications.c ui_notifications.h \ - ui_interface.c ui_interface.h \ - ui_notebook.c ui_notebook.h + ui_notifications.c ui_notifications.h \ + ui_notif_dlg.c ui_notif_dlg.h \ + ui_interface.c ui_interface.h \ + ui_notebook.c ui_notebook.h diff --git a/common/utils/itti_analyzer/libui/ui_callbacks.c b/common/utils/itti_analyzer/libui/ui_callbacks.c index 9975d1352b..902ee8903b 100644 --- a/common/utils/itti_analyzer/libui/ui_callbacks.c +++ b/common/utils/itti_analyzer/libui/ui_callbacks.c @@ -5,6 +5,9 @@ #include "rc.h" +#include "socket.h" + +#include "ui_notif_dlg.h" #include "ui_main_screen.h" #include "ui_callbacks.h" #include "ui_interface.h" @@ -12,6 +15,12 @@ #include "ui_tree_view.h" #include "ui_signal_dissect_view.h" +#include "types.h" +#include "locate_root.h" +#include "xml_parse.h" + +static gboolean ui_handle_socket_connection_failed(gint fd); + gboolean ui_callback_on_open(GtkWidget *widget, GdkEvent *event, gpointer data) @@ -41,23 +50,22 @@ ui_callback_on_select_signal(GtkTreeSelection *selection, if (gtk_tree_model_get_iter(model, &iter, path)) { gchar *name; + GValue buffer_store = G_VALUE_INIT; + gpointer buffer; + +// g_value_init (&buffer_store, G_TYPE_POINTER); - gtk_tree_model_get(model, &iter, 0, &name, -1); +// gtk_tree_model_get(model, &iter, 0, &name, -1); + + gtk_tree_model_get_value(model, &iter, COL_BUFFER, &buffer_store); + + buffer = g_value_get_pointer(&buffer_store); if (!path_currently_selected) { - if (ui_interface.dissector_ready != 0) { - uint32_t message_number; - - sscanf(name, "%u", &message_number); - /* Clear the view */ - CHECK_FCT_DO(ui_signal_dissect_clear_view(), return FALSE); - // g_print ("%s is going to be selected.\n", name); - CHECK_FCT_DO(ui_interface.dissect_signal(message_number), return FALSE); - } else { - ui_notification_dialog(DIALOG_ERROR, "No XML signal description" - " provided\n"); - } + /* Clear the view */ + CHECK_FCT_DO(ui_signal_dissect_clear_view(), return FALSE); + CHECK_FCT_DO(dissect_signal((buffer_t*)buffer), return FALSE); } else { @@ -69,21 +77,162 @@ ui_callback_on_select_signal(GtkTreeSelection *selection, return TRUE; } +void ui_signal_add_to_list(gpointer data, gpointer user_data) +{ + buffer_t *signal_buffer; + + signal_buffer = (buffer_t *)data; + + get_message_id(root, signal_buffer, &signal_buffer->message_id); + + ui_tree_view_new_signal_ind(signal_buffer->message_number, + message_id_to_string(signal_buffer->message_id), + get_origin_task_id(signal_buffer), + get_destination_task_id(signal_buffer), + data); +} + +static gboolean ui_handle_update_signal_list(gint fd, const void *data, + size_t data_length) +{ + pipe_new_signals_list_message_t *signal_list_message; + + signal_list_message = (pipe_new_signals_list_message_t *)data; + + g_assert(signal_list_message != NULL); + g_assert(signal_list_message->signal_list != NULL); + + g_list_foreach(signal_list_message->signal_list, ui_signal_add_to_list, NULL); + + free(data); + + return TRUE; +} + +static gboolean ui_handle_socket_connection_failed(gint fd) +{ + GtkWidget *dialogbox; + + dialogbox = gtk_message_dialog_new(GTK_WINDOW(ui_main_data.window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Failed to connect to provided host/ip address"); + + gtk_dialog_run(GTK_DIALOG(dialogbox)); + gtk_widget_destroy(dialogbox); + + /* Re-enable connect button */ + ui_enable_connect_button(); + return TRUE; +} + +static gboolean ui_handle_socket_connection_lost(gint fd) +{ + GtkWidget *dialogbox; + + dialogbox = gtk_message_dialog_new(GTK_WINDOW(ui_main_data.window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Connection with remote host has been lost"); + + gtk_dialog_run(GTK_DIALOG(dialogbox)); + gtk_widget_destroy(dialogbox); + + /* Re-enable connect button */ + ui_enable_connect_button(); + return TRUE; +} + +static gboolean ui_handle_socket_xml_definition(gint fd, const void *data, + size_t data_length) +{ + pipe_xml_definition_message_t *xml_definition_message; + + xml_definition_message = (pipe_xml_definition_message_t *)data; + g_assert(xml_definition_message != NULL); + g_assert(data_length == sizeof(pipe_xml_definition_message_t)); + + xml_parse_buffer(xml_definition_message->xml_definition, + xml_definition_message->xml_definition_length); + + free(data); + + return TRUE; +} + +gboolean ui_pipe_callback(gint source, gpointer user_data) +{ + void *input_data = NULL; + size_t input_data_length = 0; + pipe_input_header_t input_header; + + /* Read the header */ + if (read(source, &input_header, sizeof(input_header)) < 0) { + g_warning("Failed to read from pipe %d: %s", source, g_strerror(errno)); + return FALSE; + } + + input_data_length = input_header.message_size - sizeof(input_header); + + /* Checking for non-header part */ + if (input_data_length > 0) { + input_data = malloc(input_data_length); + + if (read(source, input_data, input_data_length) < 0) { + g_warning("Failed to read from pipe %d: %s", source, g_strerror(errno)); + return FALSE; + } + } + + switch (input_header.message_type) { + case UI_PIPE_CONNECTION_FAILED: + return ui_handle_socket_connection_failed(source); + case UI_PIPE_XML_DEFINITION: + return ui_handle_socket_xml_definition(source, input_data, input_data_length); + case UI_PIPE_CONNECTION_LOST: + return ui_handle_socket_connection_lost(source); + case UI_PIPE_UPDATE_SIGNAL_LIST: + return ui_handle_update_signal_list(source, input_data, input_data_length); + default: + g_debug("[gui] Unhandled message type %u", input_header.message_type); + g_assert_not_reached(); + } + return FALSE; +} + gboolean ui_callback_on_connect(GtkWidget *widget, GdkEvent *event, gpointer data) { /* We have to retrieve the ip address and port of remote host */ - uint16_t port; const char *ip; + uint16_t port; + int pipe_fd[2]; g_debug("Connect event occurred"); port = atoi(gtk_entry_get_text(GTK_ENTRY(ui_main_data.portentry))); ip = gtk_entry_get_text(GTK_ENTRY(ui_main_data.ipentry)); -// ui_tree_view_destroy_list(); - ui_interface.socket_connect(ip, port); + if ((ip == NULL) || (port == 0)) { + g_warning("NULL parameter given for ip address or port = 0"); + /* TODO: add dialog box here */ + return FALSE; + } + + ui_pipe_new(pipe_fd, ui_pipe_callback, NULL); + + memcpy(ui_main_data.pipe_fd, pipe_fd, sizeof(int) * 2); + + /* Disable the connect button */ + ui_disable_connect_button(); + + if (socket_connect_to_remote_host(ip, port, pipe_fd[1]) != 0) { + ui_enable_connect_button(); + return FALSE; + } return TRUE; } @@ -95,7 +244,11 @@ gboolean ui_callback_on_disconnect(GtkWidget *widget, /* We have to retrieve the ip address and port of remote host */ g_debug("Disconnect event occurred"); - ui_interface.socket_disconnect(); + + ui_pipe_write_message(ui_main_data.pipe_fd[0], UI_PIPE_DISCONNECT_EVT, + NULL, 0); + + ui_enable_connect_button(); return TRUE; } @@ -107,4 +260,3 @@ gboolean ui_callback_on_tree_view_select(GtkWidget *widget, g_debug("List selection event occurred"); return TRUE; } - diff --git a/common/utils/itti_analyzer/libui/ui_callbacks.h b/common/utils/itti_analyzer/libui/ui_callbacks.h index cf5e37d898..2f60a711f8 100644 --- a/common/utils/itti_analyzer/libui/ui_callbacks.h +++ b/common/utils/itti_analyzer/libui/ui_callbacks.h @@ -28,4 +28,6 @@ ui_callback_on_select_signal(GtkTreeSelection *selection, gboolean path_currently_selected, gpointer userdata); +gboolean ui_pipe_callback(gint source, gpointer user_data); + #endif /* UI_CALLBACKS_H_ */ diff --git a/common/utils/itti_analyzer/libui/ui_interface.c b/common/utils/itti_analyzer/libui/ui_interface.c index ae40d0d97c..78b73d8fd3 100644 --- a/common/utils/itti_analyzer/libui/ui_interface.c +++ b/common/utils/itti_analyzer/libui/ui_interface.c @@ -14,21 +14,91 @@ #include "xml_parse.h" ui_interface_t ui_interface = { - .dissector_ready = 0, - - /** core program -> UI **/ - .ui_notification_dialog = ui_notification_dialog, - .ui_disable_connect_button = ui_disable_connect_button, - .ui_enable_connect_button = ui_enable_connect_button, - .ui_progress_bar_set_fraction = ui_progress_bar_set_fraction, - .ui_progress_bar_terminate = ui_progress_bar_terminate, - .ui_tree_view_new_signal_ind = ui_tree_view_new_signal_ind, + .ui_signal_set_text = ui_signal_set_text, +}; - /** UI -> core program **/ - .socket_connect = socket_connect_to_remote_host, - .socket_disconnect = socket_disconnect_from_remote_host, +static +gboolean ui_callback_on_pipe_notification( + GIOChannel *source, GIOCondition condition, gpointer user_data) +{ + pipe_input_t *pipe_input = (pipe_input_t *)user_data; - .parse_signal_file = xml_parse_file, - .dissect_signal = dissect_signal, -}; + /* avoid reentrancy problems and stack overflow */ + g_source_remove(pipe_input->pipe_input_id); + + g_debug("Received new data on pipe %d", pipe_input->pipe_input_id); + + if (pipe_input->input_cb(pipe_input->source_fd, pipe_input->user_data)) { + /* restore pipe handler */ + pipe_input->pipe_input_id = g_io_add_watch_full(pipe_input->pipe_channel, + G_PRIORITY_HIGH, + (GIOCondition)(G_IO_IN|G_IO_ERR|G_IO_HUP), + ui_callback_on_pipe_notification, + pipe_input, + NULL); + } + return TRUE; +} + +int ui_pipe_new(int pipe_fd[2], pipe_input_cb_t input_cb, gpointer user_data) +{ + static pipe_input_t pipe_input; + + g_assert(pipe_fd != NULL); + + /* Create a pipe between GUI and a thread or a process */ + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pipe_fd) < 0) { + g_warning("Failed to create socketpair %s", g_strerror(errno)); + return RC_FAIL; + } + + /* Source taken from wireshark SVN repository */ + + pipe_input.source_fd = pipe_fd[0]; + pipe_input.input_cb = input_cb; + pipe_input.user_data = user_data; + + pipe_input.pipe_channel = g_io_channel_unix_new(pipe_fd[0]); + g_io_channel_set_encoding(pipe_input.pipe_channel, NULL, NULL); + pipe_input.pipe_input_id = g_io_add_watch_full(pipe_input.pipe_channel, + G_PRIORITY_HIGH, + G_IO_IN | G_IO_ERR | G_IO_HUP, + ui_callback_on_pipe_notification, + &pipe_input, + NULL); + + return RC_OK; +} + +int ui_pipe_write_message(int pipe_fd, const uint16_t message_type, + const void * const message, const uint16_t message_size) +{ + int ret; + pipe_input_header_t pipe_input_header; + + pipe_input_header.message_size = message_size + sizeof(pipe_input_header); + pipe_input_header.message_type = message_type; + + if (message_size > 0 && message == NULL) { + g_error("message size = %u but message is NULL", message_size); + g_assert_not_reached(); + } + + ret = write(pipe_fd, &pipe_input_header, sizeof(pipe_input_header)); + if (ret < 0) { + g_debug("Failed to write header to pipe: %s", g_strerror(errno)); + return ret; + } + + /* Only write the message to pipe if valid data to transmit */ + if (message_size > 0) { + ret = write(pipe_fd, message, message_size); + if (ret < 0) { + g_debug("Failed to write message of size %u at 0x%p to pipe: %s", + message_size, message, g_strerror(errno)); + return ret; + } + } + return 0; +} diff --git a/common/utils/itti_analyzer/libui/ui_interface.h b/common/utils/itti_analyzer/libui/ui_interface.h index 0b8f94085d..bed9c63c50 100644 --- a/common/utils/itti_analyzer/libui/ui_interface.h +++ b/common/utils/itti_analyzer/libui/ui_interface.h @@ -1,61 +1,61 @@ +#include <glib.h> + #ifndef UI_INTERFACE_H_ #define UI_INTERFACE_H_ -typedef enum dialog_type_e { - DIALOG_INFO, - DIALOG_WARNING, - DIALOG_QUESTION, - DIALOG_ERROR, - DIALOG_OTHER, - DIALOG_MAX -} dialog_type_t; - -/** - * socket_connect_t - * @param remote_ip Remote ipv4 address - * @param port Remote port number - * @return RC_OK on Success, < 0 on failure - **/ -typedef int (*socket_connect_t)(const char *remote_ip, const uint16_t port); -typedef int (*socket_disconnect_t)(void); - -typedef int (*parse_signal_file_t)(const char *filename); -typedef int (*dissect_signal_t)(const uint32_t message_number); - -/** - * ui_notification_dialog_t - * @param type Type for the new dialog box - * @param fmt String formater - * @param ... argument list - * @return RC_OK on Success, < 0 on failure - **/ -typedef int (*ui_notification_dialog_t)(dialog_type_t type, const char *fmt, ...); -typedef int (*ui_disable_connect_button_t)(void); -typedef int (*ui_enable_connect_button_t)(void); -typedef int (*ui_progress_bar_set_fraction_t)(double fraction); -typedef int (*ui_progress_bar_terminate_t)(void); - -typedef int (*ui_tree_view_new_signal_ind_t)(const uint32_t message_number, const char *signal_name); typedef int (*ui_signal_set_text_t)(char *text, int length); typedef struct { - /** UI -> core program */ - socket_connect_t socket_connect; - socket_disconnect_t socket_disconnect; - parse_signal_file_t parse_signal_file; - dissect_signal_t dissect_signal; /** core program -> UI */ - int dissector_ready; - ui_notification_dialog_t ui_notification_dialog; - ui_disable_connect_button_t ui_disable_connect_button; - ui_enable_connect_button_t ui_enable_connect_button; - ui_progress_bar_set_fraction_t ui_progress_bar_set_fraction; - ui_progress_bar_terminate_t ui_progress_bar_terminate; - ui_tree_view_new_signal_ind_t ui_tree_view_new_signal_ind; ui_signal_set_text_t ui_signal_set_text; } ui_interface_t; extern ui_interface_t ui_interface; +/******************************************************************************* + * Pipe interface between GUI thread and other thread + ******************************************************************************/ + +typedef gboolean (*pipe_input_cb_t) (gint source, gpointer user_data); + +typedef struct { + int source_fd; + guint pipe_input_id; + GIOChannel *pipe_channel; + + pipe_input_cb_t input_cb; + gpointer user_data; +} pipe_input_t; + +int ui_pipe_new(int pipe_fd[2], pipe_input_cb_t input_cb, gpointer user_data); + +int ui_pipe_write_message(int pipe_fd, const uint16_t message_type, + const void * const message, const uint16_t message_size); + +typedef struct { + uint16_t message_size; + uint16_t message_type; +} pipe_input_header_t; + +enum ui_pipe_messages_id_e { + /* Other thread -> GUI interface ids */ + UI_PIPE_CONNECTION_FAILED, + UI_PIPE_CONNECTION_LOST, + UI_PIPE_XML_DEFINITION, + UI_PIPE_UPDATE_SIGNAL_LIST, + + /* GUI -> other threads */ + UI_PIPE_DISCONNECT_EVT +}; + +typedef struct { + char *xml_definition; + size_t xml_definition_length; +} pipe_xml_definition_message_t; + +typedef struct { + GList *signal_list; +} pipe_new_signals_list_message_t; + #endif /* UI_INTERFACE_H_ */ diff --git a/common/utils/itti_analyzer/libui/ui_main_screen.h b/common/utils/itti_analyzer/libui/ui_main_screen.h index 7d5be66797..ff99dda0f7 100644 --- a/common/utils/itti_analyzer/libui/ui_main_screen.h +++ b/common/utils/itti_analyzer/libui/ui_main_screen.h @@ -13,6 +13,8 @@ typedef struct { /* Buttons */ GtkToolItem *connect; GtkToolItem *disconnect; + + int pipe_fd[2]; } ui_main_data_t; extern ui_main_data_t ui_main_data; diff --git a/common/utils/itti_analyzer/libui/ui_notif_dlg.c b/common/utils/itti_analyzer/libui/ui_notif_dlg.c new file mode 100644 index 0000000000..17894c2989 --- /dev/null +++ b/common/utils/itti_analyzer/libui/ui_notif_dlg.c @@ -0,0 +1,24 @@ +#include "rc.h" + +#include "ui_notif_dlg.h" +#include "ui_main_screen.h" + +int ui_notification_dialog(dialog_type_t type, const char *fmt, ...) +{ + va_list args; + GtkWidget *dialogbox; + + va_start(args, fmt); + + dialogbox = gtk_message_dialog_new(GTK_WINDOW(ui_main_data.window), + GTK_DIALOG_MODAL, type, + GTK_BUTTONS_OK, fmt, args); + + gtk_dialog_run(GTK_DIALOG (dialogbox)); + + gtk_widget_destroy (dialogbox); + + va_end(args); + + return RC_OK; +} diff --git a/common/utils/itti_analyzer/libui/ui_notif_dlg.h b/common/utils/itti_analyzer/libui/ui_notif_dlg.h new file mode 100644 index 0000000000..a351f31709 --- /dev/null +++ b/common/utils/itti_analyzer/libui/ui_notif_dlg.h @@ -0,0 +1,17 @@ +#include <gtk/gtk.h> + +#ifndef UI_NOTIF_DLG_H_ +#define UI_NOTIF_DLG_H_ + +typedef enum dialog_type_e { + DIALOG_INFO, + DIALOG_WARNING, + DIALOG_QUESTION, + DIALOG_ERROR, + DIALOG_OTHER, + DIALOG_MAX +} dialog_type_t; + +extern int ui_notification_dialog(dialog_type_t type, const char *fmt, ...); + +#endif /* UI_NOTIF_DLG_H_ */ diff --git a/common/utils/itti_analyzer/libui/ui_notifications.c b/common/utils/itti_analyzer/libui/ui_notifications.c index 17f0d9d3b2..5a914e3f18 100644 --- a/common/utils/itti_analyzer/libui/ui_notifications.c +++ b/common/utils/itti_analyzer/libui/ui_notifications.c @@ -10,33 +10,7 @@ #include "ui_main_screen.h" #include "ui_notifications.h" -int ui_notification_dialog(dialog_type_t type, const char *fmt, ...) -{ - va_list ap; - GtkWidget *dialogbox; - - va_start(ap, fmt); - - /* In multi-threaded environnements gtk calls should be protected by - * gdk_threads_enter before calling the GTK function - * gdk_threads_leave when GTK function has exited - */ - gdk_threads_enter(); - - dialogbox = gtk_message_dialog_new( - GTK_WINDOW(ui_main_data.window), GTK_DIALOG_MODAL, type, - GTK_BUTTONS_OK, fmt, ap); - - gtk_dialog_run(GTK_DIALOG (dialogbox)); - - gtk_widget_destroy (dialogbox); - - gdk_threads_leave(); - - va_end(ap); - - return RC_OK; -} +#include "xml_parse.h" int ui_disable_connect_button(void) { @@ -71,8 +45,8 @@ int ui_file_chooser(void) char *filename; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser)); - ui_interface.parse_signal_file(filename); - g_free (filename); + xml_parse_file(filename); + g_free(filename); } gtk_widget_destroy (filechooser); diff --git a/common/utils/itti_analyzer/libui/ui_notifications.h b/common/utils/itti_analyzer/libui/ui_notifications.h index cbc669fde9..4cee44c354 100644 --- a/common/utils/itti_analyzer/libui/ui_notifications.h +++ b/common/utils/itti_analyzer/libui/ui_notifications.h @@ -1,8 +1,6 @@ #ifndef UI_NOTIFICATIONS_H_ #define UI_NOTIFICATIONS_H_ -int ui_notification_dialog(dialog_type_t type, const char *fmt, ...); - int ui_disable_connect_button(void); int ui_enable_connect_button(void); diff --git a/common/utils/itti_analyzer/libui/ui_tree_view.c b/common/utils/itti_analyzer/libui/ui_tree_view.c index 8544b68d4f..1d70980212 100644 --- a/common/utils/itti_analyzer/libui/ui_tree_view.c +++ b/common/utils/itti_analyzer/libui/ui_tree_view.c @@ -5,21 +5,16 @@ #include "rc.h" +#include "buffers.h" + #include "ui_main_screen.h" #include "ui_tree_view.h" #include "ui_callbacks.h" #include "ui_signal_dissect_view.h" -enum -{ - COL_MSG_NUM = 0, - COL_SIGNAL, - NUM_COLS -} ; - static void -init_list(GtkWidget *list) +ui_tree_view_init_list(GtkWidget *list) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; @@ -27,22 +22,40 @@ init_list(GtkWidget *list) renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( - "Message Number", renderer, "text", COL_MSG_NUM, NULL); + "MN", renderer, "text", COL_MSG_NUM, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(list), column); column = gtk_tree_view_column_new_with_attributes( "Signal", renderer, "text", COL_SIGNAL, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(list), column); - store = gtk_list_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_STRING); + column = gtk_tree_view_column_new_with_attributes( + "From", renderer, "text", COL_FROM_TASK, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(list), column); + + column = gtk_tree_view_column_new_with_attributes( + "To", renderer, "text", COL_TO_TASK, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(list), column); + + store = gtk_list_store_new(NUM_COLS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + /* HACK: add a reference to the buffer here + * to avoid maintining multiple lists. + * The reference is not displayed + */ + G_TYPE_POINTER); gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store)); g_object_unref(store); } -static void -add_to_list(GtkWidget *list, const gchar *message_number, const gchar *signal_name) +static void ui_tree_view_add_to_list(GtkWidget *list, const gchar *message_number, + const gchar *signal_name, const char *origin_task, + const char *to_task, gpointer buffer) { GtkListStore *store; GtkTreeIter iter; @@ -51,8 +64,15 @@ add_to_list(GtkWidget *list, const gchar *message_number, const gchar *signal_na (GTK_TREE_VIEW(list))); gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, COL_MSG_NUM, message_number, - COL_SIGNAL, signal_name, -1); + gtk_list_store_set(store, &iter, + /* Columns */ + COL_MSG_NUM , message_number, + COL_SIGNAL , signal_name, + COL_FROM_TASK , origin_task, + COL_TO_TASK , to_task, + COL_BUFFER , buffer, + /* End of columns */ + -1); } void ui_tree_view_destroy_list(GtkWidget *list) @@ -92,7 +112,7 @@ int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox) gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), ui_main_data.signalslist); - init_list(ui_main_data.signalslist); + ui_tree_view_init_list(ui_main_data.signalslist); // gtk_widget_get_size_request(GTK_WIDGET(ui_main_data.signalslist), &width, NULL); gtk_widget_set_size_request(GTK_WIDGET(scrolled_window), 350, -1); @@ -110,13 +130,15 @@ int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox) return 0; } -int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signal_name) +int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signal_name, + const char *origin_task, const char *to_task, gpointer buffer) { gchar message_number_str[11]; sprintf(message_number_str, "%u", message_number); - add_to_list(ui_main_data.signalslist, message_number_str, signal_name); + ui_tree_view_add_to_list(ui_main_data.signalslist, message_number_str, signal_name, + origin_task, to_task, (buffer_t *)buffer); return RC_OK; } diff --git a/common/utils/itti_analyzer/libui/ui_tree_view.h b/common/utils/itti_analyzer/libui/ui_tree_view.h index 38f1ad8f66..9bfdcbbe0b 100644 --- a/common/utils/itti_analyzer/libui/ui_tree_view.h +++ b/common/utils/itti_analyzer/libui/ui_tree_view.h @@ -1,9 +1,20 @@ #ifndef UI_TREE_VIEW_H_ #define UI_TREE_VIEW_H_ +enum +{ + COL_MSG_NUM = 0, + COL_SIGNAL, + COL_FROM_TASK, + COL_TO_TASK, + COL_BUFFER, + NUM_COLS +}; + int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox); -int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signal_name); +int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signal_name, + const char *origin_task, const char *to_task, gpointer buffer); void ui_tree_view_destroy_list(GtkWidget *list); -- GitLab