xref: /dpdk/drivers/net/softnic/conn.c (revision ae2b3ba6430d9f86cc3583b893f442aaa8934655)
17709a63bSJasvinder Singh /* SPDX-License-Identifier: BSD-3-Clause
27709a63bSJasvinder Singh  * Copyright(c) 2010-2018 Intel Corporation
37709a63bSJasvinder Singh  */
47709a63bSJasvinder Singh 
57709a63bSJasvinder Singh #include <string.h>
67709a63bSJasvinder Singh #include <stdlib.h>
77709a63bSJasvinder Singh #include <stdio.h>
87709a63bSJasvinder Singh #include <unistd.h>
97709a63bSJasvinder Singh #include <sys/types.h>
107709a63bSJasvinder Singh 
117709a63bSJasvinder Singh #include <sys/socket.h>
127709a63bSJasvinder Singh 
137709a63bSJasvinder Singh #include <sys/epoll.h>
147709a63bSJasvinder Singh #include <netinet/in.h>
157709a63bSJasvinder Singh #include <arpa/inet.h>
167709a63bSJasvinder Singh #include <errno.h>
177709a63bSJasvinder Singh 
187709a63bSJasvinder Singh #include "conn.h"
197709a63bSJasvinder Singh 
207709a63bSJasvinder Singh #define MSG_CMD_TOO_LONG "Command too long."
217709a63bSJasvinder Singh 
227709a63bSJasvinder Singh struct softnic_conn {
237709a63bSJasvinder Singh 	char *welcome;
247709a63bSJasvinder Singh 	char *prompt;
257709a63bSJasvinder Singh 	char *buf;
267709a63bSJasvinder Singh 	char *msg_in;
277709a63bSJasvinder Singh 	char *msg_out;
287709a63bSJasvinder Singh 	size_t buf_size;
297709a63bSJasvinder Singh 	size_t msg_in_len_max;
307709a63bSJasvinder Singh 	size_t msg_out_len_max;
317709a63bSJasvinder Singh 	size_t msg_in_len;
327709a63bSJasvinder Singh 	int fd_server;
337709a63bSJasvinder Singh 	int fd_client_group;
347709a63bSJasvinder Singh 	softnic_conn_msg_handle_t msg_handle;
357709a63bSJasvinder Singh 	void *msg_handle_arg;
367709a63bSJasvinder Singh };
377709a63bSJasvinder Singh 
387709a63bSJasvinder Singh struct softnic_conn *
softnic_conn_init(struct softnic_conn_params * p)397709a63bSJasvinder Singh softnic_conn_init(struct softnic_conn_params *p)
407709a63bSJasvinder Singh {
417709a63bSJasvinder Singh 	struct sockaddr_in server_address;
427709a63bSJasvinder Singh 	struct softnic_conn *conn;
437709a63bSJasvinder Singh 	int fd_server, fd_client_group, status;
447709a63bSJasvinder Singh 
457709a63bSJasvinder Singh 	memset(&server_address, 0, sizeof(server_address));
467709a63bSJasvinder Singh 
477709a63bSJasvinder Singh 	/* Check input arguments */
487709a63bSJasvinder Singh 	if (p == NULL ||
497709a63bSJasvinder Singh 		p->welcome == NULL ||
507709a63bSJasvinder Singh 		p->prompt == NULL ||
517709a63bSJasvinder Singh 		p->addr == NULL ||
527709a63bSJasvinder Singh 		p->buf_size == 0 ||
537709a63bSJasvinder Singh 		p->msg_in_len_max == 0 ||
547709a63bSJasvinder Singh 		p->msg_out_len_max == 0 ||
557709a63bSJasvinder Singh 		p->msg_handle == NULL)
567709a63bSJasvinder Singh 		return NULL;
577709a63bSJasvinder Singh 
587709a63bSJasvinder Singh 	status = inet_aton(p->addr, &server_address.sin_addr);
597709a63bSJasvinder Singh 	if (status == 0)
607709a63bSJasvinder Singh 		return NULL;
617709a63bSJasvinder Singh 
627709a63bSJasvinder Singh 	/* Memory allocation */
637709a63bSJasvinder Singh 	conn = calloc(1, sizeof(struct softnic_conn));
647709a63bSJasvinder Singh 	if (conn == NULL)
657709a63bSJasvinder Singh 		return NULL;
667709a63bSJasvinder Singh 
677709a63bSJasvinder Singh 	conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1);
687709a63bSJasvinder Singh 	conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1);
697709a63bSJasvinder Singh 	conn->buf = calloc(1, p->buf_size);
707709a63bSJasvinder Singh 	conn->msg_in = calloc(1, p->msg_in_len_max + 1);
717709a63bSJasvinder Singh 	conn->msg_out = calloc(1, p->msg_out_len_max + 1);
727709a63bSJasvinder Singh 
737709a63bSJasvinder Singh 	if (conn->welcome == NULL ||
747709a63bSJasvinder Singh 		conn->prompt == NULL ||
757709a63bSJasvinder Singh 		conn->buf == NULL ||
767709a63bSJasvinder Singh 		conn->msg_in == NULL ||
777709a63bSJasvinder Singh 		conn->msg_out == NULL) {
787709a63bSJasvinder Singh 		softnic_conn_free(conn);
797709a63bSJasvinder Singh 		return NULL;
807709a63bSJasvinder Singh 	}
817709a63bSJasvinder Singh 
827709a63bSJasvinder Singh 	/* Server socket */
837709a63bSJasvinder Singh 	server_address.sin_family = AF_INET;
847709a63bSJasvinder Singh 	server_address.sin_port = htons(p->port);
857709a63bSJasvinder Singh 
867709a63bSJasvinder Singh 	fd_server = socket(AF_INET,
877709a63bSJasvinder Singh 		SOCK_STREAM | SOCK_NONBLOCK,
887709a63bSJasvinder Singh 		0);
897709a63bSJasvinder Singh 	if (fd_server == -1) {
907709a63bSJasvinder Singh 		softnic_conn_free(conn);
917709a63bSJasvinder Singh 		return NULL;
927709a63bSJasvinder Singh 	}
937709a63bSJasvinder Singh 
947709a63bSJasvinder Singh 	status = bind(fd_server,
957709a63bSJasvinder Singh 		(struct sockaddr *)&server_address,
967709a63bSJasvinder Singh 		sizeof(server_address));
977709a63bSJasvinder Singh 	if (status == -1) {
987709a63bSJasvinder Singh 		softnic_conn_free(conn);
997709a63bSJasvinder Singh 		close(fd_server);
1007709a63bSJasvinder Singh 		return NULL;
1017709a63bSJasvinder Singh 	}
1027709a63bSJasvinder Singh 
1037709a63bSJasvinder Singh 	status = listen(fd_server, 16);
1047709a63bSJasvinder Singh 	if (status == -1) {
1057709a63bSJasvinder Singh 		softnic_conn_free(conn);
1067709a63bSJasvinder Singh 		close(fd_server);
1077709a63bSJasvinder Singh 		return NULL;
1087709a63bSJasvinder Singh 	}
1097709a63bSJasvinder Singh 
1107709a63bSJasvinder Singh 	/* Client group */
1117709a63bSJasvinder Singh 	fd_client_group = epoll_create(1);
1127709a63bSJasvinder Singh 	if (fd_client_group == -1) {
1137709a63bSJasvinder Singh 		softnic_conn_free(conn);
1147709a63bSJasvinder Singh 		close(fd_server);
1157709a63bSJasvinder Singh 		return NULL;
1167709a63bSJasvinder Singh 	}
1177709a63bSJasvinder Singh 
1187709a63bSJasvinder Singh 	/* Fill in */
1197709a63bSJasvinder Singh 	strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX);
1207709a63bSJasvinder Singh 	strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX);
1217709a63bSJasvinder Singh 	conn->buf_size = p->buf_size;
1227709a63bSJasvinder Singh 	conn->msg_in_len_max = p->msg_in_len_max;
1237709a63bSJasvinder Singh 	conn->msg_out_len_max = p->msg_out_len_max;
1247709a63bSJasvinder Singh 	conn->msg_in_len = 0;
1257709a63bSJasvinder Singh 	conn->fd_server = fd_server;
1267709a63bSJasvinder Singh 	conn->fd_client_group = fd_client_group;
1277709a63bSJasvinder Singh 	conn->msg_handle = p->msg_handle;
1287709a63bSJasvinder Singh 	conn->msg_handle_arg = p->msg_handle_arg;
1297709a63bSJasvinder Singh 
1307709a63bSJasvinder Singh 	return conn;
1317709a63bSJasvinder Singh }
1327709a63bSJasvinder Singh 
1337709a63bSJasvinder Singh void
softnic_conn_free(struct softnic_conn * conn)1347709a63bSJasvinder Singh softnic_conn_free(struct softnic_conn *conn)
1357709a63bSJasvinder Singh {
1367709a63bSJasvinder Singh 	if (conn == NULL)
1377709a63bSJasvinder Singh 		return;
1387709a63bSJasvinder Singh 
1397709a63bSJasvinder Singh 	if (conn->fd_client_group)
1407709a63bSJasvinder Singh 		close(conn->fd_client_group);
1417709a63bSJasvinder Singh 
1427709a63bSJasvinder Singh 	if (conn->fd_server)
1437709a63bSJasvinder Singh 		close(conn->fd_server);
1447709a63bSJasvinder Singh 
1457709a63bSJasvinder Singh 	free(conn->msg_out);
1467709a63bSJasvinder Singh 	free(conn->msg_in);
147*ae2b3ba6SDapeng Yu 	free(conn->buf);
1487709a63bSJasvinder Singh 	free(conn->prompt);
1497709a63bSJasvinder Singh 	free(conn->welcome);
1507709a63bSJasvinder Singh 	free(conn);
1517709a63bSJasvinder Singh }
1527709a63bSJasvinder Singh 
1537709a63bSJasvinder Singh int
softnic_conn_poll_for_conn(struct softnic_conn * conn)1547709a63bSJasvinder Singh softnic_conn_poll_for_conn(struct softnic_conn *conn)
1557709a63bSJasvinder Singh {
1567709a63bSJasvinder Singh 	struct sockaddr_in client_address;
1577709a63bSJasvinder Singh 	struct epoll_event event;
1587709a63bSJasvinder Singh 	socklen_t client_address_length;
1597709a63bSJasvinder Singh 	int fd_client, status;
1607709a63bSJasvinder Singh 
1617709a63bSJasvinder Singh 	/* Check input arguments */
1627709a63bSJasvinder Singh 	if (conn == NULL)
1637709a63bSJasvinder Singh 		return -1;
1647709a63bSJasvinder Singh 
1657709a63bSJasvinder Singh 	/* Server socket */
1667709a63bSJasvinder Singh 	client_address_length = sizeof(client_address);
1677709a63bSJasvinder Singh 	fd_client = accept4(conn->fd_server,
1687709a63bSJasvinder Singh 		(struct sockaddr *)&client_address,
1697709a63bSJasvinder Singh 		&client_address_length,
1707709a63bSJasvinder Singh 		SOCK_NONBLOCK);
1717709a63bSJasvinder Singh 	if (fd_client == -1) {
1727709a63bSJasvinder Singh 		if (errno == EAGAIN || errno == EWOULDBLOCK)
1737709a63bSJasvinder Singh 			return 0;
1747709a63bSJasvinder Singh 
1757709a63bSJasvinder Singh 		return -1;
1767709a63bSJasvinder Singh 	}
1777709a63bSJasvinder Singh 
1787709a63bSJasvinder Singh 	/* Client group */
1797709a63bSJasvinder Singh 	event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
1807709a63bSJasvinder Singh 	event.data.fd = fd_client;
1817709a63bSJasvinder Singh 
1827709a63bSJasvinder Singh 	status = epoll_ctl(conn->fd_client_group,
1837709a63bSJasvinder Singh 		EPOLL_CTL_ADD,
1847709a63bSJasvinder Singh 		fd_client,
1857709a63bSJasvinder Singh 		&event);
1867709a63bSJasvinder Singh 	if (status == -1) {
1877709a63bSJasvinder Singh 		close(fd_client);
1887709a63bSJasvinder Singh 		return -1;
1897709a63bSJasvinder Singh 	}
1907709a63bSJasvinder Singh 
1917709a63bSJasvinder Singh 	/* Client */
1927709a63bSJasvinder Singh 	status = write(fd_client,
1937709a63bSJasvinder Singh 		conn->welcome,
1947709a63bSJasvinder Singh 		strlen(conn->welcome));
1957709a63bSJasvinder Singh 	if (status == -1) {
1967709a63bSJasvinder Singh 		close(fd_client);
1977709a63bSJasvinder Singh 		return -1;
1987709a63bSJasvinder Singh 	}
1997709a63bSJasvinder Singh 
2007709a63bSJasvinder Singh 	status = write(fd_client,
2017709a63bSJasvinder Singh 		conn->prompt,
2027709a63bSJasvinder Singh 		strlen(conn->prompt));
2037709a63bSJasvinder Singh 	if (status == -1) {
2047709a63bSJasvinder Singh 		close(fd_client);
2057709a63bSJasvinder Singh 		return -1;
2067709a63bSJasvinder Singh 	}
2077709a63bSJasvinder Singh 
2087709a63bSJasvinder Singh 	return 0;
2097709a63bSJasvinder Singh }
2107709a63bSJasvinder Singh 
2117709a63bSJasvinder Singh static int
data_event_handle(struct softnic_conn * conn,int fd_client)2127709a63bSJasvinder Singh data_event_handle(struct softnic_conn *conn,
2137709a63bSJasvinder Singh 	int fd_client)
2147709a63bSJasvinder Singh {
2157709a63bSJasvinder Singh 	ssize_t len, i, status;
2167709a63bSJasvinder Singh 
2177709a63bSJasvinder Singh 	/* Read input message */
2187709a63bSJasvinder Singh 
2197709a63bSJasvinder Singh 	len = read(fd_client,
2207709a63bSJasvinder Singh 		conn->buf,
2217709a63bSJasvinder Singh 		conn->buf_size);
2227709a63bSJasvinder Singh 	if (len == -1) {
2237709a63bSJasvinder Singh 		if (errno == EAGAIN || errno == EWOULDBLOCK)
2247709a63bSJasvinder Singh 			return 0;
2257709a63bSJasvinder Singh 
2267709a63bSJasvinder Singh 		return -1;
2277709a63bSJasvinder Singh 	}
2287709a63bSJasvinder Singh 	if (len == 0)
2297709a63bSJasvinder Singh 		return 0;
2307709a63bSJasvinder Singh 
2317709a63bSJasvinder Singh 	/* Handle input messages */
2327709a63bSJasvinder Singh 	for (i = 0; i < len; i++) {
2337709a63bSJasvinder Singh 		if (conn->buf[i] == '\n') {
2347709a63bSJasvinder Singh 			size_t n;
2357709a63bSJasvinder Singh 
2367709a63bSJasvinder Singh 			conn->msg_in[conn->msg_in_len] = 0;
2377709a63bSJasvinder Singh 			conn->msg_out[0] = 0;
2387709a63bSJasvinder Singh 
2397709a63bSJasvinder Singh 			conn->msg_handle(conn->msg_in,
2407709a63bSJasvinder Singh 				conn->msg_out,
2417709a63bSJasvinder Singh 				conn->msg_out_len_max,
2427709a63bSJasvinder Singh 				conn->msg_handle_arg);
2437709a63bSJasvinder Singh 
2447709a63bSJasvinder Singh 			n = strlen(conn->msg_out);
2457709a63bSJasvinder Singh 			if (n) {
2467709a63bSJasvinder Singh 				status = write(fd_client,
2477709a63bSJasvinder Singh 					conn->msg_out,
2487709a63bSJasvinder Singh 					n);
2497709a63bSJasvinder Singh 				if (status == -1)
2507709a63bSJasvinder Singh 					return status;
2517709a63bSJasvinder Singh 			}
2527709a63bSJasvinder Singh 
2537709a63bSJasvinder Singh 			conn->msg_in_len = 0;
2547709a63bSJasvinder Singh 		} else if (conn->msg_in_len < conn->msg_in_len_max) {
2557709a63bSJasvinder Singh 			conn->msg_in[conn->msg_in_len] = conn->buf[i];
2567709a63bSJasvinder Singh 			conn->msg_in_len++;
2577709a63bSJasvinder Singh 		} else {
2587709a63bSJasvinder Singh 			status = write(fd_client,
2597709a63bSJasvinder Singh 				MSG_CMD_TOO_LONG,
2607709a63bSJasvinder Singh 				strlen(MSG_CMD_TOO_LONG));
2617709a63bSJasvinder Singh 			if (status == -1)
2627709a63bSJasvinder Singh 				return status;
2637709a63bSJasvinder Singh 
2647709a63bSJasvinder Singh 			conn->msg_in_len = 0;
2657709a63bSJasvinder Singh 		}
2667709a63bSJasvinder Singh 	}
2677709a63bSJasvinder Singh 
2687709a63bSJasvinder Singh 	/* Write prompt */
2697709a63bSJasvinder Singh 	status = write(fd_client,
2707709a63bSJasvinder Singh 		conn->prompt,
2717709a63bSJasvinder Singh 		strlen(conn->prompt));
2727709a63bSJasvinder Singh 	if (status == -1)
2737709a63bSJasvinder Singh 		return status;
2747709a63bSJasvinder Singh 
2757709a63bSJasvinder Singh 	return 0;
2767709a63bSJasvinder Singh }
2777709a63bSJasvinder Singh 
2787709a63bSJasvinder Singh static int
control_event_handle(struct softnic_conn * conn,int fd_client)2797709a63bSJasvinder Singh control_event_handle(struct softnic_conn *conn,
2807709a63bSJasvinder Singh 	int fd_client)
2817709a63bSJasvinder Singh {
2827709a63bSJasvinder Singh 	int status;
2837709a63bSJasvinder Singh 
2847709a63bSJasvinder Singh 	status = epoll_ctl(conn->fd_client_group,
2857709a63bSJasvinder Singh 		EPOLL_CTL_DEL,
2867709a63bSJasvinder Singh 		fd_client,
2877709a63bSJasvinder Singh 		NULL);
2887709a63bSJasvinder Singh 	if (status == -1)
2897709a63bSJasvinder Singh 		return -1;
2907709a63bSJasvinder Singh 
2917709a63bSJasvinder Singh 	status = close(fd_client);
2927709a63bSJasvinder Singh 	if (status == -1)
2937709a63bSJasvinder Singh 		return -1;
2947709a63bSJasvinder Singh 
2957709a63bSJasvinder Singh 	return 0;
2967709a63bSJasvinder Singh }
2977709a63bSJasvinder Singh 
2987709a63bSJasvinder Singh int
softnic_conn_poll_for_msg(struct softnic_conn * conn)2997709a63bSJasvinder Singh softnic_conn_poll_for_msg(struct softnic_conn *conn)
3007709a63bSJasvinder Singh {
3017709a63bSJasvinder Singh 	struct epoll_event event;
3027709a63bSJasvinder Singh 	int fd_client, status, status_data = 0, status_control = 0;
3037709a63bSJasvinder Singh 
3047709a63bSJasvinder Singh 	/* Check input arguments */
3057709a63bSJasvinder Singh 	if (conn == NULL)
3067709a63bSJasvinder Singh 		return -1;
3077709a63bSJasvinder Singh 
3087709a63bSJasvinder Singh 	/* Client group */
3097709a63bSJasvinder Singh 	status = epoll_wait(conn->fd_client_group,
3107709a63bSJasvinder Singh 		&event,
3117709a63bSJasvinder Singh 		1,
3127709a63bSJasvinder Singh 		0);
3137709a63bSJasvinder Singh 	if (status == -1)
3147709a63bSJasvinder Singh 		return -1;
3157709a63bSJasvinder Singh 	if (status == 0)
3167709a63bSJasvinder Singh 		return 0;
3177709a63bSJasvinder Singh 
3187709a63bSJasvinder Singh 	fd_client = event.data.fd;
3197709a63bSJasvinder Singh 
3207709a63bSJasvinder Singh 	/* Data available */
3217709a63bSJasvinder Singh 	if (event.events & EPOLLIN)
3227709a63bSJasvinder Singh 		status_data = data_event_handle(conn, fd_client);
3237709a63bSJasvinder Singh 
3247709a63bSJasvinder Singh 	/* Control events */
3257709a63bSJasvinder Singh 	if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
3267709a63bSJasvinder Singh 		status_control = control_event_handle(conn, fd_client);
3277709a63bSJasvinder Singh 
3287709a63bSJasvinder Singh 	if (status_data || status_control)
3297709a63bSJasvinder Singh 		return -1;
3307709a63bSJasvinder Singh 
3317709a63bSJasvinder Singh 	return 0;
3327709a63bSJasvinder Singh }
333