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(const char * cookie)114 make_cookie(const 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_H)
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_H */
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 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
340 if (numfeatures == 0) {
341 strncat(features, "None",
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*
iperf_json_printf(const char * format,...)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
iperf_dump_fdset(FILE * fp,const char * str,int nfds,fd_set * fds)425 iperf_dump_fdset(FILE *fp, const char *str, int nfds, fd_set *fds)
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 }
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
daemon(int nochdir,int noclose)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.
479 * This might only matter on old SVr4-derived OSs.
480 * Note in particular that glibc and FreeBSD libc
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
getdelim(char ** buf,size_t * bufsiz,int delimiter,FILE * fp)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
getline(char ** buf,size_t * bufsiz,FILE * fp)582 getline(char **buf, size_t *bufsiz, FILE *fp)
583 {
584 return getdelim(buf, bufsiz, '\n', fp);
585 }
586
587 #endif
588