Files
openairinterface5g/common/utils/itti_analyzer/libbuffers/socket.c
T
winckel 7a178e0190 Reorganized and completed menus:
- Separated "File" into "Filters and "Messages" menus.
- Added "Enable filtering".
- Added "Reload messages file".
- Added "Go to first message".
- Added "Go to message".
- Added "Go to last message".
- Added "Display message header"
- Added "Display brace"
- Added menu key shortcuts (mnemonic and accelerator).
Created an entry box for message goto input number and modified the search function to select the closest lower number if input number is not present in messages list.
Cleared message content view when needed.
Blocked message content redisplay when not needed.
Added a signal handler to capture events on message list tree view.
Modified message content display format.
Modified some log points.

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4426 818b1a75-f10b-46b9-bf7c-635c3b92a50f
2013-11-18 10:32:48 +00:00

404 lines
13 KiB
C

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <gtk/gtk.h>
#include "itti_types.h"
#include "rc.h"
#include "ui_interface.h"
#include "ui_notifications.h"
#include "ui_notif_dlg.h"
#include "socket.h"
#include "buffers.h"
#include "xml_parse.h"
#define SOCKET_NB_SIGNALS_BEFORE_SIGNALLING 10
#define SOCKET_MS_BEFORE_SIGNALLING 100
void *socket_thread_fct(void *arg);
static ssize_t socket_read_data(socket_data_t *socket_data, void *buffer, size_t size, int flags)
{
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);
}
return recv_ret;
}
static void socket_notify_gui_update(socket_data_t *socket_data)
{
pipe_new_signals_list_message_t pipe_signal_list_message;
pipe_signal_list_message.signal_list = socket_data->signal_list;
socket_data->signal_list = NULL;
socket_data->nb_signals_since_last_update = 0;
/* 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();
}
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);
}
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;
}
}
/* 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);
}
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);
pipe_xml_definition_message.xml_definition = xml_definition;
pipe_xml_definition_message.xml_definition_length = xml_definition_length;
g_debug("Received XML definition of size %zu, effectively read %zu bytes",
xml_definition_length, total_data_read);
ui_pipe_write_message(socket_data->pipe_fd, UI_PIPE_XML_DEFINITION,
&pipe_xml_definition_message, sizeof(pipe_xml_definition_message));
return total_data_read;
}
static int socket_read(socket_data_t *socket_data)
{
int ret = 0;
itti_socket_header_t message_header;
while (ret >= 0) {
ret = socket_read_data(socket_data, &message_header, sizeof(message_header), 0);
if (ret == -1) {
return 0;
}
switch(message_header.message_type) {
case ITTI_DUMP_MESSAGE_TYPE:
socket_read_itti_message(socket_data, &message_header);
break;
case ITTI_DUMP_XML_DEFINITION:
socket_read_xml_definition(socket_data, &message_header);
break;
case ITTI_STATISTIC_MESSAGE_TYPE:
default:
g_debug("Received unknow (or not implemented) message from socket type: %d",
message_header.message_type);
break;
}
}
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));
socket_data->sd = -1;
/* Close pipe */
close(socket_data->pipe_fd);
/* Leaving the thread */
pthread_exit(NULL);
return 0;
}
static int pipe_read_message(socket_data_t *socket_data)
{
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;
}
input_data_length = input_header.message_size - sizeof(input_header);
/* Checking for non-header part */
if (input_data_length > 0) {
input_data = malloc(sizeof(uint8_t) * input_data_length);
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;
}
}
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;
}
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 GUI update
*/
if (socket_data->nb_signals_since_last_update > 0) {
g_debug("Timout on select and data new signal in list");
g_debug("-> notify GUI");
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)) {
FD_CLR(socket_data->pipe_fd, &read_fds);
pipe_read_message(socket_data);
}
/* Checking if there is data to read from the socket */
if (FD_ISSET(socket_data->sd, &read_fds)) {
FD_CLR(socket_data->sd, &read_fds);
socket_read(socket_data);
/* 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 = (1000 * 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 pipe_fd)
{
socket_data_t *socket_data;
socket_data = calloc(1, sizeof(*socket_data));
socket_data->ip_address = strdup(remote_ip);
socket_data->pipe_fd = pipe_fd;
socket_data->port = port;
socket_data->sd = -1;
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;
}
return RC_OK;
}