Issue-ID: SIM-18
[sim/e2-interface.git] / e2sim / e2apv1sim / ricsim / src / SCTP / e2sim_sctp.cpp
diff --git a/e2sim/e2apv1sim/ricsim/src/SCTP/e2sim_sctp.cpp b/e2sim/e2apv1sim/ricsim/src/SCTP/e2sim_sctp.cpp
new file mode 100644 (file)
index 0000000..55547b4
--- /dev/null
@@ -0,0 +1,297 @@
+/*****************************************************************************
+#                                                                            *
+# Copyright 2019 AT&T Intellectual Property                                  *
+# Copyright 2019 Nokia                                                       *
+#                                                                            *
+# Licensed under the Apache License, Version 2.0 (the "License");            *
+# you may not use this file except in compliance with the License.           *
+# You may obtain a copy of the License at                                    *
+#                                                                            *
+#      http://www.apache.org/licenses/LICENSE-2.0                            *
+#                                                                            *
+# 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.                                             *
+#                                                                            *
+******************************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>            //for close()
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/sctp.h>
+#include <arpa/inet.h> //for inet_ntop()
+#include <assert.h>
+
+#include "e2sim_sctp.hpp"
+// #include "e2sim_defs.h"
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/sctp.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int sctp_start_server(const char *server_ip_str, const int server_port)
+{
+  if(server_port < 1 || server_port > 65535) {
+      LOG_E("Invalid port number (%d). Valid values are between 1 and 65535.\n", server_port);
+      exit(1);
+  }
+
+  int server_fd, af;
+  struct sockaddr* server_addr;
+  size_t addr_len;
+
+  struct sockaddr_in  server4_addr;
+  memset(&server4_addr, 0, sizeof(struct sockaddr_in));
+
+  struct sockaddr_in6 server6_addr;
+  memset(&server6_addr, 0, sizeof(struct sockaddr_in6));
+
+  if(inet_pton(AF_INET, server_ip_str, &server4_addr.sin_addr) == 1)
+  {
+    server4_addr.sin_family = AF_INET;
+    server4_addr.sin_port   = htons(server_port);
+
+    server_addr = (struct sockaddr*)&server4_addr;
+    af          = AF_INET;
+    addr_len    = sizeof(server4_addr);
+  }
+  else if(inet_pton(AF_INET6, server_ip_str, &server6_addr.sin6_addr) == 1)
+  {
+    server6_addr.sin6_family = AF_INET6;
+    server6_addr.sin6_port   = htons(server_port);
+
+    server_addr = (struct sockaddr*)&server6_addr;
+    af          = AF_INET6;
+    addr_len    = sizeof(server6_addr);
+  }
+  else {
+    perror("inet_pton()");
+    exit(1);
+  }
+
+  if((server_fd = socket(af, SOCK_STREAM, IPPROTO_SCTP)) == -1) {
+    perror("socket");
+    exit(1);
+  }
+
+  //set send_buffer
+  // int sendbuff = 10000;
+  // socklen_t optlen = sizeof(sendbuff);
+  // if(getsockopt(server_fd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen) == -1) {
+  //   perror("getsockopt send");
+  //   exit(1);
+  // }
+  // else
+  //   LOG_D("[SCTP] send buffer size = %d\n", sendbuff);
+
+
+  if(bind(server_fd, server_addr, addr_len) == -1) {
+    perror("bind");
+    exit(1);
+  }
+
+  if(listen(server_fd, SERVER_LISTEN_QUEUE_SIZE) != 0) {
+    perror("listen");
+    exit(1);
+  }
+
+  assert(server_fd != 0);
+
+  LOG_I("[SCTP] Server started on %s:%d", server_ip_str, server_port);
+
+  return server_fd;
+}
+
+int sctp_start_client(const char *server_ip_str, const int server_port)
+{
+  int client_fd, af;
+
+  struct sockaddr* server_addr;
+  size_t addr_len;
+
+  struct sockaddr_in  server4_addr;
+  memset(&server4_addr, 0, sizeof(struct sockaddr_in));
+
+  struct sockaddr_in6 server6_addr;
+  memset(&server6_addr, 0, sizeof(struct sockaddr_in6));
+
+  if(inet_pton(AF_INET, server_ip_str, &server4_addr.sin_addr) == 1)
+  {
+    server4_addr.sin_family = AF_INET;
+    server4_addr.sin_port   = htons(server_port);
+    server_addr = (struct sockaddr*)&server4_addr;
+    addr_len    = sizeof(server4_addr);
+  }
+  else if(inet_pton(AF_INET6, server_ip_str, &server6_addr.sin6_addr) == 1)
+  {
+    server6_addr.sin6_family = AF_INET6;
+    server6_addr.sin6_port   = htons(server_port);
+    server_addr = (struct sockaddr*)&server6_addr;
+    addr_len    = sizeof(server6_addr);
+  }
+  else {
+    perror("inet_pton()");
+    exit(1);
+  }
+
+  if((client_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) == -1)
+  {
+     perror("socket");
+     exit(1);
+  }
+
+  // int sendbuff = 10000;
+  // socklen_t optlen = sizeof(sendbuff);
+  // if(getsockopt(client_fd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen) == -1) {
+  //   perror("getsockopt send");
+  //   exit(1);
+  // }
+  // else
+  //   LOG_D("[SCTP] send buffer size = %d\n", sendbuff);
+
+  //--------------------------------
+  //Bind before connect
+  auto optval = 1;
+  if( setsockopt(client_fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof optval) != 0 ){
+    perror("setsockopt port");
+    exit(1);
+  }
+
+  if( setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) != 0 ){
+    perror("setsockopt addr");
+    exit(1);
+  }
+
+  struct sockaddr_in6  client6_addr {};
+  client6_addr.sin6_family = AF_INET6;
+  client6_addr.sin6_port   = htons(RIC_SCTP_SRC_PORT);
+  client6_addr.sin6_addr   = in6addr_any;
+
+  LOG_I("[SCTP] Binding client socket to source port %d", RIC_SCTP_SRC_PORT);
+  if(bind(client_fd, (struct sockaddr*)&client6_addr, sizeof(client6_addr)) == -1) {
+    perror("bind");
+    exit(1);
+  }
+  // end binding ---------------------
+
+  LOG_I("[SCTP] Connecting to server at %s:%d ...", server_ip_str, server_port);
+  if(connect(client_fd, server_addr, addr_len) == -1) {
+    perror("connect");
+    exit(1);
+  }
+  assert(client_fd != 0);
+
+  LOG_I("[SCTP] Connection established");
+
+  return client_fd;
+}
+
+int sctp_accept_connection(const char *server_ip_str, const int server_fd)
+{
+  LOG_I("[SCTP] Waiting for new connection...");
+
+  struct sockaddr client_addr;
+  socklen_t       client_addr_size;
+  int             client_fd;
+
+  //Blocking call
+  client_fd = accept(server_fd, &client_addr, &client_addr_size);
+  fprintf(stderr, "client fd is %d\n", client_fd);
+  if(client_fd == -1){
+    perror("accept()");
+    close(client_fd);
+    exit(1);
+  }
+
+  //Retrieve client IP_ADDR
+  char client_ip6_addr[INET6_ADDRSTRLEN], client_ip4_addr[INET_ADDRSTRLEN];
+  if(strchr(server_ip_str, ':') != NULL) //IPv6
+  {
+    struct sockaddr_in6* client_ipv6 = (struct sockaddr_in6*)&client_addr;
+    inet_ntop(AF_INET6, &(client_ipv6->sin6_addr), client_ip6_addr, INET6_ADDRSTRLEN);
+    LOG_I("[SCTP] New client connected from %s", client_ip6_addr);
+  }
+  else {
+    struct sockaddr_in* client_ipv4 = (struct sockaddr_in*)&client_addr;
+    inet_ntop(AF_INET, &(client_ipv4->sin_addr), client_ip4_addr, INET_ADDRSTRLEN);
+    LOG_I("[SCTP] New client connected from %s", client_ip4_addr);
+  }
+
+  return client_fd;
+}
+
+int sctp_send_data(int &socket_fd, sctp_buffer_t &data)
+{
+  fprintf(stderr,"in sctp send data func\n");
+  fprintf(stderr,"data.len is %d", data.len);
+  int sent_len = send(socket_fd, (void*)(&(data.buffer[0])), data.len, 0);
+  fprintf(stderr,"after getting sent_len\n");
+
+  if(sent_len == -1) {
+    perror("[SCTP] sctp_send_data");
+    exit(1);
+  }
+
+  return sent_len;
+}
+
+int sctp_send_data_X2AP(int &socket_fd, sctp_buffer_t &data)
+{
+  int sent_len = sctp_sendmsg(socket_fd, (void*)(&(data.buffer[0])), data.len,
+                  NULL, 0, (uint32_t) X2AP_PPID, 0, 0, 0, 0);
+
+  if(sent_len == -1) {
+    perror("[SCTP] sctp_send_data");
+    exit(1);
+  }
+
+}
+
+/*
+Receive data from SCTP socket
+Outcome of recv()
+-1: exit the program
+0: close the connection
++: new data
+*/
+int sctp_receive_data(int &socket_fd, sctp_buffer_t &data)
+{
+  //clear out the data before receiving
+  fprintf(stderr, "receive data1\n");
+  memset(data.buffer, 0, sizeof(data.buffer));
+  fprintf(stderr, "receive data2\n");  
+  data.len = 0;
+
+  //receive data from the socket
+  int recv_len = recv(socket_fd, &(data.buffer), sizeof(data.buffer), 0);
+  fprintf(stderr, "receive data3\n");
+  
+  if(recv_len == -1)
+  {
+    perror("[SCTP] recv");
+    exit(1);
+  }
+  else if (recv_len == 0)
+  {
+    LOG_I("[SCTP] Connection closed by remote peer");
+    if(close(socket_fd) == -1)
+    {
+      perror("[SCTP] close");
+    }
+    return -1;
+  }
+
+  data.len = recv_len;
+
+  return recv_len;
+}