xref: /dpdk/examples/ip_pipeline/conn.c (revision e977e4199a8d6bab72cf94e154adcad1fb964e5e)
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 }
330