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