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