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 #include "iperf_config.h" 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <unistd.h> 20 #include <string.h> 21 #include <stdarg.h> 22 #include <sys/select.h> 23 #include <sys/types.h> 24 #include <sys/time.h> 25 #include <sys/resource.h> 26 #include <sys/utsname.h> 27 #include <time.h> 28 #include <errno.h> 29 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) * 1000000.0 / CLOCKS_PER_SEC) / timediff) * 100; 193 pcpu[1] = (userdiff / timediff) * 100; 194 pcpu[2] = (systemdiff / timediff) * 100; 195 } 196 197 const 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 const char * 214 get_optional_features(void) 215 { 216 static char features[1024]; 217 unsigned int numfeatures = 0; 218 219 snprintf(features, sizeof(features), "Optional features available: "); 220 221 #if defined(HAVE_CPU_AFFINITY) 222 if (numfeatures > 0) { 223 strncat(features, ", ", 224 sizeof(features) - strlen(features) - 1); 225 } 226 strncat(features, "CPU affinity setting", 227 sizeof(features) - strlen(features) - 1); 228 numfeatures++; 229 #endif /* HAVE_CPU_AFFINITY */ 230 231 #if defined(HAVE_FLOWLABEL) 232 if (numfeatures > 0) { 233 strncat(features, ", ", 234 sizeof(features) - strlen(features) - 1); 235 } 236 strncat(features, "IPv6 flow label", 237 sizeof(features) - strlen(features) - 1); 238 numfeatures++; 239 #endif /* HAVE_FLOWLABEL */ 240 241 #if defined(HAVE_SCTP) 242 if (numfeatures > 0) { 243 strncat(features, ", ", 244 sizeof(features) - strlen(features) - 1); 245 } 246 strncat(features, "SCTP", 247 sizeof(features) - strlen(features) - 1); 248 numfeatures++; 249 #endif /* HAVE_SCTP */ 250 251 #if defined(HAVE_TCP_CONGESTION) 252 if (numfeatures > 0) { 253 strncat(features, ", ", 254 sizeof(features) - strlen(features) - 1); 255 } 256 strncat(features, "TCP congestion algorithm setting", 257 sizeof(features) - strlen(features) - 1); 258 numfeatures++; 259 #endif /* HAVE_TCP_CONGESTION */ 260 261 #if defined(HAVE_SENDFILE) 262 if (numfeatures > 0) { 263 strncat(features, ", ", 264 sizeof(features) - strlen(features) - 1); 265 } 266 strncat(features, "sendfile / zerocopy", 267 sizeof(features) - strlen(features) - 1); 268 numfeatures++; 269 #endif /* HAVE_SENDFILE */ 270 271 if (numfeatures == 0) { 272 strncat(features, "None", 273 sizeof(features) - strlen(features) - 1); 274 } 275 276 return features; 277 } 278 279 /* Helper routine for building cJSON objects in a printf-like manner. 280 ** 281 ** Sample call: 282 ** j = iperf_json_printf("foo: %b bar: %d bletch: %f eep: %s", b, i, f, s); 283 ** 284 ** The four formatting characters and the types they expect are: 285 ** %b boolean int 286 ** %d integer int64_t 287 ** %f floating point double 288 ** %s string char * 289 ** If the values you're passing in are not these exact types, you must 290 ** cast them, there is no automatic type coercion/widening here. 291 ** 292 ** The colons mark the end of field names, and blanks are ignored. 293 ** 294 ** This routine is not particularly robust, but it's not part of the API, 295 ** it's just for internal iperf3 use. 296 */ 297 cJSON* 298 iperf_json_printf(const char *format, ...) 299 { 300 cJSON* o; 301 va_list argp; 302 const char *cp; 303 char name[100]; 304 char* np; 305 cJSON* j; 306 307 o = cJSON_CreateObject(); 308 if (o == NULL) 309 return NULL; 310 va_start(argp, format); 311 np = name; 312 for (cp = format; *cp != '\0'; ++cp) { 313 switch (*cp) { 314 case ' ': 315 break; 316 case ':': 317 *np = '\0'; 318 break; 319 case '%': 320 ++cp; 321 switch (*cp) { 322 case 'b': 323 j = cJSON_CreateBool(va_arg(argp, int)); 324 break; 325 case 'd': 326 j = cJSON_CreateInt(va_arg(argp, int64_t)); 327 break; 328 case 'f': 329 j = cJSON_CreateFloat(va_arg(argp, double)); 330 break; 331 case 's': 332 j = cJSON_CreateString(va_arg(argp, char *)); 333 break; 334 default: 335 return NULL; 336 } 337 if (j == NULL) 338 return NULL; 339 cJSON_AddItemToObject(o, name, j); 340 np = name; 341 break; 342 default: 343 *np++ = *cp; 344 break; 345 } 346 } 347 va_end(argp); 348 return o; 349 } 350 351 /* Debugging routine to dump out an fd_set. */ 352 void 353 iperf_dump_fdset(FILE *fp, char *str, int nfds, fd_set *fds) 354 { 355 int fd; 356 int comma; 357 358 fprintf(fp, "%s: [", str); 359 comma = 0; 360 for (fd = 0; fd < nfds; ++fd) { 361 if (FD_ISSET(fd, fds)) { 362 if (comma) 363 fprintf(fp, ", "); 364 fprintf(fp, "%d", fd); 365 comma = 1; 366 } 367 } 368 fprintf(fp, "]\n"); 369 } 370