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

Cedric Roux's avatar
Cedric Roux committed
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;
Cedric Roux's avatar
Cedric Roux committed
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
    {
Cedric Roux's avatar
Cedric Roux committed
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 */
Cedric Roux's avatar
Cedric Roux committed
535
536
                    eventfd_t sem_counter;
                    ssize_t   read_ret;
537

Cedric Roux's avatar
Cedric Roux committed
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);
Cedric Roux's avatar
Cedric Roux committed
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);
Cedric Roux's avatar
Cedric Roux committed
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;
Cedric Roux's avatar
Cedric Roux committed
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
Cedric Roux's avatar
Cedric Roux committed
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);
Cedric Roux's avatar
Cedric Roux committed
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));
Cedric Roux's avatar
Cedric Roux committed
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));
Cedric Roux's avatar
Cedric Roux committed
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));
Cedric Roux's avatar
Cedric Roux committed
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
776
        task_id = ITTI_MSG_ORIGIN_ID(item->data);

winckel's avatar
winckel committed
777
778
        if (item->data != NULL)
        {
779
            itti_free(task_id, item->data);
winckel's avatar
winckel committed
780
        }
781
        itti_free(task_id, item);
782
783
784
    }
}

785
786
void itti_dump_exit(void)
{
787
    void *arg;
winckel's avatar
winckel committed
788
789
790
    itti_dump_queue_item_t *new;

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

792
793
794
    /* Set a flag to stop recording message */
    itti_dump_running = 0;

795
    /* Send the exit signal to other thread */
winckel's avatar
winckel committed
796
    itti_dump_enqueue_message(new, 0, ITTI_DUMP_EXIT_SIGNAL);
797
798
799
800
801
802
803
804

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

805
806
    if (dump_file != NULL)
    {
807
        /* Synchronise file and then close it */
808
        fclose(dump_file);
809
        dump_file = NULL;
810
811
    }

812
813
814
815
816
817
    if (itti_dump_queue.itti_message_queue)
    {
        lfds611_ringbuffer_delete(itti_dump_queue.itti_message_queue,
                                  itti_dump_user_data_delete_function, NULL);
    }
}