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 uring\n"); 90 printf(" -S start in server mode\n"); 91 printf(" -V print out additional informations\n"); 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, sizeof(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 } 443