]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/examples/sock/hello_world/hello_sock.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / examples / sock / hello_world / hello_sock.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "spdk/stdinc.h"
35 #include "spdk/thread.h"
36 #include "spdk/env.h"
37 #include "spdk/event.h"
38 #include "spdk/log.h"
39 #include "spdk/string.h"
40
41 #include "spdk/sock.h"
42 #include "spdk/net.h"
43
44 #define ACCEPT_TIMEOUT_US 1000
45 #define CLOSE_TIMEOUT_US 1000000
46 #define BUFFER_SIZE 1024
47 #define ADDR_STR_LEN INET6_ADDRSTRLEN
48
49 static bool g_is_running;
50
51 static char *g_host;
52 static int g_port;
53 static bool g_is_server;
54 static bool g_verbose;
55
56 /*
57 * We'll use this struct to gather housekeeping hello_context to pass between
58 * our events and callbacks.
59 */
60 struct hello_context_t {
61 bool is_server;
62 char *host;
63 int port;
64
65 bool verbose;
66 int bytes_in;
67 int bytes_out;
68
69 struct spdk_sock *sock;
70
71 struct spdk_sock_group *group;
72 struct spdk_poller *poller_in;
73 struct spdk_poller *poller_out;
74 struct spdk_poller *time_out;
75
76 int rc;
77 };
78
79 /*
80 * Usage function for printing parameters that are specific to this application
81 */
82 static void
83 hello_sock_usage(void)
84 {
85 printf(" -H host_addr host address\n");
86 printf(" -P port port number\n");
87 printf(" -S start in server mode\n");
88 printf(" -V print out additional informations");
89 }
90
91 /*
92 * This function is called to parse the parameters that are specific to this application
93 */
94 static int hello_sock_parse_arg(int ch, char *arg)
95 {
96 switch (ch) {
97 case 'H':
98 g_host = arg;
99 break;
100 case 'P':
101 g_port = spdk_strtol(arg, 10);
102 if (g_port < 0) {
103 fprintf(stderr, "Invalid port ID\n");
104 return g_port;
105 }
106 break;
107 case 'S':
108 g_is_server = 1;
109 break;
110 case 'V':
111 g_verbose = true;
112 break;
113 default:
114 return -EINVAL;
115 }
116 return 0;
117 }
118
119 static void
120 hello_sock_net_fini_cb(void *cb_arg)
121 {
122 struct hello_context_t *ctx = cb_arg;
123 spdk_app_stop(ctx->rc);
124 }
125
126 static int
127 hello_sock_close_timeout_poll(void *arg)
128 {
129 struct hello_context_t *ctx = arg;
130 SPDK_NOTICELOG("Connection closed\n");
131
132 spdk_poller_unregister(&ctx->time_out);
133 spdk_poller_unregister(&ctx->poller_in);
134 spdk_sock_close(&ctx->sock);
135 spdk_sock_group_close(&ctx->group);
136
137 spdk_net_framework_fini(hello_sock_net_fini_cb, arg);
138 return 0;
139 }
140
141 static int
142 hello_sock_quit(struct hello_context_t *ctx, int rc)
143 {
144 ctx->rc = rc;
145 spdk_poller_unregister(&ctx->poller_out);
146 if (!ctx->time_out) {
147 ctx->time_out = spdk_poller_register(hello_sock_close_timeout_poll, ctx,
148 CLOSE_TIMEOUT_US);
149 }
150 return 0;
151 }
152
153 static int
154 hello_sock_recv_poll(void *arg)
155 {
156 struct hello_context_t *ctx = arg;
157 int rc;
158 char buf_in[BUFFER_SIZE];
159
160 /*
161 * Get response
162 */
163 rc = spdk_sock_recv(ctx->sock, buf_in, sizeof(buf_in) - 1);
164
165 if (rc <= 0) {
166 if (errno == EAGAIN || errno == EWOULDBLOCK) {
167 return 0;
168 }
169
170 SPDK_ERRLOG("spdk_sock_recv() failed, errno %d: %s\n",
171 errno, spdk_strerror(errno));
172 return -1;
173 }
174
175 if (rc > 0) {
176 ctx->bytes_in += rc;
177 buf_in[rc] = '\0';
178 printf("%s", buf_in);
179 }
180
181 return 0;
182 }
183
184 static int
185 hello_sock_writev_poll(void *arg)
186 {
187 struct hello_context_t *ctx = arg;
188 int rc = 0;
189 char buf_out[BUFFER_SIZE];
190 struct iovec iov;
191 ssize_t n;
192
193 n = read(STDIN_FILENO, buf_out, sizeof(buf_out));
194 if (n == 0 || !g_is_running) {
195 /* EOF */
196 SPDK_NOTICELOG("Closing connection...\n");
197 hello_sock_quit(ctx, 0);
198 return 0;
199 }
200 if (n > 0) {
201 /*
202 * Send message to the server
203 */
204 iov.iov_base = buf_out;
205 iov.iov_len = n;
206 rc = spdk_sock_writev(ctx->sock, &iov, 1);
207 if (rc > 0) {
208 ctx->bytes_out += rc;
209 }
210 }
211 return rc;
212 }
213
214 static int
215 hello_sock_connect(struct hello_context_t *ctx)
216 {
217 int rc;
218 char saddr[ADDR_STR_LEN], caddr[ADDR_STR_LEN];
219 uint16_t cport, sport;
220
221 SPDK_NOTICELOG("Connecting to the server on %s:%d\n", ctx->host, ctx->port);
222
223 ctx->sock = spdk_sock_connect(ctx->host, ctx->port);
224 if (ctx->sock == NULL) {
225 SPDK_ERRLOG("connect error(%d): %s\n", errno, spdk_strerror(errno));
226 return -1;
227 }
228
229 rc = spdk_sock_getaddr(ctx->sock, saddr, sizeof(saddr), &sport, caddr, sizeof(caddr), &cport);
230 if (rc < 0) {
231 SPDK_ERRLOG("Cannot get connection addresses\n");
232 spdk_sock_close(&ctx->sock);
233 return -1;
234 }
235
236 SPDK_NOTICELOG("Connection accepted from (%s, %hu) to (%s, %hu)\n", caddr, cport, saddr, sport);
237
238 fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
239
240 g_is_running = true;
241 ctx->poller_in = spdk_poller_register(hello_sock_recv_poll, ctx, 0);
242 ctx->poller_out = spdk_poller_register(hello_sock_writev_poll, ctx, 0);
243
244 return 0;
245 }
246
247 static void
248 hello_sock_cb(void *arg, struct spdk_sock_group *group, struct spdk_sock *sock)
249 {
250 ssize_t n;
251 char buf[BUFFER_SIZE];
252 struct iovec iov;
253 struct hello_context_t *ctx = arg;
254
255 n = spdk_sock_recv(sock, buf, sizeof(buf));
256 if (n < 0) {
257 if (errno == EAGAIN || errno == EWOULDBLOCK) {
258 SPDK_ERRLOG("spdk_sock_recv() failed, errno %d: %s\n",
259 errno, spdk_strerror(errno));
260 return;
261 }
262
263 SPDK_ERRLOG("spdk_sock_recv() failed, errno %d: %s\n",
264 errno, spdk_strerror(errno));
265 }
266
267 if (n > 0) {
268 ctx->bytes_in += n;
269 iov.iov_base = buf;
270 iov.iov_len = n;
271 n = spdk_sock_writev(sock, &iov, 1);
272 if (n > 0) {
273 ctx->bytes_out += n;
274 }
275 return;
276 }
277
278 /* Connection closed */
279 SPDK_NOTICELOG("Connection closed\n");
280 spdk_sock_group_remove_sock(group, sock);
281 spdk_sock_close(&sock);
282 }
283
284 static int
285 hello_sock_accept_poll(void *arg)
286 {
287 struct hello_context_t *ctx = arg;
288 struct spdk_sock *sock;
289 int rc;
290 int count = 0;
291 char saddr[ADDR_STR_LEN], caddr[ADDR_STR_LEN];
292 uint16_t cport, sport;
293
294 if (!g_is_running) {
295 hello_sock_quit(ctx, 0);
296 return 0;
297 }
298
299 while (1) {
300 sock = spdk_sock_accept(ctx->sock);
301 if (sock != NULL) {
302 rc = spdk_sock_getaddr(sock, saddr, sizeof(saddr), &sport, caddr, sizeof(caddr), &cport);
303 if (rc < 0) {
304 SPDK_ERRLOG("Cannot get connection addresses\n");
305 spdk_sock_close(&ctx->sock);
306 return -1;
307 }
308
309 SPDK_NOTICELOG("Accepting a new connection from (%s, %hu) to (%s, %hu)\n",
310 caddr, cport, saddr, sport);
311
312 rc = spdk_sock_group_add_sock(ctx->group, sock,
313 hello_sock_cb, ctx);
314
315 if (rc < 0) {
316 spdk_sock_close(&sock);
317 SPDK_ERRLOG("failed\n");
318 break;
319 }
320
321 count++;
322 } else {
323 if (errno != EAGAIN && errno != EWOULDBLOCK) {
324 SPDK_ERRLOG("accept error(%d): %s\n", errno, spdk_strerror(errno));
325 }
326 break;
327 }
328 }
329
330 return count;
331 }
332
333 static int
334 hello_sock_group_poll(void *arg)
335 {
336 struct hello_context_t *ctx = arg;
337 int rc;
338
339 rc = spdk_sock_group_poll(ctx->group);
340 if (rc < 0) {
341 SPDK_ERRLOG("Failed to poll sock_group=%p\n", ctx->group);
342 }
343
344 return -1;
345 }
346
347 static int
348 hello_sock_listen(struct hello_context_t *ctx)
349 {
350 ctx->sock = spdk_sock_listen(ctx->host, ctx->port);
351 if (ctx->sock == NULL) {
352 SPDK_ERRLOG("Cannot create server socket\n");
353 return -1;
354 }
355
356 SPDK_NOTICELOG("Listening connection on %s:%d\n", ctx->host, ctx->port);
357
358 /*
359 * Create sock group for server socket
360 */
361 ctx->group = spdk_sock_group_create();
362
363 g_is_running = true;
364
365 /*
366 * Start acceptor and group poller
367 */
368 ctx->poller_in = spdk_poller_register(hello_sock_accept_poll, ctx,
369 ACCEPT_TIMEOUT_US);
370 ctx->poller_out = spdk_poller_register(hello_sock_group_poll, ctx, 0);
371
372 return 0;
373 }
374
375 static void
376 hello_sock_shutdown_cb(void)
377 {
378 g_is_running = false;
379 }
380
381 /*
382 * Our initial event that kicks off everything from main().
383 */
384 static void
385 hello_start(void *arg1, int rc)
386 {
387 struct hello_context_t *ctx = arg1;
388
389 if (rc) {
390 SPDK_ERRLOG("ERROR starting application\n");
391 spdk_app_stop(-1);
392 return;
393 }
394
395 SPDK_NOTICELOG("Successfully started the application\n");
396
397 if (ctx->is_server) {
398 rc = hello_sock_listen(ctx);
399 } else {
400 rc = hello_sock_connect(ctx);
401 }
402
403 if (rc) {
404 spdk_app_stop(-1);
405 return;
406 }
407 }
408
409 static void
410 start_net_framework(void *arg1)
411 {
412 spdk_net_framework_start(hello_start, arg1);
413 }
414
415 int
416 main(int argc, char **argv)
417 {
418 struct spdk_app_opts opts = {};
419 int rc = 0;
420 struct hello_context_t hello_context = {};
421
422 /* Set default values in opts structure. */
423 spdk_app_opts_init(&opts);
424 opts.name = "hello_sock";
425 opts.config_file = "sock.conf";
426 opts.shutdown_cb = hello_sock_shutdown_cb;
427
428 if ((rc = spdk_app_parse_args(argc, argv, &opts, "H:P:SV", NULL, hello_sock_parse_arg,
429 hello_sock_usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) {
430 exit(rc);
431 }
432 hello_context.is_server = g_is_server;
433 hello_context.host = g_host;
434 hello_context.port = g_port;
435 hello_context.verbose = g_verbose;
436
437 rc = spdk_app_start(&opts, start_net_framework, &hello_context);
438 if (rc) {
439 SPDK_ERRLOG("ERROR starting application\n");
440 }
441
442 SPDK_NOTICELOG("Exiting from application\n");
443
444 if (hello_context.verbose) {
445 printf("** %d bytes received, %d bytes sent **\n",
446 hello_context.bytes_in, hello_context.bytes_out);
447 }
448
449 /* Gracefully close out all of the SPDK subsystems. */
450 spdk_app_fini();
451 return rc;
452 }