lsquic_util.c revision a500a209
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * Utility functions 4 */ 5 6#include <ctype.h> 7#include <stdint.h> 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11#include <time.h> 12#ifndef WIN32 13#include <netinet/in.h> 14#include <arpa/inet.h> 15#include <sys/socket.h> 16#include <sys/time.h> 17#include <unistd.h> 18#else 19#include <vc_compat.h> 20#include <ws2tcpip.h> 21#endif 22 23#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__) 24#include <mach/mach_time.h> 25#endif 26 27#include "lsquic_int_types.h" 28#include "lsquic_util.h" 29#if LSQUIC_COUNT_TIME_CALLS 30#include <stdlib.h> 31#include "lsquic_types.h" 32#include "lsquic_logger.h" 33#endif 34 35 36#if defined(__APPLE__) 37static mach_timebase_info_data_t timebase; 38#endif 39#if defined(WIN32) 40static LARGE_INTEGER perf_frequency; 41#endif 42 43 44#if LSQUIC_COUNT_TIME_CALLS 45static volatile unsigned long n_time_now_calls; 46 47 48static void 49print_call_stats (void) 50{ 51 LSQ_NOTICE("number of lsquic_time_now() calls: %lu", n_time_now_calls); 52} 53#endif 54 55 56void 57lsquic_init_timers (void) 58{ 59#if LSQUIC_COUNT_TIME_CALLS 60 atexit(print_call_stats); 61#endif 62#if defined(__APPLE__) 63 mach_timebase_info(&timebase); 64#endif 65#if defined(WIN32) 66 QueryPerformanceFrequency(&perf_frequency); 67#endif 68} 69 70 71lsquic_time_t 72lsquic_time_now (void) 73{ 74#if LSQUIC_COUNT_TIME_CALLS 75 ++n_time_now_calls; 76#endif 77#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 78 struct timespec ts; 79 (void) clock_gettime(CLOCK_MONOTONIC, &ts); 80 return (lsquic_time_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 81#elif defined(__APPLE__) 82 lsquic_time_t t = mach_absolute_time(); 83 t *= timebase.numer; 84 t /= timebase.denom; 85 t /= 1000; 86 return t; 87#elif defined(WIN32) 88 LARGE_INTEGER counter; 89 lsquic_time_t t; 90 QueryPerformanceCounter(&counter); 91 t = counter.QuadPart; 92 t *= 1000000; 93 t /= perf_frequency.QuadPart; 94 return t; 95#else 96# warn Monotonically increasing clock is not available on this platform 97 struct timeval tv; 98 (void) gettimeofday(&tv, NULL); 99 return (lsquic_time_t) tv.tv_sec * 1000000 + tv.tv_usec; 100#endif 101} 102 103 104int 105lsquic_is_zero (const void *pbuf, size_t bufsz) 106{ 107 const unsigned char *buf, *end; 108 const unsigned long *buf_ul; 109 unsigned n_ul; 110 unsigned long n_non_zero; 111 112 buf = pbuf; 113 end = buf + bufsz; 114 buf_ul = (unsigned long *) buf; 115 n_ul = bufsz / sizeof(buf_ul[0]); 116 buf += n_ul * sizeof(buf_ul[0]); 117 n_non_zero = 0; 118 119 while (n_ul--) 120 n_non_zero |= buf_ul[n_ul]; 121 122 while (buf < end) 123 n_non_zero |= *buf++; 124 125 return n_non_zero == 0; 126} 127 128 129/* XXX this function uses static buffer. Replace it with lsquic_hexdump() if possible */ 130char * 131lsquic_get_bin_str (const void *s, size_t len, size_t max_display_len) 132{ 133 const unsigned char *p, *pEnd; 134 char *pOutput; 135 size_t lenOrg = len; 136 static char str[512 * 2 + 40] = {0}; 137 138 /** 139 * We alloc fixed size buffer, at most max_display_len is 512 140 */ 141 size_t fit_display_len = (max_display_len > 512 ? 512 : max_display_len); 142 if (len > fit_display_len) 143 len = fit_display_len; 144 145 pOutput = &str[0] + sprintf(str, "(%zd/%zd)=0x", len, lenOrg); 146 147 for(p = s, pEnd = (unsigned char*)s + len; p < pEnd; ++p) 148 { 149 sprintf(pOutput, "%02X", *p); 150 pOutput += 2; 151 } 152 if (lenOrg > len) 153 { 154 sprintf(pOutput, "..."); 155 pOutput += 3; 156 } 157 return str; 158} 159 160 161static char 162hex_digit(uint8_t n) 163{ 164 return (n < 10) ? (n + '0') : ((n - 10) + 'a'); 165} 166 167 168size_t 169lsquic_hex_encode (const void *src, size_t src_sz, void *dst, size_t dst_sz) 170{ 171 size_t src_cur, dst_cur; 172 const uint8_t *src_hex; 173 char *dst_char; 174 175 src_hex = (const uint8_t *)src; 176 dst_char = (char *)dst; 177 src_cur = dst_cur = 0; 178 179 while (src_cur < src_sz && dst_cur < (dst_sz - 2)) 180 { 181 dst_char[dst_cur++] = hex_digit((src_hex[src_cur] & 0xf0) >> 4); 182 dst_char[dst_cur++] = hex_digit(src_hex[src_cur++] & 0x0f); 183 } 184 dst_char[dst_cur++] = '\0'; 185 return dst_cur; 186} 187 188 189void 190lsquic_hexstr (const unsigned char *buf, size_t bufsz, char *out, size_t outsz) 191{ 192 static const char b2c[16] = "0123456789ABCDEF"; 193 const unsigned char *const end_input = buf + bufsz; 194 char *const end_output = out + outsz; 195 196 while (buf < end_input && out + 2 < end_output) 197 { 198 *out++ = b2c[ *buf >> 4 ]; 199 *out++ = b2c[ *buf & 0xF ]; 200 ++buf; 201 } 202 203 if (buf < end_input) 204 out[-1] = '!'; 205 206 *out = '\0'; 207} 208 209 210size_t 211lsquic_hexdump (const void *src_void, size_t src_sz, char *out, size_t out_sz) 212{ 213/* Ruler: 214 * 215 6 31 57 73 216 | | | | 2170000 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F |................| 218 * 219 */ 220#define LINE_SIZE (74 + 1 /* newline */) 221 const unsigned char *src = src_void; 222 const unsigned char *const src_end = src + src_sz; 223 char *const out_end = out + out_sz; 224 unsigned line = 0; 225 226 while (src < src_end && out_end - out >= LINE_SIZE) 227 { 228 const unsigned char *limit = src + 16; 229 if (limit > src_end) 230 limit = src_end; 231 unsigned hex_off = 6; 232 unsigned alpha_off = 57; 233 sprintf(out, "%03X0", line++); 234 out[4] = ' '; 235 out[5] = ' '; 236 while (src < limit) 237 { 238 sprintf(out + hex_off, "%02X ", *src); 239 sprintf(out + alpha_off, "%c", isprint(*src) ? *src : '.'); 240 hex_off += 3; 241 out[hex_off] = ' '; 242 hex_off += 30 == hex_off; 243 out[hex_off] = ' '; 244 ++alpha_off; 245 out[alpha_off] = ' '; 246 ++src; 247 } 248 memset(out + hex_off, ' ', 56 - hex_off); 249 memset(out + alpha_off, '.', 73 - alpha_off); 250 out[56] = '|'; 251 out[73] = '|'; 252 out[74] = '\n'; 253 out += LINE_SIZE; 254 } 255 256 if (out < out_end) 257 *out = '\0'; 258 else 259 out_end[-1] = '\0'; 260 261 return out + out_sz - out_end; 262} 263 264 265/* Returns true if socket addresses are equal, false otherwise. Only 266 * families, IP addresses, and ports are compared. 267 */ 268int 269lsquic_sockaddr_eq (const struct sockaddr *a, const struct sockaddr *b) 270{ 271 if (a->sa_family == AF_INET) 272 return a->sa_family == b->sa_family 273 && ((struct sockaddr_in *) a)->sin_addr.s_addr 274 == ((struct sockaddr_in *) b)->sin_addr.s_addr 275 && ((struct sockaddr_in *) a)->sin_port 276 == ((struct sockaddr_in *) b)->sin_port; 277 else 278 return a->sa_family == b->sa_family 279 && ((struct sockaddr_in6 *) a)->sin6_port == 280 ((struct sockaddr_in6 *) b)->sin6_port 281 && 0 == memcmp(&((struct sockaddr_in6 *) a)->sin6_addr, 282 &((struct sockaddr_in6 *) b)->sin6_addr, 283 sizeof(((struct sockaddr_in6 *) b)->sin6_addr)); 284} 285 286 287void 288lsquic_sockaddr2str (const struct sockaddr *addr, char *buf, size_t sz) 289{ 290 unsigned short port; 291 int len; 292 293 switch (addr->sa_family) 294 { 295 case AF_INET: 296 port = ntohs(((struct sockaddr_in *) addr)->sin_port); 297 if (!inet_ntop(AF_INET, &((struct sockaddr_in *) addr)->sin_addr, 298 buf, sz)) 299 buf[0] = '\0'; 300 break; 301 case AF_INET6: 302 port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port); 303 if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *) addr)->sin6_addr, 304 buf, sz)) 305 buf[0] = '\0'; 306 break; 307 default: 308 port = 0; 309 (void) snprintf(buf, sz, "<invalid family %d>", addr->sa_family); 310 break; 311 } 312 313 len = strlen(buf); 314 if (len < (int) sz) 315 snprintf(buf + len, sz - (size_t) len, ":%hu", port); 316} 317 318 319#ifdef _MSC_VER 320char * 321lsquic_strndup (const char *s, size_t n) 322{ 323 size_t len; 324 char *copy; 325 326 len = strnlen(s, n); 327 copy = malloc(n + 1); 328 if (copy) 329 { 330 memcpy(copy, s, len); 331 copy[len] = '\0'; 332 } 333 334 return copy; 335} 336#endif 337