Annotation of embedaddon/iperf/src/iperf_util.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * iperf, Copyright (c) 2014, 2016, 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 <stdlib.h>
        !            36: #include <unistd.h>
        !            37: #include <string.h>
        !            38: #include <stdarg.h>
        !            39: #include <sys/select.h>
        !            40: #include <sys/types.h>
        !            41: #include <sys/time.h>
        !            42: #include <sys/resource.h>
        !            43: #include <sys/utsname.h>
        !            44: #include <time.h>
        !            45: #include <errno.h>
        !            46: 
        !            47: #include "cjson.h"
        !            48: 
        !            49: /* make_cookie
        !            50:  *
        !            51:  * Generate and return a cookie string
        !            52:  *
        !            53:  * Iperf uses this function to create test "cookies" which
        !            54:  * server as unique test identifiers. These cookies are also
        !            55:  * used for the authentication of stream connections.
        !            56:  */
        !            57: 
        !            58: void
        !            59: make_cookie(char *cookie)
        !            60: {
        !            61:     static int randomized = 0;
        !            62:     char hostname[500];
        !            63:     struct timeval tv;
        !            64:     char temp[1000];
        !            65: 
        !            66:     if ( ! randomized )
        !            67:         srandom((int) time(0) ^ getpid());
        !            68: 
        !            69:     /* Generate a string based on hostname, time, randomness, and filler. */
        !            70:     (void) gethostname(hostname, sizeof(hostname));
        !            71:     (void) gettimeofday(&tv, 0);
        !            72:     (void) snprintf(temp, sizeof(temp), "%s.%ld.%06ld.%08lx%08lx.%s", hostname, (unsigned long int) tv.tv_sec, (unsigned long int) tv.tv_usec, (unsigned long int) random(), (unsigned long int) random(), "1234567890123456789012345678901234567890");
        !            73: 
        !            74:     /* Now truncate it to 36 bytes and terminate. */
        !            75:     memcpy(cookie, temp, 36);
        !            76:     cookie[36] = '\0';
        !            77: }
        !            78: 
        !            79: 
        !            80: /* is_closed
        !            81:  *
        !            82:  * Test if the file descriptor fd is closed.
        !            83:  * 
        !            84:  * Iperf uses this function to test whether a TCP stream socket
        !            85:  * is closed, because accepting and denying an invalid connection
        !            86:  * in iperf_tcp_accept is not considered an error.
        !            87:  */
        !            88: 
        !            89: int
        !            90: is_closed(int fd)
        !            91: {
        !            92:     struct timeval tv;
        !            93:     fd_set readset;
        !            94: 
        !            95:     FD_ZERO(&readset);
        !            96:     FD_SET(fd, &readset);
        !            97:     tv.tv_sec = 0;
        !            98:     tv.tv_usec = 0;
        !            99: 
        !           100:     if (select(fd+1, &readset, NULL, NULL, &tv) < 0) {
        !           101:         if (errno == EBADF)
        !           102:             return 1;
        !           103:     }
        !           104:     return 0;
        !           105: }
        !           106: 
        !           107: 
        !           108: double
        !           109: timeval_to_double(struct timeval * tv)
        !           110: {
        !           111:     double d;
        !           112: 
        !           113:     d = tv->tv_sec + tv->tv_usec / 1000000;
        !           114: 
        !           115:     return d;
        !           116: }
        !           117: 
        !           118: int
        !           119: timeval_equals(struct timeval * tv0, struct timeval * tv1)
        !           120: {
        !           121:     if ( tv0->tv_sec == tv1->tv_sec && tv0->tv_usec == tv1->tv_usec )
        !           122:        return 1;
        !           123:     else
        !           124:        return 0;
        !           125: }
        !           126: 
        !           127: double
        !           128: timeval_diff(struct timeval * tv0, struct timeval * tv1)
        !           129: {
        !           130:     double time1, time2;
        !           131:     
        !           132:     time1 = tv0->tv_sec + (tv0->tv_usec / 1000000.0);
        !           133:     time2 = tv1->tv_sec + (tv1->tv_usec / 1000000.0);
        !           134: 
        !           135:     time1 = time1 - time2;
        !           136:     if (time1 < 0)
        !           137:         time1 = -time1;
        !           138:     return time1;
        !           139: }
        !           140: 
        !           141: 
        !           142: int
        !           143: delay(int64_t ns)
        !           144: {
        !           145:     struct timespec req, rem;
        !           146: 
        !           147:     req.tv_sec = 0;
        !           148: 
        !           149:     while (ns >= 1000000000L) {
        !           150:         ns -= 1000000000L;
        !           151:         req.tv_sec += 1;
        !           152:     }
        !           153: 
        !           154:     req.tv_nsec = ns;
        !           155: 
        !           156:     while (nanosleep(&req, &rem) == -1)
        !           157:         if (EINTR == errno)
        !           158:             memcpy(&req, &rem, sizeof(rem));
        !           159:         else
        !           160:             return -1;
        !           161:     return 0;
        !           162: }
        !           163: 
        !           164: # ifdef DELAY_SELECT_METHOD
        !           165: int
        !           166: delay(int us)
        !           167: {
        !           168:     struct timeval tv;
        !           169: 
        !           170:     tv.tv_sec = 0;
        !           171:     tv.tv_usec = us;
        !           172:     (void) select(1, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv);
        !           173:     return 1;
        !           174: }
        !           175: #endif
        !           176: 
        !           177: 
        !           178: void
        !           179: cpu_util(double pcpu[3])
        !           180: {
        !           181:     static struct timeval last;
        !           182:     static clock_t clast;
        !           183:     static struct rusage rlast;
        !           184:     struct timeval temp;
        !           185:     clock_t ctemp;
        !           186:     struct rusage rtemp;
        !           187:     double timediff;
        !           188:     double userdiff;
        !           189:     double systemdiff;
        !           190: 
        !           191:     if (pcpu == NULL) {
        !           192:         gettimeofday(&last, NULL);
        !           193:         clast = clock();
        !           194:        getrusage(RUSAGE_SELF, &rlast);
        !           195:         return;
        !           196:     }
        !           197: 
        !           198:     gettimeofday(&temp, NULL);
        !           199:     ctemp = clock();
        !           200:     getrusage(RUSAGE_SELF, &rtemp);
        !           201: 
        !           202:     timediff = ((temp.tv_sec * 1000000.0 + temp.tv_usec) -
        !           203:                 (last.tv_sec * 1000000.0 + last.tv_usec));
        !           204:     userdiff = ((rtemp.ru_utime.tv_sec * 1000000.0 + rtemp.ru_utime.tv_usec) -
        !           205:                 (rlast.ru_utime.tv_sec * 1000000.0 + rlast.ru_utime.tv_usec));
        !           206:     systemdiff = ((rtemp.ru_stime.tv_sec * 1000000.0 + rtemp.ru_stime.tv_usec) -
        !           207:                   (rlast.ru_stime.tv_sec * 1000000.0 + rlast.ru_stime.tv_usec));
        !           208: 
        !           209:     pcpu[0] = (((ctemp - clast) * 1000000.0 / CLOCKS_PER_SEC) / timediff) * 100;
        !           210:     pcpu[1] = (userdiff / timediff) * 100;
        !           211:     pcpu[2] = (systemdiff / timediff) * 100;
        !           212: }
        !           213: 
        !           214: const char *
        !           215: get_system_info(void)
        !           216: {
        !           217:     static char buf[1024];
        !           218:     struct utsname  uts;
        !           219: 
        !           220:     memset(buf, 0, 1024);
        !           221:     uname(&uts);
        !           222: 
        !           223:     snprintf(buf, sizeof(buf), "%s %s %s %s %s", uts.sysname, uts.nodename, 
        !           224:             uts.release, uts.version, uts.machine);
        !           225: 
        !           226:     return buf;
        !           227: }
        !           228: 
        !           229: 
        !           230: const char *
        !           231: get_optional_features(void)
        !           232: {
        !           233:     static char features[1024];
        !           234:     unsigned int numfeatures = 0;
        !           235: 
        !           236:     snprintf(features, sizeof(features), "Optional features available: ");
        !           237: 
        !           238: #if defined(HAVE_CPU_AFFINITY)
        !           239:     if (numfeatures > 0) {
        !           240:        strncat(features, ", ", 
        !           241:                sizeof(features) - strlen(features) - 1);
        !           242:     }
        !           243:     strncat(features, "CPU affinity setting", 
        !           244:        sizeof(features) - strlen(features) - 1);
        !           245:     numfeatures++;
        !           246: #endif /* HAVE_CPU_AFFINITY */
        !           247:     
        !           248: #if defined(HAVE_FLOWLABEL)
        !           249:     if (numfeatures > 0) {
        !           250:        strncat(features, ", ", 
        !           251:                sizeof(features) - strlen(features) - 1);
        !           252:     }
        !           253:     strncat(features, "IPv6 flow label", 
        !           254:        sizeof(features) - strlen(features) - 1);
        !           255:     numfeatures++;
        !           256: #endif /* HAVE_FLOWLABEL */
        !           257:     
        !           258: #if defined(HAVE_SCTP)
        !           259:     if (numfeatures > 0) {
        !           260:        strncat(features, ", ", 
        !           261:                sizeof(features) - strlen(features) - 1);
        !           262:     }
        !           263:     strncat(features, "SCTP", 
        !           264:        sizeof(features) - strlen(features) - 1);
        !           265:     numfeatures++;
        !           266: #endif /* HAVE_SCTP */
        !           267:     
        !           268: #if defined(HAVE_TCP_CONGESTION)
        !           269:     if (numfeatures > 0) {
        !           270:        strncat(features, ", ", 
        !           271:                sizeof(features) - strlen(features) - 1);
        !           272:     }
        !           273:     strncat(features, "TCP congestion algorithm setting", 
        !           274:        sizeof(features) - strlen(features) - 1);
        !           275:     numfeatures++;
        !           276: #endif /* HAVE_TCP_CONGESTION */
        !           277:     
        !           278: #if defined(HAVE_SENDFILE)
        !           279:     if (numfeatures > 0) {
        !           280:        strncat(features, ", ",
        !           281:                sizeof(features) - strlen(features) - 1);
        !           282:     }
        !           283:     strncat(features, "sendfile / zerocopy",
        !           284:        sizeof(features) - strlen(features) - 1);
        !           285:     numfeatures++;
        !           286: #endif /* HAVE_SENDFILE */
        !           287: 
        !           288: #if defined(HAVE_SO_MAX_PACING_RATE)
        !           289:     if (numfeatures > 0) {
        !           290:        strncat(features, ", ",
        !           291:                sizeof(features) - strlen(features) - 1);
        !           292:     }
        !           293:     strncat(features, "socket pacing",
        !           294:        sizeof(features) - strlen(features) - 1);
        !           295:     numfeatures++;
        !           296: #endif /* HAVE_SO_MAX_PACING_RATE */
        !           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: }

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