intertask_interface_dump.c 26.5 KB
Newer Older
Cedric Roux's avatar
 
Cedric Roux committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*******************************************************************************

  Eurecom OpenAirInterface
  Copyright(c) 1999 - 2013 Eurecom

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  more details.

  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  The full GNU General Public License is included in this distribution in
  the file called "COPYING".

  Contact Information
  Openair Admin: openair_admin@eurecom.fr
  Openair Tech : openair_tech@eurecom.fr
  Forums       : http://forums.eurecom.fr/openairinterface
  Address      : EURECOM, Campus SophiaTech, 450 Route des Chappes
                 06410 Biot FRANCE

*******************************************************************************/

/** @brief Intertask Interface Signal Dumper
32
 * Allows users to connect their itti_analyzer to this process and dump
Cedric Roux's avatar
 
Cedric Roux committed
33 34 35 36 37 38 39 40 41 42 43 44
 * signals exchanged between tasks.
 * @author Sebastien Roux <sebastien.roux@eurecom.fr>
 */

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <error.h>
45
#include <sched.h>
Cedric Roux's avatar
 
Cedric Roux committed
46 47 48 49 50 51 52

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <arpa/inet.h>

53 54
#include <sys/eventfd.h>

Cedric Roux's avatar
 
Cedric Roux committed
55
#include "assertions.h"
56
#include "liblfds611.h"
Cedric Roux's avatar
 
Cedric Roux committed
57 58 59 60

#include "intertask_interface.h"
#include "intertask_interface_dump.h"

61
#if defined(OAI_EMU) || defined(RTAI)
62 63 64
#include "vcd_signal_dumper.h"
#endif

65
#define SIGNAL_NAME_LENGTH  48
Cedric Roux's avatar
 
Cedric Roux committed
66

67
static const int itti_dump_debug = 0;
Cedric Roux's avatar
 
Cedric Roux committed
68

69 70 71 72
#ifdef RTAI
# define ITTI_DUMP_DEBUG(x, args...) do { if (itti_dump_debug) rt_printk("[ITTI][D]"x, ##args); } \
    while(0)
# define ITTI_DUMP_ERROR(x, args...) do { rt_printk("[ITTI][E]"x, ##args); } \
Cedric Roux's avatar
 
Cedric Roux committed
73
    while(0)
74 75
#else
# define ITTI_DUMP_DEBUG(x, args...) do { if (itti_dump_debug) fprintf(stdout, "[ITTI][D]"x, ##args); } \
Cedric Roux's avatar
 
Cedric Roux committed
76
    while(0)
77 78 79
# define ITTI_DUMP_ERROR(x, args...) do { fprintf(stdout, "[ITTI][E]"x, ##args); } \
    while(0)
#endif
Cedric Roux's avatar
 
Cedric Roux committed
80

81 82 83 84
#ifndef EFD_SEMAPHORE
# define KERNEL_VERSION_PRE_2_6_30 1
#endif

Cedric Roux's avatar
Cedric Roux committed
85 86 87 88
/* Message sent is an intertask dump type */
#define ITTI_DUMP_MESSAGE_TYPE      0x1
#define ITTI_STATISTIC_MESSAGE_TYPE 0x2
#define ITTI_DUMP_XML_DEFINITION    0x3
89 90
/* This signal is not meant to be used by remote analyzer */
#define ITTI_DUMP_EXIT_SIGNAL       0x4
Cedric Roux's avatar
Cedric Roux committed
91

92
typedef struct itti_dump_queue_item_s {
93 94 95 96 97 98
    MessageDef *data;
    uint32_t    data_size;
    uint32_t    message_number;
    char        message_name[SIGNAL_NAME_LENGTH];
    uint32_t    message_type;
    uint32_t    message_size;
99
} itti_dump_queue_item_t;
Cedric Roux's avatar
 
Cedric Roux committed
100 101 102 103 104 105 106

typedef struct {
    int      sd;
    uint32_t last_message_number;
} itti_client_desc_t;

typedef struct itti_desc_s {
107 108 109
    /* Asynchronous thread that write to file/accept new clients */
    pthread_t      itti_acceptor_thread;
    pthread_attr_t attr;
Cedric Roux's avatar
 
Cedric Roux committed
110 111 112

    /* List of messages to dump.
     * NOTE: we limit the size of this queue to retain only the last exchanged
113
     * messages. The size can be increased by setting up the ITTI_QUEUE_MAX_ELEMENTS
Cedric Roux's avatar
 
Cedric Roux committed
114 115
     * in mme_default_values.h or by putting a custom in the configuration file.
     */
116 117
    struct lfds611_ringbuffer_state *itti_message_queue;

Cedric Roux's avatar
 
Cedric Roux committed
118 119
    int nb_connected;

120
#ifndef RTAI
121 122
    /* Event fd used to notify new messages (semaphore) */
    int event_fd;
123 124 125
#else
    unsigned long messages_in_queue __attribute__((aligned(8)));
#endif
126 127 128

    int itti_listen_socket;

Cedric Roux's avatar
 
Cedric Roux committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
    itti_client_desc_t itti_clients[ITTI_DUMP_MAX_CON];
} itti_desc_t;

typedef struct {
    /* The size of this structure */
    uint32_t message_size;
    uint32_t message_type;
} itti_socket_header_t;

typedef struct {
    itti_socket_header_t header;

    uint32_t message_number;
    char signal_name[SIGNAL_NAME_LENGTH];

    /* Message payload is added here, this struct is used as an header */
} itti_dump_message_t;

typedef struct {
    itti_socket_header_t header;
    
} itti_statistic_message_t;

152
static itti_desc_t itti_dump_queue;
153
static FILE *dump_file = NULL;
154
static int itti_dump_running = 1;
155

156
static int itti_dump_send_message(int sd, itti_dump_queue_item_t *message);
Cedric Roux's avatar
 
Cedric Roux committed
157 158 159 160 161 162
static int itti_dump_handle_new_connection(int sd, const char *xml_definition,
                                      uint32_t xml_definition_length);
static int itti_dump_send_xml_definition(const int sd, const char *message_definition_xml,
                                         const uint32_t message_definition_xml_length);

static
163
int itti_dump_send_message(int sd, itti_dump_queue_item_t *message)
Cedric Roux's avatar
 
Cedric Roux committed
164 165
{
    itti_dump_message_t *new_message;
166 167
    ssize_t bytes_sent = 0, total_sent = 0;
    uint8_t *data_ptr;
Cedric Roux's avatar
 
Cedric Roux committed
168 169

    /* Allocate memory for message header and payload */
170
    size_t size = sizeof(itti_dump_message_t) + message->data_size;
Cedric Roux's avatar
 
Cedric Roux committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

    DevCheck(sd > 0, sd, 0, 0);
    DevAssert(message != NULL);

    new_message = calloc(1, size);
    DevAssert(new_message != NULL);

    /* Preparing the header */
    new_message->header.message_size = size;
    new_message->header.message_type = ITTI_DUMP_MESSAGE_TYPE;

    new_message->message_number = message->message_number;
    /* Copy the name, but leaves last byte set to 0 in case name is too long */
    memcpy(new_message->signal_name, message->message_name, SIGNAL_NAME_LENGTH - 1);
    /* Appends message payload */
    memcpy(&new_message[1], message->data, message->data_size);

188 189 190 191 192
    data_ptr = (uint8_t *)&new_message[0];

    do {
        bytes_sent = send(sd, &data_ptr[total_sent], size - total_sent, 0);
        if (bytes_sent < 0) {
193
            ITTI_DUMP_ERROR("[%d] Failed to send %zu bytes to socket (%d:%s)\n",
194 195 196 197 198 199
                       sd, size, errno, strerror(errno));
            free(new_message);
            return -1;
        }
        total_sent += bytes_sent;
    } while (total_sent != size);
Cedric Roux's avatar
 
Cedric Roux committed
200 201

    free(new_message);
202
    return total_sent;
Cedric Roux's avatar
 
Cedric Roux committed
203 204
}

205 206 207 208 209 210 211 212 213 214 215 216 217
static void itti_dump_fwrite_message(itti_dump_queue_item_t *message)
{
    itti_socket_header_t header;

    if (dump_file != NULL && message) {

        header.message_size = message->message_size + sizeof(itti_dump_message_t);
        header.message_type = message->message_type;

        fwrite (&header, sizeof(itti_socket_header_t), 1, dump_file);
        fwrite (&message->message_number, sizeof(message->message_number), 1, dump_file);
        fwrite (message->message_name, sizeof(message->message_name), 1, dump_file);
        fwrite (message->data, message->data_size, 1, dump_file);
218 219 220
// #if !defined(RTAI)
        fflush (dump_file);
// #endif
221 222 223
    }
}

Cedric Roux's avatar
 
Cedric Roux committed
224 225 226
static int itti_dump_send_xml_definition(const int sd, const char *message_definition_xml,
                                         const uint32_t message_definition_xml_length)
{
227 228 229 230 231
    itti_socket_header_t *itti_dump_message;
    /* Allocate memory for message header and payload */
    size_t itti_dump_message_size;
    ssize_t bytes_sent = 0, total_sent = 0;
    uint8_t *data_ptr;
Cedric Roux's avatar
 
Cedric Roux committed
232 233 234 235

    DevCheck(sd > 0, sd, 0, 0);
    DevAssert(message_definition_xml != NULL);

236 237 238 239
    itti_dump_message_size = sizeof(itti_socket_header_t) + message_definition_xml_length;

    itti_dump_message = calloc(1, itti_dump_message_size);

240
    ITTI_DUMP_DEBUG("[%d] Sending XML definition message of size %zu to observer peer\n",
241 242 243 244 245 246 247 248 249 250 251 252 253
               sd, itti_dump_message_size);

    itti_dump_message->message_size = itti_dump_message_size;
    itti_dump_message->message_type = ITTI_DUMP_XML_DEFINITION;

    /* Copying message definition */
    memcpy(&itti_dump_message[1], message_definition_xml, message_definition_xml_length);

    data_ptr = (uint8_t *)&itti_dump_message[0];

    do {
        bytes_sent = send(sd, &data_ptr[total_sent], itti_dump_message_size - total_sent, 0);
        if (bytes_sent < 0) {
254
            ITTI_DUMP_ERROR("[%d] Failed to send %zu bytes to socket (%d:%s)\n",
255 256 257 258 259 260 261 262 263
                       sd, itti_dump_message_size, errno, strerror(errno));
            free(itti_dump_message);
            return -1;
        }
        total_sent += bytes_sent;
    } while (total_sent != itti_dump_message_size);

    free(itti_dump_message);

Cedric Roux's avatar
 
Cedric Roux committed
264 265 266
    return 0;
}

267
static int itti_dump_enqueue_message(itti_dump_queue_item_t *new, uint32_t message_size,
268
                                     uint32_t message_type)
Cedric Roux's avatar
Cedric Roux committed
269
{
270
    struct lfds611_freelist_element *new_queue_element = NULL;
Cedric Roux's avatar
Cedric Roux committed
271

272
    DevAssert(new != NULL);
Cedric Roux's avatar
Cedric Roux committed
273

274
#if defined(OAI_EMU) || defined(RTAI)
275 276 277
    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE, VCD_FUNCTION_IN);
#endif

278 279
    new->message_type = message_type;
    new->message_size = message_size;
Cedric Roux's avatar
Cedric Roux committed
280

281 282
    new_queue_element = lfds611_ringbuffer_get_write_element(
        itti_dump_queue.itti_message_queue, &new_queue_element, NULL);
Cedric Roux's avatar
Cedric Roux committed
283

284
    lfds611_freelist_set_user_data_in_element(new_queue_element, (void *)new);
Cedric Roux's avatar
Cedric Roux committed
285

286 287
    lfds611_ringbuffer_put_write_element(itti_dump_queue.itti_message_queue,
                                         new_queue_element);
Cedric Roux's avatar
Cedric Roux committed
288

289 290 291 292
#ifdef RTAI
    __sync_fetch_and_add (&itti_dump_queue.messages_in_queue, 1);
#else
    {
293 294
        ssize_t   write_ret;
        eventfd_t sem_counter = 1;
295 296 297 298 299 300 301

        /* Call to write for an event fd must be of 8 bytes */
        write_ret = write(itti_dump_queue.event_fd, &sem_counter, sizeof(sem_counter));
        DevCheck(write_ret == sizeof(sem_counter), write_ret, sem_counter, 0);
    }
#endif

302
#if defined(OAI_EMU) || defined(RTAI)
303 304
    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE, VCD_FUNCTION_OUT);
#endif
Cedric Roux's avatar
Cedric Roux committed
305 306 307 308

    return 0;
}

309 310
int itti_dump_queue_message(task_id_t sender_task,
                            message_number_t message_number,
Cedric Roux's avatar
 
Cedric Roux committed
311 312 313 314
                            MessageDef *message_p,
                            const char *message_name,
                            const uint32_t message_size)
{
315 316 317 318
    if (itti_dump_running)
    {
        itti_dump_queue_item_t *new;
        size_t message_name_length;
Cedric Roux's avatar
 
Cedric Roux committed
319

320 321
        DevAssert(message_name != NULL);
        DevAssert(message_p != NULL);
Cedric Roux's avatar
 
Cedric Roux committed
322

323 324 325 326 327 328 329
#if defined(OAI_EMU) || defined(RTAI)
        vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC, VCD_FUNCTION_IN);
#endif
        new = itti_malloc(sender_task, sizeof(itti_dump_queue_item_t));
#if defined(OAI_EMU) || defined(RTAI)
        vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC, VCD_FUNCTION_OUT);
#endif
Cedric Roux's avatar
 
Cedric Roux committed
330

331 332 333 334 335 336 337
#if defined(OAI_EMU) || defined(RTAI)
        vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC, VCD_FUNCTION_IN);
#endif
        new->data = itti_malloc(sender_task, message_size);
#if defined(OAI_EMU) || defined(RTAI)
        vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC, VCD_FUNCTION_OUT);
#endif
Cedric Roux's avatar
 
Cedric Roux committed
338

339
        memcpy(new->data, message_p, message_size);
340 341
        new->data_size       = message_size;
        new->message_number  = message_number;
Cedric Roux's avatar
 
Cedric Roux committed
342

343 344 345 346
        message_name_length = strlen(message_name) + 1;
        DevCheck(message_name_length <= SIGNAL_NAME_LENGTH, message_name_length,
                 SIGNAL_NAME_LENGTH, 0);
        memcpy(new->message_name, message_name, message_name_length);
Cedric Roux's avatar
 
Cedric Roux committed
347

348
        itti_dump_enqueue_message(new, message_size, ITTI_DUMP_MESSAGE_TYPE);
Cedric Roux's avatar
 
Cedric Roux committed
349 350 351 352 353
    }

    return 0;
}

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
static void itti_dump_flush_ring_buffer(int flush_all)
{
    struct lfds611_freelist_element *element = NULL;
    void *user_data;
    int   j;

#ifdef RTAI
    unsigned long number_of_messages;

    number_of_messages = itti_dump_queue.messages_in_queue;

    ITTI_DUMP_DEBUG("%lu elements in queue\n", number_of_messages);

    if (number_of_messages == 0) {
        return;
    }

    __sync_sub_and_fetch(&itti_dump_queue.messages_in_queue, number_of_messages);
#endif

    do {
        /* Acquire the ring element */
        lfds611_ringbuffer_get_read_element(itti_dump_queue.itti_message_queue, &element);

        DevAssert(element != NULL);

        /* Retrieve user part of the message */
        lfds611_freelist_get_user_data_from_element(element, &user_data);

        if (((itti_dump_queue_item_t *)user_data)->message_type == ITTI_DUMP_EXIT_SIGNAL)
        {
#ifndef RTAI
            close(itti_dump_queue.event_fd);
#endif
            close(itti_dump_queue.itti_listen_socket);

            lfds611_ringbuffer_put_read_element(itti_dump_queue.itti_message_queue, element);

            /* Leave the thread as we detected end signal */
            pthread_exit(NULL);
        }

        /* Write message to file */
        itti_dump_fwrite_message((itti_dump_queue_item_t *)user_data);

        /* Send message to remote analyzer */
        for (j = 0; j < ITTI_DUMP_MAX_CON; j++) {
            if (itti_dump_queue.itti_clients[j].sd > 0) {
                itti_dump_send_message(itti_dump_queue.itti_clients[j].sd,
                                        (itti_dump_queue_item_t *)user_data);
            }
        }

        /* We have finished with this element, reinsert it in the ring buffer */
        lfds611_ringbuffer_put_read_element(itti_dump_queue.itti_message_queue, element);
    } while(flush_all
#ifdef RTAI
            && --number_of_messages
#endif
            );
}

Cedric Roux's avatar
 
Cedric Roux committed
416 417 418 419 420 421 422
static void *itti_dump_socket(void *arg_p)
{
    uint32_t message_definition_xml_length;
    char *message_definition_xml;
    int rc;
    int itti_listen_socket, max_sd;
    int on = 1;
423
    fd_set read_set, working_set;
Cedric Roux's avatar
 
Cedric Roux committed
424 425
    struct sockaddr_in servaddr; /* socket address structure */

426 427 428 429 430
    struct timeval *timeout_p = NULL;
#ifdef RTAI
    struct timeval  timeout;
#endif

431
    ITTI_DUMP_DEBUG("Creating TCP dump socket on port %u\n", ITTI_PORT);
Cedric Roux's avatar
 
Cedric Roux committed
432 433 434 435 436 437 438

    message_definition_xml = (char *)arg_p;
    DevAssert(message_definition_xml != NULL);

    message_definition_xml_length = strlen(message_definition_xml) + 1;

    if ((itti_listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
439
        ITTI_DUMP_ERROR("Socket creation failed (%d:%s)\n", errno, strerror(errno));
Cedric Roux's avatar
 
Cedric Roux committed
440 441 442 443 444 445 446
        pthread_exit(NULL);
    }

    /* Allow socket reuse */
    rc = setsockopt(itti_listen_socket, SOL_SOCKET, SO_REUSEADDR,
                    (char *)&on, sizeof(on));
    if (rc < 0) {
447
        ITTI_DUMP_ERROR("setsockopt SO_REUSEADDR failed (%d:%s)\n", errno, strerror(errno));
Cedric Roux's avatar
 
Cedric Roux committed
448 449 450 451 452 453 454 455 456
        close(itti_listen_socket);
        pthread_exit(NULL);
    }

    /* Set socket to be non-blocking.
     * NOTE: sockets accepted will inherit this option.
     */
    rc = ioctl(itti_listen_socket, FIONBIO, (char *)&on);
    if (rc < 0) {
457
        ITTI_DUMP_ERROR("ioctl FIONBIO (non-blocking) failed (%d:%s)\n", errno, strerror(errno));
Cedric Roux's avatar
 
Cedric Roux committed
458 459 460 461 462 463 464 465 466 467
        close(itti_listen_socket);
        pthread_exit(NULL);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(ITTI_PORT);

    if (bind(itti_listen_socket, (struct sockaddr *) &servaddr,
468
             sizeof(servaddr)) < 0) {
469
        ITTI_DUMP_ERROR("Bind failed (%d:%s)\n", errno, strerror(errno));
Cedric Roux's avatar
 
Cedric Roux committed
470 471
        pthread_exit(NULL);
    }
472
    if (listen(itti_listen_socket, 5) < 0) {
473
        ITTI_DUMP_ERROR("Listen failed (%d:%s)\n", errno, strerror(errno));
Cedric Roux's avatar
 
Cedric Roux committed
474 475 476
        pthread_exit(NULL);
    }

477 478 479 480 481
    FD_ZERO(&read_set);

    /* Add the listener */
    FD_SET(itti_listen_socket, &read_set);

482
#ifndef RTAI
483 484 485 486 487
    /* Add the event fd */
    FD_SET(itti_dump_queue.event_fd, &read_set);

    /* Max of both sd */
    max_sd = itti_listen_socket > itti_dump_queue.event_fd ? itti_listen_socket : itti_dump_queue.event_fd;
488 489 490
#else
    max_sd = itti_listen_socket;
#endif
491 492

    itti_dump_queue.itti_listen_socket = itti_listen_socket;
Cedric Roux's avatar
 
Cedric Roux committed
493 494 495 496 497 498 499 500 501

    /* Loop waiting for incoming connects or for incoming data
     * on any of the connected sockets.
     */
    while (1) {
        int desc_ready;
        int client_socket = -1;
        int i;

502
        memcpy(&working_set, &read_set, sizeof(read_set));
503 504 505 506 507 508 509 510
#ifdef RTAI
        timeout.tv_sec  = 0;
        timeout.tv_usec = 100000;

        timeout_p = &timeout;
#else
        timeout_p = NULL;
#endif
Cedric Roux's avatar
 
Cedric Roux committed
511 512 513 514

        /* No timeout: select blocks till a new event has to be handled
         * on sd's.
         */
515
        rc = select(max_sd + 1, &working_set, NULL, NULL, timeout_p);
Cedric Roux's avatar
 
Cedric Roux committed
516 517

        if (rc < 0) {
518
            ITTI_DUMP_ERROR("select failed (%d:%s)\n", errno, strerror(errno));
Cedric Roux's avatar
 
Cedric Roux committed
519
            pthread_exit(NULL);
520 521 522
        } else if (rc == 0) {
            /* Timeout */
            itti_dump_flush_ring_buffer(1);
Cedric Roux's avatar
 
Cedric Roux committed
523 524 525
        }

        desc_ready = rc;
526 527 528 529
        for (i = 0; i <= max_sd && desc_ready > 0; i++)
        {
            if (FD_ISSET(i, &working_set))
            {
Cedric Roux's avatar
 
Cedric Roux committed
530
                desc_ready -= 1;
531

532
#ifndef RTAI
533 534
                if (i == itti_dump_queue.event_fd) {
                    /* Notification of new element to dump from other tasks */
535 536
                    eventfd_t sem_counter;
                    ssize_t   read_ret;
537

538
                    /* Read will always return 1 for kernel versions > 2.6.30 */
539 540 541 542 543 544
                    read_ret = read (itti_dump_queue.event_fd, &sem_counter, sizeof(sem_counter));
                    if (read_ret < 0) {
                        ITTI_DUMP_ERROR("Failed read for semaphore: %s\n", strerror(errno));
                        pthread_exit(NULL);
                    }
                    DevCheck(read_ret == sizeof(sem_counter), read_ret, sizeof(sem_counter), 0);
545 546 547
#if defined(KERNEL_VERSION_PRE_2_6_30)
                    itti_dump_flush_ring_buffer(1);
#else
548
                    itti_dump_flush_ring_buffer(0);
549
#endif
550
                    ITTI_DUMP_DEBUG("Write element to file\n");
551 552 553
                } else
#endif
                if (i == itti_listen_socket) {
Cedric Roux's avatar
 
Cedric Roux committed
554 555 556 557 558
                    do {
                        client_socket = accept(itti_listen_socket, NULL, NULL);
                        if (client_socket < 0) {
                            if (errno == EWOULDBLOCK || errno == EAGAIN) {
                                /* No more new connection */
559
                                ITTI_DUMP_DEBUG("No more new connection\n");
Cedric Roux's avatar
 
Cedric Roux committed
560 561
                                continue;
                            } else {
562
                                ITTI_DUMP_ERROR("accept failed (%d:%s)\n", errno, strerror(errno));
Cedric Roux's avatar
 
Cedric Roux committed
563 564 565 566
                                pthread_exit(NULL);
                            }
                        }
                        if (itti_dump_handle_new_connection(client_socket, message_definition_xml,
567 568
                            message_definition_xml_length) == 0)
                        {
Cedric Roux's avatar
 
Cedric Roux committed
569 570 571
                            /* The socket has been accepted.
                             * We have to update the set to include this new sd.
                             */
572
                            FD_SET(client_socket, &read_set);
Cedric Roux's avatar
 
Cedric Roux committed
573 574 575 576 577 578 579 580 581 582
                            if (client_socket > max_sd)
                                max_sd = client_socket;
                        }
                    } while(client_socket != -1);
                } else {
                    /* For now the MME itti dumper should not receive data
                     * other than connection oriented (CLOSE).
                     */
                    uint8_t j;

583
                    ITTI_DUMP_DEBUG("Socket %d disconnected\n", i);
Cedric Roux's avatar
 
Cedric Roux committed
584 585 586 587 588

                    /* Close the socket and update info related to this connection */
                    close(i);

                    for (j = 0; j < ITTI_DUMP_MAX_CON; j++) {
589
                        if (itti_dump_queue.itti_clients[j].sd == i)
Cedric Roux's avatar
 
Cedric Roux committed
590 591 592 593 594 595 596 597 598 599 600
                            break;
                    }

                    /* In case we don't find the matching sd in list of known
                     * connections -> assert.
                     */
                    DevCheck(j < ITTI_DUMP_MAX_CON, j, ITTI_DUMP_MAX_CON, i);

                    /* Re-initialize the socket to -1 so we can accept new
                     * incoming connections.
                     */
601 602 603
                    itti_dump_queue.itti_clients[j].sd                  = -1;
                    itti_dump_queue.itti_clients[j].last_message_number = 0;
                    itti_dump_queue.nb_connected--;
Cedric Roux's avatar
 
Cedric Roux committed
604 605

                    /* Remove the socket from the FD set and update the max sd */
606
                    FD_CLR(i, &read_set);
Cedric Roux's avatar
 
Cedric Roux committed
607 608
                    if (i == max_sd)
                    {
609
                        if (itti_dump_queue.nb_connected == 0) {
Cedric Roux's avatar
 
Cedric Roux committed
610 611 612
                            /* No more new connection max_sd = itti_listen_socket */
                            max_sd = itti_listen_socket;
                        } else {
613
                            while (FD_ISSET(max_sd, &read_set) == 0) {
Cedric Roux's avatar
 
Cedric Roux committed
614 615 616 617 618 619 620 621 622 623 624 625 626 627
                                max_sd -= 1;
                            }
                        }
                    }
                }
            }
        }
    }
    return NULL;
}

static
int itti_dump_handle_new_connection(int sd, const char *xml_definition, uint32_t xml_definition_length)
{
628
    if (itti_dump_queue.nb_connected < ITTI_DUMP_MAX_CON) {
Cedric Roux's avatar
 
Cedric Roux committed
629 630 631 632
        uint8_t i;

        for (i = 0; i < ITTI_DUMP_MAX_CON; i++) {
            /* Let's find a place to store the new client */
633
            if (itti_dump_queue.itti_clients[i].sd == -1) {
Cedric Roux's avatar
 
Cedric Roux committed
634 635 636 637
                break;
            }
        }

638
        ITTI_DUMP_DEBUG("Found place to store new connection: %d\n", i);
Cedric Roux's avatar
 
Cedric Roux committed
639 640

        DevCheck(i < ITTI_DUMP_MAX_CON, i, ITTI_DUMP_MAX_CON, sd);
641

642
        ITTI_DUMP_DEBUG("Socket %d accepted\n", sd);
Cedric Roux's avatar
 
Cedric Roux committed
643 644 645

        /* Send the XML message definition */
        if (itti_dump_send_xml_definition(sd, xml_definition, xml_definition_length) < 0) {
646
            ITTI_DUMP_ERROR("Failed to send XML definition\n");
Cedric Roux's avatar
 
Cedric Roux committed
647 648 649 650
            close (sd);
            return -1;
        }

651 652
        itti_dump_queue.itti_clients[i].sd = sd;
        itti_dump_queue.nb_connected++;
Cedric Roux's avatar
 
Cedric Roux committed
653
    } else {
654
        ITTI_DUMP_DEBUG("Socket %d rejected\n", sd);
Cedric Roux's avatar
 
Cedric Roux committed
655 656 657 658 659 660 661 662 663 664
        /* We have reached max number of users connected...
         * Reject the connection.
         */
        close (sd);
        return -1;
    }

    return 0;
}

665 666 667 668 669 670
/* This function should be called by each thread that will use the ring buffer */
void itti_dump_thread_use_ring_buffer(void)
{
    lfds611_ringbuffer_use(itti_dump_queue.itti_message_queue);
}

671
int itti_dump_init(const char * const messages_definition_xml, const char * const dump_file_name)
Cedric Roux's avatar
 
Cedric Roux committed
672
{
673
    int i, ret;
674 675
    struct sched_param scheduler_param;

676
    scheduler_param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1;
Cedric Roux's avatar
 
Cedric Roux committed
677

678 679
    if (dump_file_name != NULL)
    {
winckel's avatar
winckel committed
680
        dump_file = fopen(dump_file_name, "wb");
681 682 683

        if (dump_file == NULL)
        {
684
            ITTI_DUMP_ERROR("can not open dump file \"%s\" (%d:%s)\n", dump_file_name, errno, strerror(errno));
685 686 687
        }
        else
        {
688
            /* Output the XML to file */
winckel's avatar
winckel committed
689
            uint32_t message_size = strlen(messages_definition_xml) + 1;
690 691
            itti_socket_header_t header;

winckel's avatar
winckel committed
692
            header.message_size = sizeof(itti_socket_header_t) + message_size;
693 694 695 696
            header.message_type = ITTI_DUMP_XML_DEFINITION;

            fwrite (&header, sizeof(itti_socket_header_t), 1, dump_file);
            fwrite (messages_definition_xml, message_size, 1, dump_file);
697
            fflush (dump_file);
698 699 700
        }
    }

701
    memset(&itti_dump_queue, 0, sizeof(itti_desc_t));
Cedric Roux's avatar
 
Cedric Roux committed
702

703 704 705 706 707 708 709 710 711 712 713 714 715
    ITTI_DUMP_DEBUG("Creating new ring buffer for itti dump of %u elements\n",
                    ITTI_QUEUE_MAX_ELEMENTS);

    if (lfds611_ringbuffer_new(&itti_dump_queue.itti_message_queue,
                               ITTI_QUEUE_MAX_ELEMENTS,
                               NULL,
                               NULL) != 1)
    {
        ITTI_DUMP_ERROR("Failed to create ring buffer...\n");
        /* Always assert on this condition */
        DevAssert(0 == 1);
    }

716 717 718
#ifdef RTAI
    itti_dump_queue.messages_in_queue = 0;
#else
719 720 721
# if defined(KERNEL_VERSION_PRE_2_6_30)
    itti_dump_queue.event_fd = eventfd(0, 0);
# else
722
    itti_dump_queue.event_fd = eventfd(0, EFD_SEMAPHORE);
723
# endif
724 725 726 727 728 729
    if (itti_dump_queue.event_fd == -1)
    {
        ITTI_DUMP_ERROR("eventfd failed: %s\n", strerror(errno));
        /* Always assert on this condition */
        DevAssert(0 == 1);
    }
730
#endif
731 732

    itti_dump_queue.nb_connected = 0;
Cedric Roux's avatar
 
Cedric Roux committed
733 734

    for(i = 0; i < ITTI_DUMP_MAX_CON; i++) {
735 736 737 738 739 740 741 742
        itti_dump_queue.itti_clients[i].sd = -1;
        itti_dump_queue.itti_clients[i].last_message_number = 0;
    }

    /* initialized with default attributes */
    ret = pthread_attr_init(&itti_dump_queue.attr);
    if (ret < 0) {
        ITTI_DUMP_ERROR("pthread_attr_init failed (%d:%s)\n", errno, strerror(errno));
743
        DevAssert(0 == 1);
744
    }
745

746
    ret = pthread_attr_setschedpolicy(&itti_dump_queue.attr, SCHED_FIFO);
747 748
    if (ret < 0) {
        ITTI_DUMP_ERROR("pthread_attr_setschedpolicy (SCHED_IDLE) failed (%d:%s)\n", errno, strerror(errno));
749 750 751 752 753 754
        DevAssert(0 == 1);
    }
    ret = pthread_attr_setschedparam(&itti_dump_queue.attr, &scheduler_param);
    if (ret < 0) {
        ITTI_DUMP_ERROR("pthread_attr_setschedparam failed (%d:%s)\n", errno, strerror(errno));
        DevAssert(0 == 1);
Cedric Roux's avatar
 
Cedric Roux committed
755
    }
756 757 758 759 760

    ret = pthread_create(&itti_dump_queue.itti_acceptor_thread, &itti_dump_queue.attr,
                         &itti_dump_socket, (void *)messages_definition_xml);
    if (ret < 0) {
        ITTI_DUMP_ERROR("pthread_create failed (%d:%s)\n", errno, strerror(errno));
761
        DevAssert(0 == 1);
Cedric Roux's avatar
 
Cedric Roux committed
762
    }
763

Cedric Roux's avatar
 
Cedric Roux committed
764 765
    return 0;
}
766

767
static void itti_dump_user_data_delete_function(void *user_data, void *user_state)
768 769 770 771
{
    if (user_data != NULL)
    {
        itti_dump_queue_item_t *item;
772
        task_id_t task_id;
773 774

        item = (itti_dump_queue_item_t *)user_data;
775

winckel's avatar
winckel committed
776 777
        if (item->data != NULL)
        {
778
            task_id = ITTI_MSG_ORIGIN_ID(item->data);
779
            itti_free(task_id, item->data);
winckel's avatar
winckel committed
780
        }
781 782 783 784
        else
        {
            task_id = TASK_UNKNOWN;
        }
785
        itti_free(task_id, item);
786 787 788
    }
}

789 790
void itti_dump_exit(void)
{
791
    void *arg;
winckel's avatar
winckel committed
792 793 794
    itti_dump_queue_item_t *new;

    new = calloc(1, sizeof(itti_dump_queue_item_t));
795

796 797 798
    /* Set a flag to stop recording message */
    itti_dump_running = 0;

799
    /* Send the exit signal to other thread */
winckel's avatar
winckel committed
800
    itti_dump_enqueue_message(new, 0, ITTI_DUMP_EXIT_SIGNAL);
801 802 803 804 805 806 807 808

    ITTI_DUMP_DEBUG("waiting for dumper thread to finish\n");

    /* wait for the thread to terminate */
    pthread_join(itti_dump_queue.itti_acceptor_thread, &arg);

    ITTI_DUMP_DEBUG("dumper thread correctly exited\n");

809 810
    if (dump_file != NULL)
    {
811
        /* Synchronise file and then close it */
812
        fclose(dump_file);
813
        dump_file = NULL;
814 815
    }

816 817 818 819 820 821
    if (itti_dump_queue.itti_message_queue)
    {
        lfds611_ringbuffer_delete(itti_dump_queue.itti_message_queue,
                                  itti_dump_user_data_delete_function, NULL);
    }
}