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