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