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