Preparation for packet mis-ordering stats
[samplevnf.git] / VNFs / DPPD-PROX / input_conn.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <string.h>
18 #include <netinet/in.h>
19 #include <sys/socket.h>
20 #include <sys/un.h>
21 #include <unistd.h>
22
23 #include <rte_cycles.h>
24 #include "input_conn.h"
25 #include "input.h"
26 #include "log.h"
27 #include "run.h"
28 #include "cmd_parser.h"
29 #include "prox_cfg.h"
30
31 static struct input tcp_server;
32 int tcp_server_started;
33 static struct input uds_server;
34 int uds_server_started;
35
36 /* Active clients */
37 struct client_conn {
38         struct input input;
39         int          enabled;
40         int          n_buf;
41         char         buf[32768];
42 };
43
44 struct client_conn clients[32];
45
46 static int start_listen_tcp(void)
47 {
48         struct sockaddr_in server;
49         int ret, sock;
50         int optval = 1;
51
52         memset(&server, 0, sizeof(server));
53         sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
54
55         if (sock == -1)
56                 return -1;
57
58         server.sin_family = AF_INET;
59         server.sin_port = ntohs(8474);
60         server.sin_addr.s_addr = ntohl(INADDR_ANY);
61
62         ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
63
64         if (ret)
65                 return -1;
66
67         if (bind(sock, (struct sockaddr *) &server, sizeof(server)) == -1)
68                 return -1;
69
70         if (listen(sock, 1) == -1)
71                 return -1;
72
73         return sock;
74 }
75
76 static int start_listen_uds(void)
77 {
78         int sock;
79         struct sockaddr_un server = {
80                 .sun_path = "/tmp/prox.sock",
81                 .sun_family = AF_UNIX
82         };
83
84         sock = socket(AF_UNIX, SOCK_STREAM, 0);
85         if (sock == -1)
86                 return -1;
87
88         /* Unlink can fail, i.e. when /tmp/prox.sock does not
89            exists. This is not fatal. */
90         unlink(server.sun_path);
91
92         if (bind(sock, (struct sockaddr *) &server, sizeof(server)) == -1)
93                 return -1;
94
95         if (listen(sock, 1) == -1)
96                 return -1;
97
98         return sock;
99 }
100
101 static void write_client(struct input *input, const char *buf, size_t len)
102 {
103         int ret;
104
105         while ((ret = write(input->fd, buf, len)) != (int)len) {
106                 buf += ret;
107                 len -= ret;
108         }
109 }
110
111 static void handle_client(struct input* client_input)
112 {
113         char cur[1024];
114         size_t i;
115         int ret;
116         struct client_conn *c = NULL;
117
118         /* Get the client structure that uses this input */
119         for (i = 0; i < sizeof(clients)/sizeof(clients[0]); ++i) {
120                 if (&clients[i].input == client_input) {
121                         c = &clients[i];
122                         break;
123                 }
124         }
125
126         /* handle_client function called non-tcp client */
127         if (c == NULL)
128                 return ;
129
130         ret = read(c->input.fd, cur, sizeof(cur));
131
132         if (ret == 0) {
133                 c->enabled = 0;
134                 unreg_input(&c->input);
135                 return ;
136         }
137
138         prox_cfg.heartbeat_tsc = rte_rdtsc() + prox_cfg.heartbeat_timeout * rte_get_tsc_hz();
139
140         /* Scan in data until \n (\r skipped if followed by \n) */
141         for (int i = 0; i < ret; ++i) {
142                 if (cur[i] == '\r' && i + 1 < ret && cur[i + 1] == '\n')
143                         continue;
144
145                 if (cur[i] == '\n') {
146                         c->buf[c->n_buf] = 0;
147                         if (c->n_buf)
148                                 cmd_parser_parse(c->buf, client_input);
149                         c->n_buf = 0;
150                 }
151                 else if (c->n_buf + 1 < (int)sizeof(c->buf))
152                         c->buf[c->n_buf++] = cur[i];
153                 else
154                         c->n_buf = 0;
155         }
156 }
157
158 void stop_handling_client(void)
159 {
160         size_t i;
161         for (i = 0; i < sizeof(clients)/sizeof(clients[0]); ++i) {
162                 if (clients[i].enabled) {
163                         close(clients[i].input.fd);
164                         clients[i].enabled = 0;
165                         unreg_input(&clients[i].input);
166                 }
167         }
168 }
169
170 static void handle_new_client(struct input* server)
171 {
172         size_t i;
173
174         int new_client = accept(server->fd, NULL, NULL);
175
176         for (i = 0; i < sizeof(clients)/sizeof(clients[0]); ++i) {
177                 if (clients[i].enabled == 0) {
178                         break;
179                 }
180         }
181
182         if (i == sizeof(clients)/sizeof(clients[0])) {
183                 close(new_client);
184                 return ;
185         }
186
187         clients[i].enabled = 1;
188         clients[i].n_buf = 0;
189         clients[i].input.fd = new_client;
190         clients[i].input.reply = server->reply;
191         clients[i].input.proc_input = handle_client;
192
193         reg_input(&clients[i].input);
194 }
195
196 int reg_input_tcp(void)
197 {
198         int fd;
199
200         if (tcp_server_started)
201                 return -1;
202         if ((fd = start_listen_tcp()) < 0)
203                 return -1;
204
205         tcp_server.fd = fd;
206         tcp_server.proc_input = handle_new_client;
207         tcp_server.reply = write_client;
208         if (reg_input(&tcp_server) != 0) {
209                 close(fd);
210                 return -1;
211         }
212         tcp_server_started = 1;
213         return 0;
214 }
215
216 int reg_input_uds(void)
217 {
218         int fd;
219
220         if (uds_server_started)
221                 return -1;
222
223         if ((fd = start_listen_uds()) < 0)
224                 return -1;
225
226         uds_server.fd = fd;
227         uds_server.proc_input = handle_new_client;
228         uds_server.reply = write_client;
229         if (reg_input(&uds_server) != 0) {
230                 close(fd);
231                 return -1;
232         }
233         uds_server_started = 1;
234         return 0;
235 }
236
237 void unreg_input_tcp(void)
238 {
239         if (!tcp_server_started)
240                 return;
241         tcp_server_started = 0;
242         close(tcp_server.fd);
243         unreg_input(&tcp_server);
244 }
245
246 void unreg_input_uds(void)
247 {
248         if (!uds_server_started)
249                 return;
250         uds_server_started = 0;
251         close(tcp_server.fd);
252         unreg_input(&tcp_server);
253 }