xref: /dpdk/drivers/net/softnic/conn.c (revision ae2b3ba6430d9f86cc3583b893f442aaa8934655)
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 #include <sys/socket.h>
12 
13 #include <sys/epoll.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
16 #include <errno.h>
17 
18 #include "conn.h"
19 
20 #define MSG_CMD_TOO_LONG "Command too long."
21 
22 struct softnic_conn {
23 	char *welcome;
24 	char *prompt;
25 	char *buf;
26 	char *msg_in;
27 	char *msg_out;
28 	size_t buf_size;
29 	size_t msg_in_len_max;
30 	size_t msg_out_len_max;
31 	size_t msg_in_len;
32 	int fd_server;
33 	int fd_client_group;
34 	softnic_conn_msg_handle_t msg_handle;
35 	void *msg_handle_arg;
36 };
37 
38 struct softnic_conn *
softnic_conn_init(struct softnic_conn_params * p)39 softnic_conn_init(struct softnic_conn_params *p)
40 {
41 	struct sockaddr_in server_address;
42 	struct softnic_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 softnic_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 		softnic_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 		softnic_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 		softnic_conn_free(conn);
99 		close(fd_server);
100 		return NULL;
101 	}
102 
103 	status = listen(fd_server, 16);
104 	if (status == -1) {
105 		softnic_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 		softnic_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 	conn->msg_handle_arg = p->msg_handle_arg;
129 
130 	return conn;
131 }
132 
133 void
softnic_conn_free(struct softnic_conn * conn)134 softnic_conn_free(struct softnic_conn *conn)
135 {
136 	if (conn == NULL)
137 		return;
138 
139 	if (conn->fd_client_group)
140 		close(conn->fd_client_group);
141 
142 	if (conn->fd_server)
143 		close(conn->fd_server);
144 
145 	free(conn->msg_out);
146 	free(conn->msg_in);
147 	free(conn->buf);
148 	free(conn->prompt);
149 	free(conn->welcome);
150 	free(conn);
151 }
152 
153 int
softnic_conn_poll_for_conn(struct softnic_conn * conn)154 softnic_conn_poll_for_conn(struct softnic_conn *conn)
155 {
156 	struct sockaddr_in client_address;
157 	struct epoll_event event;
158 	socklen_t client_address_length;
159 	int fd_client, status;
160 
161 	/* Check input arguments */
162 	if (conn == NULL)
163 		return -1;
164 
165 	/* Server socket */
166 	client_address_length = sizeof(client_address);
167 	fd_client = accept4(conn->fd_server,
168 		(struct sockaddr *)&client_address,
169 		&client_address_length,
170 		SOCK_NONBLOCK);
171 	if (fd_client == -1) {
172 		if (errno == EAGAIN || errno == EWOULDBLOCK)
173 			return 0;
174 
175 		return -1;
176 	}
177 
178 	/* Client group */
179 	event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
180 	event.data.fd = fd_client;
181 
182 	status = epoll_ctl(conn->fd_client_group,
183 		EPOLL_CTL_ADD,
184 		fd_client,
185 		&event);
186 	if (status == -1) {
187 		close(fd_client);
188 		return -1;
189 	}
190 
191 	/* Client */
192 	status = write(fd_client,
193 		conn->welcome,
194 		strlen(conn->welcome));
195 	if (status == -1) {
196 		close(fd_client);
197 		return -1;
198 	}
199 
200 	status = write(fd_client,
201 		conn->prompt,
202 		strlen(conn->prompt));
203 	if (status == -1) {
204 		close(fd_client);
205 		return -1;
206 	}
207 
208 	return 0;
209 }
210 
211 static int
data_event_handle(struct softnic_conn * conn,int fd_client)212 data_event_handle(struct softnic_conn *conn,
213 	int fd_client)
214 {
215 	ssize_t len, i, status;
216 
217 	/* Read input message */
218 
219 	len = read(fd_client,
220 		conn->buf,
221 		conn->buf_size);
222 	if (len == -1) {
223 		if (errno == EAGAIN || errno == EWOULDBLOCK)
224 			return 0;
225 
226 		return -1;
227 	}
228 	if (len == 0)
229 		return 0;
230 
231 	/* Handle input messages */
232 	for (i = 0; i < len; i++) {
233 		if (conn->buf[i] == '\n') {
234 			size_t n;
235 
236 			conn->msg_in[conn->msg_in_len] = 0;
237 			conn->msg_out[0] = 0;
238 
239 			conn->msg_handle(conn->msg_in,
240 				conn->msg_out,
241 				conn->msg_out_len_max,
242 				conn->msg_handle_arg);
243 
244 			n = strlen(conn->msg_out);
245 			if (n) {
246 				status = write(fd_client,
247 					conn->msg_out,
248 					n);
249 				if (status == -1)
250 					return status;
251 			}
252 
253 			conn->msg_in_len = 0;
254 		} else if (conn->msg_in_len < conn->msg_in_len_max) {
255 			conn->msg_in[conn->msg_in_len] = conn->buf[i];
256 			conn->msg_in_len++;
257 		} else {
258 			status = write(fd_client,
259 				MSG_CMD_TOO_LONG,
260 				strlen(MSG_CMD_TOO_LONG));
261 			if (status == -1)
262 				return status;
263 
264 			conn->msg_in_len = 0;
265 		}
266 	}
267 
268 	/* Write prompt */
269 	status = write(fd_client,
270 		conn->prompt,
271 		strlen(conn->prompt));
272 	if (status == -1)
273 		return status;
274 
275 	return 0;
276 }
277 
278 static int
control_event_handle(struct softnic_conn * conn,int fd_client)279 control_event_handle(struct softnic_conn *conn,
280 	int fd_client)
281 {
282 	int status;
283 
284 	status = epoll_ctl(conn->fd_client_group,
285 		EPOLL_CTL_DEL,
286 		fd_client,
287 		NULL);
288 	if (status == -1)
289 		return -1;
290 
291 	status = close(fd_client);
292 	if (status == -1)
293 		return -1;
294 
295 	return 0;
296 }
297 
298 int
softnic_conn_poll_for_msg(struct softnic_conn * conn)299 softnic_conn_poll_for_msg(struct softnic_conn *conn)
300 {
301 	struct epoll_event event;
302 	int fd_client, status, status_data = 0, status_control = 0;
303 
304 	/* Check input arguments */
305 	if (conn == NULL)
306 		return -1;
307 
308 	/* Client group */
309 	status = epoll_wait(conn->fd_client_group,
310 		&event,
311 		1,
312 		0);
313 	if (status == -1)
314 		return -1;
315 	if (status == 0)
316 		return 0;
317 
318 	fd_client = event.data.fd;
319 
320 	/* Data available */
321 	if (event.events & EPOLLIN)
322 		status_data = data_event_handle(conn, fd_client);
323 
324 	/* Control events */
325 	if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
326 		status_control = control_event_handle(conn, fd_client);
327 
328 	if (status_data || status_control)
329 		return -1;
330 
331 	return 0;
332 }
333