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