socket_link.c 16.1 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
 * 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
 */ 
21 22 23 24 25 26 27 28 29 30 31

/*! \file socket_link.c
 * \brief this is the implementation of a TCP socket ASYNC IF
 * \author Cedric Roux
 * \date November 2015
 * \version 1.0
 * \email: cedric.roux@eurecom.fr
 * @ingroup _mac
 */

#include "socket_link.h"
32
#include "common/utils/LOG/log.h"
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdint.h>

socket_link_t *new_link_server(int port)
{
  socket_link_t      *ret = NULL;
  int                reuse;
  struct sockaddr_in addr;
  socklen_t          addrlen;
  int                socket_server = -1;
  int no_delay;
54

55
  
56 57
  ret = calloc(1, sizeof(socket_link_t));
  if (ret == NULL) {
58
    LOG_E(MAC, "%s:%d: out of memory\n", __FILE__, __LINE__);
59 60 61 62
    goto error;
  }
  ret->socket_fd = -1;

63

64
  //printf("MAC create a new link server socket at port %d\n", port);
65 66 67

  socket_server = socket(AF_INET, SOCK_STREAM, 0);
  if (socket_server == -1) {
68
    LOG_E(MAC, "%s:%d: socket: %s\n", __FILE__, __LINE__, strerror(errno));
69 70
    goto error;
  }
71
  ret->type = SOCK_STREAM;
72 73 74

  reuse = 1;
  if (setsockopt(socket_server, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
75

76
    LOG_E(MAC, "%s:%d: setsockopt: %s\n", __FILE__, __LINE__, strerror(errno));
77 78 79 80 81
    goto error;
  }

  no_delay = 1;
  if (setsockopt(socket_server, IPPROTO_TCP, TCP_NODELAY, &no_delay, sizeof(no_delay)) == -1) {
82

83
    LOG_E(MAC, "%s:%d: setsockopt: %s\n", __FILE__, __LINE__, strerror(errno));
84 85 86 87 88 89 90
    goto error;
  }
  
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.s_addr = INADDR_ANY;
  if (bind(socket_server, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
91
    LOG_E(MAC, "%s:%d: bind: %s\n", __FILE__, __LINE__, strerror(errno));
92 93 94 95
    goto error;
  }

  if (listen(socket_server, 5)) {
96
    LOG_E(MAC, "%s:%d: listen: %s\n", __FILE__, __LINE__, strerror(errno));
97 98 99 100 101 102
    goto error;
  }

  addrlen = sizeof(addr);
  ret->socket_fd = accept(socket_server, (struct sockaddr *)&addr, &addrlen);
  if (ret->socket_fd == -1) {
103
    LOG_E(MAC, "%s:%d: accept: %s\n", __FILE__, __LINE__, strerror(errno));
104 105
    goto error;
  }
106

107
  //printf("MAC connection from %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
108 109 110 111 112 113
  return ret;

error:
  close(socket_server);
  if (ret != NULL) close(ret->socket_fd);
  free(ret);
114

115
  LOG_E(MAC, "ERROR in new_link_server (see above), returning NULL\n");
116 117 118
  return NULL;
}

119
socket_link_t *new_link_client(const char *server, int port)
120 121 122 123 124 125 126 127 128 129 130 131
{
  socket_link_t      *ret = NULL;
  struct sockaddr_in addr;
  int no_delay;

  ret = calloc(1, sizeof(socket_link_t));
  if (ret == NULL) {
    LOG_E(MAC, "%s:%d: out of memory\n", __FILE__, __LINE__);
    goto error;
  }
  ret->socket_fd = -1;

132
  LOG_D(MAC, "create a new link client socket connecting to %s:%d\n", server, port);
133 134 135

  ret->socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (ret->socket_fd == -1) {
136
    LOG_E(MAC, "%s:%d: socket: %s\n", __FILE__, __LINE__, strerror(errno));
137 138
    goto error;
  }
139
  ret->type = SOCK_STREAM;
140 141 142

  no_delay = 1;
  if (setsockopt(ret->socket_fd, SOL_TCP, TCP_NODELAY, &no_delay, sizeof(no_delay)) == -1) {
143
    LOG_E(MAC, "%s:%d: setsockopt: %s\n", __FILE__, __LINE__, strerror(errno));
144 145 146 147 148 149
    goto error;
  }
  
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  if (inet_aton(server, &addr.sin_addr) == 0) {
150
    LOG_E(MAC, "invalid IP address '%s', use a.b.c.d notation\n", server);
151 152 153
    goto error;
  }
  if (connect(ret->socket_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
154
    LOG_E(MAC, "%s:%d: connect: %s\n", __FILE__, __LINE__, strerror(errno));
155 156
    goto error;
  }
157 158

  LOG_D(MAC, "connection to %s:%d established\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
159 160 161 162 163 164 165 166 167
  return ret;

error:
  if (ret != NULL) close(ret->socket_fd);
  free(ret);
  LOG_E(MAC, "ERROR in new_link_client (see above), returning NULL\n");
  return NULL;
}

168 169
socket_link_t *new_link_udp_server(const char *bind_addr, int bind_port)
{
170 171
  socket_link_t  *ret = NULL;

172 173
  struct sockaddr_in si_me;
  int socket_server = -1;
174 175 176 177 178 179 180 181

  ret = calloc(1, sizeof(socket_link_t));
  if (ret == NULL) {
    LOG_D(PROTO_AGENT, "%s:%d: out of memory\n", __FILE__, __LINE__);
    goto error;
  }
  ret->socket_fd = -1;

182
  //printf("PROTO_AGENT: create a new udp link server socket at port %d\n", port);
183 184 185

  //create a UDP socket
  if ((socket_server=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
186
    goto error;
187
  }
188
  ret->type = SOCK_DGRAM;
189 190 191 192 193

  // zero out the structure
  memset((char *) &si_me, 0, sizeof(si_me));

  si_me.sin_family = AF_INET;
194 195 196 197 198 199 200
  si_me.sin_port = htons(bind_port);
  if (bind_addr) {
    if (!inet_aton(bind_addr, &si_me.sin_addr))
      goto error;
  } else {
    si_me.sin_addr.s_addr = INADDR_ANY;
  }
201 202 203

  //bind socket to port
  if( bind(socket_server , (struct sockaddr*)&si_me, sizeof(si_me) ) == -1) {
204 205
    fprintf(stderr, "could not bind to address %s: %s\n", bind_addr, strerror(errno));
    goto error;
206 207 208 209 210
  }
  ret->socket_fd = socket_server;
  return ret;
  
error:
211
  if (socket_server != -1) close(socket_server);
212 213
  if (ret != NULL) close(ret->socket_fd);
  free(ret);
214
  //printf("\n\n\nERROR PROTO_AGENT: ERROR in new_link_udp_server (see above), returning NULL\n");
215 216 217 218
  return NULL;
}


219
socket_link_t *new_link_udp_client(const char *server, int port){
220 221 222 223 224

  socket_link_t      *ret = NULL;
  ret = calloc(1, sizeof(socket_link_t));
  if (ret == NULL) {
    LOG_E(MAC, "%s:%d: out of memory\n", __FILE__, __LINE__);
225
    goto error;
226 227 228
  }
  ret->socket_fd = -1;

229 230
  struct sockaddr_in si_other;
  int s;
231
  socklen_t slen = 0;
232 233 234 235
 
  if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
        goto error;
  }
236
  ret->type = SOCK_DGRAM;
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
 
  memset((char *) &si_other, 0, sizeof(si_other));
  si_other.sin_family = AF_INET;
  si_other.sin_port = 0; //htons(port);
  

  
  if (inet_aton(server, &si_other.sin_addr) == 0){
        fprintf(stderr, "inet_aton() failed\n");
        goto error;
  }
  connect(s, (struct sockaddr *)&si_other, sizeof(si_other)); 
  
  getsockname(s, (struct sockaddr *)&si_other, &slen);

  ret->socket_fd = s;
 
  return ret;
error:
256 257 258 259
  if (ret != NULL) {
    close(ret->socket_fd);
    free(ret);
  }
260 261 262 263 264 265 266 267 268 269
  LOG_E(MAC, "ERROR in new_link_udp_client (see above), returning NULL\n");
  return NULL;
}


socket_link_t *new_link_sctp_server(int port)
{

  socket_link_t  *ret = NULL;

270
  int listenSock = -1, temp;
271 272 273 274 275 276 277 278 279 280 281
  struct sockaddr_in servaddr;
 
  listenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_SCTP);
  if(listenSock == -1)
  {
      perror("socket()");
      exit(1);
  }
 
  bzero ((void *) &servaddr, sizeof (servaddr));
  servaddr.sin_family = AF_INET;
282
  servaddr.sin_addr.s_addr = INADDR_ANY;
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
  servaddr.sin_port = htons(port);
 
  temp = bind (listenSock, (struct sockaddr *) &servaddr, sizeof (servaddr));
 
  if(temp == -1 )
  {
      perror("bind()");
      close(listenSock);
      exit(1);
  }
 
  temp = listen (listenSock, 5);
    if(temp == -1 )
  {
      perror("listen()");
      close(listenSock);
      exit(1);
  }
301 302 303 304 305 306
  ret = calloc(1, sizeof(socket_link_t));
  if (ret == NULL) {
    LOG_D(PROTO_AGENT, "%s:%d: out of memory\n", __FILE__, __LINE__);
    goto error;
  }
  ret->socket_fd = -1;
307

308
  ret->socket_fd = accept (listenSock, NULL, NULL);
309
  ret->type = SOCK_STREAM;
310 311 312 313
  
  return ret;

error:
314
  if (listenSock != -1) close(listenSock);
315 316
  if (ret != NULL) close(ret->socket_fd);
  free(ret);
317
  LOG_E(MAC,"ERROR in new_link_sctp_server (see above), returning NULL\n");
318 319 320
  return NULL;
}

321
socket_link_t *new_link_sctp_client(const char *server, int port)
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
{

  socket_link_t      *ret = NULL;
  ret = calloc(1, sizeof(socket_link_t));
  if (ret == NULL) {
    LOG_D(PROTO_AGENT, "%s:%d: out of memory\n", __FILE__, __LINE__);
    goto error;
  }
  ret->socket_fd = -1;

  int temp;
  struct sockaddr_in servaddr;
    
  ret->socket_fd = socket (AF_INET, SOCK_STREAM, IPPROTO_SCTP);
 
  if (ret->socket_fd == -1)
  {
      perror("socket()");
      exit(1);
  }
342
  ret->type = SOCK_STREAM;
343 344 345 346
 
  bzero ((void *) &servaddr, sizeof (servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons (port);
347

348
  if (inet_aton(server, &servaddr.sin_addr) == 0) {
349
    LOG_E(MAC,"invalid IP address '%s', use a.b.c.d notation\n", server);
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    goto error;
  }

  temp = connect (ret->socket_fd, (struct sockaddr *) &servaddr, sizeof (servaddr));
 
  if (temp == -1)
  {
      perror("connect()");
      close(ret->socket_fd);
      exit(1);
  }

  return ret;

error:
  if (ret != NULL) close(ret->socket_fd);
  free(ret);
  LOG_E(MAC, "ERROR in new_link_sctp_client (see above), returning NULL\n");
  return NULL;
}

371
static int socket_udp_send(int socket_fd, void *buf, int size, const char *peer_addr, int port)
372 373 374
{
  struct sockaddr_in si_other;
  int slen = sizeof(si_other);
375
  int l;
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
  int my_socket;
  
  LOG_D(PROTO_AGENT,"UDP send\n");

  my_socket = socket_fd;
  memset((char *) &si_other, 0, sizeof(si_other));
  si_other.sin_family = AF_INET;
  si_other.sin_port = htons(port);
     
  if (inet_aton(peer_addr , &si_other.sin_addr) == 0) 
  {
      fprintf(stderr, "inet_aton() failed\n");
      exit(1);
  }

391 392
  l = sendto(my_socket, buf, size, 0, (struct sockaddr *) &si_other, slen);
  if (l == -1) goto error;
393
  
394
  return l;
395
error:
396
  LOG_E(MAC,"socket_udp_send: ERROR: %s\n", strerror(errno));
397 398 399
  return -1;
}

400
static int socket_udp_receive(int socket_fd, void *buf, int size)
401
{
402 403 404
  LOG_D(PROTO_AGENT,"UDP RECEIVE\n");

  struct sockaddr_in client;
405
  socklen_t slen = 0;
406 407
  int   l;

408 409 410 411
  l = recvfrom(socket_fd, buf, size, 0, (struct sockaddr *) &client, &slen);
  //getsockname(socket_fd, (struct sockaddr *)&client, &slen);
  if (l == -1) goto error;
  if (l == 0) goto socket_closed;
412

413
  return l;
414 415

error:
416
  LOG_E(MAC, "socket_udp_receive: ERROR: %s\n", strerror(errno));
417 418 419
  return -1;

socket_closed:
420
  LOG_E(MAC, "socket_udp_receive: socket closed\n");
421 422 423
  return -1;
}

424

425
/*
426
 * return -1 on error and 0 if the sending was fine
427
 */
428
static int socket_send(int socket_fd, void *buf, int size)
429
{
430 431
  char *s = buf;
  int   l;
432

433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
  while (size) {
    l = send(socket_fd, s, size, MSG_NOSIGNAL);
    if (l == -1) goto error;
    if (l == 0) { LOG_E(MAC, "%s:%d: this cannot happen, normally...\n", __FILE__, __LINE__); abort(); }
    size -= l;
    s += l;
  }

  return 0;

error:
  LOG_E(MAC, "socket_send: ERROR: %s\n", strerror(errno));
  return -1;
}

/*
 * return -1 on error and 0 if the receiving was fine
 */
static int socket_receive(int socket_fd, void *buf, int size)
{
453 454 455 456
  char *s = buf;
  int   l;

  while (size) {
457
    l = read(socket_fd, s, size);
458 459 460 461 462 463
    if (l == -1) goto error;
    if (l == 0) goto socket_closed;
    size -= l;
    s += l;
  }

464
  return 0;
465 466

error:
467
  LOG_E(MAC, "socket_receive: ERROR: %s\n", strerror(errno));
468 469 470
  return -1;

socket_closed:
471
  LOG_E(MAC, "socket_receive: socket closed\n");
472 473 474
  return -1;
}

475 476 477
/*
 * return -1 on error and 0 if the sending was fine
 */
478
int link_send_packet(socket_link_t *link, void *data, int size, const char *peer_addr, int peer_port)
479 480 481
{
  char sizebuf[4];
  int32_t s = size;
482 483
  switch (link->type) {
  case SOCK_STREAM:
484 485 486 487 488
    /* send the size first, maximum is 2^31 bytes */
    sizebuf[0] = (s >> 24) & 255;
    sizebuf[1] = (s >> 16) & 255;
    sizebuf[2] = (s >> 8) & 255;
    sizebuf[3] = s & 255;
489
    if (socket_send(link->socket_fd, sizebuf, 4) == -1)
490
      return -1;
491

492
    link->bytes_sent += 4;
493

494
    if (socket_send(link->socket_fd, data, size) == -1)
495 496 497
      return -1;
    break;
  case SOCK_DGRAM:
498 499
    /* UDP is connectionless -> only send the data */
    if (socket_udp_send(link->socket_fd, data, size, peer_addr, peer_port) == -1)
500 501 502 503 504
      return -1;
    break;
  default:
    LOG_E(MAC, "unknown socket type %d\n", link->type);
    return -1;
505
  }
506

507 508 509
  link->bytes_sent += size;
  link->packets_sent++;

510 511 512 513 514 515
  return 0;
}

/*
 * return -1 on error and 0 if the sending was fine
 */
516

517
int link_receive_packet(socket_link_t *link, void **ret_data, int *ret_size)
518 519
{
  unsigned char sizebuf[4];
520
  int32_t       size = 0;
521
  void          *data = NULL;
522
  
523
  /* received the size first, maximum is 2^31 bytes */
524 525
  switch (link->type) {
  case SOCK_STREAM:
526 527
    if (socket_receive(link->socket_fd, sizebuf, 4) == -1)
      goto error;
528

529 530 531 532
    size = (sizebuf[0] << 24) |
           (sizebuf[1] << 16) |
           (sizebuf[2] << 8)  |
            sizebuf[3];
533

534 535 536 537 538 539 540
    link->bytes_received += 4;

    data = malloc(size);
    if (data == NULL) {
      LOG_E(MAC, "%s:%d: out of memory\n", __FILE__, __LINE__);
      goto error;
    }
541

542 543
    if (socket_receive(link->socket_fd, data, size) == -1)
      goto error;
544 545
    break;
  case SOCK_DGRAM:
546 547 548 549 550 551 552 553 554 555 556
    /* we get a single packet (no size, UDP could lose it). Therefore, prepare
     * for the maximum UDP packet size */
    size = 65535;
    data = malloc(size);
    if (data == NULL) {
      LOG_E(MAC, "%s:%d: out of memory\n", __FILE__, __LINE__);
      goto error;
    }

    size = socket_udp_receive(link->socket_fd, data, size);
    if (size < 0)
557
      goto error;
558 559 560 561
    break;
  default:
    LOG_E(MAC, "unknown socket type %d\n", link->type);
    goto error;
562
  }
563

564 565
  link->bytes_received += size;
  link->packets_received++;
566

567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
  *ret_data = data;
  *ret_size = size;
  return 0;

error:
  free(data);
  *ret_data = NULL;
  *ret_size = 0;
  return -1;
}

/*
 * return -1 on error, 0 if all is fine
 */
int close_link(socket_link_t *link)
{
  close(link->socket_fd);
  memset(link, 0, sizeof(socket_link_t));
  free(link);
  return 0;
}

#ifdef SERVER_TEST

#include <inttypes.h>

int main(void)
{
  void *data;
  int size;
  socket_link_t *l = new_link_server(2210);
  if (l == NULL) { printf("no link created\n"); return 1; }
  printf("link is up\n");
  printf("server starts sleeping...\n");
  /* this sleep is here to test for broken pipe. You can run "nc localhost 2210"
   * and interrupt it quickly so that the server gets a 'broken' pipe on the
   * following link_send_packet.
   */
  sleep(1);
  printf("... done\n");
607 608
  if (link_send_packet(l, "hello\n", 6+1, NULL, 0) ||
      link_send_packet(l, "world\n", 6+1, NULL, 0)) return 1;
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
  if (link_receive_packet(l, &data, &size)) return 1; printf("%s", (char *)data); free(data);
  if (link_receive_packet(l, &data, &size)) return 1; printf("%s", (char *)data); free(data);
  printf("stats:\n");
  printf("    sent packets %"PRIu64"\n", l->packets_sent);
  printf("    sent bytes %"PRIu64"\n", l->bytes_sent);
  printf("    received packets %"PRIu64"\n", l->packets_received);
  printf("    received bytes %"PRIu64"\n", l->bytes_received);
  if (close_link(l)) return 1;
  printf("link is down\n");
  return 0;
}

#endif

#ifdef CLIENT_TEST

#include <inttypes.h>

int main(void)
{
  void *data;
  int size;
  socket_link_t *l = new_link_client("127.0.0.1", 2210);
  if (l == NULL) { printf("no link created\n"); return 1; }
  printf("link is up\n");
  if (link_receive_packet(l, &data, &size)) return 1; printf("%s", (char *)data); free(data);
  if (link_receive_packet(l, &data, &size)) return 1; printf("%s", (char *)data); free(data);
636 637
  if (link_send_packet(l, "bye\n", 4+1, NULL, 0) ||
      link_send_packet(l, "server\n", 7+1, NULL, 0)) return 1;
638 639 640 641 642 643 644 645 646 647 648
  printf("stats:\n");
  printf("    sent packets %"PRIu64"\n", l->packets_sent);
  printf("    sent bytes %"PRIu64"\n", l->bytes_sent);
  printf("    received packets %"PRIu64"\n", l->packets_received);
  printf("    received bytes %"PRIu64"\n", l->bytes_received);
  if (close_link(l)) return 1;
  printf("link is down\n");
  return 0;
}

#endif