6b08e9e8e88c83d661f3915951c1d0c4951f00d9
[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                 close(fd_server);
100                 return NULL;
101         }
102
103         status = listen(fd_server, 16);
104         if (status == -1) {
105                 conn_free(conn);
106                 close(fd_server);
107                 return NULL;
108         }
109
110         /* Client group */
111         fd_client_group = epoll_create(1);
112         if (fd_client_group == -1) {
113                 conn_free(conn);
114                 close(fd_server);
115                 return NULL;
116         }
117
118         /* Fill in */
119         strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX);
120         strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX);
121         conn->buf_size = p->buf_size;
122         conn->msg_in_len_max = p->msg_in_len_max;
123         conn->msg_out_len_max = p->msg_out_len_max;
124         conn->msg_in_len = 0;
125         conn->fd_server = fd_server;
126         conn->fd_client_group = fd_client_group;
127         conn->msg_handle = p->msg_handle;
128
129         return conn;
130 }
131
132 void
133 conn_free(struct conn *conn)
134 {
135         if (conn == NULL)
136                 return;
137
138         if (conn->fd_client_group)
139                 close(conn->fd_client_group);
140
141         if (conn->fd_server)
142                 close(conn->fd_server);
143
144         free(conn->msg_out);
145         free(conn->msg_in);
146         free(conn->prompt);
147         free(conn->welcome);
148         free(conn);
149 }
150
151 int
152 conn_poll_for_conn(struct conn *conn)
153 {
154         struct sockaddr_in client_address;
155         struct epoll_event event;
156         socklen_t client_address_length;
157         int fd_client, status;
158
159         /* Check input arguments */
160         if (conn == NULL)
161                 return -1;
162
163         /* Server socket */
164         client_address_length = sizeof(client_address);
165         fd_client = accept4(conn->fd_server,
166                 (struct sockaddr *) &client_address,
167                 &client_address_length,
168                 SOCK_NONBLOCK);
169         if (fd_client == -1) {
170                 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
171                         return 0;
172
173                 return -1;
174         }
175
176         /* Client group */
177         event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
178         event.data.fd = fd_client;
179
180         status = epoll_ctl(conn->fd_client_group,
181                 EPOLL_CTL_ADD,
182                 fd_client,
183                 &event);
184         if (status == -1) {
185                 close(fd_client);
186                 return -1;
187         }
188
189         /* Client */
190         status = write(fd_client,
191                 conn->welcome,
192                 strlen(conn->welcome));
193         if (status == -1) {
194                 close(fd_client);
195                 return -1;
196         }
197
198         status = write(fd_client,
199                 conn->prompt,
200                 strlen(conn->prompt));
201         if (status == -1) {
202                 close(fd_client);
203                 return -1;
204         }
205
206         return 0;
207 }
208
209 static int
210 data_event_handle(struct conn *conn,
211         int fd_client)
212 {
213         ssize_t len, i, status;
214
215         /* Read input message */
216
217         len = read(fd_client,
218                 conn->buf,
219                 conn->buf_size);
220         if (len == -1) {
221                 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
222                         return 0;
223
224                 return -1;
225         }
226         if (len == 0)
227                 return 0;
228
229         /* Handle input messages */
230         for (i = 0; i < len; i++) {
231                 if (conn->buf[i] == '\n') {
232                         size_t n;
233
234                         conn->msg_in[conn->msg_in_len] = 0;
235                         conn->msg_out[0] = 0;
236
237                         conn->msg_handle(conn->msg_in,
238                                 conn->msg_out,
239                                 conn->msg_out_len_max);
240
241                         n = strlen(conn->msg_out);
242                         if (n) {
243                                 status = write(fd_client,
244                                         conn->msg_out,
245                                         n);
246                                 if (status == -1)
247                                         return status;
248                         }
249
250                         conn->msg_in_len = 0;
251                 } else if (conn->msg_in_len < conn->msg_in_len_max) {
252                         conn->msg_in[conn->msg_in_len] = conn->buf[i];
253                         conn->msg_in_len++;
254                 } else {
255                         status = write(fd_client,
256                                 MSG_CMD_TOO_LONG,
257                                 strlen(MSG_CMD_TOO_LONG));
258                         if (status == -1)
259                                 return status;
260
261                         conn->msg_in_len = 0;
262                 }
263         }
264
265         /* Write prompt */
266         status = write(fd_client,
267                 conn->prompt,
268                 strlen(conn->prompt));
269         if (status == -1)
270                 return status;
271
272         return 0;
273 }
274
275 static int
276 control_event_handle(struct conn *conn,
277         int fd_client)
278 {
279         int status;
280
281         status = epoll_ctl(conn->fd_client_group,
282                 EPOLL_CTL_DEL,
283                 fd_client,
284                 NULL);
285         if (status == -1)
286                 return -1;
287
288         status = close(fd_client);
289         if (status == -1)
290                 return -1;
291
292         return 0;
293 }
294
295 int
296 conn_poll_for_msg(struct conn *conn)
297 {
298         struct epoll_event event;
299         int fd_client, status, status_data = 0, status_control = 0;
300
301         /* Check input arguments */
302         if (conn == NULL)
303                 return -1;
304
305         /* Client group */
306         status = epoll_wait(conn->fd_client_group,
307                 &event,
308                 1,
309                 0);
310         if (status == -1)
311                 return -1;
312         if (status == 0)
313                 return 0;
314
315         fd_client = event.data.fd;
316
317         /* Data available */
318         if (event.events & EPOLLIN)
319                 status_data = data_event_handle(conn, fd_client);
320
321         /* Control events */
322         if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
323                 status_control = control_event_handle(conn, fd_client);
324
325         if (status_data || status_control)
326                 return -1;
327
328         return 0;
329 }