xref: /iperf/src/iperf_util.c (revision ba7b91d2)
1 /*
2  * Copyright (c) 2009-2011, The Regents of the University of California,
3  * through Lawrence Berkeley National Laboratory (subject to receipt of any
4  * required approvals from the U.S. Dept. of Energy).  All rights reserved.
5  *
6  * This code is distributed under a BSD style license, see the LICENSE file
7  * for complete information.
8  */
9 
10 /* iperf_util.c
11  *
12  * Iperf utility functions
13  *
14  */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <stdarg.h>
21 #include <sys/select.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <time.h>
25 #include <errno.h>
26 
27 #include "config.h"
28 #include "cjson.h"
29 
30 /* make_cookie
31  *
32  * Generate and return a cookie string
33  *
34  * Iperf uses this function to create test "cookies" which
35  * server as unique test identifiers. These cookies are also
36  * used for the authentication of stream connections.
37  */
38 
39 void
40 make_cookie(char *cookie)
41 {
42     static int randomized = 0;
43     char hostname[500];
44     struct timeval tv;
45     char temp[1000];
46 
47     if ( ! randomized )
48         srandom((int) time(0) ^ getpid());
49 
50     /* Generate a string based on hostname, time, randomness, and filler. */
51     (void) gethostname(hostname, sizeof(hostname));
52     (void) gettimeofday(&tv, 0);
53     (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");
54 
55     /* Now truncate it to 36 bytes and terminate. */
56     memcpy(cookie, temp, 36);
57     cookie[36] = '\0';
58 }
59 
60 
61 /* is_closed
62  *
63  * Test if the file descriptor fd is closed.
64  *
65  * Iperf uses this function to test whether a TCP stream socket
66  * is closed, because accepting and denying an invalid connection
67  * in iperf_tcp_accept is not considered an error.
68  */
69 
70 int
71 is_closed(int fd)
72 {
73     struct timeval tv;
74     fd_set readset;
75 
76     FD_ZERO(&readset);
77     FD_SET(fd, &readset);
78     tv.tv_sec = 0;
79     tv.tv_usec = 0;
80 
81     if (select(fd+1, &readset, NULL, NULL, &tv) < 0) {
82         if (errno == EBADF)
83             return 1;
84     }
85     return 0;
86 }
87 
88 
89 double
90 timeval_to_double(struct timeval * tv)
91 {
92     double d;
93 
94     d = tv->tv_sec + tv->tv_usec / 1000000;
95 
96     return d;
97 }
98 
99 int
100 timeval_equals(struct timeval * tv0, struct timeval * tv1)
101 {
102     if ( tv0->tv_sec == tv1->tv_sec && tv0->tv_usec == tv1->tv_usec )
103 	return 1;
104     else
105 	return 0;
106 }
107 
108 double
109 timeval_diff(struct timeval * tv0, struct timeval * tv1)
110 {
111     double time1, time2;
112 
113     time1 = tv0->tv_sec + (tv0->tv_usec / 1000000.0);
114     time2 = tv1->tv_sec + (tv1->tv_usec / 1000000.0);
115 
116     time1 = time1 - time2;
117     if (time1 < 0)
118         time1 = -time1;
119     return time1;
120 }
121 
122 
123 int
124 delay(int64_t ns)
125 {
126     struct timespec req, rem;
127 
128     req.tv_sec = 0;
129 
130     while (ns >= 1000000000L) {
131         ns -= 1000000000L;
132         req.tv_sec += 1;
133     }
134 
135     req.tv_nsec = ns;
136 
137     while (nanosleep(&req, &rem) == -1)
138         if (EINTR == errno)
139             memcpy(&req, &rem, sizeof(rem));
140         else
141             return -1;
142     return 0;
143 }
144 
145 # ifdef DELAY_SELECT_METHOD
146 int
147 delay(int us)
148 {
149     struct timeval tv;
150 
151     tv.tv_sec = 0;
152     tv.tv_usec = us;
153     (void) select(1, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv);
154     return 1;
155 }
156 #endif
157 
158 
159 void
160 cpu_util(double *pcpu)
161 {
162     static struct timeval last;
163     static clock_t clast;
164     struct timeval temp;
165     clock_t ctemp;
166     double timediff;
167 
168     if (pcpu == NULL) {
169         gettimeofday(&last, NULL);
170         clast = clock();
171         return;
172     }
173 
174     gettimeofday(&temp, NULL);
175     ctemp = clock();
176 
177     timediff = ((temp.tv_sec * 1000000.0 + temp.tv_usec) -
178             (last.tv_sec * 1000000.0 + last.tv_usec));
179 
180     *pcpu = ((ctemp - clast) / timediff) * 100;
181 }
182 
183 char*
184 get_system_info(void)
185     {
186     FILE* fp;
187     static char buf[1000];
188 
189     fp = popen("uname -a", "r");
190     if (fp == NULL)
191 	return NULL;
192     fgets(buf, sizeof(buf), fp);
193     pclose(fp);
194     return buf;
195     }
196 
197 
198 /* Helper routine for building cJSON objects in a printf-like manner.
199 **
200 ** Sample call:
201 **   j = iperf_json_printf("foo: %b  bar: %d  bletch: %f  eep: %s", b, i, f, s);
202 **
203 ** The four formatting characters and the types they expect are:
204 **   %b  boolean           int
205 **   %d  integer           int64_t
206 **   %f  floating point    double
207 **   %s  string            char *
208 ** If the values you're passing in are not these exact types, you must
209 ** cast them, there is no automatic type coercion/widening here.
210 **
211 ** The colons mark the end of field names, and blanks are ignored.
212 **
213 ** This routine is not particularly robust, but it's not part of the API,
214 ** it's just for internal iperf3 use.
215 */
216 cJSON*
217 iperf_json_printf(const char *format, ...)
218 {
219     cJSON* o;
220     va_list argp;
221     const char *cp;
222     char name[100];
223     char* np;
224     cJSON* j;
225 
226     o = cJSON_CreateObject();
227     if (o == NULL)
228         return NULL;
229     va_start(argp, format);
230     np = name;
231     for (cp = format; *cp != '\0'; ++cp) {
232 	switch (*cp) {
233 	    case ' ':
234 	    break;
235 	    case ':':
236 	    *np = '\0';
237 	    break;
238 	    case '%':
239 	    ++cp;
240 	    switch (*cp) {
241 		case 'b':
242 		j = cJSON_CreateBool(va_arg(argp, int));
243 		break;
244 		case 'd':
245 		j = cJSON_CreateInt(va_arg(argp, int64_t));
246 		break;
247 		case 'f':
248 		j = cJSON_CreateFloat(va_arg(argp, double));
249 		break;
250 		case 's':
251 		j = cJSON_CreateString(va_arg(argp, char *));
252 		break;
253 		default:
254 		return NULL;
255 	    }
256 	    if (j == NULL)
257 		return NULL;
258 	    cJSON_AddItemToObject(o, name, j);
259 	    np = name;
260 	    break;
261 	    default:
262 	    *np++ = *cp;
263 	    break;
264 	}
265     }
266     va_end(argp);
267     return o;
268 }
269