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