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 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 conn_msg_handle_t msg_handle; 35 }; 36 37 struct conn * 38 conn_init(struct conn_params *p) 39 { 40 struct sockaddr_in server_address; 41 struct conn *conn; 42 int fd_server, fd_client_group, status; 43 44 memset(&server_address, 0, sizeof(server_address)); 45 46 /* Check input arguments */ 47 if ((p == NULL) || 48 (p->welcome == NULL) || 49 (p->prompt == NULL) || 50 (p->addr == NULL) || 51 (p->buf_size == 0) || 52 (p->msg_in_len_max == 0) || 53 (p->msg_out_len_max == 0) || 54 (p->msg_handle == NULL)) 55 return NULL; 56 57 status = inet_aton(p->addr, &server_address.sin_addr); 58 if (status == 0) 59 return NULL; 60 61 /* Memory allocation */ 62 conn = calloc(1, sizeof(struct conn)); 63 if (conn == NULL) 64 return NULL; 65 66 conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1); 67 conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1); 68 conn->buf = calloc(1, p->buf_size); 69 conn->msg_in = calloc(1, p->msg_in_len_max + 1); 70 conn->msg_out = calloc(1, p->msg_out_len_max + 1); 71 72 if ((conn->welcome == NULL) || 73 (conn->prompt == NULL) || 74 (conn->buf == NULL) || 75 (conn->msg_in == NULL) || 76 (conn->msg_out == NULL)) { 77 conn_free(conn); 78 return NULL; 79 } 80 81 /* Server socket */ 82 server_address.sin_family = AF_INET; 83 server_address.sin_port = htons(p->port); 84 85 fd_server = socket(AF_INET, 86 SOCK_STREAM | SOCK_NONBLOCK, 87 0); 88 if (fd_server == -1) { 89 conn_free(conn); 90 return NULL; 91 } 92 93 status = bind(fd_server, 94 (struct sockaddr *) &server_address, 95 sizeof(server_address)); 96 if (status == -1) { 97 conn_free(conn); 98 close(fd_server); 99 return NULL; 100 } 101 102 status = listen(fd_server, 16); 103 if (status == -1) { 104 conn_free(conn); 105 close(fd_server); 106 return NULL; 107 } 108 109 /* Client group */ 110 fd_client_group = epoll_create(1); 111 if (fd_client_group == -1) { 112 conn_free(conn); 113 close(fd_server); 114 return NULL; 115 } 116 117 /* Fill in */ 118 strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX); 119 strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX); 120 conn->buf_size = p->buf_size; 121 conn->msg_in_len_max = p->msg_in_len_max; 122 conn->msg_out_len_max = p->msg_out_len_max; 123 conn->msg_in_len = 0; 124 conn->fd_server = fd_server; 125 conn->fd_client_group = fd_client_group; 126 conn->msg_handle = p->msg_handle; 127 128 return conn; 129 } 130 131 void 132 conn_free(struct conn *conn) 133 { 134 if (conn == NULL) 135 return; 136 137 if (conn->fd_client_group) 138 close(conn->fd_client_group); 139 140 if (conn->fd_server) 141 close(conn->fd_server); 142 143 free(conn->msg_out); 144 free(conn->msg_in); 145 free(conn->prompt); 146 free(conn->welcome); 147 free(conn); 148 } 149 150 int 151 conn_poll_for_conn(struct conn *conn) 152 { 153 struct sockaddr_in client_address; 154 struct epoll_event event; 155 socklen_t client_address_length; 156 int fd_client, status; 157 158 /* Check input arguments */ 159 if (conn == NULL) 160 return -1; 161 162 /* Server socket */ 163 client_address_length = sizeof(client_address); 164 fd_client = accept4(conn->fd_server, 165 (struct sockaddr *) &client_address, 166 &client_address_length, 167 SOCK_NONBLOCK); 168 if (fd_client == -1) { 169 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) 170 return 0; 171 172 return -1; 173 } 174 175 /* Client group */ 176 event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP; 177 event.data.fd = fd_client; 178 179 status = epoll_ctl(conn->fd_client_group, 180 EPOLL_CTL_ADD, 181 fd_client, 182 &event); 183 if (status == -1) { 184 close(fd_client); 185 return -1; 186 } 187 188 /* Client */ 189 status = write(fd_client, 190 conn->welcome, 191 strlen(conn->welcome)); 192 if (status == -1) { 193 close(fd_client); 194 return -1; 195 } 196 197 status = write(fd_client, 198 conn->prompt, 199 strlen(conn->prompt)); 200 if (status == -1) { 201 close(fd_client); 202 return -1; 203 } 204 205 return 0; 206 } 207 208 static int 209 data_event_handle(struct conn *conn, 210 int fd_client) 211 { 212 ssize_t len, i, status; 213 214 /* Read input message */ 215 216 len = read(fd_client, 217 conn->buf, 218 conn->buf_size); 219 if (len == -1) { 220 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) 221 return 0; 222 223 return -1; 224 } 225 if (len == 0) 226 return 0; 227 228 /* Handle input messages */ 229 for (i = 0; i < len; i++) { 230 if (conn->buf[i] == '\n') { 231 size_t n; 232 233 conn->msg_in[conn->msg_in_len] = 0; 234 conn->msg_out[0] = 0; 235 236 conn->msg_handle(conn->msg_in, 237 conn->msg_out, 238 conn->msg_out_len_max); 239 240 n = strlen(conn->msg_out); 241 if (n) { 242 status = write(fd_client, 243 conn->msg_out, 244 n); 245 if (status == -1) 246 return status; 247 } 248 249 conn->msg_in_len = 0; 250 } else if (conn->msg_in_len < conn->msg_in_len_max) { 251 conn->msg_in[conn->msg_in_len] = conn->buf[i]; 252 conn->msg_in_len++; 253 } else { 254 status = write(fd_client, 255 MSG_CMD_TOO_LONG, 256 strlen(MSG_CMD_TOO_LONG)); 257 if (status == -1) 258 return status; 259 260 conn->msg_in_len = 0; 261 } 262 } 263 264 /* Write prompt */ 265 status = write(fd_client, 266 conn->prompt, 267 strlen(conn->prompt)); 268 if (status == -1) 269 return status; 270 271 return 0; 272 } 273 274 static int 275 control_event_handle(struct conn *conn, 276 int fd_client) 277 { 278 int status; 279 280 status = epoll_ctl(conn->fd_client_group, 281 EPOLL_CTL_DEL, 282 fd_client, 283 NULL); 284 if (status == -1) 285 return -1; 286 287 status = close(fd_client); 288 if (status == -1) 289 return -1; 290 291 return 0; 292 } 293 294 int 295 conn_poll_for_msg(struct conn *conn) 296 { 297 struct epoll_event event; 298 int fd_client, status, status_data = 0, status_control = 0; 299 300 /* Check input arguments */ 301 if (conn == NULL) 302 return -1; 303 304 /* Client group */ 305 status = epoll_wait(conn->fd_client_group, 306 &event, 307 1, 308 0); 309 if (status == -1) 310 return -1; 311 if (status == 0) 312 return 0; 313 314 fd_client = event.data.fd; 315 316 /* Data available */ 317 if (event.events & EPOLLIN) 318 status_data = data_event_handle(conn, fd_client); 319 320 /* Control events */ 321 if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) 322 status_control = control_event_handle(conn, fd_client); 323 324 if (status_data || status_control) 325 return -1; 326 327 return 0; 328 } 329