examples/ip_pipeline: add CLI interface
[dpdk.git] / examples / ip_pipeline / conn.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4
5 #include <string.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10
11 #define __USE_GNU
12 #include <sys/socket.h>
13
14 #include <sys/epoll.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
17 #include <errno.h>
18
19 #include "conn.h"
20
21 #define MSG_CMD_TOO_LONG "Command too long."
22
23 struct conn {
24         char *welcome;
25         char *prompt;
26         char *buf;
27         char *msg_in;
28         char *msg_out;
29         size_t buf_size;
30         size_t msg_in_len_max;
31         size_t msg_out_len_max;
32         size_t msg_in_len;
33         int fd_server;
34         int fd_client_group;
35         conn_msg_handle_t msg_handle;
36 };
37
38 struct conn *
39 conn_init(struct conn_params *p)
40 {
41         struct sockaddr_in server_address;
42         struct conn *conn;
43         int fd_server, fd_client_group, status;
44
45         memset(&server_address, 0, sizeof(server_address));
46
47         /* Check input arguments */
48         if ((p == NULL) ||
49                 (p->welcome == NULL) ||
50                 (p->prompt == NULL) ||
51                 (p->addr == NULL) ||
52                 (p->buf_size == 0) ||
53                 (p->msg_in_len_max == 0) ||
54                 (p->msg_out_len_max == 0) ||
55                 (p->msg_handle == NULL))
56                 return NULL;
57
58         status = inet_aton(p->addr, &server_address.sin_addr);
59         if (status == 0)
60                 return NULL;
61
62         /* Memory allocation */
63         conn = calloc(1, sizeof(struct conn));
64         if (conn == NULL)
65                 return NULL;
66
67         conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1);
68         conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1);
69         conn->buf = calloc(1, p->buf_size);
70         conn->msg_in = calloc(1, p->msg_in_len_max + 1);
71         conn->msg_out = calloc(1, p->msg_out_len_max + 1);
72
73         if ((conn->welcome == NULL) ||
74                 (conn->prompt == NULL) ||
75                 (conn->buf == NULL) ||
76                 (conn->msg_in == NULL) ||
77                 (conn->msg_out == NULL)) {
78                 conn_free(conn);
79                 return NULL;
80         }
81
82         /* Server socket */
83         server_address.sin_family = AF_INET;
84         server_address.sin_port = htons(p->port);
85
86         fd_server = socket(AF_INET,
87                 SOCK_STREAM | SOCK_NONBLOCK,
88                 0);
89         if (fd_server == -1) {
90                 conn_free(conn);
91                 return NULL;
92         }
93
94         status = bind(fd_server,
95                 (struct sockaddr *) &server_address,
96                 sizeof(server_address));
97         if (status == -1) {
98                 conn_free(conn);
99                 return NULL;
100         }
101
102         status = listen(fd_server, 16);
103         if (status == -1) {
104                 conn_free(conn);
105                 return NULL;
106         }
107
108         /* Client group */
109         fd_client_group = epoll_create(1);
110         if (fd_client_group == -1) {
111                 conn_free(conn);
112                 return NULL;
113         }
114
115         /* Fill in */
116         strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX);
117         strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX);
118         conn->buf_size = p->buf_size;
119         conn->msg_in_len_max = p->msg_in_len_max;
120         conn->msg_out_len_max = p->msg_out_len_max;
121         conn->msg_in_len = 0;
122         conn->fd_server = fd_server;
123         conn->fd_client_group = fd_client_group;
124         conn->msg_handle = p->msg_handle;
125
126         return conn;
127 }
128
129 void
130 conn_free(struct conn *conn)
131 {
132         if (conn == NULL)
133                 return;
134
135         if (conn->fd_client_group)
136                 close(conn->fd_client_group);
137
138         if (conn->fd_server)
139                 close(conn->fd_server);
140
141         free(conn->msg_out);
142         free(conn->msg_in);
143         free(conn->prompt);
144         free(conn->welcome);
145         free(conn);
146 }
147
148 int
149 conn_poll_for_conn(struct conn *conn)
150 {
151         struct sockaddr_in client_address;
152         struct epoll_event event;
153         socklen_t client_address_length;
154         int fd_client, status;
155
156         /* Check input arguments */
157         if (conn == NULL)
158                 return -1;
159
160         /* Server socket */
161         client_address_length = sizeof(client_address);
162         fd_client = accept4(conn->fd_server,
163                 (struct sockaddr *) &client_address,
164                 &client_address_length,
165                 SOCK_NONBLOCK);
166         if (fd_client == -1) {
167                 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
168                         return 0;
169
170                 return -1;
171         }
172
173         /* Client group */
174         event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
175         event.data.fd = fd_client;
176
177         status = epoll_ctl(conn->fd_client_group,
178                 EPOLL_CTL_ADD,
179                 fd_client,
180                 &event);
181         if (status == -1) {
182                 close(fd_client);
183                 return -1;
184         }
185
186         /* Client */
187         status = write(fd_client,
188                 conn->welcome,
189                 strlen(conn->welcome));
190         if (status == -1) {
191                 close(fd_client);
192                 return -1;
193         }
194
195         status = write(fd_client,
196                 conn->prompt,
197                 strlen(conn->prompt));
198         if (status == -1) {
199                 close(fd_client);
200                 return -1;
201         }
202
203         return 0;
204 }
205
206 static int
207 data_event_handle(struct conn *conn,
208         int fd_client)
209 {
210         ssize_t len, i, status;
211
212         /* Read input message */
213
214         len = read(fd_client,
215                 conn->buf,
216                 conn->buf_size);
217         if (len == -1) {
218                 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
219                         return 0;
220
221                 return -1;
222         }
223         if (len == 0)
224                 return 0;
225
226         /* Handle input messages */
227         for (i = 0; i < len; i++) {
228                 if (conn->buf[i] == '\n') {
229                         size_t n;
230
231                         conn->msg_in[conn->msg_in_len] = 0;
232                         conn->msg_out[0] = 0;
233
234                         conn->msg_handle(conn->msg_in,
235                                 conn->msg_out,
236                                 conn->msg_out_len_max);
237
238                         n = strlen(conn->msg_out);
239                         if (n) {
240                                 status = write(fd_client,
241                                         conn->msg_out,
242                                         n);
243                                 if (status == -1)
244                                         return status;
245                         }
246
247                         conn->msg_in_len = 0;
248                 } else if (conn->msg_in_len < conn->msg_in_len_max) {
249                         conn->msg_in[conn->msg_in_len] = conn->buf[i];
250                         conn->msg_in_len++;
251                 } else {
252                         status = write(fd_client,
253                                 MSG_CMD_TOO_LONG,
254                                 strlen(MSG_CMD_TOO_LONG));
255                         if (status == -1)
256                                 return status;
257
258                         conn->msg_in_len = 0;
259                 }
260         }
261
262         /* Write prompt */
263         status = write(fd_client,
264                 conn->prompt,
265                 strlen(conn->prompt));
266         if (status == -1)
267                 return status;
268
269         return 0;
270 }
271
272 static int
273 control_event_handle(struct conn *conn,
274         int fd_client)
275 {
276         int status;
277
278         status = epoll_ctl(conn->fd_client_group,
279                 EPOLL_CTL_DEL,
280                 fd_client,
281                 NULL);
282         if (status == -1)
283                 return -1;
284
285         status = close(fd_client);
286         if (status == -1)
287                 return -1;
288
289         return 0;
290 }
291
292 int
293 conn_poll_for_msg(struct conn *conn)
294 {
295         struct epoll_event event;
296         int fd_client, status, status_data = 0, status_control = 0;
297
298         /* Check input arguments */
299         if (conn == NULL)
300                 return -1;
301
302         /* Client group */
303         status = epoll_wait(conn->fd_client_group,
304                 &event,
305                 1,
306                 0);
307         if (status == -1)
308                 return -1;
309         if (status == 0)
310                 return 0;
311
312         fd_client = event.data.fd;
313
314         /* Data available */
315         if (event.events & EPOLLIN)
316                 status_data = data_event_handle(conn, fd_client);
317
318         /* Control events */
319         if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
320                 status_control = control_event_handle(conn, fd_client);
321
322         if (status_data || status_control)
323                 return -1;
324
325         return 0;
326 }