1 /* 2 * iperf, Copyright (c) 2014, 2016, 2017, The Regents of the University of 3 * California, through Lawrence Berkeley National Laboratory (subject 4 * to receipt of any required approvals from the U.S. Dept. of 5 * Energy). All rights reserved. 6 * 7 * If you have questions about your rights to use or distribute this 8 * software, please contact Berkeley Lab's Technology Transfer 9 * Department at [email protected]. 10 * 11 * NOTICE. This software is owned by the U.S. Department of Energy. 12 * As such, the U.S. Government has been granted for itself and others 13 * acting on its behalf a paid-up, nonexclusive, irrevocable, 14 * worldwide license in the Software to reproduce, prepare derivative 15 * works, and perform publicly and display publicly. Beginning five 16 * (5) years after the date permission to assert copyright is obtained 17 * from the U.S. Department of Energy, and subject to any subsequent 18 * five (5) year renewals, the U.S. Government is granted for itself 19 * and others acting on its behalf a paid-up, nonexclusive, 20 * irrevocable, worldwide license in the Software to reproduce, 21 * prepare derivative works, distribute copies to the public, perform 22 * publicly and display publicly, and to permit others to do so. 23 * 24 * This code is distributed under a BSD style license, see the LICENSE 25 * file for complete information. 26 */ 27 /* iperf_util.c 28 * 29 * Iperf utility functions 30 * 31 */ 32 #include "iperf_config.h" 33 34 #include <stdio.h> 35 #include <signal.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <string.h> 39 #include <stdarg.h> 40 #include <sys/select.h> 41 #include <sys/types.h> 42 #include <sys/time.h> 43 #include <sys/resource.h> 44 #include <sys/utsname.h> 45 #include <time.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 49 #include "cjson.h" 50 #include "iperf.h" 51 #include "iperf_api.h" 52 53 /* 54 * Read entropy from /dev/urandom 55 * Errors are fatal. 56 * Returns 0 on success. 57 */ 58 int readentropy(void *out, size_t outsize) 59 { 60 static FILE *frandom; 61 static const char rndfile[] = "/dev/urandom"; 62 63 if (!outsize) return 0; 64 65 if (frandom == NULL) { 66 frandom = fopen(rndfile, "rb"); 67 if (frandom == NULL) { 68 iperf_errexit(NULL, "error - failed to open %s: %s\n", 69 rndfile, strerror(errno)); 70 } 71 setbuf(frandom, NULL); 72 } 73 if (fread(out, 1, outsize, frandom) != outsize) { 74 iperf_errexit(NULL, "error - failed to read %s: %s\n", 75 rndfile, 76 feof(frandom) ? "EOF" : strerror(errno)); 77 } 78 return 0; 79 } 80 81 82 /* 83 * Fills buffer with repeating pattern (similar to pattern that used in iperf2) 84 */ 85 void fill_with_repeating_pattern(void *out, size_t outsize) 86 { 87 size_t i; 88 int counter = 0; 89 char *buf = (char *)out; 90 91 if (!outsize) return; 92 93 for (i = 0; i < outsize; i++) { 94 buf[i] = (char)('0' + counter); 95 if (counter >= 9) 96 counter = 0; 97 else 98 counter++; 99 } 100 } 101 102 103 /* make_cookie 104 * 105 * Generate and return a cookie string 106 * 107 * Iperf uses this function to create test "cookies" which 108 * server as unique test identifiers. These cookies are also 109 * used for the authentication of stream connections. 110 * Assumes cookie has size (COOKIE_SIZE + 1) char's. 111 */ 112 113 void 114 make_cookie(const char *cookie) 115 { 116 unsigned char *out = (unsigned char*)cookie; 117 size_t pos; 118 static const unsigned char rndchars[] = "abcdefghijklmnopqrstuvwxyz234567"; 119 120 readentropy(out, COOKIE_SIZE); 121 for (pos = 0; pos < (COOKIE_SIZE - 1); pos++) { 122 out[pos] = rndchars[out[pos] % (sizeof(rndchars) - 1)]; 123 } 124 out[pos] = '\0'; 125 } 126 127 128 /* is_closed 129 * 130 * Test if the file descriptor fd is closed. 131 * 132 * Iperf uses this function to test whether a TCP stream socket 133 * is closed, because accepting and denying an invalid connection 134 * in iperf_tcp_accept is not considered an error. 135 */ 136 137 int 138 is_closed(int fd) 139 { 140 struct timeval tv; 141 fd_set readset; 142 143 FD_ZERO(&readset); 144 FD_SET(fd, &readset); 145 tv.tv_sec = 0; 146 tv.tv_usec = 0; 147 148 if (select(fd+1, &readset, NULL, NULL, &tv) < 0) { 149 if (errno == EBADF) 150 return 1; 151 } 152 return 0; 153 } 154 155 156 double 157 timeval_to_double(struct timeval * tv) 158 { 159 double d; 160 161 d = tv->tv_sec + tv->tv_usec / 1000000; 162 163 return d; 164 } 165 166 int 167 timeval_equals(struct timeval * tv0, struct timeval * tv1) 168 { 169 if ( tv0->tv_sec == tv1->tv_sec && tv0->tv_usec == tv1->tv_usec ) 170 return 1; 171 else 172 return 0; 173 } 174 175 double 176 timeval_diff(struct timeval * tv0, struct timeval * tv1) 177 { 178 double time1, time2; 179 180 time1 = tv0->tv_sec + (tv0->tv_usec / 1000000.0); 181 time2 = tv1->tv_sec + (tv1->tv_usec / 1000000.0); 182 183 time1 = time1 - time2; 184 if (time1 < 0) 185 time1 = -time1; 186 return time1; 187 } 188 189 void 190 cpu_util(double pcpu[3]) 191 { 192 static struct iperf_time last; 193 static clock_t clast; 194 static struct rusage rlast; 195 struct iperf_time now, temp_time; 196 clock_t ctemp; 197 struct rusage rtemp; 198 double timediff; 199 double userdiff; 200 double systemdiff; 201 202 if (pcpu == NULL) { 203 iperf_time_now(&last); 204 clast = clock(); 205 getrusage(RUSAGE_SELF, &rlast); 206 return; 207 } 208 209 iperf_time_now(&now); 210 ctemp = clock(); 211 getrusage(RUSAGE_SELF, &rtemp); 212 213 iperf_time_diff(&now, &last, &temp_time); 214 timediff = iperf_time_in_usecs(&temp_time); 215 216 userdiff = ((rtemp.ru_utime.tv_sec * 1000000.0 + rtemp.ru_utime.tv_usec) - 217 (rlast.ru_utime.tv_sec * 1000000.0 + rlast.ru_utime.tv_usec)); 218 systemdiff = ((rtemp.ru_stime.tv_sec * 1000000.0 + rtemp.ru_stime.tv_usec) - 219 (rlast.ru_stime.tv_sec * 1000000.0 + rlast.ru_stime.tv_usec)); 220 221 pcpu[0] = (((ctemp - clast) * 1000000.0 / CLOCKS_PER_SEC) / timediff) * 100; 222 pcpu[1] = (userdiff / timediff) * 100; 223 pcpu[2] = (systemdiff / timediff) * 100; 224 } 225 226 const char * 227 get_system_info(void) 228 { 229 static char buf[1024]; 230 struct utsname uts; 231 232 memset(buf, 0, 1024); 233 uname(&uts); 234 235 snprintf(buf, sizeof(buf), "%s %s %s %s %s", uts.sysname, uts.nodename, 236 uts.release, uts.version, uts.machine); 237 238 return buf; 239 } 240 241 242 const char * 243 get_optional_features(void) 244 { 245 static char features[1024]; 246 unsigned int numfeatures = 0; 247 248 snprintf(features, sizeof(features), "Optional features available: "); 249 250 #if defined(HAVE_CPU_AFFINITY) 251 if (numfeatures > 0) { 252 strncat(features, ", ", 253 sizeof(features) - strlen(features) - 1); 254 } 255 strncat(features, "CPU affinity setting", 256 sizeof(features) - strlen(features) - 1); 257 numfeatures++; 258 #endif /* HAVE_CPU_AFFINITY */ 259 260 #if defined(HAVE_FLOWLABEL) 261 if (numfeatures > 0) { 262 strncat(features, ", ", 263 sizeof(features) - strlen(features) - 1); 264 } 265 strncat(features, "IPv6 flow label", 266 sizeof(features) - strlen(features) - 1); 267 numfeatures++; 268 #endif /* HAVE_FLOWLABEL */ 269 270 #if defined(HAVE_SCTP_H) 271 if (numfeatures > 0) { 272 strncat(features, ", ", 273 sizeof(features) - strlen(features) - 1); 274 } 275 strncat(features, "SCTP", 276 sizeof(features) - strlen(features) - 1); 277 numfeatures++; 278 #endif /* HAVE_SCTP_H */ 279 280 #if defined(HAVE_TCP_CONGESTION) 281 if (numfeatures > 0) { 282 strncat(features, ", ", 283 sizeof(features) - strlen(features) - 1); 284 } 285 strncat(features, "TCP congestion algorithm setting", 286 sizeof(features) - strlen(features) - 1); 287 numfeatures++; 288 #endif /* HAVE_TCP_CONGESTION */ 289 290 #if defined(HAVE_SENDFILE) 291 if (numfeatures > 0) { 292 strncat(features, ", ", 293 sizeof(features) - strlen(features) - 1); 294 } 295 strncat(features, "sendfile / zerocopy", 296 sizeof(features) - strlen(features) - 1); 297 numfeatures++; 298 #endif /* HAVE_SENDFILE */ 299 300 #if defined(HAVE_SO_MAX_PACING_RATE) 301 if (numfeatures > 0) { 302 strncat(features, ", ", 303 sizeof(features) - strlen(features) - 1); 304 } 305 strncat(features, "socket pacing", 306 sizeof(features) - strlen(features) - 1); 307 numfeatures++; 308 #endif /* HAVE_SO_MAX_PACING_RATE */ 309 310 #if defined(HAVE_SSL) 311 if (numfeatures > 0) { 312 strncat(features, ", ", 313 sizeof(features) - strlen(features) - 1); 314 } 315 strncat(features, "authentication", 316 sizeof(features) - strlen(features) - 1); 317 numfeatures++; 318 #endif /* HAVE_SSL */ 319 320 #if defined(HAVE_SO_BINDTODEVICE) 321 if (numfeatures > 0) { 322 strncat(features, ", ", 323 sizeof(features) - strlen(features) - 1); 324 } 325 strncat(features, "bind to device", 326 sizeof(features) - strlen(features) - 1); 327 numfeatures++; 328 #endif /* HAVE_SO_BINDTODEVICE */ 329 330 if (numfeatures == 0) { 331 strncat(features, "None", 332 sizeof(features) - strlen(features) - 1); 333 } 334 335 return features; 336 } 337 338 /* Helper routine for building cJSON objects in a printf-like manner. 339 ** 340 ** Sample call: 341 ** j = iperf_json_printf("foo: %b bar: %d bletch: %f eep: %s", b, i, f, s); 342 ** 343 ** The four formatting characters and the types they expect are: 344 ** %b boolean int 345 ** %d integer int64_t 346 ** %f floating point double 347 ** %s string char * 348 ** If the values you're passing in are not these exact types, you must 349 ** cast them, there is no automatic type coercion/widening here. 350 ** 351 ** The colons mark the end of field names, and blanks are ignored. 352 ** 353 ** This routine is not particularly robust, but it's not part of the API, 354 ** it's just for internal iperf3 use. 355 */ 356 cJSON* 357 iperf_json_printf(const char *format, ...) 358 { 359 cJSON* o; 360 va_list argp; 361 const char *cp; 362 char name[100]; 363 char* np; 364 cJSON* j; 365 366 o = cJSON_CreateObject(); 367 if (o == NULL) 368 return NULL; 369 va_start(argp, format); 370 np = name; 371 for (cp = format; *cp != '\0'; ++cp) { 372 switch (*cp) { 373 case ' ': 374 break; 375 case ':': 376 *np = '\0'; 377 break; 378 case '%': 379 ++cp; 380 switch (*cp) { 381 case 'b': 382 j = cJSON_CreateBool(va_arg(argp, int)); 383 break; 384 case 'd': 385 j = cJSON_CreateNumber(va_arg(argp, int64_t)); 386 break; 387 case 'f': 388 j = cJSON_CreateNumber(va_arg(argp, double)); 389 break; 390 case 's': 391 j = cJSON_CreateString(va_arg(argp, char *)); 392 break; 393 default: 394 va_end(argp); 395 return NULL; 396 } 397 if (j == NULL) { 398 va_end(argp); 399 return NULL; 400 } 401 cJSON_AddItemToObject(o, name, j); 402 np = name; 403 break; 404 default: 405 *np++ = *cp; 406 break; 407 } 408 } 409 va_end(argp); 410 return o; 411 } 412 413 /* Debugging routine to dump out an fd_set. */ 414 void 415 iperf_dump_fdset(FILE *fp, const char *str, int nfds, fd_set *fds) 416 { 417 int fd; 418 int comma; 419 420 fprintf(fp, "%s: [", str); 421 comma = 0; 422 for (fd = 0; fd < nfds; ++fd) { 423 if (FD_ISSET(fd, fds)) { 424 if (comma) 425 fprintf(fp, ", "); 426 fprintf(fp, "%d", fd); 427 comma = 1; 428 } 429 } 430 fprintf(fp, "]\n"); 431 } 432 433 /* 434 * daemon(3) implementation for systems lacking one. 435 * Cobbled together from various daemon(3) implementations, 436 * not intended to be general-purpose. */ 437 #ifndef HAVE_DAEMON 438 int daemon(int nochdir, int noclose) 439 { 440 pid_t pid = 0; 441 pid_t sid = 0; 442 int fd; 443 444 /* 445 * Ignore any possible SIGHUP when the parent process exits. 446 * Note that the iperf3 server process will eventually install 447 * its own signal handler for SIGHUP, so we can be a little 448 * sloppy about not restoring the prior value. This does not 449 * generalize. 450 */ 451 signal(SIGHUP, SIG_IGN); 452 453 pid = fork(); 454 if (pid < 0) { 455 return -1; 456 } 457 if (pid > 0) { 458 /* Use _exit() to avoid doing atexit() stuff. */ 459 _exit(0); 460 } 461 462 sid = setsid(); 463 if (sid < 0) { 464 return -1; 465 } 466 467 /* 468 * Fork again to avoid becoming a session leader. 469 * This might only matter on old SVr4-derived OSs. 470 * Note in particular that glibc and FreeBSD libc 471 * only fork once. 472 */ 473 pid = fork(); 474 if (pid == -1) { 475 return -1; 476 } else if (pid != 0) { 477 _exit(0); 478 } 479 480 if (!nochdir) { 481 chdir("/"); 482 } 483 484 if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { 485 dup2(fd, STDIN_FILENO); 486 dup2(fd, STDOUT_FILENO); 487 dup2(fd, STDERR_FILENO); 488 if (fd > 2) { 489 close(fd); 490 } 491 } 492 return (0); 493 } 494 #endif /* HAVE_DAEMON */ 495 496 /* Compatibility version of getline(3) for systems that don't have it.. */ 497 #ifndef HAVE_GETLINE 498 /* The following code adopted from NetBSD's getline.c, which is: */ 499 500 /*- 501 * Copyright (c) 2011 The NetBSD Foundation, Inc. 502 * All rights reserved. 503 * 504 * This code is derived from software contributed to The NetBSD Foundation 505 * by Christos Zoulas. 506 * 507 * Redistribution and use in source and binary forms, with or without 508 * modification, are permitted provided that the following conditions 509 * are met: 510 * 1. Redistributions of source code must retain the above copyright 511 * notice, this list of conditions and the following disclaimer. 512 * 2. Redistributions in binary form must reproduce the above copyright 513 * notice, this list of conditions and the following disclaimer in the 514 * documentation and/or other materials provided with the distribution. 515 * 516 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 517 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 518 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 519 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 520 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 521 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 522 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 523 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 524 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 525 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 526 * POSSIBILITY OF SUCH DAMAGE. 527 */ 528 ssize_t 529 getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) 530 { 531 char *ptr, *eptr; 532 533 534 if (*buf == NULL || *bufsiz == 0) { 535 *bufsiz = BUFSIZ; 536 if ((*buf = malloc(*bufsiz)) == NULL) 537 return -1; 538 } 539 540 for (ptr = *buf, eptr = *buf + *bufsiz;;) { 541 int c = fgetc(fp); 542 if (c == -1) { 543 if (feof(fp)) { 544 ssize_t diff = (ssize_t)(ptr - *buf); 545 if (diff != 0) { 546 *ptr = '\0'; 547 return diff; 548 } 549 } 550 return -1; 551 } 552 *ptr++ = c; 553 if (c == delimiter) { 554 *ptr = '\0'; 555 return ptr - *buf; 556 } 557 if (ptr + 2 >= eptr) { 558 char *nbuf; 559 size_t nbufsiz = *bufsiz * 2; 560 ssize_t d = ptr - *buf; 561 if ((nbuf = realloc(*buf, nbufsiz)) == NULL) 562 return -1; 563 *buf = nbuf; 564 *bufsiz = nbufsiz; 565 eptr = nbuf + nbufsiz; 566 ptr = nbuf + d; 567 } 568 } 569 } 570 571 ssize_t 572 getline(char **buf, size_t *bufsiz, FILE *fp) 573 { 574 return getdelim(buf, bufsiz, '\n', fp); 575 } 576 577 #endif 578