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