Annotation of embedaddon/iperf/src/iperf_util.c, revision 1.1.1.3
1.1 misho 1: /*
1.1.1.2 misho 2: * iperf, Copyright (c) 2014, 2016, 2017, The Regents of the University of
1.1 misho 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>
1.1.1.2 misho 35: #include <signal.h>
1.1 misho 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>
1.1.1.2 misho 47: #include <fcntl.h>
1.1 misho 48:
49: #include "cjson.h"
1.1.1.2 misho 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:
1.1 misho 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.
1.1.1.2 misho 110: * Assumes cookie has size (COOKIE_SIZE + 1) char's.
1.1 misho 111: */
112:
113: void
1.1.1.2 misho 114: make_cookie(const char *cookie)
1.1 misho 115: {
1.1.1.2 misho 116: unsigned char *out = (unsigned char*)cookie;
117: size_t pos;
118: static const unsigned char rndchars[] = "abcdefghijklmnopqrstuvwxyz234567";
1.1 misho 119:
1.1.1.2 misho 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';
1.1 misho 125: }
126:
127:
128: /* is_closed
129: *
130: * Test if the file descriptor fd is closed.
1.1.1.3 ! misho 131: *
1.1 misho 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;
1.1.1.3 ! misho 179:
1.1 misho 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: {
1.1.1.2 misho 192: static struct iperf_time last;
1.1 misho 193: static clock_t clast;
194: static struct rusage rlast;
1.1.1.2 misho 195: struct iperf_time now, temp_time;
1.1 misho 196: clock_t ctemp;
197: struct rusage rtemp;
198: double timediff;
199: double userdiff;
200: double systemdiff;
201:
202: if (pcpu == NULL) {
1.1.1.2 misho 203: iperf_time_now(&last);
1.1 misho 204: clast = clock();
205: getrusage(RUSAGE_SELF, &rlast);
206: return;
207: }
208:
1.1.1.2 misho 209: iperf_time_now(&now);
1.1 misho 210: ctemp = clock();
211: getrusage(RUSAGE_SELF, &rtemp);
212:
1.1.1.2 misho 213: iperf_time_diff(&now, &last, &temp_time);
214: timediff = iperf_time_in_usecs(&temp_time);
215:
1.1 misho 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:
1.1.1.3 ! misho 235: snprintf(buf, sizeof(buf), "%s %s %s %s %s", uts.sysname, uts.nodename,
1.1 misho 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) {
1.1.1.3 ! misho 252: strncat(features, ", ",
1.1 misho 253: sizeof(features) - strlen(features) - 1);
254: }
1.1.1.3 ! misho 255: strncat(features, "CPU affinity setting",
1.1 misho 256: sizeof(features) - strlen(features) - 1);
257: numfeatures++;
258: #endif /* HAVE_CPU_AFFINITY */
1.1.1.3 ! misho 259:
1.1 misho 260: #if defined(HAVE_FLOWLABEL)
261: if (numfeatures > 0) {
1.1.1.3 ! misho 262: strncat(features, ", ",
1.1 misho 263: sizeof(features) - strlen(features) - 1);
264: }
1.1.1.3 ! misho 265: strncat(features, "IPv6 flow label",
1.1 misho 266: sizeof(features) - strlen(features) - 1);
267: numfeatures++;
268: #endif /* HAVE_FLOWLABEL */
1.1.1.3 ! misho 269:
1.1.1.2 misho 270: #if defined(HAVE_SCTP_H)
1.1 misho 271: if (numfeatures > 0) {
1.1.1.3 ! misho 272: strncat(features, ", ",
1.1 misho 273: sizeof(features) - strlen(features) - 1);
274: }
1.1.1.3 ! misho 275: strncat(features, "SCTP",
1.1 misho 276: sizeof(features) - strlen(features) - 1);
277: numfeatures++;
1.1.1.2 misho 278: #endif /* HAVE_SCTP_H */
1.1.1.3 ! misho 279:
1.1 misho 280: #if defined(HAVE_TCP_CONGESTION)
281: if (numfeatures > 0) {
1.1.1.3 ! misho 282: strncat(features, ", ",
1.1 misho 283: sizeof(features) - strlen(features) - 1);
284: }
1.1.1.3 ! misho 285: strncat(features, "TCP congestion algorithm setting",
1.1 misho 286: sizeof(features) - strlen(features) - 1);
287: numfeatures++;
288: #endif /* HAVE_TCP_CONGESTION */
1.1.1.3 ! misho 289:
1.1 misho 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:
1.1.1.2 misho 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:
1.1.1.3 ! misho 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:
1.1 misho 340: if (numfeatures == 0) {
1.1.1.3 ! misho 341: strncat(features, "None",
1.1 misho 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
1.1.1.2 misho 425: iperf_dump_fdset(FILE *fp, const char *str, int nfds, fd_set *fds)
1.1 misho 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: }
1.1.1.2 misho 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.
1.1.1.3 ! misho 479: * This might only matter on old SVr4-derived OSs.
! 480: * Note in particular that glibc and FreeBSD libc
1.1.1.2 misho 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>