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