xref: /dpdk/examples/ip_pipeline/conn.c (revision 5d7b673d5fd6663b20c675dd382d9fb43b42af18)
14bbf8e30SJasvinder Singh /* SPDX-License-Identifier: BSD-3-Clause
24bbf8e30SJasvinder Singh  * Copyright(c) 2010-2018 Intel Corporation
34bbf8e30SJasvinder Singh  */
44bbf8e30SJasvinder Singh 
54bbf8e30SJasvinder Singh #include <string.h>
64bbf8e30SJasvinder Singh #include <stdlib.h>
74bbf8e30SJasvinder Singh #include <stdio.h>
84bbf8e30SJasvinder Singh #include <unistd.h>
94bbf8e30SJasvinder Singh #include <sys/types.h>
104bbf8e30SJasvinder Singh 
114bbf8e30SJasvinder Singh #include <sys/socket.h>
124bbf8e30SJasvinder Singh 
134bbf8e30SJasvinder Singh #include <sys/epoll.h>
144bbf8e30SJasvinder Singh #include <netinet/in.h>
154bbf8e30SJasvinder Singh #include <arpa/inet.h>
164bbf8e30SJasvinder Singh #include <errno.h>
174bbf8e30SJasvinder Singh 
184bbf8e30SJasvinder Singh #include "conn.h"
194bbf8e30SJasvinder Singh 
204bbf8e30SJasvinder Singh #define MSG_CMD_TOO_LONG "Command too long."
214bbf8e30SJasvinder Singh 
224bbf8e30SJasvinder Singh struct conn {
234bbf8e30SJasvinder Singh 	char *welcome;
244bbf8e30SJasvinder Singh 	char *prompt;
254bbf8e30SJasvinder Singh 	char *buf;
264bbf8e30SJasvinder Singh 	char *msg_in;
274bbf8e30SJasvinder Singh 	char *msg_out;
284bbf8e30SJasvinder Singh 	size_t buf_size;
294bbf8e30SJasvinder Singh 	size_t msg_in_len_max;
304bbf8e30SJasvinder Singh 	size_t msg_out_len_max;
314bbf8e30SJasvinder Singh 	size_t msg_in_len;
324bbf8e30SJasvinder Singh 	int fd_server;
334bbf8e30SJasvinder Singh 	int fd_client_group;
344bbf8e30SJasvinder Singh 	conn_msg_handle_t msg_handle;
354bbf8e30SJasvinder Singh };
364bbf8e30SJasvinder Singh 
374bbf8e30SJasvinder Singh struct conn *
conn_init(struct conn_params * p)384bbf8e30SJasvinder Singh conn_init(struct conn_params *p)
394bbf8e30SJasvinder Singh {
404bbf8e30SJasvinder Singh 	struct sockaddr_in server_address;
414bbf8e30SJasvinder Singh 	struct conn *conn;
424bbf8e30SJasvinder Singh 	int fd_server, fd_client_group, status;
434bbf8e30SJasvinder Singh 
444bbf8e30SJasvinder Singh 	memset(&server_address, 0, sizeof(server_address));
454bbf8e30SJasvinder Singh 
464bbf8e30SJasvinder Singh 	/* Check input arguments */
474bbf8e30SJasvinder Singh 	if ((p == NULL) ||
484bbf8e30SJasvinder Singh 		(p->welcome == NULL) ||
494bbf8e30SJasvinder Singh 		(p->prompt == NULL) ||
504bbf8e30SJasvinder Singh 		(p->addr == NULL) ||
514bbf8e30SJasvinder Singh 		(p->buf_size == 0) ||
524bbf8e30SJasvinder Singh 		(p->msg_in_len_max == 0) ||
534bbf8e30SJasvinder Singh 		(p->msg_out_len_max == 0) ||
544bbf8e30SJasvinder Singh 		(p->msg_handle == NULL))
554bbf8e30SJasvinder Singh 		return NULL;
564bbf8e30SJasvinder Singh 
574bbf8e30SJasvinder Singh 	status = inet_aton(p->addr, &server_address.sin_addr);
584bbf8e30SJasvinder Singh 	if (status == 0)
594bbf8e30SJasvinder Singh 		return NULL;
604bbf8e30SJasvinder Singh 
614bbf8e30SJasvinder Singh 	/* Memory allocation */
624bbf8e30SJasvinder Singh 	conn = calloc(1, sizeof(struct conn));
634bbf8e30SJasvinder Singh 	if (conn == NULL)
644bbf8e30SJasvinder Singh 		return NULL;
654bbf8e30SJasvinder Singh 
664bbf8e30SJasvinder Singh 	conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1);
674bbf8e30SJasvinder Singh 	conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1);
684bbf8e30SJasvinder Singh 	conn->buf = calloc(1, p->buf_size);
694bbf8e30SJasvinder Singh 	conn->msg_in = calloc(1, p->msg_in_len_max + 1);
704bbf8e30SJasvinder Singh 	conn->msg_out = calloc(1, p->msg_out_len_max + 1);
714bbf8e30SJasvinder Singh 
724bbf8e30SJasvinder Singh 	if ((conn->welcome == NULL) ||
734bbf8e30SJasvinder Singh 		(conn->prompt == NULL) ||
744bbf8e30SJasvinder Singh 		(conn->buf == NULL) ||
754bbf8e30SJasvinder Singh 		(conn->msg_in == NULL) ||
764bbf8e30SJasvinder Singh 		(conn->msg_out == NULL)) {
774bbf8e30SJasvinder Singh 		conn_free(conn);
784bbf8e30SJasvinder Singh 		return NULL;
794bbf8e30SJasvinder Singh 	}
804bbf8e30SJasvinder Singh 
814bbf8e30SJasvinder Singh 	/* Server socket */
824bbf8e30SJasvinder Singh 	server_address.sin_family = AF_INET;
834bbf8e30SJasvinder Singh 	server_address.sin_port = htons(p->port);
844bbf8e30SJasvinder Singh 
854bbf8e30SJasvinder Singh 	fd_server = socket(AF_INET,
864bbf8e30SJasvinder Singh 		SOCK_STREAM | SOCK_NONBLOCK,
874bbf8e30SJasvinder Singh 		0);
884bbf8e30SJasvinder Singh 	if (fd_server == -1) {
894bbf8e30SJasvinder Singh 		conn_free(conn);
904bbf8e30SJasvinder Singh 		return NULL;
914bbf8e30SJasvinder Singh 	}
924bbf8e30SJasvinder Singh 
934bbf8e30SJasvinder Singh 	status = bind(fd_server,
944bbf8e30SJasvinder Singh 		(struct sockaddr *) &server_address,
954bbf8e30SJasvinder Singh 		sizeof(server_address));
964bbf8e30SJasvinder Singh 	if (status == -1) {
974bbf8e30SJasvinder Singh 		conn_free(conn);
98*89668b1cSKevin Laatz 		close(fd_server);
994bbf8e30SJasvinder Singh 		return NULL;
1004bbf8e30SJasvinder Singh 	}
1014bbf8e30SJasvinder Singh 
1024bbf8e30SJasvinder Singh 	status = listen(fd_server, 16);
1034bbf8e30SJasvinder Singh 	if (status == -1) {
1044bbf8e30SJasvinder Singh 		conn_free(conn);
105*89668b1cSKevin Laatz 		close(fd_server);
1064bbf8e30SJasvinder Singh 		return NULL;
1074bbf8e30SJasvinder Singh 	}
1084bbf8e30SJasvinder Singh 
1094bbf8e30SJasvinder Singh 	/* Client group */
1104bbf8e30SJasvinder Singh 	fd_client_group = epoll_create(1);
1114bbf8e30SJasvinder Singh 	if (fd_client_group == -1) {
1124bbf8e30SJasvinder Singh 		conn_free(conn);
113*89668b1cSKevin Laatz 		close(fd_server);
1144bbf8e30SJasvinder Singh 		return NULL;
1154bbf8e30SJasvinder Singh 	}
1164bbf8e30SJasvinder Singh 
1174bbf8e30SJasvinder Singh 	/* Fill in */
1184bbf8e30SJasvinder Singh 	strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX);
1194bbf8e30SJasvinder Singh 	strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX);
1204bbf8e30SJasvinder Singh 	conn->buf_size = p->buf_size;
1214bbf8e30SJasvinder Singh 	conn->msg_in_len_max = p->msg_in_len_max;
1224bbf8e30SJasvinder Singh 	conn->msg_out_len_max = p->msg_out_len_max;
1234bbf8e30SJasvinder Singh 	conn->msg_in_len = 0;
1244bbf8e30SJasvinder Singh 	conn->fd_server = fd_server;
1254bbf8e30SJasvinder Singh 	conn->fd_client_group = fd_client_group;
1264bbf8e30SJasvinder Singh 	conn->msg_handle = p->msg_handle;
1274bbf8e30SJasvinder Singh 
1284bbf8e30SJasvinder Singh 	return conn;
1294bbf8e30SJasvinder Singh }
1304bbf8e30SJasvinder Singh 
1314bbf8e30SJasvinder Singh void
conn_free(struct conn * conn)1324bbf8e30SJasvinder Singh conn_free(struct conn *conn)
1334bbf8e30SJasvinder Singh {
1344bbf8e30SJasvinder Singh 	if (conn == NULL)
1354bbf8e30SJasvinder Singh 		return;
1364bbf8e30SJasvinder Singh 
1374bbf8e30SJasvinder Singh 	if (conn->fd_client_group)
1384bbf8e30SJasvinder Singh 		close(conn->fd_client_group);
1394bbf8e30SJasvinder Singh 
1404bbf8e30SJasvinder Singh 	if (conn->fd_server)
1414bbf8e30SJasvinder Singh 		close(conn->fd_server);
1424bbf8e30SJasvinder Singh 
1434bbf8e30SJasvinder Singh 	free(conn->msg_out);
1444bbf8e30SJasvinder Singh 	free(conn->msg_in);
1454bbf8e30SJasvinder Singh 	free(conn->prompt);
1464bbf8e30SJasvinder Singh 	free(conn->welcome);
1474bbf8e30SJasvinder Singh 	free(conn);
1484bbf8e30SJasvinder Singh }
1494bbf8e30SJasvinder Singh 
1504bbf8e30SJasvinder Singh int
conn_poll_for_conn(struct conn * conn)1514bbf8e30SJasvinder Singh conn_poll_for_conn(struct conn *conn)
1524bbf8e30SJasvinder Singh {
1534bbf8e30SJasvinder Singh 	struct sockaddr_in client_address;
1544bbf8e30SJasvinder Singh 	struct epoll_event event;
1554bbf8e30SJasvinder Singh 	socklen_t client_address_length;
1564bbf8e30SJasvinder Singh 	int fd_client, status;
1574bbf8e30SJasvinder Singh 
1584bbf8e30SJasvinder Singh 	/* Check input arguments */
1594bbf8e30SJasvinder Singh 	if (conn == NULL)
1604bbf8e30SJasvinder Singh 		return -1;
1614bbf8e30SJasvinder Singh 
1624bbf8e30SJasvinder Singh 	/* Server socket */
1634bbf8e30SJasvinder Singh 	client_address_length = sizeof(client_address);
1644bbf8e30SJasvinder Singh 	fd_client = accept4(conn->fd_server,
1654bbf8e30SJasvinder Singh 		(struct sockaddr *) &client_address,
1664bbf8e30SJasvinder Singh 		&client_address_length,
1674bbf8e30SJasvinder Singh 		SOCK_NONBLOCK);
1684bbf8e30SJasvinder Singh 	if (fd_client == -1) {
1694bbf8e30SJasvinder Singh 		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
1704bbf8e30SJasvinder Singh 			return 0;
1714bbf8e30SJasvinder Singh 
1724bbf8e30SJasvinder Singh 		return -1;
1734bbf8e30SJasvinder Singh 	}
1744bbf8e30SJasvinder Singh 
1754bbf8e30SJasvinder Singh 	/* Client group */
1764bbf8e30SJasvinder Singh 	event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
1774bbf8e30SJasvinder Singh 	event.data.fd = fd_client;
1784bbf8e30SJasvinder Singh 
1794bbf8e30SJasvinder Singh 	status = epoll_ctl(conn->fd_client_group,
1804bbf8e30SJasvinder Singh 		EPOLL_CTL_ADD,
1814bbf8e30SJasvinder Singh 		fd_client,
1824bbf8e30SJasvinder Singh 		&event);
1834bbf8e30SJasvinder Singh 	if (status == -1) {
1844bbf8e30SJasvinder Singh 		close(fd_client);
1854bbf8e30SJasvinder Singh 		return -1;
1864bbf8e30SJasvinder Singh 	}
1874bbf8e30SJasvinder Singh 
1884bbf8e30SJasvinder Singh 	/* Client */
1894bbf8e30SJasvinder Singh 	status = write(fd_client,
1904bbf8e30SJasvinder Singh 		conn->welcome,
1914bbf8e30SJasvinder Singh 		strlen(conn->welcome));
1924bbf8e30SJasvinder Singh 	if (status == -1) {
1934bbf8e30SJasvinder Singh 		close(fd_client);
1944bbf8e30SJasvinder Singh 		return -1;
1954bbf8e30SJasvinder Singh 	}
1964bbf8e30SJasvinder Singh 
1974bbf8e30SJasvinder Singh 	status = write(fd_client,
1984bbf8e30SJasvinder Singh 		conn->prompt,
1994bbf8e30SJasvinder Singh 		strlen(conn->prompt));
2004bbf8e30SJasvinder Singh 	if (status == -1) {
2014bbf8e30SJasvinder Singh 		close(fd_client);
2024bbf8e30SJasvinder Singh 		return -1;
2034bbf8e30SJasvinder Singh 	}
2044bbf8e30SJasvinder Singh 
2054bbf8e30SJasvinder Singh 	return 0;
2064bbf8e30SJasvinder Singh }
2074bbf8e30SJasvinder Singh 
2084bbf8e30SJasvinder Singh static int
data_event_handle(struct conn * conn,int fd_client)2094bbf8e30SJasvinder Singh data_event_handle(struct conn *conn,
2104bbf8e30SJasvinder Singh 	int fd_client)
2114bbf8e30SJasvinder Singh {
2124bbf8e30SJasvinder Singh 	ssize_t len, i, status;
2134bbf8e30SJasvinder Singh 
2144bbf8e30SJasvinder Singh 	/* Read input message */
2154bbf8e30SJasvinder Singh 
2164bbf8e30SJasvinder Singh 	len = read(fd_client,
2174bbf8e30SJasvinder Singh 		conn->buf,
2184bbf8e30SJasvinder Singh 		conn->buf_size);
2194bbf8e30SJasvinder Singh 	if (len == -1) {
2204bbf8e30SJasvinder Singh 		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
2214bbf8e30SJasvinder Singh 			return 0;
2224bbf8e30SJasvinder Singh 
2234bbf8e30SJasvinder Singh 		return -1;
2244bbf8e30SJasvinder Singh 	}
2254bbf8e30SJasvinder Singh 	if (len == 0)
2264bbf8e30SJasvinder Singh 		return 0;
2274bbf8e30SJasvinder Singh 
2284bbf8e30SJasvinder Singh 	/* Handle input messages */
2294bbf8e30SJasvinder Singh 	for (i = 0; i < len; i++) {
2304bbf8e30SJasvinder Singh 		if (conn->buf[i] == '\n') {
2314bbf8e30SJasvinder Singh 			size_t n;
2324bbf8e30SJasvinder Singh 
2334bbf8e30SJasvinder Singh 			conn->msg_in[conn->msg_in_len] = 0;
2344bbf8e30SJasvinder Singh 			conn->msg_out[0] = 0;
2354bbf8e30SJasvinder Singh 
2364bbf8e30SJasvinder Singh 			conn->msg_handle(conn->msg_in,
2374bbf8e30SJasvinder Singh 				conn->msg_out,
2384bbf8e30SJasvinder Singh 				conn->msg_out_len_max);
2394bbf8e30SJasvinder Singh 
2404bbf8e30SJasvinder Singh 			n = strlen(conn->msg_out);
2414bbf8e30SJasvinder Singh 			if (n) {
2424bbf8e30SJasvinder Singh 				status = write(fd_client,
2434bbf8e30SJasvinder Singh 					conn->msg_out,
2444bbf8e30SJasvinder Singh 					n);
2454bbf8e30SJasvinder Singh 				if (status == -1)
2464bbf8e30SJasvinder Singh 					return status;
2474bbf8e30SJasvinder Singh 			}
2484bbf8e30SJasvinder Singh 
2494bbf8e30SJasvinder Singh 			conn->msg_in_len = 0;
2504bbf8e30SJasvinder Singh 		} else if (conn->msg_in_len < conn->msg_in_len_max) {
2514bbf8e30SJasvinder Singh 			conn->msg_in[conn->msg_in_len] = conn->buf[i];
2524bbf8e30SJasvinder Singh 			conn->msg_in_len++;
2534bbf8e30SJasvinder Singh 		} else {
2544bbf8e30SJasvinder Singh 			status = write(fd_client,
2554bbf8e30SJasvinder Singh 				MSG_CMD_TOO_LONG,
2564bbf8e30SJasvinder Singh 				strlen(MSG_CMD_TOO_LONG));
2574bbf8e30SJasvinder Singh 			if (status == -1)
2584bbf8e30SJasvinder Singh 				return status;
2594bbf8e30SJasvinder Singh 
2604bbf8e30SJasvinder Singh 			conn->msg_in_len = 0;
2614bbf8e30SJasvinder Singh 		}
2624bbf8e30SJasvinder Singh 	}
2634bbf8e30SJasvinder Singh 
2644bbf8e30SJasvinder Singh 	/* Write prompt */
2654bbf8e30SJasvinder Singh 	status = write(fd_client,
2664bbf8e30SJasvinder Singh 		conn->prompt,
2674bbf8e30SJasvinder Singh 		strlen(conn->prompt));
2684bbf8e30SJasvinder Singh 	if (status == -1)
2694bbf8e30SJasvinder Singh 		return status;
2704bbf8e30SJasvinder Singh 
2714bbf8e30SJasvinder Singh 	return 0;
2724bbf8e30SJasvinder Singh }
2734bbf8e30SJasvinder Singh 
2744bbf8e30SJasvinder Singh static int
control_event_handle(struct conn * conn,int fd_client)2754bbf8e30SJasvinder Singh control_event_handle(struct conn *conn,
2764bbf8e30SJasvinder Singh 	int fd_client)
2774bbf8e30SJasvinder Singh {
2784bbf8e30SJasvinder Singh 	int status;
2794bbf8e30SJasvinder Singh 
2804bbf8e30SJasvinder Singh 	status = epoll_ctl(conn->fd_client_group,
2814bbf8e30SJasvinder Singh 		EPOLL_CTL_DEL,
2824bbf8e30SJasvinder Singh 		fd_client,
2834bbf8e30SJasvinder Singh 		NULL);
2844bbf8e30SJasvinder Singh 	if (status == -1)
2854bbf8e30SJasvinder Singh 		return -1;
2864bbf8e30SJasvinder Singh 
2874bbf8e30SJasvinder Singh 	status = close(fd_client);
2884bbf8e30SJasvinder Singh 	if (status == -1)
2894bbf8e30SJasvinder Singh 		return -1;
2904bbf8e30SJasvinder Singh 
2914bbf8e30SJasvinder Singh 	return 0;
2924bbf8e30SJasvinder Singh }
2934bbf8e30SJasvinder Singh 
2944bbf8e30SJasvinder Singh int
conn_poll_for_msg(struct conn * conn)2954bbf8e30SJasvinder Singh conn_poll_for_msg(struct conn *conn)
2964bbf8e30SJasvinder Singh {
2974bbf8e30SJasvinder Singh 	struct epoll_event event;
2984bbf8e30SJasvinder Singh 	int fd_client, status, status_data = 0, status_control = 0;
2994bbf8e30SJasvinder Singh 
3004bbf8e30SJasvinder Singh 	/* Check input arguments */
3014bbf8e30SJasvinder Singh 	if (conn == NULL)
3024bbf8e30SJasvinder Singh 		return -1;
3034bbf8e30SJasvinder Singh 
3044bbf8e30SJasvinder Singh 	/* Client group */
3054bbf8e30SJasvinder Singh 	status = epoll_wait(conn->fd_client_group,
3064bbf8e30SJasvinder Singh 		&event,
3074bbf8e30SJasvinder Singh 		1,
3084bbf8e30SJasvinder Singh 		0);
3094bbf8e30SJasvinder Singh 	if (status == -1)
3104bbf8e30SJasvinder Singh 		return -1;
3114bbf8e30SJasvinder Singh 	if (status == 0)
3124bbf8e30SJasvinder Singh 		return 0;
3134bbf8e30SJasvinder Singh 
3144bbf8e30SJasvinder Singh 	fd_client = event.data.fd;
3154bbf8e30SJasvinder Singh 
3164bbf8e30SJasvinder Singh 	/* Data available */
3174bbf8e30SJasvinder Singh 	if (event.events & EPOLLIN)
3184bbf8e30SJasvinder Singh 		status_data = data_event_handle(conn, fd_client);
3194bbf8e30SJasvinder Singh 
3204bbf8e30SJasvinder Singh 	/* Control events */
3214bbf8e30SJasvinder Singh 	if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
3224bbf8e30SJasvinder Singh 		status_control = control_event_handle(conn, fd_client);
3234bbf8e30SJasvinder Singh 
3244bbf8e30SJasvinder Singh 	if (status_data || status_control)
3254bbf8e30SJasvinder Singh 		return -1;
3264bbf8e30SJasvinder Singh 
3274bbf8e30SJasvinder Singh 	return 0;
3284bbf8e30SJasvinder Singh }
329