xref: /iperf/src/iperf_util.c (revision ff1ea4e5)
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 /* make_cookie
83  *
84  * Generate and return a cookie string
85  *
86  * Iperf uses this function to create test "cookies" which
87  * server as unique test identifiers. These cookies are also
88  * used for the authentication of stream connections.
89  * Assumes cookie has size (COOKIE_SIZE + 1) char's.
90  */
91 
92 void
93 make_cookie(char *cookie)
94 {
95     unsigned char *out = (unsigned char*)cookie;
96     size_t pos;
97     static const unsigned char rndchars[] = "abcdefghijklmnopqrstuvwxyz234567";
98 
99     readentropy(out, COOKIE_SIZE);
100     for (pos = 0; pos < (COOKIE_SIZE - 1); pos++) {
101         out[pos] = rndchars[out[pos] % (sizeof(rndchars) - 1)];
102     }
103     out[pos] = '\0';
104 }
105 
106 
107 /* is_closed
108  *
109  * Test if the file descriptor fd is closed.
110  *
111  * Iperf uses this function to test whether a TCP stream socket
112  * is closed, because accepting and denying an invalid connection
113  * in iperf_tcp_accept is not considered an error.
114  */
115 
116 int
117 is_closed(int fd)
118 {
119     struct timeval tv;
120     fd_set readset;
121 
122     FD_ZERO(&readset);
123     FD_SET(fd, &readset);
124     tv.tv_sec = 0;
125     tv.tv_usec = 0;
126 
127     if (select(fd+1, &readset, NULL, NULL, &tv) < 0) {
128         if (errno == EBADF)
129             return 1;
130     }
131     return 0;
132 }
133 
134 
135 double
136 timeval_to_double(struct timeval * tv)
137 {
138     double d;
139 
140     d = tv->tv_sec + tv->tv_usec / 1000000;
141 
142     return d;
143 }
144 
145 int
146 timeval_equals(struct timeval * tv0, struct timeval * tv1)
147 {
148     if ( tv0->tv_sec == tv1->tv_sec && tv0->tv_usec == tv1->tv_usec )
149 	return 1;
150     else
151 	return 0;
152 }
153 
154 double
155 timeval_diff(struct timeval * tv0, struct timeval * tv1)
156 {
157     double time1, time2;
158 
159     time1 = tv0->tv_sec + (tv0->tv_usec / 1000000.0);
160     time2 = tv1->tv_sec + (tv1->tv_usec / 1000000.0);
161 
162     time1 = time1 - time2;
163     if (time1 < 0)
164         time1 = -time1;
165     return time1;
166 }
167 
168 void
169 cpu_util(double pcpu[3])
170 {
171     static struct timeval last;
172     static clock_t clast;
173     static struct rusage rlast;
174     struct timeval temp;
175     clock_t ctemp;
176     struct rusage rtemp;
177     double timediff;
178     double userdiff;
179     double systemdiff;
180 
181     if (pcpu == NULL) {
182         gettimeofday(&last, NULL);
183         clast = clock();
184 	getrusage(RUSAGE_SELF, &rlast);
185         return;
186     }
187 
188     gettimeofday(&temp, NULL);
189     ctemp = clock();
190     getrusage(RUSAGE_SELF, &rtemp);
191 
192     timediff = ((temp.tv_sec * 1000000.0 + temp.tv_usec) -
193                 (last.tv_sec * 1000000.0 + last.tv_usec));
194     userdiff = ((rtemp.ru_utime.tv_sec * 1000000.0 + rtemp.ru_utime.tv_usec) -
195                 (rlast.ru_utime.tv_sec * 1000000.0 + rlast.ru_utime.tv_usec));
196     systemdiff = ((rtemp.ru_stime.tv_sec * 1000000.0 + rtemp.ru_stime.tv_usec) -
197                   (rlast.ru_stime.tv_sec * 1000000.0 + rlast.ru_stime.tv_usec));
198 
199     pcpu[0] = (((ctemp - clast) * 1000000.0 / CLOCKS_PER_SEC) / timediff) * 100;
200     pcpu[1] = (userdiff / timediff) * 100;
201     pcpu[2] = (systemdiff / timediff) * 100;
202 }
203 
204 const char *
205 get_system_info(void)
206 {
207     static char buf[1024];
208     struct utsname  uts;
209 
210     memset(buf, 0, 1024);
211     uname(&uts);
212 
213     snprintf(buf, sizeof(buf), "%s %s %s %s %s", uts.sysname, uts.nodename,
214 	     uts.release, uts.version, uts.machine);
215 
216     return buf;
217 }
218 
219 
220 const char *
221 get_optional_features(void)
222 {
223     static char features[1024];
224     unsigned int numfeatures = 0;
225 
226     snprintf(features, sizeof(features), "Optional features available: ");
227 
228 #if defined(HAVE_CPU_AFFINITY)
229     if (numfeatures > 0) {
230 	strncat(features, ", ",
231 		sizeof(features) - strlen(features) - 1);
232     }
233     strncat(features, "CPU affinity setting",
234 	sizeof(features) - strlen(features) - 1);
235     numfeatures++;
236 #endif /* HAVE_CPU_AFFINITY */
237 
238 #if defined(HAVE_FLOWLABEL)
239     if (numfeatures > 0) {
240 	strncat(features, ", ",
241 		sizeof(features) - strlen(features) - 1);
242     }
243     strncat(features, "IPv6 flow label",
244 	sizeof(features) - strlen(features) - 1);
245     numfeatures++;
246 #endif /* HAVE_FLOWLABEL */
247 
248 #if defined(HAVE_SCTP)
249     if (numfeatures > 0) {
250 	strncat(features, ", ",
251 		sizeof(features) - strlen(features) - 1);
252     }
253     strncat(features, "SCTP",
254 	sizeof(features) - strlen(features) - 1);
255     numfeatures++;
256 #endif /* HAVE_SCTP */
257 
258 #if defined(HAVE_TCP_CONGESTION)
259     if (numfeatures > 0) {
260 	strncat(features, ", ",
261 		sizeof(features) - strlen(features) - 1);
262     }
263     strncat(features, "TCP congestion algorithm setting",
264 	sizeof(features) - strlen(features) - 1);
265     numfeatures++;
266 #endif /* HAVE_TCP_CONGESTION */
267 
268 #if defined(HAVE_SENDFILE)
269     if (numfeatures > 0) {
270 	strncat(features, ", ",
271 		sizeof(features) - strlen(features) - 1);
272     }
273     strncat(features, "sendfile / zerocopy",
274 	sizeof(features) - strlen(features) - 1);
275     numfeatures++;
276 #endif /* HAVE_SENDFILE */
277 
278 #if defined(HAVE_SO_MAX_PACING_RATE)
279     if (numfeatures > 0) {
280 	strncat(features, ", ",
281 		sizeof(features) - strlen(features) - 1);
282     }
283     strncat(features, "socket pacing",
284 	sizeof(features) - strlen(features) - 1);
285     numfeatures++;
286 #endif /* HAVE_SO_MAX_PACING_RATE */
287 
288 #if defined(HAVE_SSL)
289     if (numfeatures > 0) {
290 	strncat(features, ", ",
291 		sizeof(features) - strlen(features) - 1);
292     }
293     strncat(features, "authentication",
294 	sizeof(features) - strlen(features) - 1);
295     numfeatures++;
296 #endif /* HAVE_SSL */
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 }
400 
401 /*
402  * daemon(3) implementation for systems lacking one.
403  * Cobbled together from various daemon(3) implementations,
404  * not intended to be general-purpose. */
405 #ifndef HAVE_DAEMON
406 int daemon(int nochdir, int noclose)
407 {
408     pid_t pid = 0;
409     pid_t sid = 0;
410     int fd;
411 
412     /*
413      * Ignore any possible SIGHUP when the parent process exits.
414      * Note that the iperf3 server process will eventually install
415      * its own signal handler for SIGHUP, so we can be a little
416      * sloppy about not restoring the prior value.  This does not
417      * generalize.
418      */
419     signal(SIGHUP, SIG_IGN);
420 
421     pid = fork();
422     if (pid < 0) {
423 	    return -1;
424     }
425     if (pid > 0) {
426 	/* Use _exit() to avoid doing atexit() stuff. */
427 	_exit(0);
428     }
429 
430     sid = setsid();
431     if (sid < 0) {
432 	return -1;
433     }
434 
435     /*
436      * Fork again to avoid becoming a session leader.
437      * This might only matter on old SVr4-derived OSs.
438      * Note in particular that glibc and FreeBSD libc
439      * only fork once.
440      */
441     pid = fork();
442     if (pid == -1) {
443 	return -1;
444     } else if (pid != 0) {
445 	_exit(0);
446     }
447 
448     if (!nochdir) {
449 	chdir("/");
450     }
451 
452     if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
453 	dup2(fd, STDIN_FILENO);
454 	dup2(fd, STDOUT_FILENO);
455 	dup2(fd, STDERR_FILENO);
456 	if (fd > 2) {
457 	    close(fd);
458 	}
459     }
460     return (0);
461 }
462 #endif /* HAVE_DAEMON */
463 
464 /* Compatibility version of getline(3) for systems that don't have it.. */
465 #ifndef HAVE_GETLINE
466 /* The following code adopted from NetBSD's getline.c, which is: */
467 
468 /*-
469  * Copyright (c) 2011 The NetBSD Foundation, Inc.
470  * All rights reserved.
471  *
472  * This code is derived from software contributed to The NetBSD Foundation
473  * by Christos Zoulas.
474  *
475  * Redistribution and use in source and binary forms, with or without
476  * modification, are permitted provided that the following conditions
477  * are met:
478  * 1. Redistributions of source code must retain the above copyright
479  *    notice, this list of conditions and the following disclaimer.
480  * 2. Redistributions in binary form must reproduce the above copyright
481  *    notice, this list of conditions and the following disclaimer in the
482  *    documentation and/or other materials provided with the distribution.
483  *
484  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
485  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
486  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
487  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
488  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
489  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
490  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
491  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
492  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
493  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
494  * POSSIBILITY OF SUCH DAMAGE.
495  */
496 ssize_t
497 getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
498 {
499 	char *ptr, *eptr;
500 
501 
502 	if (*buf == NULL || *bufsiz == 0) {
503 		*bufsiz = BUFSIZ;
504 		if ((*buf = malloc(*bufsiz)) == NULL)
505 			return -1;
506 	}
507 
508 	for (ptr = *buf, eptr = *buf + *bufsiz;;) {
509 		int c = fgetc(fp);
510 		if (c == -1) {
511 			if (feof(fp)) {
512 				ssize_t diff = (ssize_t)(ptr - *buf);
513 				if (diff != 0) {
514 					*ptr = '\0';
515 					return diff;
516 				}
517 			}
518 			return -1;
519 		}
520 		*ptr++ = c;
521 		if (c == delimiter) {
522 			*ptr = '\0';
523 			return ptr - *buf;
524 		}
525 		if (ptr + 2 >= eptr) {
526 			char *nbuf;
527 			size_t nbufsiz = *bufsiz * 2;
528 			ssize_t d = ptr - *buf;
529 			if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
530 				return -1;
531 			*buf = nbuf;
532 			*bufsiz = nbufsiz;
533 			eptr = nbuf + nbufsiz;
534 			ptr = nbuf + d;
535 		}
536 	}
537 }
538 
539 ssize_t
540 getline(char **buf, size_t *bufsiz, FILE *fp)
541 {
542 	return getdelim(buf, bufsiz, '\n', fp);
543 }
544 
545 #endif
546