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