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>