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