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 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 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 * 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 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 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 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