xref: /iperf/src/iperf_util.c (revision 2c2dfb01)
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 [email protected].
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(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 timeval last;
193     static clock_t clast;
194     static struct rusage rlast;
195     struct timeval temp;
196     clock_t ctemp;
197     struct rusage rtemp;
198     double timediff;
199     double userdiff;
200     double systemdiff;
201 
202     if (pcpu == NULL) {
203         gettimeofday(&last, NULL);
204         clast = clock();
205 	getrusage(RUSAGE_SELF, &rlast);
206         return;
207     }
208 
209     gettimeofday(&temp, NULL);
210     ctemp = clock();
211     getrusage(RUSAGE_SELF, &rtemp);
212 
213     timediff = ((temp.tv_sec * 1000000.0 + temp.tv_usec) -
214                 (last.tv_sec * 1000000.0 + last.tv_usec));
215     userdiff = ((rtemp.ru_utime.tv_sec * 1000000.0 + rtemp.ru_utime.tv_usec) -
216                 (rlast.ru_utime.tv_sec * 1000000.0 + rlast.ru_utime.tv_usec));
217     systemdiff = ((rtemp.ru_stime.tv_sec * 1000000.0 + rtemp.ru_stime.tv_usec) -
218                   (rlast.ru_stime.tv_sec * 1000000.0 + rlast.ru_stime.tv_usec));
219 
220     pcpu[0] = (((ctemp - clast) * 1000000.0 / CLOCKS_PER_SEC) / timediff) * 100;
221     pcpu[1] = (userdiff / timediff) * 100;
222     pcpu[2] = (systemdiff / timediff) * 100;
223 }
224 
225 const char *
226 get_system_info(void)
227 {
228     static char buf[1024];
229     struct utsname  uts;
230 
231     memset(buf, 0, 1024);
232     uname(&uts);
233 
234     snprintf(buf, sizeof(buf), "%s %s %s %s %s", uts.sysname, uts.nodename,
235 	     uts.release, uts.version, uts.machine);
236 
237     return buf;
238 }
239 
240 
241 const char *
242 get_optional_features(void)
243 {
244     static char features[1024];
245     unsigned int numfeatures = 0;
246 
247     snprintf(features, sizeof(features), "Optional features available: ");
248 
249 #if defined(HAVE_CPU_AFFINITY)
250     if (numfeatures > 0) {
251 	strncat(features, ", ",
252 		sizeof(features) - strlen(features) - 1);
253     }
254     strncat(features, "CPU affinity setting",
255 	sizeof(features) - strlen(features) - 1);
256     numfeatures++;
257 #endif /* HAVE_CPU_AFFINITY */
258 
259 #if defined(HAVE_FLOWLABEL)
260     if (numfeatures > 0) {
261 	strncat(features, ", ",
262 		sizeof(features) - strlen(features) - 1);
263     }
264     strncat(features, "IPv6 flow label",
265 	sizeof(features) - strlen(features) - 1);
266     numfeatures++;
267 #endif /* HAVE_FLOWLABEL */
268 
269 #if defined(HAVE_SCTP)
270     if (numfeatures > 0) {
271 	strncat(features, ", ",
272 		sizeof(features) - strlen(features) - 1);
273     }
274     strncat(features, "SCTP",
275 	sizeof(features) - strlen(features) - 1);
276     numfeatures++;
277 #endif /* HAVE_SCTP */
278 
279 #if defined(HAVE_TCP_CONGESTION)
280     if (numfeatures > 0) {
281 	strncat(features, ", ",
282 		sizeof(features) - strlen(features) - 1);
283     }
284     strncat(features, "TCP congestion algorithm setting",
285 	sizeof(features) - strlen(features) - 1);
286     numfeatures++;
287 #endif /* HAVE_TCP_CONGESTION */
288 
289 #if defined(HAVE_SENDFILE)
290     if (numfeatures > 0) {
291 	strncat(features, ", ",
292 		sizeof(features) - strlen(features) - 1);
293     }
294     strncat(features, "sendfile / zerocopy",
295 	sizeof(features) - strlen(features) - 1);
296     numfeatures++;
297 #endif /* HAVE_SENDFILE */
298 
299 #if defined(HAVE_SO_MAX_PACING_RATE)
300     if (numfeatures > 0) {
301 	strncat(features, ", ",
302 		sizeof(features) - strlen(features) - 1);
303     }
304     strncat(features, "socket pacing",
305 	sizeof(features) - strlen(features) - 1);
306     numfeatures++;
307 #endif /* HAVE_SO_MAX_PACING_RATE */
308 
309 #if defined(HAVE_SSL)
310     if (numfeatures > 0) {
311 	strncat(features, ", ",
312 		sizeof(features) - strlen(features) - 1);
313     }
314     strncat(features, "authentication",
315 	sizeof(features) - strlen(features) - 1);
316     numfeatures++;
317 #endif /* HAVE_SSL */
318 
319     if (numfeatures == 0) {
320 	strncat(features, "None",
321 		sizeof(features) - strlen(features) - 1);
322     }
323 
324     return features;
325 }
326 
327 /* Helper routine for building cJSON objects in a printf-like manner.
328 **
329 ** Sample call:
330 **   j = iperf_json_printf("foo: %b  bar: %d  bletch: %f  eep: %s", b, i, f, s);
331 **
332 ** The four formatting characters and the types they expect are:
333 **   %b  boolean           int
334 **   %d  integer           int64_t
335 **   %f  floating point    double
336 **   %s  string            char *
337 ** If the values you're passing in are not these exact types, you must
338 ** cast them, there is no automatic type coercion/widening here.
339 **
340 ** The colons mark the end of field names, and blanks are ignored.
341 **
342 ** This routine is not particularly robust, but it's not part of the API,
343 ** it's just for internal iperf3 use.
344 */
345 cJSON*
346 iperf_json_printf(const char *format, ...)
347 {
348     cJSON* o;
349     va_list argp;
350     const char *cp;
351     char name[100];
352     char* np;
353     cJSON* j;
354 
355     o = cJSON_CreateObject();
356     if (o == NULL)
357         return NULL;
358     va_start(argp, format);
359     np = name;
360     for (cp = format; *cp != '\0'; ++cp) {
361 	switch (*cp) {
362 	    case ' ':
363 	    break;
364 	    case ':':
365 	    *np = '\0';
366 	    break;
367 	    case '%':
368 	    ++cp;
369 	    switch (*cp) {
370 		case 'b':
371 		j = cJSON_CreateBool(va_arg(argp, int));
372 		break;
373 		case 'd':
374 		j = cJSON_CreateNumber(va_arg(argp, int64_t));
375 		break;
376 		case 'f':
377 		j = cJSON_CreateNumber(va_arg(argp, double));
378 		break;
379 		case 's':
380 		j = cJSON_CreateString(va_arg(argp, char *));
381 		break;
382 		default:
383 		va_end(argp);
384 		return NULL;
385 	    }
386 	    if (j == NULL) {
387 	    	va_end(argp);
388 	    	return NULL;
389 	    }
390 	    cJSON_AddItemToObject(o, name, j);
391 	    np = name;
392 	    break;
393 	    default:
394 	    *np++ = *cp;
395 	    break;
396 	}
397     }
398     va_end(argp);
399     return o;
400 }
401 
402 /* Debugging routine to dump out an fd_set. */
403 void
404 iperf_dump_fdset(FILE *fp, char *str, int nfds, fd_set *fds)
405 {
406     int fd;
407     int comma;
408 
409     fprintf(fp, "%s: [", str);
410     comma = 0;
411     for (fd = 0; fd < nfds; ++fd) {
412         if (FD_ISSET(fd, fds)) {
413 	    if (comma)
414 		fprintf(fp, ", ");
415 	    fprintf(fp, "%d", fd);
416 	    comma = 1;
417 	}
418     }
419     fprintf(fp, "]\n");
420 }
421 
422 /*
423  * daemon(3) implementation for systems lacking one.
424  * Cobbled together from various daemon(3) implementations,
425  * not intended to be general-purpose. */
426 #ifndef HAVE_DAEMON
427 int daemon(int nochdir, int noclose)
428 {
429     pid_t pid = 0;
430     pid_t sid = 0;
431     int fd;
432 
433     /*
434      * Ignore any possible SIGHUP when the parent process exits.
435      * Note that the iperf3 server process will eventually install
436      * its own signal handler for SIGHUP, so we can be a little
437      * sloppy about not restoring the prior value.  This does not
438      * generalize.
439      */
440     signal(SIGHUP, SIG_IGN);
441 
442     pid = fork();
443     if (pid < 0) {
444 	    return -1;
445     }
446     if (pid > 0) {
447 	/* Use _exit() to avoid doing atexit() stuff. */
448 	_exit(0);
449     }
450 
451     sid = setsid();
452     if (sid < 0) {
453 	return -1;
454     }
455 
456     /*
457      * Fork again to avoid becoming a session leader.
458      * This might only matter on old SVr4-derived OSs.
459      * Note in particular that glibc and FreeBSD libc
460      * only fork once.
461      */
462     pid = fork();
463     if (pid == -1) {
464 	return -1;
465     } else if (pid != 0) {
466 	_exit(0);
467     }
468 
469     if (!nochdir) {
470 	chdir("/");
471     }
472 
473     if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
474 	dup2(fd, STDIN_FILENO);
475 	dup2(fd, STDOUT_FILENO);
476 	dup2(fd, STDERR_FILENO);
477 	if (fd > 2) {
478 	    close(fd);
479 	}
480     }
481     return (0);
482 }
483 #endif /* HAVE_DAEMON */
484 
485 /* Compatibility version of getline(3) for systems that don't have it.. */
486 #ifndef HAVE_GETLINE
487 /* The following code adopted from NetBSD's getline.c, which is: */
488 
489 /*-
490  * Copyright (c) 2011 The NetBSD Foundation, Inc.
491  * All rights reserved.
492  *
493  * This code is derived from software contributed to The NetBSD Foundation
494  * by Christos Zoulas.
495  *
496  * Redistribution and use in source and binary forms, with or without
497  * modification, are permitted provided that the following conditions
498  * are met:
499  * 1. Redistributions of source code must retain the above copyright
500  *    notice, this list of conditions and the following disclaimer.
501  * 2. Redistributions in binary form must reproduce the above copyright
502  *    notice, this list of conditions and the following disclaimer in the
503  *    documentation and/or other materials provided with the distribution.
504  *
505  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
506  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
507  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
508  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
509  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
510  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
511  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
512  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
513  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
514  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
515  * POSSIBILITY OF SUCH DAMAGE.
516  */
517 ssize_t
518 getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
519 {
520 	char *ptr, *eptr;
521 
522 
523 	if (*buf == NULL || *bufsiz == 0) {
524 		*bufsiz = BUFSIZ;
525 		if ((*buf = malloc(*bufsiz)) == NULL)
526 			return -1;
527 	}
528 
529 	for (ptr = *buf, eptr = *buf + *bufsiz;;) {
530 		int c = fgetc(fp);
531 		if (c == -1) {
532 			if (feof(fp)) {
533 				ssize_t diff = (ssize_t)(ptr - *buf);
534 				if (diff != 0) {
535 					*ptr = '\0';
536 					return diff;
537 				}
538 			}
539 			return -1;
540 		}
541 		*ptr++ = c;
542 		if (c == delimiter) {
543 			*ptr = '\0';
544 			return ptr - *buf;
545 		}
546 		if (ptr + 2 >= eptr) {
547 			char *nbuf;
548 			size_t nbufsiz = *bufsiz * 2;
549 			ssize_t d = ptr - *buf;
550 			if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
551 				return -1;
552 			*buf = nbuf;
553 			*bufsiz = nbufsiz;
554 			eptr = nbuf + nbufsiz;
555 			ptr = nbuf + d;
556 		}
557 	}
558 }
559 
560 ssize_t
561 getline(char **buf, size_t *bufsiz, FILE *fp)
562 {
563 	return getdelim(buf, bufsiz, '\n', fp);
564 }
565 
566 #endif
567