File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iperf / src / iperf_util.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:36:46 2021 UTC (3 years, 3 months ago) by misho
Branches: iperf, MAIN
CVS tags: v3_3_9, HEAD
iperf 3.3.9

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

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