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