Merge "Initial support for DPDK 18.05"
[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 "input_conn.h"
24 #include "input.h"
25 #include "run.h"
26 #include "cmd_parser.h"
27
28 static struct input tcp_server;
29 int tcp_server_started;
30 static struct input uds_server;
31 int uds_server_started;
32
33 /* Active clients */
34 struct client_conn {
35         struct input input;
36         int          enabled;
37         int          n_buf;
38         char         buf[32768];
39 };
40
41 struct client_conn clients[32];
42
43 static int start_listen_tcp(void)
44 {
45         struct sockaddr_in server;
46         int ret, sock;
47         int optval = 1;
48
49         memset(&server, 0, sizeof(server));
50         sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
51
52         if (sock == -1)
53                 return -1;
54
55         server.sin_family = AF_INET;
56         server.sin_port = ntohs(8474);
57         server.sin_addr.s_addr = ntohl(INADDR_ANY);
58
59         ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
60
61         if (ret)
62                 return -1;
63
64         if (bind(sock, (struct sockaddr *) &server, sizeof(server)) == -1)
65                 return -1;
66
67         if (listen(sock, 1) == -1)
68                 return -1;
69
70         return sock;
71 }
72
73 static int start_listen_uds(void)
74 {
75         int sock;
76         struct sockaddr_un server = {
77                 .sun_path = "/tmp/prox.sock",
78                 .sun_family = AF_UNIX
79         };
80
81         sock = socket(AF_UNIX, SOCK_STREAM, 0);
82         if (sock == -1)
83                 return -1;
84
85         /* Unlink can fail, i.e. when /tmp/prox.sock does not
86            exists. This is not fatal. */
87         unlink(server.sun_path);
88
89         if (bind(sock, (struct sockaddr *) &server, sizeof(server)) == -1)
90                 return -1;
91
92         if (listen(sock, 1) == -1)
93                 return -1;
94
95         return sock;
96 }
97
98 static void write_client(struct input *input, const char *buf, size_t len)
99 {
100         int ret;
101
102         while ((ret = write(input->fd, buf, len)) != (int)len) {
103                 buf += ret;
104                 len -= ret;
105         }
106 }
107
108 static void handle_client(struct input* client_input)
109 {
110         char cur[1024];
111         size_t i;
112         int ret;
113         struct client_conn *c = NULL;
114
115         /* Get the client structure that uses this input */
116         for (i = 0; i < sizeof(clients)/sizeof(clients[0]); ++i) {
117                 if (&clients[i].input == client_input) {
118                         c = &clients[i];
119                         break;
120                 }
121         }
122
123         /* handle_client function called non-tcp client */
124         if (c == NULL)
125                 return ;
126
127         ret = read(c->input.fd, cur, sizeof(cur));
128
129         if (ret == 0) {
130                 c->enabled = 0;
131                 unreg_input(&c->input);
132                 return ;
133         }
134
135         /* Scan in data until \n (\r skipped if followed by \n) */
136         for (int i = 0; i < ret; ++i) {
137                 if (cur[i] == '\r' && i + 1 < ret && cur[i + 1] == '\n')
138                         continue;
139
140                 if (cur[i] == '\n') {
141                         c->buf[c->n_buf] = 0;
142                         if (c->n_buf)
143                                 cmd_parser_parse(c->buf, client_input);
144                         c->n_buf = 0;
145                 }
146                 else if (c->n_buf + 1 < (int)sizeof(c->buf))
147                         c->buf[c->n_buf++] = cur[i];
148                 else
149                         c->n_buf = 0;
150         }
151 }
152
153 static void handle_new_client(struct input* server)
154 {
155         size_t i;
156
157         int new_client = accept(server->fd, NULL, NULL);
158
159         for (i = 0; i < sizeof(clients)/sizeof(clients[0]); ++i) {
160                 if (clients[i].enabled == 0) {
161                         break;
162                 }
163         }
164
165         if (i == sizeof(clients)/sizeof(clients[0])) {
166                 close(new_client);
167                 return ;
168         }
169
170         clients[i].enabled = 1;
171         clients[i].n_buf = 0;
172         clients[i].input.fd = new_client;
173         clients[i].input.reply = server->reply;
174         clients[i].input.proc_input = handle_client;
175
176         reg_input(&clients[i].input);
177 }
178
179 int reg_input_tcp(void)
180 {
181         int fd;
182
183         if (tcp_server_started)
184                 return -1;
185         if ((fd = start_listen_tcp()) < 0)
186                 return -1;
187
188         tcp_server.fd = fd;
189         tcp_server.proc_input = handle_new_client;
190         tcp_server.reply = write_client;
191         if (reg_input(&tcp_server) != 0) {
192                 close(fd);
193                 return -1;
194         }
195         tcp_server_started = 1;
196         return 0;
197 }
198
199 int reg_input_uds(void)
200 {
201         int fd;
202
203         if (uds_server_started)
204                 return -1;
205
206         if ((fd = start_listen_uds()) < 0)
207                 return -1;
208
209         uds_server.fd = fd;
210         uds_server.proc_input = handle_new_client;
211         uds_server.reply = write_client;
212         if (reg_input(&uds_server) != 0) {
213                 close(fd);
214                 return -1;
215         }
216         uds_server_started = 1;
217         return 0;
218 }
219
220 void unreg_input_tcp(void)
221 {
222         if (!tcp_server_started)
223                 return;
224         tcp_server_started = 0;
225         close(tcp_server.fd);
226         unreg_input(&tcp_server);
227 }
228
229 void unreg_input_uds(void)
230 {
231         if (!uds_server_started)
232                 return;
233         uds_server_started = 0;
234         close(tcp_server.fd);
235         unreg_input(&tcp_server);
236 }