socket.c 14.6 KB
Newer Older
1 2 3 4 5
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

Cedric Roux's avatar
 
Cedric Roux committed
22 23 24 25 26 27 28
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
Cedric Roux's avatar
Cedric Roux committed
29
#include <fcntl.h>
Cedric Roux's avatar
 
Cedric Roux committed
30

31 32
#define G_LOG_DOMAIN ("BUFFERS")

Cedric Roux's avatar
 
Cedric Roux committed
33 34
#include <gtk/gtk.h>

35
#include "logs.h"
36
#include "itti_types.h"
37
#include "rc.h"
Cedric Roux's avatar
 
Cedric Roux committed
38 39 40

#include "ui_interface.h"
#include "ui_notifications.h"
Cedric Roux's avatar
Cedric Roux committed
41
#include "ui_notif_dlg.h"
Cedric Roux's avatar
 
Cedric Roux committed
42 43 44 45 46 47

#include "socket.h"
#include "buffers.h"

#include "xml_parse.h"

winckel's avatar
winckel committed
48 49 50 51
/* Retry connection after 100 ms */
#define SOCKET_US_BEFORE_CONNECT_RETRY      (100 * 1000)
/* About 10 minutes time-out for connecting to peer */
#define SOCKET_NB_CONNECT_RETRY             ((10 * 60 * 1000 * 1000) / SOCKET_US_BEFORE_CONNECT_RETRY)
52

Cedric Roux's avatar
Cedric Roux committed
53 54
#define SOCKET_NB_SIGNALS_BEFORE_SIGNALLING 10
#define SOCKET_MS_BEFORE_SIGNALLING         100
Cedric Roux's avatar
 
Cedric Roux committed
55

56 57
gboolean socket_abort_connection = FALSE;

Cedric Roux's avatar
Cedric Roux committed
58
void *socket_thread_fct(void *arg);
Cedric Roux's avatar
 
Cedric Roux committed
59

Cedric Roux's avatar
Cedric Roux committed
60
static ssize_t socket_read_data(socket_data_t *socket_data, void *buffer, size_t size, int flags)
Cedric Roux's avatar
 
Cedric Roux committed
61
{
Cedric Roux's avatar
Cedric Roux committed
62 63 64 65 66 67 68 69 70 71
    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:
72
                g_info("recv failed: %s", g_strerror(errno));
Cedric Roux's avatar
Cedric Roux committed
73 74 75 76 77 78 79 80 81 82 83
                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);
    }
Cedric Roux's avatar
 
Cedric Roux committed
84

Cedric Roux's avatar
Cedric Roux committed
85 86
    return recv_ret;
}
Cedric Roux's avatar
 
Cedric Roux committed
87

Cedric Roux's avatar
Cedric Roux committed
88 89 90
static void socket_notify_gui_update(socket_data_t *socket_data)
{
    pipe_new_signals_list_message_t pipe_signal_list_message;
Cedric Roux's avatar
 
Cedric Roux committed
91

Cedric Roux's avatar
Cedric Roux committed
92
    pipe_signal_list_message.signal_list = socket_data->signal_list;
Cedric Roux's avatar
 
Cedric Roux committed
93

Cedric Roux's avatar
Cedric Roux committed
94 95
    socket_data->signal_list                  = NULL;
    socket_data->nb_signals_since_last_update = 0;
Cedric Roux's avatar
 
Cedric Roux committed
96

Cedric Roux's avatar
Cedric Roux committed
97 98 99 100 101 102 103 104
    /* 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();
}
Cedric Roux's avatar
 
Cedric Roux committed
105

Cedric Roux's avatar
Cedric Roux committed
106 107 108 109 110 111 112 113 114 115 116 117
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);

winckel's avatar
winckel committed
118
    g_debug("Attempting to read signal header from socket");
Cedric Roux's avatar
Cedric Roux committed
119 120 121 122 123

    /* 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);
Cedric Roux's avatar
 
Cedric Roux committed
124 125
    }

Cedric Roux's avatar
Cedric Roux committed
126 127 128
    data_length = message_header->message_size - sizeof(itti_socket_header_t) - sizeof(itti_signal_header_t);
    data = malloc(sizeof(uint8_t) * data_length);

129
    while (total_data_read < data_length) {
Cedric Roux's avatar
Cedric Roux committed
130 131 132 133 134 135 136
        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;
Cedric Roux's avatar
 
Cedric Roux committed
137
        }
Cedric Roux's avatar
Cedric Roux committed
138
    }
Cedric Roux's avatar
 
Cedric Roux committed
139

Cedric Roux's avatar
Cedric Roux committed
140
    /* Create the new buffer */
winckel's avatar
winckel committed
141
    if (buffer_new_from_data(&buffer, data, data_length - sizeof(itti_message_types_t), 1) != RC_OK) {
Cedric Roux's avatar
Cedric Roux committed
142 143 144 145
        g_error("Failed to create new buffer");
        g_assert_not_reached();
    }

146
    sscanf (itti_signal_header.message_number_char, MESSAGE_NUMBER_CHAR_FORMAT, &buffer->message_number);
147
//     buffer_dump(buffer, stdout);
Cedric Roux's avatar
Cedric Roux committed
148 149 150 151 152 153 154 155 156 157

    /* 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);
    }

158
    g_debug("Successfully read new signal %u from socket", buffer->message_number);
Cedric Roux's avatar
Cedric Roux committed
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

    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;
Cedric Roux's avatar
 
Cedric Roux committed
189
        }
Cedric Roux's avatar
Cedric Roux committed
190
    } while (total_data_read != xml_definition_length);
Cedric Roux's avatar
 
Cedric Roux committed
191

Cedric Roux's avatar
Cedric Roux committed
192
    pipe_xml_definition_message.xml_definition        = xml_definition;
winckel's avatar
winckel committed
193
    pipe_xml_definition_message.xml_definition_length = xml_definition_length - sizeof(itti_message_types_t);
Cedric Roux's avatar
 
Cedric Roux committed
194

Cedric Roux's avatar
Cedric Roux committed
195 196
    g_debug("Received XML definition of size %zu, effectively read %zu bytes",
            xml_definition_length, total_data_read);
Cedric Roux's avatar
 
Cedric Roux committed
197

Cedric Roux's avatar
Cedric Roux committed
198 199
    ui_pipe_write_message(socket_data->pipe_fd, UI_PIPE_XML_DEFINITION,
                          &pipe_xml_definition_message, sizeof(pipe_xml_definition_message));
Cedric Roux's avatar
 
Cedric Roux committed
200

Cedric Roux's avatar
Cedric Roux committed
201 202
    return total_data_read;
}
Cedric Roux's avatar
 
Cedric Roux committed
203

Cedric Roux's avatar
Cedric Roux committed
204 205 206 207
static int socket_read(socket_data_t *socket_data)
{
    int ret = 0;
    itti_socket_header_t message_header;
Cedric Roux's avatar
 
Cedric Roux committed
208

Cedric Roux's avatar
Cedric Roux committed
209 210
    while (ret >= 0) {
        ret = socket_read_data(socket_data, &message_header, sizeof(message_header), 0);
Cedric Roux's avatar
 
Cedric Roux committed
211

Cedric Roux's avatar
Cedric Roux committed
212
        if (ret == -1) {
213
            return 0;
Cedric Roux's avatar
Cedric Roux committed
214
        }
Cedric Roux's avatar
 
Cedric Roux committed
215

Cedric Roux's avatar
Cedric Roux committed
216
        switch(message_header.message_type) {
217
            case ITTI_DUMP_XML_DEFINITION:
Cedric Roux's avatar
Cedric Roux committed
218 219
                socket_read_xml_definition(socket_data, &message_header);
                break;
winckel's avatar
winckel committed
220 221 222 223 224

            case ITTI_DUMP_MESSAGE_TYPE:
                socket_read_itti_message(socket_data, &message_header);
                break;

225
            case ITTI_STATISTIC_MESSAGE_TYPE:
Cedric Roux's avatar
 
Cedric Roux committed
226
            default:
227 228
                g_warning("Received unknow (or not implemented) message from socket type: %d",
                          message_header.message_type);
Cedric Roux's avatar
 
Cedric Roux committed
229 230 231 232
                break;
        }
    }

Cedric Roux's avatar
Cedric Roux committed
233 234 235 236 237 238 239 240 241
    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));
Cedric Roux's avatar
 
Cedric Roux committed
242

Cedric Roux's avatar
Cedric Roux committed
243 244 245 246 247 248
    socket_data->sd = -1;

    /* Close pipe */
    close(socket_data->pipe_fd);

    /* Leaving the thread */
Cedric Roux's avatar
 
Cedric Roux committed
249
    pthread_exit(NULL);
Cedric Roux's avatar
Cedric Roux committed
250 251

    return 0;
Cedric Roux's avatar
 
Cedric Roux committed
252 253
}

Cedric Roux's avatar
Cedric Roux committed
254
static int pipe_read_message(socket_data_t *socket_data)
Cedric Roux's avatar
 
Cedric Roux committed
255
{
Cedric Roux's avatar
Cedric Roux committed
256 257 258 259 260 261 262 263 264 265
    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;
    }
Cedric Roux's avatar
 
Cedric Roux committed
266

Cedric Roux's avatar
Cedric Roux committed
267
    input_data_length = input_header.message_size - sizeof(input_header);
Cedric Roux's avatar
 
Cedric Roux committed
268

Cedric Roux's avatar
Cedric Roux committed
269 270 271
    /* Checking for non-header part */
    if (input_data_length > 0) {
        input_data = malloc(sizeof(uint8_t) * input_data_length);
Cedric Roux's avatar
 
Cedric Roux committed
272

Cedric Roux's avatar
Cedric Roux committed
273 274 275 276 277 278
        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;
        }
    }
Cedric Roux's avatar
 
Cedric Roux committed
279

Cedric Roux's avatar
Cedric Roux committed
280 281 282 283
    switch (input_header.message_type) {
        case UI_PIPE_DISCONNECT_EVT:
            return socket_handle_disconnect_evt(socket_data);
        default:
284
            g_warning("[socket] Unhandled message type %u", input_header.message_type);
Cedric Roux's avatar
Cedric Roux committed
285 286 287 288
            g_assert_not_reached();
    }
    return 0;
}
Cedric Roux's avatar
 
Cedric Roux committed
289

Cedric Roux's avatar
Cedric Roux committed
290 291 292 293 294
void *socket_thread_fct(void *arg)
{
    int                 ret;
    struct sockaddr_in  si_me;
    socket_data_t      *socket_data;
295
    int                 retry = SOCKET_NB_CONNECT_RETRY;
Cedric Roux's avatar
Cedric Roux committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309

    /* 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) {
310
        g_warning("socket failed: %s", g_strerror(errno));
Cedric Roux's avatar
Cedric Roux committed
311 312 313 314 315 316 317 318 319
        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) {
320
        g_warning("inet_aton() failed\n");
Cedric Roux's avatar
Cedric Roux committed
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
        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;

345 346
    do {
        /* Connecting to remote peer */
347 348 349 350 351 352 353 354 355
        ret = connect(socket_data->sd, (struct sockaddr *) &si_me, sizeof(struct sockaddr_in));
        if (ret < 0) {
            if ((socket_abort_connection) || (retry < 0)) {
                if (retry < 0) {
                    g_warning("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);
winckel's avatar
winckel committed
356
                socket_abort_connection = FALSE;
357 358
                /* Quit the thread */
                pthread_exit(NULL);
359
            }
360 361
            usleep(SOCKET_US_BEFORE_CONNECT_RETRY);
            retry--;
362 363
        }
    } while (ret < 0);
Cedric Roux's avatar
Cedric Roux committed
364 365 366 367 368 369 370 371 372

    /* 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) {
373
            g_warning("Error in select: %s", g_strerror(errno));
Cedric Roux's avatar
Cedric Roux committed
374 375 376 377 378
            free(socket_data->ip_address);
            free(socket_data);
            /* Quit the thread */
            pthread_exit(NULL);
        } else if (ret == 0) {
379 380
            /* Timeout for select: check if there is new incoming messages
             * since last GUI update
Cedric Roux's avatar
Cedric Roux committed
381 382
             */
            if (socket_data->nb_signals_since_last_update > 0) {
383 384
                g_debug("Timout on select and data new signal in list");
                g_debug("-> notify GUI");
Cedric Roux's avatar
Cedric Roux committed
385 386 387 388 389 390 391 392 393
                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)) {
394
            FD_CLR(socket_data->pipe_fd, &read_fds);
Cedric Roux's avatar
Cedric Roux committed
395 396 397 398 399
            pipe_read_message(socket_data);
        }

        /* Checking if there is data to read from the socket */
        if (FD_ISSET(socket_data->sd, &read_fds)) {
400
            FD_CLR(socket_data->sd, &read_fds);
Cedric Roux's avatar
Cedric Roux committed
401 402 403 404 405 406 407 408 409 410 411 412 413
            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 */
414
                    tv.tv_usec = (1000 * SOCKET_MS_BEFORE_SIGNALLING) - (current_time - socket_data->last_data_notification);
Cedric Roux's avatar
Cedric Roux committed
415 416 417 418 419 420
                }
            }
        }
    }

    return NULL;
Cedric Roux's avatar
 
Cedric Roux committed
421 422
}

Cedric Roux's avatar
Cedric Roux committed
423 424
int socket_connect_to_remote_host(const char *remote_ip, const uint16_t port,
                                  int pipe_fd)
Cedric Roux's avatar
 
Cedric Roux committed
425
{
Cedric Roux's avatar
Cedric Roux committed
426
    socket_data_t *socket_data;
Cedric Roux's avatar
 
Cedric Roux committed
427

Cedric Roux's avatar
Cedric Roux committed
428
    socket_data = calloc(1, sizeof(*socket_data));
Cedric Roux's avatar
 
Cedric Roux committed
429

Cedric Roux's avatar
Cedric Roux committed
430
    socket_data->ip_address = strdup(remote_ip);
Cedric Roux's avatar
 
Cedric Roux committed
431

Cedric Roux's avatar
Cedric Roux committed
432 433 434
    socket_data->pipe_fd = pipe_fd;
    socket_data->port    = port;
    socket_data->sd      = -1;
Cedric Roux's avatar
 
Cedric Roux committed
435

Cedric Roux's avatar
Cedric Roux committed
436 437 438 439
    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);
Cedric Roux's avatar
 
Cedric Roux committed
440 441 442 443 444
        return RC_FAIL;
    }

    return RC_OK;
}