File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iperf / src / iperf_util.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:14:54 2023 UTC (9 months, 2 weeks ago) by misho
Branches: iperf, MAIN
CVS tags: v3_15, HEAD
Version 3.15

    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 TTD@lbl.gov.
   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 defined(HAVE_DONT_FRAGMENT)
  331:     if (numfeatures > 0) {
  332: 	strncat(features, ", ",
  333: 		sizeof(features) - strlen(features) - 1);
  334:     }
  335:     strncat(features, "support IPv4 don't fragment",
  336: 	sizeof(features) - strlen(features) - 1);
  337:     numfeatures++;
  338: #endif /* HAVE_DONT_FRAGMENT */
  339: 
  340:     if (numfeatures == 0) {
  341: 	strncat(features, "None",
  342: 		sizeof(features) - strlen(features) - 1);
  343:     }
  344: 
  345:     return features;
  346: }
  347: 
  348: /* Helper routine for building cJSON objects in a printf-like manner.
  349: **
  350: ** Sample call:
  351: **   j = iperf_json_printf("foo: %b  bar: %d  bletch: %f  eep: %s", b, i, f, s);
  352: **
  353: ** The four formatting characters and the types they expect are:
  354: **   %b  boolean           int
  355: **   %d  integer           int64_t
  356: **   %f  floating point    double
  357: **   %s  string            char *
  358: ** If the values you're passing in are not these exact types, you must
  359: ** cast them, there is no automatic type coercion/widening here.
  360: **
  361: ** The colons mark the end of field names, and blanks are ignored.
  362: **
  363: ** This routine is not particularly robust, but it's not part of the API,
  364: ** it's just for internal iperf3 use.
  365: */
  366: cJSON*
  367: iperf_json_printf(const char *format, ...)
  368: {
  369:     cJSON* o;
  370:     va_list argp;
  371:     const char *cp;
  372:     char name[100];
  373:     char* np;
  374:     cJSON* j;
  375: 
  376:     o = cJSON_CreateObject();
  377:     if (o == NULL)
  378:         return NULL;
  379:     va_start(argp, format);
  380:     np = name;
  381:     for (cp = format; *cp != '\0'; ++cp) {
  382: 	switch (*cp) {
  383: 	    case ' ':
  384: 	    break;
  385: 	    case ':':
  386: 	    *np = '\0';
  387: 	    break;
  388: 	    case '%':
  389: 	    ++cp;
  390: 	    switch (*cp) {
  391: 		case 'b':
  392: 		j = cJSON_CreateBool(va_arg(argp, int));
  393: 		break;
  394: 		case 'd':
  395: 		j = cJSON_CreateNumber(va_arg(argp, int64_t));
  396: 		break;
  397: 		case 'f':
  398: 		j = cJSON_CreateNumber(va_arg(argp, double));
  399: 		break;
  400: 		case 's':
  401: 		j = cJSON_CreateString(va_arg(argp, char *));
  402: 		break;
  403: 		default:
  404: 		va_end(argp);
  405: 		return NULL;
  406: 	    }
  407: 	    if (j == NULL) {
  408: 	    	va_end(argp);
  409: 	    	return NULL;
  410: 	    }
  411: 	    cJSON_AddItemToObject(o, name, j);
  412: 	    np = name;
  413: 	    break;
  414: 	    default:
  415: 	    *np++ = *cp;
  416: 	    break;
  417: 	}
  418:     }
  419:     va_end(argp);
  420:     return o;
  421: }
  422: 
  423: /* Debugging routine to dump out an fd_set. */
  424: void
  425: iperf_dump_fdset(FILE *fp, const char *str, int nfds, fd_set *fds)
  426: {
  427:     int fd;
  428:     int comma;
  429: 
  430:     fprintf(fp, "%s: [", str);
  431:     comma = 0;
  432:     for (fd = 0; fd < nfds; ++fd) {
  433:         if (FD_ISSET(fd, fds)) {
  434: 	    if (comma)
  435: 		fprintf(fp, ", ");
  436: 	    fprintf(fp, "%d", fd);
  437: 	    comma = 1;
  438: 	}
  439:     }
  440:     fprintf(fp, "]\n");
  441: }
  442: 
  443: /*
  444:  * daemon(3) implementation for systems lacking one.
  445:  * Cobbled together from various daemon(3) implementations,
  446:  * not intended to be general-purpose. */
  447: #ifndef HAVE_DAEMON
  448: int daemon(int nochdir, int noclose)
  449: {
  450:     pid_t pid = 0;
  451:     pid_t sid = 0;
  452:     int fd;
  453: 
  454:     /*
  455:      * Ignore any possible SIGHUP when the parent process exits.
  456:      * Note that the iperf3 server process will eventually install
  457:      * its own signal handler for SIGHUP, so we can be a little
  458:      * sloppy about not restoring the prior value.  This does not
  459:      * generalize.
  460:      */
  461:     signal(SIGHUP, SIG_IGN);
  462: 
  463:     pid = fork();
  464:     if (pid < 0) {
  465: 	    return -1;
  466:     }
  467:     if (pid > 0) {
  468: 	/* Use _exit() to avoid doing atexit() stuff. */
  469: 	_exit(0);
  470:     }
  471: 
  472:     sid = setsid();
  473:     if (sid < 0) {
  474: 	return -1;
  475:     }
  476: 
  477:     /*
  478:      * Fork again to avoid becoming a session leader.
  479:      * This might only matter on old SVr4-derived OSs.
  480:      * Note in particular that glibc and FreeBSD libc
  481:      * only fork once.
  482:      */
  483:     pid = fork();
  484:     if (pid == -1) {
  485: 	return -1;
  486:     } else if (pid != 0) {
  487: 	_exit(0);
  488:     }
  489: 
  490:     if (!nochdir) {
  491: 	chdir("/");
  492:     }
  493: 
  494:     if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
  495: 	dup2(fd, STDIN_FILENO);
  496: 	dup2(fd, STDOUT_FILENO);
  497: 	dup2(fd, STDERR_FILENO);
  498: 	if (fd > 2) {
  499: 	    close(fd);
  500: 	}
  501:     }
  502:     return (0);
  503: }
  504: #endif /* HAVE_DAEMON */
  505: 
  506: /* Compatibility version of getline(3) for systems that don't have it.. */
  507: #ifndef HAVE_GETLINE
  508: /* The following code adopted from NetBSD's getline.c, which is: */
  509: 
  510: /*-
  511:  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  512:  * All rights reserved.
  513:  *
  514:  * This code is derived from software contributed to The NetBSD Foundation
  515:  * by Christos Zoulas.
  516:  *
  517:  * Redistribution and use in source and binary forms, with or without
  518:  * modification, are permitted provided that the following conditions
  519:  * are met:
  520:  * 1. Redistributions of source code must retain the above copyright
  521:  *    notice, this list of conditions and the following disclaimer.
  522:  * 2. Redistributions in binary form must reproduce the above copyright
  523:  *    notice, this list of conditions and the following disclaimer in the
  524:  *    documentation and/or other materials provided with the distribution.
  525:  *
  526:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  527:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  528:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  529:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  530:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  531:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  532:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  533:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  534:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  535:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  536:  * POSSIBILITY OF SUCH DAMAGE.
  537:  */
  538: ssize_t
  539: getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
  540: {
  541: 	char *ptr, *eptr;
  542: 
  543: 
  544: 	if (*buf == NULL || *bufsiz == 0) {
  545: 		*bufsiz = BUFSIZ;
  546: 		if ((*buf = malloc(*bufsiz)) == NULL)
  547: 			return -1;
  548: 	}
  549: 
  550: 	for (ptr = *buf, eptr = *buf + *bufsiz;;) {
  551: 		int c = fgetc(fp);
  552: 		if (c == -1) {
  553: 			if (feof(fp)) {
  554: 				ssize_t diff = (ssize_t)(ptr - *buf);
  555: 				if (diff != 0) {
  556: 					*ptr = '\0';
  557: 					return diff;
  558: 				}
  559: 			}
  560: 			return -1;
  561: 		}
  562: 		*ptr++ = c;
  563: 		if (c == delimiter) {
  564: 			*ptr = '\0';
  565: 			return ptr - *buf;
  566: 		}
  567: 		if (ptr + 2 >= eptr) {
  568: 			char *nbuf;
  569: 			size_t nbufsiz = *bufsiz * 2;
  570: 			ssize_t d = ptr - *buf;
  571: 			if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
  572: 				return -1;
  573: 			*buf = nbuf;
  574: 			*bufsiz = nbufsiz;
  575: 			eptr = nbuf + nbufsiz;
  576: 			ptr = nbuf + d;
  577: 		}
  578: 	}
  579: }
  580: 
  581: ssize_t
  582: getline(char **buf, size_t *bufsiz, FILE *fp)
  583: {
  584: 	return getdelim(buf, bufsiz, '\n', fp);
  585: }
  586: 
  587: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>