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 /* make_cookie 83 * 84 * Generate and return a cookie string 85 * 86 * Iperf uses this function to create test "cookies" which 87 * server as unique test identifiers. These cookies are also 88 * used for the authentication of stream connections. 89 * Assumes cookie has size (COOKIE_SIZE + 1) char's. 90 */ 91 92 void 93 make_cookie(char *cookie) 94 { 95 unsigned char *out = (unsigned char*)cookie; 96 size_t pos; 97 static const unsigned char rndchars[] = "abcdefghijklmnopqrstuvwxyz234567"; 98 99 readentropy(out, COOKIE_SIZE); 100 for (pos = 0; pos < (COOKIE_SIZE - 1); pos++) { 101 out[pos] = rndchars[out[pos] % (sizeof(rndchars) - 1)]; 102 } 103 out[pos] = '\0'; 104 } 105 106 107 /* is_closed 108 * 109 * Test if the file descriptor fd is closed. 110 * 111 * Iperf uses this function to test whether a TCP stream socket 112 * is closed, because accepting and denying an invalid connection 113 * in iperf_tcp_accept is not considered an error. 114 */ 115 116 int 117 is_closed(int fd) 118 { 119 struct timeval tv; 120 fd_set readset; 121 122 FD_ZERO(&readset); 123 FD_SET(fd, &readset); 124 tv.tv_sec = 0; 125 tv.tv_usec = 0; 126 127 if (select(fd+1, &readset, NULL, NULL, &tv) < 0) { 128 if (errno == EBADF) 129 return 1; 130 } 131 return 0; 132 } 133 134 135 double 136 timeval_to_double(struct timeval * tv) 137 { 138 double d; 139 140 d = tv->tv_sec + tv->tv_usec / 1000000; 141 142 return d; 143 } 144 145 int 146 timeval_equals(struct timeval * tv0, struct timeval * tv1) 147 { 148 if ( tv0->tv_sec == tv1->tv_sec && tv0->tv_usec == tv1->tv_usec ) 149 return 1; 150 else 151 return 0; 152 } 153 154 double 155 timeval_diff(struct timeval * tv0, struct timeval * tv1) 156 { 157 double time1, time2; 158 159 time1 = tv0->tv_sec + (tv0->tv_usec / 1000000.0); 160 time2 = tv1->tv_sec + (tv1->tv_usec / 1000000.0); 161 162 time1 = time1 - time2; 163 if (time1 < 0) 164 time1 = -time1; 165 return time1; 166 } 167 168 void 169 cpu_util(double pcpu[3]) 170 { 171 static struct timeval last; 172 static clock_t clast; 173 static struct rusage rlast; 174 struct timeval temp; 175 clock_t ctemp; 176 struct rusage rtemp; 177 double timediff; 178 double userdiff; 179 double systemdiff; 180 181 if (pcpu == NULL) { 182 gettimeofday(&last, NULL); 183 clast = clock(); 184 getrusage(RUSAGE_SELF, &rlast); 185 return; 186 } 187 188 gettimeofday(&temp, NULL); 189 ctemp = clock(); 190 getrusage(RUSAGE_SELF, &rtemp); 191 192 timediff = ((temp.tv_sec * 1000000.0 + temp.tv_usec) - 193 (last.tv_sec * 1000000.0 + last.tv_usec)); 194 userdiff = ((rtemp.ru_utime.tv_sec * 1000000.0 + rtemp.ru_utime.tv_usec) - 195 (rlast.ru_utime.tv_sec * 1000000.0 + rlast.ru_utime.tv_usec)); 196 systemdiff = ((rtemp.ru_stime.tv_sec * 1000000.0 + rtemp.ru_stime.tv_usec) - 197 (rlast.ru_stime.tv_sec * 1000000.0 + rlast.ru_stime.tv_usec)); 198 199 pcpu[0] = (((ctemp - clast) * 1000000.0 / CLOCKS_PER_SEC) / timediff) * 100; 200 pcpu[1] = (userdiff / timediff) * 100; 201 pcpu[2] = (systemdiff / timediff) * 100; 202 } 203 204 const char * 205 get_system_info(void) 206 { 207 static char buf[1024]; 208 struct utsname uts; 209 210 memset(buf, 0, 1024); 211 uname(&uts); 212 213 snprintf(buf, sizeof(buf), "%s %s %s %s %s", uts.sysname, uts.nodename, 214 uts.release, uts.version, uts.machine); 215 216 return buf; 217 } 218 219 220 const char * 221 get_optional_features(void) 222 { 223 static char features[1024]; 224 unsigned int numfeatures = 0; 225 226 snprintf(features, sizeof(features), "Optional features available: "); 227 228 #if defined(HAVE_CPU_AFFINITY) 229 if (numfeatures > 0) { 230 strncat(features, ", ", 231 sizeof(features) - strlen(features) - 1); 232 } 233 strncat(features, "CPU affinity setting", 234 sizeof(features) - strlen(features) - 1); 235 numfeatures++; 236 #endif /* HAVE_CPU_AFFINITY */ 237 238 #if defined(HAVE_FLOWLABEL) 239 if (numfeatures > 0) { 240 strncat(features, ", ", 241 sizeof(features) - strlen(features) - 1); 242 } 243 strncat(features, "IPv6 flow label", 244 sizeof(features) - strlen(features) - 1); 245 numfeatures++; 246 #endif /* HAVE_FLOWLABEL */ 247 248 #if defined(HAVE_SCTP) 249 if (numfeatures > 0) { 250 strncat(features, ", ", 251 sizeof(features) - strlen(features) - 1); 252 } 253 strncat(features, "SCTP", 254 sizeof(features) - strlen(features) - 1); 255 numfeatures++; 256 #endif /* HAVE_SCTP */ 257 258 #if defined(HAVE_TCP_CONGESTION) 259 if (numfeatures > 0) { 260 strncat(features, ", ", 261 sizeof(features) - strlen(features) - 1); 262 } 263 strncat(features, "TCP congestion algorithm setting", 264 sizeof(features) - strlen(features) - 1); 265 numfeatures++; 266 #endif /* HAVE_TCP_CONGESTION */ 267 268 #if defined(HAVE_SENDFILE) 269 if (numfeatures > 0) { 270 strncat(features, ", ", 271 sizeof(features) - strlen(features) - 1); 272 } 273 strncat(features, "sendfile / zerocopy", 274 sizeof(features) - strlen(features) - 1); 275 numfeatures++; 276 #endif /* HAVE_SENDFILE */ 277 278 #if defined(HAVE_SO_MAX_PACING_RATE) 279 if (numfeatures > 0) { 280 strncat(features, ", ", 281 sizeof(features) - strlen(features) - 1); 282 } 283 strncat(features, "socket pacing", 284 sizeof(features) - strlen(features) - 1); 285 numfeatures++; 286 #endif /* HAVE_SO_MAX_PACING_RATE */ 287 288 #if defined(HAVE_SSL) 289 if (numfeatures > 0) { 290 strncat(features, ", ", 291 sizeof(features) - strlen(features) - 1); 292 } 293 strncat(features, "authentication", 294 sizeof(features) - strlen(features) - 1); 295 numfeatures++; 296 #endif /* HAVE_SSL */ 297 298 if (numfeatures == 0) { 299 strncat(features, "None", 300 sizeof(features) - strlen(features) - 1); 301 } 302 303 return features; 304 } 305 306 /* Helper routine for building cJSON objects in a printf-like manner. 307 ** 308 ** Sample call: 309 ** j = iperf_json_printf("foo: %b bar: %d bletch: %f eep: %s", b, i, f, s); 310 ** 311 ** The four formatting characters and the types they expect are: 312 ** %b boolean int 313 ** %d integer int64_t 314 ** %f floating point double 315 ** %s string char * 316 ** If the values you're passing in are not these exact types, you must 317 ** cast them, there is no automatic type coercion/widening here. 318 ** 319 ** The colons mark the end of field names, and blanks are ignored. 320 ** 321 ** This routine is not particularly robust, but it's not part of the API, 322 ** it's just for internal iperf3 use. 323 */ 324 cJSON* 325 iperf_json_printf(const char *format, ...) 326 { 327 cJSON* o; 328 va_list argp; 329 const char *cp; 330 char name[100]; 331 char* np; 332 cJSON* j; 333 334 o = cJSON_CreateObject(); 335 if (o == NULL) 336 return NULL; 337 va_start(argp, format); 338 np = name; 339 for (cp = format; *cp != '\0'; ++cp) { 340 switch (*cp) { 341 case ' ': 342 break; 343 case ':': 344 *np = '\0'; 345 break; 346 case '%': 347 ++cp; 348 switch (*cp) { 349 case 'b': 350 j = cJSON_CreateBool(va_arg(argp, int)); 351 break; 352 case 'd': 353 j = cJSON_CreateNumber(va_arg(argp, int64_t)); 354 break; 355 case 'f': 356 j = cJSON_CreateNumber(va_arg(argp, double)); 357 break; 358 case 's': 359 j = cJSON_CreateString(va_arg(argp, char *)); 360 break; 361 default: 362 va_end(argp); 363 return NULL; 364 } 365 if (j == NULL) { 366 va_end(argp); 367 return NULL; 368 } 369 cJSON_AddItemToObject(o, name, j); 370 np = name; 371 break; 372 default: 373 *np++ = *cp; 374 break; 375 } 376 } 377 va_end(argp); 378 return o; 379 } 380 381 /* Debugging routine to dump out an fd_set. */ 382 void 383 iperf_dump_fdset(FILE *fp, char *str, int nfds, fd_set *fds) 384 { 385 int fd; 386 int comma; 387 388 fprintf(fp, "%s: [", str); 389 comma = 0; 390 for (fd = 0; fd < nfds; ++fd) { 391 if (FD_ISSET(fd, fds)) { 392 if (comma) 393 fprintf(fp, ", "); 394 fprintf(fp, "%d", fd); 395 comma = 1; 396 } 397 } 398 fprintf(fp, "]\n"); 399 } 400 401 /* 402 * daemon(3) implementation for systems lacking one. 403 * Cobbled together from various daemon(3) implementations, 404 * not intended to be general-purpose. */ 405 #ifndef HAVE_DAEMON 406 int daemon(int nochdir, int noclose) 407 { 408 pid_t pid = 0; 409 pid_t sid = 0; 410 int fd; 411 412 /* 413 * Ignore any possible SIGHUP when the parent process exits. 414 * Note that the iperf3 server process will eventually install 415 * its own signal handler for SIGHUP, so we can be a little 416 * sloppy about not restoring the prior value. This does not 417 * generalize. 418 */ 419 signal(SIGHUP, SIG_IGN); 420 421 pid = fork(); 422 if (pid < 0) { 423 return -1; 424 } 425 if (pid > 0) { 426 /* Use _exit() to avoid doing atexit() stuff. */ 427 _exit(0); 428 } 429 430 sid = setsid(); 431 if (sid < 0) { 432 return -1; 433 } 434 435 /* 436 * Fork again to avoid becoming a session leader. 437 * This might only matter on old SVr4-derived OSs. 438 * Note in particular that glibc and FreeBSD libc 439 * only fork once. 440 */ 441 pid = fork(); 442 if (pid == -1) { 443 return -1; 444 } else if (pid != 0) { 445 _exit(0); 446 } 447 448 if (!nochdir) { 449 chdir("/"); 450 } 451 452 if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { 453 dup2(fd, STDIN_FILENO); 454 dup2(fd, STDOUT_FILENO); 455 dup2(fd, STDERR_FILENO); 456 if (fd > 2) { 457 close(fd); 458 } 459 } 460 return (0); 461 } 462 #endif /* HAVE_DAEMON */ 463 464 /* Compatibility version of getline(3) for systems that don't have it.. */ 465 #ifndef HAVE_GETLINE 466 /* The following code adopted from NetBSD's getline.c, which is: */ 467 468 /*- 469 * Copyright (c) 2011 The NetBSD Foundation, Inc. 470 * All rights reserved. 471 * 472 * This code is derived from software contributed to The NetBSD Foundation 473 * by Christos Zoulas. 474 * 475 * Redistribution and use in source and binary forms, with or without 476 * modification, are permitted provided that the following conditions 477 * are met: 478 * 1. Redistributions of source code must retain the above copyright 479 * notice, this list of conditions and the following disclaimer. 480 * 2. Redistributions in binary form must reproduce the above copyright 481 * notice, this list of conditions and the following disclaimer in the 482 * documentation and/or other materials provided with the distribution. 483 * 484 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 485 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 486 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 487 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 488 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 489 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 490 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 491 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 492 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 493 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 494 * POSSIBILITY OF SUCH DAMAGE. 495 */ 496 ssize_t 497 getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) 498 { 499 char *ptr, *eptr; 500 501 502 if (*buf == NULL || *bufsiz == 0) { 503 *bufsiz = BUFSIZ; 504 if ((*buf = malloc(*bufsiz)) == NULL) 505 return -1; 506 } 507 508 for (ptr = *buf, eptr = *buf + *bufsiz;;) { 509 int c = fgetc(fp); 510 if (c == -1) { 511 if (feof(fp)) { 512 ssize_t diff = (ssize_t)(ptr - *buf); 513 if (diff != 0) { 514 *ptr = '\0'; 515 return diff; 516 } 517 } 518 return -1; 519 } 520 *ptr++ = c; 521 if (c == delimiter) { 522 *ptr = '\0'; 523 return ptr - *buf; 524 } 525 if (ptr + 2 >= eptr) { 526 char *nbuf; 527 size_t nbufsiz = *bufsiz * 2; 528 ssize_t d = ptr - *buf; 529 if ((nbuf = realloc(*buf, nbufsiz)) == NULL) 530 return -1; 531 *buf = nbuf; 532 *bufsiz = nbufsiz; 533 eptr = nbuf + nbufsiz; 534 ptr = nbuf + d; 535 } 536 } 537 } 538 539 ssize_t 540 getline(char **buf, size_t *bufsiz, FILE *fp) 541 { 542 return getdelim(buf, bufsiz, '\n', fp); 543 } 544 545 #endif 546