Annotation of embedaddon/iperf/src/iperf_util.c, revision 1.1.1.1
1.1 misho 1: /*
2: * iperf, Copyright (c) 2014, 2016, 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 <stdlib.h>
36: #include <unistd.h>
37: #include <string.h>
38: #include <stdarg.h>
39: #include <sys/select.h>
40: #include <sys/types.h>
41: #include <sys/time.h>
42: #include <sys/resource.h>
43: #include <sys/utsname.h>
44: #include <time.h>
45: #include <errno.h>
46:
47: #include "cjson.h"
48:
49: /* make_cookie
50: *
51: * Generate and return a cookie string
52: *
53: * Iperf uses this function to create test "cookies" which
54: * server as unique test identifiers. These cookies are also
55: * used for the authentication of stream connections.
56: */
57:
58: void
59: make_cookie(char *cookie)
60: {
61: static int randomized = 0;
62: char hostname[500];
63: struct timeval tv;
64: char temp[1000];
65:
66: if ( ! randomized )
67: srandom((int) time(0) ^ getpid());
68:
69: /* Generate a string based on hostname, time, randomness, and filler. */
70: (void) gethostname(hostname, sizeof(hostname));
71: (void) gettimeofday(&tv, 0);
72: (void) snprintf(temp, sizeof(temp), "%s.%ld.%06ld.%08lx%08lx.%s", hostname, (unsigned long int) tv.tv_sec, (unsigned long int) tv.tv_usec, (unsigned long int) random(), (unsigned long int) random(), "1234567890123456789012345678901234567890");
73:
74: /* Now truncate it to 36 bytes and terminate. */
75: memcpy(cookie, temp, 36);
76: cookie[36] = '\0';
77: }
78:
79:
80: /* is_closed
81: *
82: * Test if the file descriptor fd is closed.
83: *
84: * Iperf uses this function to test whether a TCP stream socket
85: * is closed, because accepting and denying an invalid connection
86: * in iperf_tcp_accept is not considered an error.
87: */
88:
89: int
90: is_closed(int fd)
91: {
92: struct timeval tv;
93: fd_set readset;
94:
95: FD_ZERO(&readset);
96: FD_SET(fd, &readset);
97: tv.tv_sec = 0;
98: tv.tv_usec = 0;
99:
100: if (select(fd+1, &readset, NULL, NULL, &tv) < 0) {
101: if (errno == EBADF)
102: return 1;
103: }
104: return 0;
105: }
106:
107:
108: double
109: timeval_to_double(struct timeval * tv)
110: {
111: double d;
112:
113: d = tv->tv_sec + tv->tv_usec / 1000000;
114:
115: return d;
116: }
117:
118: int
119: timeval_equals(struct timeval * tv0, struct timeval * tv1)
120: {
121: if ( tv0->tv_sec == tv1->tv_sec && tv0->tv_usec == tv1->tv_usec )
122: return 1;
123: else
124: return 0;
125: }
126:
127: double
128: timeval_diff(struct timeval * tv0, struct timeval * tv1)
129: {
130: double time1, time2;
131:
132: time1 = tv0->tv_sec + (tv0->tv_usec / 1000000.0);
133: time2 = tv1->tv_sec + (tv1->tv_usec / 1000000.0);
134:
135: time1 = time1 - time2;
136: if (time1 < 0)
137: time1 = -time1;
138: return time1;
139: }
140:
141:
142: int
143: delay(int64_t ns)
144: {
145: struct timespec req, rem;
146:
147: req.tv_sec = 0;
148:
149: while (ns >= 1000000000L) {
150: ns -= 1000000000L;
151: req.tv_sec += 1;
152: }
153:
154: req.tv_nsec = ns;
155:
156: while (nanosleep(&req, &rem) == -1)
157: if (EINTR == errno)
158: memcpy(&req, &rem, sizeof(rem));
159: else
160: return -1;
161: return 0;
162: }
163:
164: # ifdef DELAY_SELECT_METHOD
165: int
166: delay(int us)
167: {
168: struct timeval tv;
169:
170: tv.tv_sec = 0;
171: tv.tv_usec = us;
172: (void) select(1, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv);
173: return 1;
174: }
175: #endif
176:
177:
178: void
179: cpu_util(double pcpu[3])
180: {
181: static struct timeval last;
182: static clock_t clast;
183: static struct rusage rlast;
184: struct timeval temp;
185: clock_t ctemp;
186: struct rusage rtemp;
187: double timediff;
188: double userdiff;
189: double systemdiff;
190:
191: if (pcpu == NULL) {
192: gettimeofday(&last, NULL);
193: clast = clock();
194: getrusage(RUSAGE_SELF, &rlast);
195: return;
196: }
197:
198: gettimeofday(&temp, NULL);
199: ctemp = clock();
200: getrusage(RUSAGE_SELF, &rtemp);
201:
202: timediff = ((temp.tv_sec * 1000000.0 + temp.tv_usec) -
203: (last.tv_sec * 1000000.0 + last.tv_usec));
204: userdiff = ((rtemp.ru_utime.tv_sec * 1000000.0 + rtemp.ru_utime.tv_usec) -
205: (rlast.ru_utime.tv_sec * 1000000.0 + rlast.ru_utime.tv_usec));
206: systemdiff = ((rtemp.ru_stime.tv_sec * 1000000.0 + rtemp.ru_stime.tv_usec) -
207: (rlast.ru_stime.tv_sec * 1000000.0 + rlast.ru_stime.tv_usec));
208:
209: pcpu[0] = (((ctemp - clast) * 1000000.0 / CLOCKS_PER_SEC) / timediff) * 100;
210: pcpu[1] = (userdiff / timediff) * 100;
211: pcpu[2] = (systemdiff / timediff) * 100;
212: }
213:
214: const char *
215: get_system_info(void)
216: {
217: static char buf[1024];
218: struct utsname uts;
219:
220: memset(buf, 0, 1024);
221: uname(&uts);
222:
223: snprintf(buf, sizeof(buf), "%s %s %s %s %s", uts.sysname, uts.nodename,
224: uts.release, uts.version, uts.machine);
225:
226: return buf;
227: }
228:
229:
230: const char *
231: get_optional_features(void)
232: {
233: static char features[1024];
234: unsigned int numfeatures = 0;
235:
236: snprintf(features, sizeof(features), "Optional features available: ");
237:
238: #if defined(HAVE_CPU_AFFINITY)
239: if (numfeatures > 0) {
240: strncat(features, ", ",
241: sizeof(features) - strlen(features) - 1);
242: }
243: strncat(features, "CPU affinity setting",
244: sizeof(features) - strlen(features) - 1);
245: numfeatures++;
246: #endif /* HAVE_CPU_AFFINITY */
247:
248: #if defined(HAVE_FLOWLABEL)
249: if (numfeatures > 0) {
250: strncat(features, ", ",
251: sizeof(features) - strlen(features) - 1);
252: }
253: strncat(features, "IPv6 flow label",
254: sizeof(features) - strlen(features) - 1);
255: numfeatures++;
256: #endif /* HAVE_FLOWLABEL */
257:
258: #if defined(HAVE_SCTP)
259: if (numfeatures > 0) {
260: strncat(features, ", ",
261: sizeof(features) - strlen(features) - 1);
262: }
263: strncat(features, "SCTP",
264: sizeof(features) - strlen(features) - 1);
265: numfeatures++;
266: #endif /* HAVE_SCTP */
267:
268: #if defined(HAVE_TCP_CONGESTION)
269: if (numfeatures > 0) {
270: strncat(features, ", ",
271: sizeof(features) - strlen(features) - 1);
272: }
273: strncat(features, "TCP congestion algorithm setting",
274: sizeof(features) - strlen(features) - 1);
275: numfeatures++;
276: #endif /* HAVE_TCP_CONGESTION */
277:
278: #if defined(HAVE_SENDFILE)
279: if (numfeatures > 0) {
280: strncat(features, ", ",
281: sizeof(features) - strlen(features) - 1);
282: }
283: strncat(features, "sendfile / zerocopy",
284: sizeof(features) - strlen(features) - 1);
285: numfeatures++;
286: #endif /* HAVE_SENDFILE */
287:
288: #if defined(HAVE_SO_MAX_PACING_RATE)
289: if (numfeatures > 0) {
290: strncat(features, ", ",
291: sizeof(features) - strlen(features) - 1);
292: }
293: strncat(features, "socket pacing",
294: sizeof(features) - strlen(features) - 1);
295: numfeatures++;
296: #endif /* HAVE_SO_MAX_PACING_RATE */
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>