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