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 [email protected]. 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 defined(HAVE_SSL) 299 if (numfeatures > 0) { 300 strncat(features, ", ", 301 sizeof(features) - strlen(features) - 1); 302 } 303 strncat(features, "authentication", 304 sizeof(features) - strlen(features) - 1); 305 numfeatures++; 306 #endif /* HAVE_SSL */ 307 308 if (numfeatures == 0) { 309 strncat(features, "None", 310 sizeof(features) - strlen(features) - 1); 311 } 312 313 return features; 314 } 315 316 /* Helper routine for building cJSON objects in a printf-like manner. 317 ** 318 ** Sample call: 319 ** j = iperf_json_printf("foo: %b bar: %d bletch: %f eep: %s", b, i, f, s); 320 ** 321 ** The four formatting characters and the types they expect are: 322 ** %b boolean int 323 ** %d integer int64_t 324 ** %f floating point double 325 ** %s string char * 326 ** If the values you're passing in are not these exact types, you must 327 ** cast them, there is no automatic type coercion/widening here. 328 ** 329 ** The colons mark the end of field names, and blanks are ignored. 330 ** 331 ** This routine is not particularly robust, but it's not part of the API, 332 ** it's just for internal iperf3 use. 333 */ 334 cJSON* 335 iperf_json_printf(const char *format, ...) 336 { 337 cJSON* o; 338 va_list argp; 339 const char *cp; 340 char name[100]; 341 char* np; 342 cJSON* j; 343 344 o = cJSON_CreateObject(); 345 if (o == NULL) 346 return NULL; 347 va_start(argp, format); 348 np = name; 349 for (cp = format; *cp != '\0'; ++cp) { 350 switch (*cp) { 351 case ' ': 352 break; 353 case ':': 354 *np = '\0'; 355 break; 356 case '%': 357 ++cp; 358 switch (*cp) { 359 case 'b': 360 j = cJSON_CreateBool(va_arg(argp, int)); 361 break; 362 case 'd': 363 j = cJSON_CreateNumber(va_arg(argp, int64_t)); 364 break; 365 case 'f': 366 j = cJSON_CreateNumber(va_arg(argp, double)); 367 break; 368 case 's': 369 j = cJSON_CreateString(va_arg(argp, char *)); 370 break; 371 default: 372 va_end(argp); 373 return NULL; 374 } 375 if (j == NULL) { 376 va_end(argp); 377 return NULL; 378 } 379 cJSON_AddItemToObject(o, name, j); 380 np = name; 381 break; 382 default: 383 *np++ = *cp; 384 break; 385 } 386 } 387 va_end(argp); 388 return o; 389 } 390 391 /* Debugging routine to dump out an fd_set. */ 392 void 393 iperf_dump_fdset(FILE *fp, char *str, int nfds, fd_set *fds) 394 { 395 int fd; 396 int comma; 397 398 fprintf(fp, "%s: [", str); 399 comma = 0; 400 for (fd = 0; fd < nfds; ++fd) { 401 if (FD_ISSET(fd, fds)) { 402 if (comma) 403 fprintf(fp, ", "); 404 fprintf(fp, "%d", fd); 405 comma = 1; 406 } 407 } 408 fprintf(fp, "]\n"); 409 } 410