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