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