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