]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/examples/sock/hello_world/hello_sock.c
update source to Ceph Pacific 16.2.2
[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 char *g_sock_impl_name;
53 static int g_port;
54 static bool g_is_server;
55 static bool g_verbose;
56
57 /*
58 * We'll use this struct to gather housekeeping hello_context to pass between
59 * our events and callbacks.
60 */
61 struct hello_context_t {
62 bool is_server;
63 char *host;
64 char *sock_impl_name;
65 int port;
66
67 bool verbose;
68 int bytes_in;
69 int bytes_out;
70
71 struct spdk_sock *sock;
72
73 struct spdk_sock_group *group;
74 struct spdk_poller *poller_in;
75 struct spdk_poller *poller_out;
76 struct spdk_poller *time_out;
77
78 int rc;
79 };
80
81 /*
82 * Usage function for printing parameters that are specific to this application
83 */
84 static void
85 hello_sock_usage(void)
86 {
87 printf(" -H host_addr host address\n");
88 printf(" -P port port number\n");
89 printf(" -N sock_impl socket implementation, e.g., -N posix or -N vpp\n");
90 printf(" -S start in server mode\n");
91 printf(" -V print out additional informations");
92 }
93
94 /*
95 * This function is called to parse the parameters that are specific to this application
96 */
97 static int hello_sock_parse_arg(int ch, char *arg)
98 {
99 switch (ch) {
100 case 'H':
101 g_host = arg;
102 break;
103 case 'N':
104 g_sock_impl_name = arg;
105 break;
106 case 'P':
107 g_port = spdk_strtol(arg, 10);
108 if (g_port < 0) {
109 fprintf(stderr, "Invalid port ID\n");
110 return g_port;
111 }
112 break;
113 case 'S':
114 g_is_server = 1;
115 break;
116 case 'V':
117 g_verbose = true;
118 break;
119 default:
120 return -EINVAL;
121 }
122 return 0;
123 }
124
125 static int
126 hello_sock_close_timeout_poll(void *arg)
127 {
128 struct hello_context_t *ctx = arg;
129 SPDK_NOTICELOG("Connection closed\n");
130
131 spdk_poller_unregister(&ctx->time_out);
132 spdk_poller_unregister(&ctx->poller_in);
133 spdk_sock_close(&ctx->sock);
134 spdk_sock_group_close(&ctx->group);
135
136 spdk_app_stop(ctx->rc);
137 return 0;
138 }
139
140 static int
141 hello_sock_quit(struct hello_context_t *ctx, int rc)
142 {
143 ctx->rc = rc;
144 spdk_poller_unregister(&ctx->poller_out);
145 if (!ctx->time_out) {
146 ctx->time_out = SPDK_POLLER_REGISTER(hello_sock_close_timeout_poll, ctx,
147 CLOSE_TIMEOUT_US);
148 }
149 return 0;
150 }
151
152 static int
153 hello_sock_recv_poll(void *arg)
154 {
155 struct hello_context_t *ctx = arg;
156 int rc;
157 char buf_in[BUFFER_SIZE];
158
159 /*
160 * Get response
161 */
162 rc = spdk_sock_recv(ctx->sock, buf_in, sizeof(buf_in) - 1);
163
164 if (rc <= 0) {
165 if (errno == EAGAIN || errno == EWOULDBLOCK) {
166 return 0;
167 }
168
169 SPDK_ERRLOG("spdk_sock_recv() failed, errno %d: %s\n",
170 errno, spdk_strerror(errno));
171 return -1;
172 }
173
174 if (rc > 0) {
175 ctx->bytes_in += rc;
176 buf_in[rc] = '\0';
177 printf("%s", buf_in);
178 }
179
180 return 0;
181 }
182
183 static int
184 hello_sock_writev_poll(void *arg)
185 {
186 struct hello_context_t *ctx = arg;
187 int rc = 0;
188 char buf_out[BUFFER_SIZE];
189 struct iovec iov;
190 ssize_t n;
191
192 n = read(STDIN_FILENO, buf_out, sizeof(buf_out));
193 if (n == 0 || !g_is_running) {
194 /* EOF */
195 SPDK_NOTICELOG("Closing connection...\n");
196 hello_sock_quit(ctx, 0);
197 return 0;
198 }
199 if (n > 0) {
200 /*
201 * Send message to the server
202 */
203 iov.iov_base = buf_out;
204 iov.iov_len = n;
205 rc = spdk_sock_writev(ctx->sock, &iov, 1);
206 if (rc > 0) {
207 ctx->bytes_out += rc;
208 }
209 }
210 return rc;
211 }
212
213 static int
214 hello_sock_connect(struct hello_context_t *ctx)
215 {
216 int rc;
217 char saddr[ADDR_STR_LEN], caddr[ADDR_STR_LEN];
218 uint16_t cport, sport;
219
220 SPDK_NOTICELOG("Connecting to the server on %s:%d with sock_impl(%s)\n", ctx->host, ctx->port,
221 ctx->sock_impl_name);
222
223 ctx->sock = spdk_sock_connect(ctx->host, ctx->port, ctx->sock_impl_name);
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, ctx->sock_impl_name);
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 with sock_impl(%s)\n", ctx->host, ctx->port,
357 ctx->sock_impl_name);
358
359 /*
360 * Create sock group for server socket
361 */
362 ctx->group = spdk_sock_group_create(NULL);
363
364 g_is_running = true;
365
366 /*
367 * Start acceptor and group poller
368 */
369 ctx->poller_in = SPDK_POLLER_REGISTER(hello_sock_accept_poll, ctx,
370 ACCEPT_TIMEOUT_US);
371 ctx->poller_out = SPDK_POLLER_REGISTER(hello_sock_group_poll, ctx, 0);
372
373 return 0;
374 }
375
376 static void
377 hello_sock_shutdown_cb(void)
378 {
379 g_is_running = false;
380 }
381
382 /*
383 * Our initial event that kicks off everything from main().
384 */
385 static void
386 hello_start(void *arg1)
387 {
388 struct hello_context_t *ctx = arg1;
389 int rc;
390
391 SPDK_NOTICELOG("Successfully started the application\n");
392
393 if (ctx->is_server) {
394 rc = hello_sock_listen(ctx);
395 } else {
396 rc = hello_sock_connect(ctx);
397 }
398
399 if (rc) {
400 spdk_app_stop(-1);
401 return;
402 }
403 }
404
405 int
406 main(int argc, char **argv)
407 {
408 struct spdk_app_opts opts = {};
409 int rc = 0;
410 struct hello_context_t hello_context = {};
411
412 /* Set default values in opts structure. */
413 spdk_app_opts_init(&opts);
414 opts.name = "hello_sock";
415 opts.shutdown_cb = hello_sock_shutdown_cb;
416
417 if ((rc = spdk_app_parse_args(argc, argv, &opts, "H:N:P:SV", NULL, hello_sock_parse_arg,
418 hello_sock_usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) {
419 exit(rc);
420 }
421 hello_context.is_server = g_is_server;
422 hello_context.host = g_host;
423 hello_context.sock_impl_name = g_sock_impl_name;
424 hello_context.port = g_port;
425 hello_context.verbose = g_verbose;
426
427 rc = spdk_app_start(&opts, hello_start, &hello_context);
428 if (rc) {
429 SPDK_ERRLOG("ERROR starting application\n");
430 }
431
432 SPDK_NOTICELOG("Exiting from application\n");
433
434 if (hello_context.verbose) {
435 printf("** %d bytes received, %d bytes sent **\n",
436 hello_context.bytes_in, hello_context.bytes_out);
437 }
438
439 /* Gracefully close out all of the SPDK subsystems. */
440 spdk_app_fini();
441 return rc;
442 }