1 /* 2 * Copyright (c) 2009-2014, 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 <sys/resource.h> 25 #include <sys/utsname.h> 26 #include <time.h> 27 #include <errno.h> 28 29 #include "config.h" 30 #include "cjson.h" 31 32 /* make_cookie 33 * 34 * Generate and return a cookie string 35 * 36 * Iperf uses this function to create test "cookies" which 37 * server as unique test identifiers. These cookies are also 38 * used for the authentication of stream connections. 39 */ 40 41 void 42 make_cookie(char *cookie) 43 { 44 static int randomized = 0; 45 char hostname[500]; 46 struct timeval tv; 47 char temp[1000]; 48 49 if ( ! randomized ) 50 srandom((int) time(0) ^ getpid()); 51 52 /* Generate a string based on hostname, time, randomness, and filler. */ 53 (void) gethostname(hostname, sizeof(hostname)); 54 (void) gettimeofday(&tv, 0); 55 (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"); 56 57 /* Now truncate it to 36 bytes and terminate. */ 58 memcpy(cookie, temp, 36); 59 cookie[36] = '\0'; 60 } 61 62 63 /* is_closed 64 * 65 * Test if the file descriptor fd is closed. 66 * 67 * Iperf uses this function to test whether a TCP stream socket 68 * is closed, because accepting and denying an invalid connection 69 * in iperf_tcp_accept is not considered an error. 70 */ 71 72 int 73 is_closed(int fd) 74 { 75 struct timeval tv; 76 fd_set readset; 77 78 FD_ZERO(&readset); 79 FD_SET(fd, &readset); 80 tv.tv_sec = 0; 81 tv.tv_usec = 0; 82 83 if (select(fd+1, &readset, NULL, NULL, &tv) < 0) { 84 if (errno == EBADF) 85 return 1; 86 } 87 return 0; 88 } 89 90 91 double 92 timeval_to_double(struct timeval * tv) 93 { 94 double d; 95 96 d = tv->tv_sec + tv->tv_usec / 1000000; 97 98 return d; 99 } 100 101 int 102 timeval_equals(struct timeval * tv0, struct timeval * tv1) 103 { 104 if ( tv0->tv_sec == tv1->tv_sec && tv0->tv_usec == tv1->tv_usec ) 105 return 1; 106 else 107 return 0; 108 } 109 110 double 111 timeval_diff(struct timeval * tv0, struct timeval * tv1) 112 { 113 double time1, time2; 114 115 time1 = tv0->tv_sec + (tv0->tv_usec / 1000000.0); 116 time2 = tv1->tv_sec + (tv1->tv_usec / 1000000.0); 117 118 time1 = time1 - time2; 119 if (time1 < 0) 120 time1 = -time1; 121 return time1; 122 } 123 124 125 int 126 delay(int64_t ns) 127 { 128 struct timespec req, rem; 129 130 req.tv_sec = 0; 131 132 while (ns >= 1000000000L) { 133 ns -= 1000000000L; 134 req.tv_sec += 1; 135 } 136 137 req.tv_nsec = ns; 138 139 while (nanosleep(&req, &rem) == -1) 140 if (EINTR == errno) 141 memcpy(&req, &rem, sizeof(rem)); 142 else 143 return -1; 144 return 0; 145 } 146 147 # ifdef DELAY_SELECT_METHOD 148 int 149 delay(int us) 150 { 151 struct timeval tv; 152 153 tv.tv_sec = 0; 154 tv.tv_usec = us; 155 (void) select(1, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv); 156 return 1; 157 } 158 #endif 159 160 161 void 162 cpu_util(double pcpu[3]) 163 { 164 static struct timeval last; 165 static clock_t clast; 166 static struct rusage rlast; 167 struct timeval temp; 168 clock_t ctemp; 169 struct rusage rtemp; 170 double timediff; 171 double userdiff; 172 double systemdiff; 173 174 if (pcpu == NULL) { 175 gettimeofday(&last, NULL); 176 clast = clock(); 177 getrusage(RUSAGE_SELF, &rlast); 178 return; 179 } 180 181 gettimeofday(&temp, NULL); 182 ctemp = clock(); 183 getrusage(RUSAGE_SELF, &rtemp); 184 185 timediff = ((temp.tv_sec * 1000000.0 + temp.tv_usec) - 186 (last.tv_sec * 1000000.0 + last.tv_usec)); 187 userdiff = ((rtemp.ru_utime.tv_sec * 1000000.0 + rtemp.ru_utime.tv_usec) - 188 (rlast.ru_utime.tv_sec * 1000000.0 + rlast.ru_utime.tv_usec)); 189 systemdiff = ((rtemp.ru_stime.tv_sec * 1000000.0 + rtemp.ru_stime.tv_usec) - 190 (rlast.ru_stime.tv_sec * 1000000.0 + rlast.ru_stime.tv_usec)); 191 192 pcpu[0] = ((ctemp - clast) / timediff) * 100; 193 pcpu[1] = (userdiff / timediff) * 100; 194 pcpu[2] = (systemdiff / timediff) * 100; 195 } 196 197 char * 198 get_system_info(void) 199 { 200 static char buf[1024]; 201 struct utsname uts; 202 203 memset(buf, 0, 1024); 204 uname(&uts); 205 206 snprintf(buf, sizeof(buf), "%s %s %s %s %s", uts.sysname, uts.nodename, 207 uts.release, uts.version, uts.machine); 208 209 return buf; 210 } 211 212 213 /* Helper routine for building cJSON objects in a printf-like manner. 214 ** 215 ** Sample call: 216 ** j = iperf_json_printf("foo: %b bar: %d bletch: %f eep: %s", b, i, f, s); 217 ** 218 ** The four formatting characters and the types they expect are: 219 ** %b boolean int 220 ** %d integer int64_t 221 ** %f floating point double 222 ** %s string char * 223 ** If the values you're passing in are not these exact types, you must 224 ** cast them, there is no automatic type coercion/widening here. 225 ** 226 ** The colons mark the end of field names, and blanks are ignored. 227 ** 228 ** This routine is not particularly robust, but it's not part of the API, 229 ** it's just for internal iperf3 use. 230 */ 231 cJSON* 232 iperf_json_printf(const char *format, ...) 233 { 234 cJSON* o; 235 va_list argp; 236 const char *cp; 237 char name[100]; 238 char* np; 239 cJSON* j; 240 241 o = cJSON_CreateObject(); 242 if (o == NULL) 243 return NULL; 244 va_start(argp, format); 245 np = name; 246 for (cp = format; *cp != '\0'; ++cp) { 247 switch (*cp) { 248 case ' ': 249 break; 250 case ':': 251 *np = '\0'; 252 break; 253 case '%': 254 ++cp; 255 switch (*cp) { 256 case 'b': 257 j = cJSON_CreateBool(va_arg(argp, int)); 258 break; 259 case 'd': 260 j = cJSON_CreateInt(va_arg(argp, int64_t)); 261 break; 262 case 'f': 263 j = cJSON_CreateFloat(va_arg(argp, double)); 264 break; 265 case 's': 266 j = cJSON_CreateString(va_arg(argp, char *)); 267 break; 268 default: 269 return NULL; 270 } 271 if (j == NULL) 272 return NULL; 273 cJSON_AddItemToObject(o, name, j); 274 np = name; 275 break; 276 default: 277 *np++ = *cp; 278 break; 279 } 280 } 281 va_end(argp); 282 return o; 283 } 284 285 /* Debugging routine to dump out an fd_set. */ 286 void 287 iperf_dump_fdset(FILE *fp, char *str, int nfds, fd_set *fds) 288 { 289 int fd; 290 int comma; 291 292 fprintf(fp, "%s: [", str); 293 comma = 0; 294 for (fd = 0; fd < nfds; ++fd) { 295 if (FD_ISSET(fd, fds)) { 296 if (comma) 297 fprintf(fp, ", "); 298 fprintf(fp, "%d", fd); 299 comma = 1; 300 } 301 } 302 fprintf(fp, "]\n"); 303 } 304