diff options
| author | David M. Syzdek <david@syzdek.net> | 2020-02-07 16:39:39 -0900 |
|---|---|---|
| committer | David M. Syzdek <david@syzdek.net> | 2020-02-07 16:39:39 -0900 |
| commit | e5458fc2fa378a1b29cb4d6cdbf6727b4763b712 (patch) | |
| tree | ddf72383b8236ed7a321ad4c89c243144b065d56 | |
| parent | 1d9ed2af174b283c282e228433ecfc22bf989ccb (diff) | |
| download | akcom-udpecho-e5458fc2fa378a1b29cb4d6cdbf6727b4763b712.tar.gz akcom-udpecho-e5458fc2fa378a1b29cb4d6cdbf6727b4763b712.tar.bz2 akcom-udpecho-e5458fc2fa378a1b29cb4d6cdbf6727b4763b712.tar.xz akcom-udpecho-e5458fc2fa378a1b29cb4d6cdbf6727b4763b712.zip | |
akcom-udpecho: adding network code and refactoring options
| -rw-r--r-- | src/akcom-udpecho.c | 350 |
1 files changed, 329 insertions, 21 deletions
diff --git a/src/akcom-udpecho.c b/src/akcom-udpecho.c index 5b6d6e9..1dbfe1f 100644 --- a/src/akcom-udpecho.c +++ b/src/akcom-udpecho.c | |||
| @@ -82,6 +82,8 @@ | |||
| 82 | #include <syslog.h> | 82 | #include <syslog.h> |
| 83 | #include <signal.h> | 83 | #include <signal.h> |
| 84 | #include <poll.h> | 84 | #include <poll.h> |
| 85 | #include <string.h> | ||
| 86 | #include <strings.h> | ||
| 85 | 87 | ||
| 86 | #include "akcom-udpecho.h" | 88 | #include "akcom-udpecho.h" |
| 87 | 89 | ||
| @@ -111,6 +113,12 @@ | |||
| 111 | ///////////////// | 113 | ///////////////// |
| 112 | #pragma mark - Datatypes | 114 | #pragma mark - Datatypes |
| 113 | 115 | ||
| 116 | union udp_buffer | ||
| 117 | { | ||
| 118 | uint8_t * data; | ||
| 119 | struct udp_echo_plus * echoplus; | ||
| 120 | }; | ||
| 121 | |||
| 114 | 122 | ||
| 115 | ///////////////// | 123 | ///////////////// |
| 116 | // // | 124 | // // |
| @@ -119,12 +127,17 @@ | |||
| 119 | ///////////////// | 127 | ///////////////// |
| 120 | #pragma mark - Variables | 128 | #pragma mark - Variables |
| 121 | 129 | ||
| 122 | static const char * prog_name = PROGRAM_NAME; | 130 | static const char * prog_name = PROGRAM_NAME; |
| 123 | static int cnf_echoplus = 0; | 131 | static uint32_t cnf_count = 0; |
| 124 | static int cnf_verbose = 0; | 132 | static int cnf_echoplus = 0; |
| 125 | static time_t cnf_timeout = 5; | 133 | static int cnf_verbose = 0; |
| 126 | static short cnf_port = 30006; | 134 | static int cnf_silent = 0; |
| 127 | static const char * cnf_host = NULL; | 135 | static unsigned long cnf_timeout = 5; |
| 136 | static const char * cnf_port = "30006"; | ||
| 137 | static const char * cnf_host = NULL; | ||
| 138 | static unsigned long cnf_interval = 1; | ||
| 139 | static size_t cnf_packetsize = sizeof(struct udp_echo_plus); | ||
| 140 | static int should_stop = 0; | ||
| 128 | 141 | ||
| 129 | 142 | ||
| 130 | ////////////////// | 143 | ////////////////// |
| @@ -137,6 +150,9 @@ static const char * cnf_host = NULL; | |||
| 137 | // main statement | 150 | // main statement |
| 138 | int main(int argc, char * argv[]); | 151 | int main(int argc, char * argv[]); |
| 139 | 152 | ||
| 153 | // signal system stop | ||
| 154 | void my_stop(int signum); | ||
| 155 | |||
| 140 | // display program usage | 156 | // display program usage |
| 141 | void my_usage(void); | 157 | void my_usage(void); |
| 142 | 158 | ||
| @@ -155,16 +171,46 @@ void my_usage_error(const char * fmt, ...); | |||
| 155 | int main(int argc, char * argv[]) | 171 | int main(int argc, char * argv[]) |
| 156 | { | 172 | { |
| 157 | int c; | 173 | int c; |
| 174 | int s; | ||
| 175 | int fd; | ||
| 176 | int rc; | ||
| 158 | int opt_index; | 177 | int opt_index; |
| 178 | uint32_t count; | ||
| 179 | uint32_t rcvd; | ||
| 180 | uint64_t epoch; | ||
| 181 | uint64_t epoch_adj; | ||
| 182 | uint64_t epoch_max; | ||
| 183 | uint64_t delay; | ||
| 184 | uint64_t max; | ||
| 185 | uint64_t max_adj; | ||
| 186 | uint64_t min; | ||
| 187 | uint64_t min_adj; | ||
| 188 | uint64_t avg; | ||
| 189 | uint64_t avg_adj; | ||
| 190 | ssize_t size; | ||
| 191 | unsigned short port; | ||
| 159 | char * ptr; | 192 | char * ptr; |
| 160 | //union my_sa sa; | 193 | char addrstr[INET6_ADDRSTRLEN]; |
| 194 | char logmsg[256]; | ||
| 195 | union my_sa sa; | ||
| 196 | socklen_t socklen; | ||
| 197 | struct addrinfo * res; | ||
| 198 | struct addrinfo * info; | ||
| 199 | struct addrinfo hints; | ||
| 200 | struct timespec start; | ||
| 201 | struct timespec now; | ||
| 202 | struct pollfd fds[2]; | ||
| 203 | union udp_buffer sndbuff; | ||
| 204 | union udp_buffer rcvbuff; | ||
| 161 | 205 | ||
| 162 | // getopt options | 206 | // getopt options |
| 163 | static char short_opt[] = "d:D:efg:hl:np:P:ru:vV"; | 207 | static char short_opt[] = "46c:ehi:qrs:t:vV"; |
| 164 | static struct option long_opt[] = | 208 | static struct option long_opt[] = |
| 165 | { | 209 | { |
| 166 | {"echoplus", no_argument, 0, 'e'}, | 210 | {"echoplus", no_argument, 0, 'e'}, |
| 167 | {"help", no_argument, 0, 'h'}, | 211 | {"help", no_argument, 0, 'h'}, |
| 212 | {"quiet", no_argument, 0, 'q'}, | ||
| 213 | {"silent", no_argument, 0, 'q'}, | ||
| 168 | {"rfc", no_argument, 0, 'r'}, | 214 | {"rfc", no_argument, 0, 'r'}, |
| 169 | {"verbose", no_argument, 0, 'v'}, | 215 | {"verbose", no_argument, 0, 'v'}, |
| 170 | {"version", no_argument, 0, 'V'}, | 216 | {"version", no_argument, 0, 'V'}, |
| @@ -176,6 +222,13 @@ int main(int argc, char * argv[]) | |||
| 176 | if ((ptr = rindex(argv[0], '/')) != NULL) | 222 | if ((ptr = rindex(argv[0], '/')) != NULL) |
| 177 | prog_name = &ptr[1]; | 223 | prog_name = &ptr[1]; |
| 178 | 224 | ||
| 225 | // initializes variables | ||
| 226 | bzero(&hints, sizeof(struct addrinfo)); | ||
| 227 | hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED | AI_ALL; | ||
| 228 | hints.ai_family = PF_UNSPEC; | ||
| 229 | hints.ai_socktype = SOCK_DGRAM; | ||
| 230 | hints.ai_protocol = IPPROTO_UDP; | ||
| 231 | |||
| 179 | // process arguments | 232 | // process arguments |
| 180 | while((c = getopt_long(argc, argv, short_opt, long_opt, &opt_index)) != -1) | 233 | while((c = getopt_long(argc, argv, short_opt, long_opt, &opt_index)) != -1) |
| 181 | { | 234 | { |
| @@ -185,6 +238,18 @@ int main(int argc, char * argv[]) | |||
| 185 | case 0: // long options toggles | 238 | case 0: // long options toggles |
| 186 | break; | 239 | break; |
| 187 | 240 | ||
| 241 | case '4': | ||
| 242 | hints.ai_family = PF_INET; | ||
| 243 | break; | ||
| 244 | |||
| 245 | case '6': | ||
| 246 | hints.ai_family = PF_INET6; | ||
| 247 | break; | ||
| 248 | |||
| 249 | case 'c': | ||
| 250 | cnf_count = (uint32_t)strtoul(optarg, NULL, 10); | ||
| 251 | break; | ||
| 252 | |||
| 188 | case 'e': | 253 | case 'e': |
| 189 | cnf_echoplus = 1; | 254 | cnf_echoplus = 1; |
| 190 | break; | 255 | break; |
| @@ -197,6 +262,22 @@ int main(int argc, char * argv[]) | |||
| 197 | my_usage(); | 262 | my_usage(); |
| 198 | return(0); | 263 | return(0); |
| 199 | 264 | ||
| 265 | case 'i': | ||
| 266 | cnf_interval = (unsigned)strtoul(optarg, NULL, 10); | ||
| 267 | break; | ||
| 268 | |||
| 269 | case 'q': | ||
| 270 | cnf_silent = 1; | ||
| 271 | break; | ||
| 272 | |||
| 273 | case 's': | ||
| 274 | cnf_packetsize = (size_t)strtoull(optarg, NULL, 10); | ||
| 275 | break; | ||
| 276 | |||
| 277 | case 't': | ||
| 278 | cnf_interval = (unsigned)strtoul(optarg, NULL, 10); | ||
| 279 | break; | ||
| 280 | |||
| 200 | case 'v': | 281 | case 'v': |
| 201 | cnf_verbose++; | 282 | cnf_verbose++; |
| 202 | break; | 283 | break; |
| @@ -222,12 +303,7 @@ int main(int argc, char * argv[]) | |||
| 222 | cnf_host = argv[optind++]; | 303 | cnf_host = argv[optind++]; |
| 223 | if (optind < argc) | 304 | if (optind < argc) |
| 224 | { | 305 | { |
| 225 | cnf_port = (short)strtoul(argv[optind++], &ptr, 10); | 306 | cnf_port = argv[optind++]; |
| 226 | if ( (!(cnf_port)) || ((ptr[0])) ) | ||
| 227 | { | ||
| 228 | my_usage_error("invalid port number"); | ||
| 229 | return(1); | ||
| 230 | }; | ||
| 231 | }; | 307 | }; |
| 232 | if (optind < argc) | 308 | if (optind < argc) |
| 233 | { | 309 | { |
| @@ -235,23 +311,255 @@ int main(int argc, char * argv[]) | |||
| 235 | return(1); | 311 | return(1); |
| 236 | }; | 312 | }; |
| 237 | 313 | ||
| 238 | printf("connect to %s:%hu\n", cnf_host, cnf_port); | 314 | |
| 315 | // allocate buffer | ||
| 316 | if ((fd = open("/dev/urandom", O_RDONLY)) == -1) | ||
| 317 | { | ||
| 318 | fprintf(stderr, "%s: open(/dev/urandom): %s\n", prog_name, strerror(errno)); | ||
| 319 | return(1); | ||
| 320 | }; | ||
| 321 | if (cnf_packetsize < sizeof(struct udp_echo_plus)) | ||
| 322 | cnf_packetsize = sizeof(struct udp_echo_plus); | ||
| 323 | if ((sndbuff.data = malloc(cnf_packetsize)) == NULL) | ||
| 324 | { | ||
| 325 | fprintf(stderr, "%s: out of virtual memory\n", prog_name); | ||
| 326 | close(fd); | ||
| 327 | return(1); | ||
| 328 | }; | ||
| 329 | if ((rcvbuff.data = malloc(cnf_packetsize)) == NULL) | ||
| 330 | { | ||
| 331 | fprintf(stderr, "%s: out of virtual memory\n", prog_name); | ||
| 332 | close(fd); | ||
| 333 | return(1); | ||
| 334 | }; | ||
| 335 | if ((size = read(fd, sndbuff.data, cnf_packetsize)) == -1) | ||
| 336 | { | ||
| 337 | fprintf(stderr, "%s: read(): %s\n", prog_name, strerror(errno)); | ||
| 338 | close(fd); | ||
| 339 | free(sndbuff.data); | ||
| 340 | free(rcvbuff.data); | ||
| 341 | return(1); | ||
| 342 | }; | ||
| 343 | close(fd); | ||
| 344 | bzero(sndbuff.data, sizeof(struct udp_echo_plus)); | ||
| 345 | |||
| 346 | |||
| 347 | // resolve host | ||
| 348 | bzero(&sa, sizeof(sa)); | ||
| 349 | bzero(addrstr, sizeof(addrstr)); | ||
| 350 | socklen = 0; | ||
| 351 | if ((rc = getaddrinfo(cnf_host, cnf_port, &hints, &res)) != 0) | ||
| 352 | { | ||
| 353 | fprintf(stderr, "%s: getaddrinfo(): %s\n", prog_name, gai_strerror(rc)); | ||
| 354 | free(sndbuff.data); | ||
| 355 | free(rcvbuff.data); | ||
| 356 | return(1); | ||
| 357 | }; | ||
| 358 | for(info = res; (info != NULL); info = info->ai_next) | ||
| 359 | { | ||
| 360 | if (info->ai_addr->sa_family != AF_INET6) | ||
| 361 | continue; | ||
| 362 | socklen = info->ai_addrlen; | ||
| 363 | memcpy(&sa, info->ai_addr, socklen); | ||
| 364 | inet_ntop(AF_INET6, &sa.sin6.sin6_addr, addrstr, sizeof(addrstr)); | ||
| 365 | port = ntohs(sa.sin6.sin6_port); | ||
| 366 | snprintf(logmsg, sizeof(logmsg), "UDPECHO %s:%hu ([%s]:%hu): %zu bytes\n", cnf_host, port, addrstr, port, cnf_packetsize); | ||
| 367 | } | ||
| 368 | if (sa.sa.sa_family != AF_INET6) | ||
| 369 | { | ||
| 370 | socklen = res->ai_addrlen; | ||
| 371 | memcpy(&sa.sa, res->ai_addr, socklen); | ||
| 372 | inet_ntop(AF_INET, &sa.sin.sin_addr, addrstr, sizeof(addrstr)); | ||
| 373 | port = ntohs(sa.sin.sin_port); | ||
| 374 | snprintf(logmsg, sizeof(logmsg), "UDPECHO %s:%hu (%s:%hu): %zu bytes\n", cnf_host, port, addrstr, port, cnf_packetsize); | ||
| 375 | }; | ||
| 376 | freeaddrinfo(res); | ||
| 377 | if (!(cnf_silent)) | ||
| 378 | printf("%s", logmsg); | ||
| 379 | |||
| 380 | |||
| 381 | // open and connect socket | ||
| 382 | if ((s = socket(sa.sa.sa_family, SOCK_DGRAM, 0)) == -1) | ||
| 383 | { | ||
| 384 | fprintf(stderr, "%s: socket(): %s\n", prog_name, strerror(errno)); | ||
| 385 | free(sndbuff.data); | ||
| 386 | free(rcvbuff.data); | ||
| 387 | return(1); | ||
| 388 | }; | ||
| 389 | if ((rc = connect(s, &sa.sa, socklen)) == -1) | ||
| 390 | { | ||
| 391 | fprintf(stderr, "%s: connect(): %s\n", prog_name, strerror(errno)); | ||
| 392 | free(sndbuff.data); | ||
| 393 | free(rcvbuff.data); | ||
| 394 | return(1); | ||
| 395 | }; | ||
| 396 | fds[0].fd = s; | ||
| 397 | fds[0].events = POLLIN; | ||
| 398 | fds[0].revents = 0; | ||
| 399 | fds[1].fd = -1; | ||
| 400 | fds[1].events = 0; | ||
| 401 | fds[1].revents = 0; | ||
| 402 | |||
| 403 | |||
| 404 | // configure signals | ||
| 405 | signal(SIGPIPE, SIG_IGN); | ||
| 406 | signal(SIGINFO, SIG_IGN); | ||
| 407 | signal(SIGUSR1, SIG_IGN); | ||
| 408 | signal(SIGUSR2, SIG_IGN); | ||
| 409 | signal(SIGHUP, my_stop); | ||
| 410 | signal(SIGINT, my_stop); | ||
| 411 | signal(SIGQUIT, my_stop); | ||
| 412 | signal(SIGALRM, my_stop); | ||
| 413 | signal(SIGTERM, my_stop); | ||
| 414 | |||
| 415 | |||
| 416 | // initialize statistics | ||
| 417 | count = 0; | ||
| 418 | rcvd = 0; | ||
| 419 | min = 0; | ||
| 420 | min_adj = 0; | ||
| 421 | max = 0; | ||
| 422 | max_adj = 0; | ||
| 423 | avg = 0; | ||
| 424 | avg_adj = 0; | ||
| 425 | |||
| 426 | |||
| 427 | // start clock | ||
| 428 | clock_gettime(CLOCK_MONOTONIC_RAW, &start); | ||
| 429 | start.tv_sec -= cnf_interval; | ||
| 430 | epoch = 0; | ||
| 431 | |||
| 432 | |||
| 433 | // master loop | ||
| 434 | while (!(should_stop)) | ||
| 435 | { | ||
| 436 | // calculate loop epoch | ||
| 437 | clock_gettime(CLOCK_MONOTONIC_RAW, &now); | ||
| 438 | epoch = ((uint64_t)now.tv_sec * 10000) + ((uint64_t)now.tv_nsec / 100000); | ||
| 439 | epoch -= ((uint64_t)start.tv_sec * 10000) + ((uint64_t)start.tv_nsec / 100000); | ||
| 440 | |||
| 441 | // trigger stop | ||
| 442 | if ( ((cnf_count)) && (count >= cnf_count) ) | ||
| 443 | { | ||
| 444 | epoch_max = cnf_count * (uint64_t)cnf_interval * 10000; | ||
| 445 | epoch_max += (uint64_t)cnf_timeout * 10000; | ||
| 446 | if (( epoch >= epoch_max) || (rcvd >= count)) | ||
| 447 | should_stop = 1; | ||
| 448 | }; | ||
| 449 | |||
| 450 | // send UDP echo request | ||
| 451 | if ((count < (epoch/(10000*cnf_interval))) && ((count < cnf_count) || (!(cnf_count))) ) | ||
| 452 | { | ||
| 453 | count++; | ||
| 454 | sndbuff.echoplus->req_sn = count; | ||
| 455 | send(s, sndbuff.data, cnf_packetsize, 0); | ||
| 456 | }; | ||
| 457 | |||
| 458 | // receive UDP echo response | ||
| 459 | if ((rc = poll(fds, 1, 0)) > 0) | ||
| 460 | { | ||
| 461 | if ((size = recv(s, rcvbuff.data, cnf_packetsize, 0)) == (ssize_t)cnf_packetsize) | ||
| 462 | { | ||
| 463 | rcvd++; | ||
| 464 | delay = rcvbuff.echoplus->reply_time - rcvbuff.echoplus->recv_time; | ||
| 465 | delay /= 100000000; | ||
| 466 | epoch -= (rcvbuff.echoplus->req_sn * 10000); | ||
| 467 | epoch_adj = epoch - delay; | ||
| 468 | avg += epoch; | ||
| 469 | avg_adj += epoch_adj; | ||
| 470 | if ( (!(min)) || (epoch < min) ) | ||
| 471 | min = epoch; | ||
| 472 | if ( (!(max)) || (epoch > max) ) | ||
| 473 | max = epoch; | ||
| 474 | if ( (!(min_adj)) || (epoch_adj < min_adj) ) | ||
| 475 | min_adj = epoch_adj; | ||
| 476 | if ( (!(max_adj)) || (epoch_adj > max_adj) ) | ||
| 477 | max_adj = epoch_adj; | ||
| 478 | if ((cnf_echoplus)) | ||
| 479 | { | ||
| 480 | printf("udpecho_seq=%u time=%llu.%llu ms delay=%llu.%llu ms adj_time=%llu.%llu ms\n", | ||
| 481 | rcvbuff.echoplus->req_sn, | ||
| 482 | epoch/10, epoch%10, | ||
| 483 | delay/10, delay%10, | ||
| 484 | epoch_adj/10, epoch_adj%10 | ||
| 485 | ); | ||
| 486 | } else | ||
| 487 | { | ||
| 488 | printf("udpecho_seq=%u time=%llu.%llu ms\n", | ||
| 489 | rcvbuff.echoplus->req_sn, | ||
| 490 | epoch/10, epoch%10 | ||
| 491 | ); | ||
| 492 | }; | ||
| 493 | }; | ||
| 494 | } else | ||
| 495 | { | ||
| 496 | usleep(100); | ||
| 497 | }; | ||
| 498 | }; | ||
| 499 | |||
| 500 | |||
| 501 | if (!(cnf_silent)) | ||
| 502 | { | ||
| 503 | printf("\n"); | ||
| 504 | printf("--- %s udpecho statistics ---\n", cnf_host); | ||
| 505 | printf("%i packets transmitted, %i packets received, %i.%i%% packet loss\n", | ||
| 506 | count, | ||
| 507 | rcvd, | ||
| 508 | ((count - rcvd) * 100) / count, | ||
| 509 | (((count - rcvd) * 1000) / count) % 10 | ||
| 510 | ); | ||
| 511 | printf("round-trip min/avg/max = %llu.%llu/%llu.%llu/%llu.%llu ms\n", | ||
| 512 | min/10, min%10, | ||
| 513 | (avg/rcvd)/10, (avg/rcvd)%10, | ||
| 514 | max/10, max%10 | ||
| 515 | ); | ||
| 516 | if ((cnf_echoplus)) | ||
| 517 | { | ||
| 518 | printf("adjusted round-trip min/avg/max = %llu.%llu/%llu.%llu/%llu.%llu ms\n", | ||
| 519 | min_adj/10, min_adj%10, | ||
| 520 | (avg_adj/rcvd)/10, (avg_adj/rcvd)%10, | ||
| 521 | max_adj/10, max_adj%10 | ||
| 522 | ); | ||
| 523 | }; | ||
| 524 | }; | ||
| 525 | |||
| 526 | |||
| 527 | // free resources | ||
| 528 | free(sndbuff.data); | ||
| 529 | free(rcvbuff.data); | ||
| 530 | close(s); | ||
| 531 | |||
| 239 | 532 | ||
| 240 | return(0); | 533 | return(0); |
| 241 | } | 534 | } |
| 242 | 535 | ||
| 243 | 536 | ||
| 537 | // signal system stop | ||
| 538 | void my_stop(int signum) | ||
| 539 | { | ||
| 540 | should_stop = 1; | ||
| 541 | signal(signum, my_stop); | ||
| 542 | return; | ||
| 543 | } | ||
| 544 | |||
| 545 | |||
| 244 | // display program usage | 546 | // display program usage |
| 245 | void my_usage(void) | 547 | void my_usage(void) |
| 246 | { | 548 | { |
| 247 | printf("Usage: %s [options] host [port]\n", prog_name); | 549 | printf("Usage: %s [options] host [port]\n", prog_name); |
| 248 | printf("OPTIONS:\n"); | 550 | printf("OPTIONS:\n"); |
| 249 | printf(" -e, --echoplus enable echo plus, not RFC compliant%s\n", ((cnf_echoplus)) ? " (default)" : ""); | 551 | printf(" -4 connect via IPv4 only\n"); |
| 250 | printf(" -h, --help print this help and exit\n"); | 552 | printf(" -6 connect via IPv6 only\n"); |
| 251 | printf(" -r, --rfc RFC compliant echo protocol%s\n", (!(cnf_echoplus)) ? " (default)" : ""); | 553 | printf(" -c count stop after sending count packets\n"); |
| 252 | printf(" -t sec response timeout (default: %lu s)\n", cnf_timeout); | 554 | printf(" -e, --echoplus expect echo plus response%s\n", ((cnf_echoplus)) ? " (default)" : ""); |
| 253 | printf(" -v, --verbose enable verbose output\n"); | 555 | printf(" -h, --help print this help and exit\n"); |
| 254 | printf(" -V, --version print version number and exit\n"); | 556 | printf(" -i interval interval between packet (default: %lu sec)\n", cnf_interval); |
| 557 | printf(" -r, --rfc expect RFC compliant echo response%s\n", (!(cnf_echoplus)) ? " (default)" : ""); | ||
| 558 | printf(" -q, --quiet, --silent do not print messages\n"); | ||
| 559 | printf(" -s packetsize size of data bytes to be sent. (default: %zu bytes)\n", cnf_packetsize); | ||
| 560 | printf(" -t sec response timeout (default: %lu sec)\n", cnf_timeout); | ||
| 561 | printf(" -v, --verbose enable verbose output\n"); | ||
| 562 | printf(" -V, --version print version number and exit\n"); | ||
| 255 | printf("\n"); | 563 | printf("\n"); |
| 256 | return; | 564 | return; |
| 257 | } | 565 | } |
