Annotation of embedaddon/iperf/src/iperf_util.c, revision 1.1.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>