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