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