]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/examples/sock/hello_world/hello_sock.c
update sources to ceph Nautilus 14.2.1
[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
77 /*
78 * Usage function for printing parameters that are specific to this application
79 */
80 static void
81 hello_sock_usage(void)
82 {
83 printf(" -H host_addr host address\n");
84 printf(" -P port port number\n");
85 printf(" -S start in server mode\n");
86 printf(" -V print out additional informations");
87 }
88
89 /*
90 * This function is called to parse the parameters that are specific to this application
91 */
92 static void hello_sock_parse_arg(int ch, char *arg)
93 {
94 switch (ch) {
95 case 'H':
96 g_host = arg;
97 break;
98 case 'P':
99 g_port = atoi(arg);
100 break;
101 case 'S':
102 g_is_server = 1;
103 break;
104 case 'V':
105 g_verbose = true;
106 }
107 }
108
109 static int
110 hello_sock_close_timeout_poll(void *arg)
111 {
112 struct hello_context_t *ctx = arg;
113 SPDK_NOTICELOG("Connection closed\n");
114
115 spdk_poller_unregister(&ctx->time_out);
116 spdk_poller_unregister(&ctx->poller_in);
117 spdk_sock_close(&ctx->sock);
118
119 spdk_app_stop(0);
120 return 0;
121 }
122
123 static int
124 hello_sock_recv_poll(void *arg)
125 {
126 struct hello_context_t *ctx = arg;
127 int rc;
128 char buf_in[BUFFER_SIZE];
129
130 /*
131 * Get response
132 */
133 rc = spdk_sock_recv(ctx->sock, buf_in, sizeof(buf_in) - 1);
134
135 if (rc <= 0) {
136 if (errno == EAGAIN || errno == EWOULDBLOCK) {
137 return 0;
138 }
139
140 SPDK_ERRLOG("spdk_sock_recv() failed, errno %d: %s\n",
141 errno, spdk_strerror(errno));
142 return -1;
143 }
144
145 if (rc > 0) {
146 ctx->bytes_in += rc;
147 buf_in[rc] = '\0';
148 printf("%s", buf_in);
149 }
150
151 return 0;
152 }
153
154 static int
155 hello_sock_writev_poll(void *arg)
156 {
157 struct hello_context_t *ctx = arg;
158 int rc = 0;
159 char buf_out[BUFFER_SIZE];
160 struct iovec iov;
161 ssize_t n;
162
163 n = read(STDIN_FILENO, buf_out, sizeof(buf_out));
164 if (n == 0 || !g_is_running) {
165 /* EOF */
166 SPDK_NOTICELOG("Closing connection...\n");
167
168 ctx->time_out = spdk_poller_register(hello_sock_close_timeout_poll, ctx,
169 CLOSE_TIMEOUT_US);
170
171 spdk_poller_unregister(&ctx->poller_out);
172 return 0;
173 }
174 if (n > 0) {
175 /*
176 * Send message to the server
177 */
178 iov.iov_base = buf_out;
179 iov.iov_len = n;
180 rc = spdk_sock_writev(ctx->sock, &iov, 1);
181 if (rc > 0) {
182 ctx->bytes_out += rc;
183 }
184 }
185 return rc;
186 }
187
188 static int
189 hello_sock_connect(struct hello_context_t *ctx)
190 {
191 int rc;
192 char saddr[ADDR_STR_LEN], caddr[ADDR_STR_LEN];
193 uint16_t cport, sport;
194
195 SPDK_NOTICELOG("Connecting to the server on %s:%d\n", ctx->host, ctx->port);
196
197 ctx->sock = spdk_sock_connect(ctx->host, ctx->port);
198 if (ctx->sock == NULL) {
199 SPDK_ERRLOG("connect error(%d): %s\n", errno, spdk_strerror(errno));
200 return -1;
201 }
202
203 rc = spdk_sock_getaddr(ctx->sock, saddr, sizeof(saddr), &sport, caddr, sizeof(caddr), &cport);
204 if (rc < 0) {
205 SPDK_ERRLOG("Cannot get connection addresses\n");
206 spdk_sock_close(&ctx->sock);
207 return -1;
208 }
209
210 SPDK_NOTICELOG("Connection accepted from (%s, %hu) to (%s, %hu)\n", caddr, cport, saddr, sport);
211
212 fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
213
214 g_is_running = true;
215 ctx->poller_in = spdk_poller_register(hello_sock_recv_poll, ctx, 0);
216 ctx->poller_out = spdk_poller_register(hello_sock_writev_poll, ctx, 0);
217
218 return 0;
219 }
220
221 static void
222 hello_sock_cb(void *arg, struct spdk_sock_group *group, struct spdk_sock *sock)
223 {
224 ssize_t n;
225 char buf[BUFFER_SIZE];
226 struct iovec iov;
227 struct hello_context_t *ctx = arg;
228
229 n = spdk_sock_recv(sock, buf, sizeof(buf));
230 if (n < 0) {
231 if (errno == EAGAIN || errno == EWOULDBLOCK) {
232 SPDK_ERRLOG("spdk_sock_recv() failed, errno %d: %s\n",
233 errno, spdk_strerror(errno));
234 return;
235 }
236
237 SPDK_ERRLOG("spdk_sock_recv() failed, errno %d: %s\n",
238 errno, spdk_strerror(errno));
239 }
240
241 if (n > 0) {
242 ctx->bytes_in += n;
243 iov.iov_base = buf;
244 iov.iov_len = n;
245 n = spdk_sock_writev(sock, &iov, 1);
246 if (n > 0) {
247 ctx->bytes_out += n;
248 }
249 return;
250 }
251
252 /* Connection closed */
253 SPDK_NOTICELOG("Connection closed\n");
254 spdk_sock_group_remove_sock(group, sock);
255 spdk_sock_close(&sock);
256 }
257
258 static int
259 hello_sock_accept_poll(void *arg)
260 {
261 struct hello_context_t *ctx = arg;
262 struct spdk_sock *sock;
263 int rc;
264 int count = 0;
265 char saddr[ADDR_STR_LEN], caddr[ADDR_STR_LEN];
266 uint16_t cport, sport;
267
268 if (!g_is_running) {
269 spdk_poller_unregister(&ctx->poller_in);
270 spdk_poller_unregister(&ctx->poller_out);
271 spdk_sock_close(&ctx->sock);
272 spdk_sock_group_close(&ctx->group);
273 spdk_app_stop(0);
274 return 0;
275 }
276
277 while (1) {
278 sock = spdk_sock_accept(ctx->sock);
279 if (sock != NULL) {
280 spdk_sock_getaddr(sock, saddr, sizeof(saddr), &sport, caddr, sizeof(caddr), &cport);
281
282 SPDK_NOTICELOG("Accepting a new connection from (%s, %hu) to (%s, %hu)\n",
283 caddr, cport, saddr, sport);
284
285 rc = spdk_sock_group_add_sock(ctx->group, sock,
286 hello_sock_cb, ctx);
287
288 if (rc < 0) {
289 spdk_sock_close(&sock);
290 SPDK_ERRLOG("failed\n");
291 break;
292 }
293
294 count++;
295 } else {
296 if (errno != EAGAIN && errno != EWOULDBLOCK) {
297 SPDK_ERRLOG("accept error(%d): %s\n", errno, spdk_strerror(errno));
298 }
299 break;
300 }
301 }
302
303 return count;
304 }
305
306 static int
307 hello_sock_group_poll(void *arg)
308 {
309 struct hello_context_t *ctx = arg;
310 int rc;
311
312 rc = spdk_sock_group_poll(ctx->group);
313 if (rc < 0) {
314 SPDK_ERRLOG("Failed to poll sock_group=%p\n", ctx->group);
315 }
316
317 return -1;
318 }
319
320 static int
321 hello_sock_listen(struct hello_context_t *ctx)
322 {
323 ctx->sock = spdk_sock_listen(ctx->host, ctx->port);
324 if (ctx->sock == NULL) {
325 SPDK_ERRLOG("Cannot create server socket\n");
326 return -1;
327 }
328
329 SPDK_NOTICELOG("Listening connection on %s:%d\n", ctx->host, ctx->port);
330
331 /*
332 * Create sock group for server socket
333 */
334 ctx->group = spdk_sock_group_create();
335
336 g_is_running = true;
337
338 /*
339 * Start acceptor and group poller
340 */
341 ctx->poller_in = spdk_poller_register(hello_sock_accept_poll, ctx,
342 ACCEPT_TIMEOUT_US);
343 ctx->poller_out = spdk_poller_register(hello_sock_group_poll, ctx, 0);
344
345 return 0;
346 }
347
348 static void
349 hello_sock_shutdown_cb(void)
350 {
351 g_is_running = false;
352 }
353 /*
354 * Our initial event that kicks off everything from main().
355 */
356 static void
357 hello_start(void *arg1, void *arg2)
358 {
359 struct hello_context_t *ctx = arg1;
360 int rc = 0;
361
362 SPDK_NOTICELOG("Successfully started the application\n");
363
364 if (ctx->is_server) {
365 rc = hello_sock_listen(ctx);
366 } else {
367 rc = hello_sock_connect(ctx);
368 }
369
370 if (rc) {
371 spdk_app_stop(-1);
372 return;
373 }
374 }
375
376 int
377 main(int argc, char **argv)
378 {
379 struct spdk_app_opts opts = {};
380 int rc = 0;
381 struct hello_context_t hello_context = {};
382
383 /* Set default values in opts structure. */
384 spdk_app_opts_init(&opts);
385 opts.name = "hello_sock";
386 opts.config_file = "sock.conf";
387 opts.shutdown_cb = hello_sock_shutdown_cb;
388
389 if ((rc = spdk_app_parse_args(argc, argv, &opts, "H:P:SV", NULL, hello_sock_parse_arg,
390 hello_sock_usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) {
391 exit(rc);
392 }
393 hello_context.is_server = g_is_server;
394 hello_context.host = g_host;
395 hello_context.port = g_port;
396 hello_context.verbose = g_verbose;
397
398 rc = spdk_net_framework_start();
399 if (rc) {
400 SPDK_ERRLOG("ERROR starting application\n");
401 goto end;
402 }
403
404 rc = spdk_app_start(&opts, hello_start, &hello_context, NULL);
405 if (rc) {
406 SPDK_ERRLOG("ERROR starting application\n");
407 }
408
409 end:
410 SPDK_NOTICELOG("Exiting from application\n");
411
412 if (hello_context.verbose) {
413 printf("** %d bytes received, %d bytes sent **\n",
414 hello_context.bytes_in, hello_context.bytes_out);
415 }
416
417 spdk_net_framework_fini();
418
419 /* Gracefully close out all of the SPDK subsystems. */
420 spdk_app_fini();
421 return rc;
422 }