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