Merge "Reorganize directories and switch libaries to using asn1c"
[it/test.git] / simulators / e2sim / src / SCTP / e2sim_sctp.cpp
1 /*****************************************************************************
2 #                                                                            *
3 # Copyright 2019 AT&T Intellectual Property                                  *
4 # Copyright 2019 Nokia                                                       *
5 #                                                                            *
6 # Licensed under the Apache License, Version 2.0 (the "License");            *
7 # you may not use this file except in compliance with the License.           *
8 # You may obtain a copy of the License at                                    *
9 #                                                                            *
10 #      http://www.apache.org/licenses/LICENSE-2.0                            *
11 #                                                                            *
12 # Unless required by applicable law or agreed to in writing, software        *
13 # distributed under the License is distributed on an "AS IS" BASIS,          *
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
15 # See the License for the specific language governing permissions and        *
16 # limitations under the License.                                             *
17 #                                                                            *
18 ******************************************************************************/
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>             //for close()
22 #include <stdlib.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <netinet/sctp.h>
26 #include <arpa/inet.h>  //for inet_ntop()
27 #include <assert.h>
28
29 #include "e2sim_sctp.hpp"
30 // #include "e2sim_defs.h"
31
32
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/sctp.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41
42 int sctp_start_server(const char *server_ip_str, const int server_port)
43 {
44   if(server_port < 1 || server_port > 65535) {
45       LOG_E("Invalid port number (%d). Valid values are between 1 and 65535.\n", server_port);
46       exit(1);
47   }
48
49   int server_fd, af;
50   struct sockaddr* server_addr;
51   size_t addr_len;
52
53   struct sockaddr_in  server4_addr;
54   memset(&server4_addr, 0, sizeof(struct sockaddr_in));
55
56   struct sockaddr_in6 server6_addr;
57   memset(&server6_addr, 0, sizeof(struct sockaddr_in6));
58
59   if(inet_pton(AF_INET, server_ip_str, &server4_addr.sin_addr) == 1)
60   {
61     server4_addr.sin_family = AF_INET;
62     server4_addr.sin_port   = htons(server_port);
63
64     server_addr = (struct sockaddr*)&server4_addr;
65     af          = AF_INET;
66     addr_len    = sizeof(server4_addr);
67   }
68   else if(inet_pton(AF_INET6, server_ip_str, &server6_addr.sin6_addr) == 1)
69   {
70     server6_addr.sin6_family = AF_INET6;
71     server6_addr.sin6_port   = htons(server_port);
72
73     server_addr = (struct sockaddr*)&server6_addr;
74     af          = AF_INET6;
75     addr_len    = sizeof(server6_addr);
76   }
77   else {
78     perror("inet_pton()");
79     exit(1);
80   }
81
82   if((server_fd = socket(af, SOCK_STREAM, IPPROTO_SCTP)) == -1) {
83     perror("socket");
84     exit(1);
85   }
86
87   if(bind(server_fd, server_addr, addr_len) == -1) {
88     perror("bind");
89     exit(1);
90   }
91
92   if(listen(server_fd, SERVER_LISTEN_QUEUE_SIZE) != 0) {
93     perror("listen");
94     exit(1);
95   }
96
97   assert(server_fd != 0);
98
99   LOG_I("[SCTP] Server started on %s:%d", server_ip_str, server_port);
100
101   return server_fd;
102 }
103
104 int sctp_start_client(const char *server_ip_str, const int server_port)
105 {
106   int client_fd, af;
107
108   struct sockaddr* server_addr;
109   size_t addr_len;
110
111   struct sockaddr_in  server4_addr;
112   memset(&server4_addr, 0, sizeof(struct sockaddr_in));
113
114   struct sockaddr_in6 server6_addr;
115   memset(&server6_addr, 0, sizeof(struct sockaddr_in6));
116
117   if(inet_pton(AF_INET, server_ip_str, &server4_addr.sin_addr) == 1)
118   {
119     server4_addr.sin_family = AF_INET;
120     server4_addr.sin_port   = htons(server_port);
121     server_addr = (struct sockaddr*)&server4_addr;
122     addr_len    = sizeof(server4_addr);
123   }
124   else if(inet_pton(AF_INET6, server_ip_str, &server6_addr.sin6_addr) == 1)
125   {
126     server6_addr.sin6_family = AF_INET6;
127     server6_addr.sin6_port   = htons(server_port);
128     server_addr = (struct sockaddr*)&server6_addr;
129     addr_len    = sizeof(server6_addr);
130   }
131   else {
132     perror("inet_pton()");
133     exit(1);
134   }
135
136   if((client_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) == -1)
137   {
138      perror("socket");
139      exit(1);
140   }
141
142   //--------------------------------
143   //Bind before connect
144   auto optval = 1;
145   if( setsockopt(client_fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof optval) != 0 ){
146     perror("setsockopt port");
147     exit(1);
148   }
149
150   if( setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) != 0 ){
151     perror("setsockopt addr");
152     exit(1);
153   }
154
155   struct sockaddr_in6  client6_addr {};
156   client6_addr.sin6_family = AF_INET6;
157   client6_addr.sin6_port   = htons(RIC_SCTP_SRC_PORT);
158   client6_addr.sin6_addr   = in6addr_any;
159
160   LOG_I("[SCTP] Binding client socket to source port %d", RIC_SCTP_SRC_PORT);
161   if(bind(client_fd, (struct sockaddr*)&client6_addr, sizeof(client6_addr)) == -1) {
162     perror("bind");
163     exit(1);
164   }
165   // end binding ---------------------
166
167   LOG_I("[SCTP] Connecting to server at %s:%d ...", server_ip_str, server_port);
168   if(connect(client_fd, server_addr, addr_len) == -1) {
169     perror("connect");
170     exit(1);
171   }
172   assert(client_fd != 0);
173
174   LOG_I("[SCTP] Connection established");
175
176   return client_fd;
177 }
178
179 int sctp_accept_connection(const char *server_ip_str, const int server_fd)
180 {
181   LOG_I("[SCTP] Waiting for new connection...");
182
183   struct sockaddr client_addr;
184   socklen_t       client_addr_size;
185   int             client_fd;
186
187   //Blocking call
188   client_fd = accept(server_fd, &client_addr, &client_addr_size);
189   if(client_fd == -1){
190     perror("accept()");
191     close(client_fd);
192     exit(1);
193   }
194
195   //Retrieve client IP_ADDR
196   char client_ip6_addr[INET6_ADDRSTRLEN], client_ip4_addr[INET_ADDRSTRLEN];
197   if(strchr(server_ip_str, ':') != NULL) //IPv6
198   {
199     struct sockaddr_in6* client_ipv6 = (struct sockaddr_in6*)&client_addr;
200     inet_ntop(AF_INET6, &(client_ipv6->sin6_addr), client_ip6_addr, INET6_ADDRSTRLEN);
201     LOG_I("[SCTP] New client connected from %s", client_ip6_addr);
202   }
203   else {
204     struct sockaddr_in* client_ipv4 = (struct sockaddr_in*)&client_addr;
205     inet_ntop(AF_INET, &(client_ipv4->sin_addr), client_ip4_addr, INET_ADDRSTRLEN);
206     LOG_I("[SCTP] New client connected from %s", client_ip4_addr);
207   }
208
209   return client_fd;
210 }
211
212 int sctp_send_data(int &socket_fd, sctp_buffer_t &data)
213 {
214   int sent_len = send(socket_fd, (void*)(&(data.buffer[0])), data.len, 0);
215
216   if(sent_len == -1) {
217     perror("[SCTP] sctp_send_data");
218     exit(1);
219   }
220
221   return sent_len;
222 }
223
224 int sctp_send_data_X2AP(int &socket_fd, sctp_buffer_t &data)
225 {
226   int sent_len = sctp_sendmsg(socket_fd, (void*)(&(data.buffer[0])), data.len,
227                   NULL, 0, (uint32_t) X2AP_PPID, 0, 0, 0, 0);
228
229   if(sent_len == -1) {
230     perror("[SCTP] sctp_send_data");
231     exit(1);
232   }
233
234 }
235
236 /*
237 Receive data from SCTP socket
238 Outcome of recv()
239 -1: exit the program
240 0: close the connection
241 +: new data
242 */
243 int sctp_receive_data(int &socket_fd, sctp_buffer_t &data)
244 {
245   //clear out the data before receiving
246   memset(data.buffer, 0, sizeof(data.buffer));
247   data.len = 0;
248
249   //receive data from the socket
250   int recv_len = recv(socket_fd, &(data.buffer), sizeof(data.buffer), 0);
251   if(recv_len == -1)
252   {
253     perror("[SCTP] recv");
254     exit(1);
255   }
256   else if (recv_len == 0)
257   {
258     LOG_I("[SCTP] Connection closed by remote peer");
259     if(close(socket_fd) == -1)
260     {
261       perror("[SCTP] close");
262     }
263     return -1;
264   }
265
266   data.len = recv_len;
267
268   return recv_len;
269 }