1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 250aadb33SDmitri Tikhonov/* 350aadb33SDmitri Tikhonov * Utility functions 450aadb33SDmitri Tikhonov */ 550aadb33SDmitri Tikhonov 650aadb33SDmitri Tikhonov#include <ctype.h> 750aadb33SDmitri Tikhonov#include <stdint.h> 850aadb33SDmitri Tikhonov#include <stdio.h> 9a500a209SDmitri Tikhonov#include <stdlib.h> 1050aadb33SDmitri Tikhonov#include <string.h> 1183287402SDmitri Tikhonov#include <time.h> 12461e84d8SAmol Deshpande#ifndef WIN32 13fb3e20e0SDmitri Tikhonov#include <netinet/in.h> 14fb3e20e0SDmitri Tikhonov#include <arpa/inet.h> 15fb3e20e0SDmitri Tikhonov#include <sys/socket.h> 16461e84d8SAmol Deshpande#include <sys/time.h> 1783287402SDmitri Tikhonov#include <unistd.h> 18461e84d8SAmol Deshpande#else 19461e84d8SAmol Deshpande#include <vc_compat.h> 20fb3e20e0SDmitri Tikhonov#include <ws2tcpip.h> 21461e84d8SAmol Deshpande#endif 2283287402SDmitri Tikhonov 2383287402SDmitri Tikhonov#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__) 2483287402SDmitri Tikhonov#include <mach/mach_time.h> 2583287402SDmitri Tikhonov#endif 2650aadb33SDmitri Tikhonov 2750aadb33SDmitri Tikhonov#include "lsquic_int_types.h" 2850aadb33SDmitri Tikhonov#include "lsquic_util.h" 295392f7a3SLiteSpeed Tech#if LSQUIC_COUNT_TIME_CALLS 305392f7a3SLiteSpeed Tech#include <stdlib.h> 315392f7a3SLiteSpeed Tech#include "lsquic_types.h" 325392f7a3SLiteSpeed Tech#include "lsquic_logger.h" 335392f7a3SLiteSpeed Tech#endif 3450aadb33SDmitri Tikhonov 3550aadb33SDmitri Tikhonov 3683287402SDmitri Tikhonov#if defined(__APPLE__) 3783287402SDmitri Tikhonovstatic mach_timebase_info_data_t timebase; 3883287402SDmitri Tikhonov#endif 39461e84d8SAmol Deshpande#if defined(WIN32) 40461e84d8SAmol Deshpandestatic LARGE_INTEGER perf_frequency; 41461e84d8SAmol Deshpande#endif 4283287402SDmitri Tikhonov 435392f7a3SLiteSpeed Tech 445392f7a3SLiteSpeed Tech#if LSQUIC_COUNT_TIME_CALLS 455392f7a3SLiteSpeed Techstatic volatile unsigned long n_time_now_calls; 465392f7a3SLiteSpeed Tech 475392f7a3SLiteSpeed Tech 485392f7a3SLiteSpeed Techstatic void 495392f7a3SLiteSpeed Techprint_call_stats (void) 505392f7a3SLiteSpeed Tech{ 515392f7a3SLiteSpeed Tech LSQ_NOTICE("number of lsquic_time_now() calls: %lu", n_time_now_calls); 525392f7a3SLiteSpeed Tech} 535392f7a3SLiteSpeed Tech#endif 545392f7a3SLiteSpeed Tech 555392f7a3SLiteSpeed Tech 5683287402SDmitri Tikhonovvoid 5783287402SDmitri Tikhonovlsquic_init_timers (void) 5883287402SDmitri Tikhonov{ 595392f7a3SLiteSpeed Tech#if LSQUIC_COUNT_TIME_CALLS 605392f7a3SLiteSpeed Tech atexit(print_call_stats); 615392f7a3SLiteSpeed Tech#endif 6283287402SDmitri Tikhonov#if defined(__APPLE__) 6383287402SDmitri Tikhonov mach_timebase_info(&timebase); 6483287402SDmitri Tikhonov#endif 65461e84d8SAmol Deshpande#if defined(WIN32) 66461e84d8SAmol Deshpande QueryPerformanceFrequency(&perf_frequency); 67461e84d8SAmol Deshpande#endif 6883287402SDmitri Tikhonov} 6983287402SDmitri Tikhonov 7083287402SDmitri Tikhonov 7150aadb33SDmitri Tikhonovlsquic_time_t 7250aadb33SDmitri Tikhonovlsquic_time_now (void) 7350aadb33SDmitri Tikhonov{ 745392f7a3SLiteSpeed Tech#if LSQUIC_COUNT_TIME_CALLS 755392f7a3SLiteSpeed Tech ++n_time_now_calls; 765392f7a3SLiteSpeed Tech#endif 7783287402SDmitri Tikhonov#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 7883287402SDmitri Tikhonov struct timespec ts; 7983287402SDmitri Tikhonov (void) clock_gettime(CLOCK_MONOTONIC, &ts); 8083287402SDmitri Tikhonov return (lsquic_time_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 8183287402SDmitri Tikhonov#elif defined(__APPLE__) 8283287402SDmitri Tikhonov lsquic_time_t t = mach_absolute_time(); 8383287402SDmitri Tikhonov t *= timebase.numer; 8483287402SDmitri Tikhonov t /= timebase.denom; 8583287402SDmitri Tikhonov t /= 1000; 8683287402SDmitri Tikhonov return t; 87461e84d8SAmol Deshpande#elif defined(WIN32) 88461e84d8SAmol Deshpande LARGE_INTEGER counter; 89461e84d8SAmol Deshpande lsquic_time_t t; 90461e84d8SAmol Deshpande QueryPerformanceCounter(&counter); 91461e84d8SAmol Deshpande t = counter.QuadPart; 92461e84d8SAmol Deshpande t *= 1000000; 93461e84d8SAmol Deshpande t /= perf_frequency.QuadPart; 94461e84d8SAmol Deshpande return t; 9583287402SDmitri Tikhonov#else 9683287402SDmitri Tikhonov# warn Monotonically increasing clock is not available on this platform 9750aadb33SDmitri Tikhonov struct timeval tv; 9850aadb33SDmitri Tikhonov (void) gettimeofday(&tv, NULL); 9950aadb33SDmitri Tikhonov return (lsquic_time_t) tv.tv_sec * 1000000 + tv.tv_usec; 10083287402SDmitri Tikhonov#endif 10150aadb33SDmitri Tikhonov} 10250aadb33SDmitri Tikhonov 10350aadb33SDmitri Tikhonov 10450aadb33SDmitri Tikhonovint 10550aadb33SDmitri Tikhonovlsquic_is_zero (const void *pbuf, size_t bufsz) 10650aadb33SDmitri Tikhonov{ 10750aadb33SDmitri Tikhonov const unsigned char *buf, *end; 10850aadb33SDmitri Tikhonov const unsigned long *buf_ul; 10950aadb33SDmitri Tikhonov unsigned n_ul; 11050aadb33SDmitri Tikhonov unsigned long n_non_zero; 11150aadb33SDmitri Tikhonov 11250aadb33SDmitri Tikhonov buf = pbuf; 11350aadb33SDmitri Tikhonov end = buf + bufsz; 11450aadb33SDmitri Tikhonov buf_ul = (unsigned long *) buf; 11550aadb33SDmitri Tikhonov n_ul = bufsz / sizeof(buf_ul[0]); 11650aadb33SDmitri Tikhonov buf += n_ul * sizeof(buf_ul[0]); 11750aadb33SDmitri Tikhonov n_non_zero = 0; 11850aadb33SDmitri Tikhonov 11950aadb33SDmitri Tikhonov while (n_ul--) 12050aadb33SDmitri Tikhonov n_non_zero |= buf_ul[n_ul]; 12150aadb33SDmitri Tikhonov 12250aadb33SDmitri Tikhonov while (buf < end) 12350aadb33SDmitri Tikhonov n_non_zero |= *buf++; 12450aadb33SDmitri Tikhonov 12550aadb33SDmitri Tikhonov return n_non_zero == 0; 12650aadb33SDmitri Tikhonov} 12750aadb33SDmitri Tikhonov 12850aadb33SDmitri Tikhonov 1295392f7a3SLiteSpeed Tech/* XXX this function uses static buffer. Replace it with lsquic_hexdump() if possible */ 130a5fa05f9SDmitri Tikhonovchar * 131a5fa05f9SDmitri Tikhonovlsquic_get_bin_str (const void *s, size_t len, size_t max_display_len) 13250aadb33SDmitri Tikhonov{ 13350aadb33SDmitri Tikhonov const unsigned char *p, *pEnd; 13450aadb33SDmitri Tikhonov char *pOutput; 13550aadb33SDmitri Tikhonov size_t lenOrg = len; 13650aadb33SDmitri Tikhonov static char str[512 * 2 + 40] = {0}; 13750aadb33SDmitri Tikhonov 13850aadb33SDmitri Tikhonov /** 13950aadb33SDmitri Tikhonov * We alloc fixed size buffer, at most max_display_len is 512 14050aadb33SDmitri Tikhonov */ 14150aadb33SDmitri Tikhonov size_t fit_display_len = (max_display_len > 512 ? 512 : max_display_len); 14250aadb33SDmitri Tikhonov if (len > fit_display_len) 14350aadb33SDmitri Tikhonov len = fit_display_len; 14450aadb33SDmitri Tikhonov 14550aadb33SDmitri Tikhonov pOutput = &str[0] + sprintf(str, "(%zd/%zd)=0x", len, lenOrg); 14650aadb33SDmitri Tikhonov 147461e84d8SAmol Deshpande for(p = s, pEnd = (unsigned char*)s + len; p < pEnd; ++p) 14850aadb33SDmitri Tikhonov { 14950aadb33SDmitri Tikhonov sprintf(pOutput, "%02X", *p); 15050aadb33SDmitri Tikhonov pOutput += 2; 15150aadb33SDmitri Tikhonov } 15250aadb33SDmitri Tikhonov if (lenOrg > len) 15350aadb33SDmitri Tikhonov { 15450aadb33SDmitri Tikhonov sprintf(pOutput, "..."); 15550aadb33SDmitri Tikhonov pOutput += 3; 15650aadb33SDmitri Tikhonov } 15750aadb33SDmitri Tikhonov return str; 15850aadb33SDmitri Tikhonov} 15950aadb33SDmitri Tikhonov 16050aadb33SDmitri Tikhonov 16155cd0b38SDmitri Tikhonovstatic char 16255cd0b38SDmitri Tikhonovhex_digit(uint8_t n) 16355cd0b38SDmitri Tikhonov{ 16455cd0b38SDmitri Tikhonov return (n < 10) ? (n + '0') : ((n - 10) + 'a'); 16555cd0b38SDmitri Tikhonov} 16655cd0b38SDmitri Tikhonov 16755cd0b38SDmitri Tikhonov 16855cd0b38SDmitri Tikhonovsize_t 16955cd0b38SDmitri Tikhonovlsquic_hex_encode (const void *src, size_t src_sz, void *dst, size_t dst_sz) 17055cd0b38SDmitri Tikhonov{ 17155cd0b38SDmitri Tikhonov size_t src_cur, dst_cur; 17255cd0b38SDmitri Tikhonov const uint8_t *src_hex; 17355cd0b38SDmitri Tikhonov char *dst_char; 17455cd0b38SDmitri Tikhonov 17555cd0b38SDmitri Tikhonov src_hex = (const uint8_t *)src; 17655cd0b38SDmitri Tikhonov dst_char = (char *)dst; 17755cd0b38SDmitri Tikhonov src_cur = dst_cur = 0; 17855cd0b38SDmitri Tikhonov 17955cd0b38SDmitri Tikhonov while (src_cur < src_sz && dst_cur < (dst_sz - 2)) 18055cd0b38SDmitri Tikhonov { 18155cd0b38SDmitri Tikhonov dst_char[dst_cur++] = hex_digit((src_hex[src_cur] & 0xf0) >> 4); 18255cd0b38SDmitri Tikhonov dst_char[dst_cur++] = hex_digit(src_hex[src_cur++] & 0x0f); 18355cd0b38SDmitri Tikhonov } 18455cd0b38SDmitri Tikhonov dst_char[dst_cur++] = '\0'; 18555cd0b38SDmitri Tikhonov return dst_cur; 18655cd0b38SDmitri Tikhonov} 18755cd0b38SDmitri Tikhonov 18855cd0b38SDmitri Tikhonov 1895392f7a3SLiteSpeed Techvoid 1905392f7a3SLiteSpeed Techlsquic_hexstr (const unsigned char *buf, size_t bufsz, char *out, size_t outsz) 1915392f7a3SLiteSpeed Tech{ 1925392f7a3SLiteSpeed Tech static const char b2c[16] = "0123456789ABCDEF"; 1935392f7a3SLiteSpeed Tech const unsigned char *const end_input = buf + bufsz; 1945392f7a3SLiteSpeed Tech char *const end_output = out + outsz; 1955392f7a3SLiteSpeed Tech 1965392f7a3SLiteSpeed Tech while (buf < end_input && out + 2 < end_output) 1975392f7a3SLiteSpeed Tech { 1985392f7a3SLiteSpeed Tech *out++ = b2c[ *buf >> 4 ]; 1995392f7a3SLiteSpeed Tech *out++ = b2c[ *buf & 0xF ]; 2005392f7a3SLiteSpeed Tech ++buf; 2015392f7a3SLiteSpeed Tech } 2025392f7a3SLiteSpeed Tech 2035392f7a3SLiteSpeed Tech if (buf < end_input) 2045392f7a3SLiteSpeed Tech out[-1] = '!'; 2055392f7a3SLiteSpeed Tech 2065392f7a3SLiteSpeed Tech *out = '\0'; 2075392f7a3SLiteSpeed Tech} 2085392f7a3SLiteSpeed Tech 2095392f7a3SLiteSpeed Tech 21050aadb33SDmitri Tikhonovsize_t 2115392f7a3SLiteSpeed Techlsquic_hexdump (const void *src_void, size_t src_sz, char *out, size_t out_sz) 21250aadb33SDmitri Tikhonov{ 21350aadb33SDmitri Tikhonov/* Ruler: 21450aadb33SDmitri Tikhonov * 21550aadb33SDmitri Tikhonov 6 31 57 73 21650aadb33SDmitri Tikhonov | | | | 21750aadb33SDmitri Tikhonov0000 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F |................| 21850aadb33SDmitri Tikhonov * 21950aadb33SDmitri Tikhonov */ 22050aadb33SDmitri Tikhonov#define LINE_SIZE (74 + 1 /* newline */) 22150aadb33SDmitri Tikhonov const unsigned char *src = src_void; 22250aadb33SDmitri Tikhonov const unsigned char *const src_end = src + src_sz; 22350aadb33SDmitri Tikhonov char *const out_end = out + out_sz; 22450aadb33SDmitri Tikhonov unsigned line = 0; 22550aadb33SDmitri Tikhonov 22650aadb33SDmitri Tikhonov while (src < src_end && out_end - out >= LINE_SIZE) 22750aadb33SDmitri Tikhonov { 22850aadb33SDmitri Tikhonov const unsigned char *limit = src + 16; 22950aadb33SDmitri Tikhonov if (limit > src_end) 23050aadb33SDmitri Tikhonov limit = src_end; 23150aadb33SDmitri Tikhonov unsigned hex_off = 6; 23250aadb33SDmitri Tikhonov unsigned alpha_off = 57; 2335392f7a3SLiteSpeed Tech sprintf(out, "%03X0", line++); 23450aadb33SDmitri Tikhonov out[4] = ' '; 23550aadb33SDmitri Tikhonov out[5] = ' '; 23650aadb33SDmitri Tikhonov while (src < limit) 23750aadb33SDmitri Tikhonov { 23850aadb33SDmitri Tikhonov sprintf(out + hex_off, "%02X ", *src); 23950aadb33SDmitri Tikhonov sprintf(out + alpha_off, "%c", isprint(*src) ? *src : '.'); 24050aadb33SDmitri Tikhonov hex_off += 3; 24150aadb33SDmitri Tikhonov out[hex_off] = ' '; 24250aadb33SDmitri Tikhonov hex_off += 30 == hex_off; 24350aadb33SDmitri Tikhonov out[hex_off] = ' '; 24450aadb33SDmitri Tikhonov ++alpha_off; 24550aadb33SDmitri Tikhonov out[alpha_off] = ' '; 24650aadb33SDmitri Tikhonov ++src; 24750aadb33SDmitri Tikhonov } 24850aadb33SDmitri Tikhonov memset(out + hex_off, ' ', 56 - hex_off); 24950aadb33SDmitri Tikhonov memset(out + alpha_off, '.', 73 - alpha_off); 25050aadb33SDmitri Tikhonov out[56] = '|'; 25150aadb33SDmitri Tikhonov out[73] = '|'; 25250aadb33SDmitri Tikhonov out[74] = '\n'; 25350aadb33SDmitri Tikhonov out += LINE_SIZE; 25450aadb33SDmitri Tikhonov } 25550aadb33SDmitri Tikhonov 25650aadb33SDmitri Tikhonov if (out < out_end) 25750aadb33SDmitri Tikhonov *out = '\0'; 25850aadb33SDmitri Tikhonov else 25950aadb33SDmitri Tikhonov out_end[-1] = '\0'; 26050aadb33SDmitri Tikhonov 26150aadb33SDmitri Tikhonov return out + out_sz - out_end; 26250aadb33SDmitri Tikhonov} 2638c1565cbSDmitri Tikhonov 2648c1565cbSDmitri Tikhonov 2658c1565cbSDmitri Tikhonov/* Returns true if socket addresses are equal, false otherwise. Only 2668c1565cbSDmitri Tikhonov * families, IP addresses, and ports are compared. 2678c1565cbSDmitri Tikhonov */ 2688c1565cbSDmitri Tikhonovint 2698c1565cbSDmitri Tikhonovlsquic_sockaddr_eq (const struct sockaddr *a, const struct sockaddr *b) 2708c1565cbSDmitri Tikhonov{ 2718c1565cbSDmitri Tikhonov if (a->sa_family == AF_INET) 2728c1565cbSDmitri Tikhonov return a->sa_family == b->sa_family 2738c1565cbSDmitri Tikhonov && ((struct sockaddr_in *) a)->sin_addr.s_addr 2748c1565cbSDmitri Tikhonov == ((struct sockaddr_in *) b)->sin_addr.s_addr 2758c1565cbSDmitri Tikhonov && ((struct sockaddr_in *) a)->sin_port 2768c1565cbSDmitri Tikhonov == ((struct sockaddr_in *) b)->sin_port; 2778c1565cbSDmitri Tikhonov else 2788c1565cbSDmitri Tikhonov return a->sa_family == b->sa_family 2798c1565cbSDmitri Tikhonov && ((struct sockaddr_in6 *) a)->sin6_port == 2808c1565cbSDmitri Tikhonov ((struct sockaddr_in6 *) b)->sin6_port 2818c1565cbSDmitri Tikhonov && 0 == memcmp(&((struct sockaddr_in6 *) a)->sin6_addr, 2828c1565cbSDmitri Tikhonov &((struct sockaddr_in6 *) b)->sin6_addr, 2838c1565cbSDmitri Tikhonov sizeof(((struct sockaddr_in6 *) b)->sin6_addr)); 2848c1565cbSDmitri Tikhonov} 285f2a7fa84SDmitri Tikhonov 286f2a7fa84SDmitri Tikhonov 287f2a7fa84SDmitri Tikhonovvoid 288f2a7fa84SDmitri Tikhonovlsquic_sockaddr2str (const struct sockaddr *addr, char *buf, size_t sz) 289f2a7fa84SDmitri Tikhonov{ 290f2a7fa84SDmitri Tikhonov unsigned short port; 291f2a7fa84SDmitri Tikhonov int len; 292f2a7fa84SDmitri Tikhonov 293f2a7fa84SDmitri Tikhonov switch (addr->sa_family) 294f2a7fa84SDmitri Tikhonov { 295f2a7fa84SDmitri Tikhonov case AF_INET: 296f2a7fa84SDmitri Tikhonov port = ntohs(((struct sockaddr_in *) addr)->sin_port); 297f2a7fa84SDmitri Tikhonov if (!inet_ntop(AF_INET, &((struct sockaddr_in *) addr)->sin_addr, 298f2a7fa84SDmitri Tikhonov buf, sz)) 299f2a7fa84SDmitri Tikhonov buf[0] = '\0'; 300f2a7fa84SDmitri Tikhonov break; 301f2a7fa84SDmitri Tikhonov case AF_INET6: 302f2a7fa84SDmitri Tikhonov port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port); 303f2a7fa84SDmitri Tikhonov if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *) addr)->sin6_addr, 304f2a7fa84SDmitri Tikhonov buf, sz)) 305f2a7fa84SDmitri Tikhonov buf[0] = '\0'; 306f2a7fa84SDmitri Tikhonov break; 307f2a7fa84SDmitri Tikhonov default: 308f2a7fa84SDmitri Tikhonov port = 0; 309f2a7fa84SDmitri Tikhonov (void) snprintf(buf, sz, "<invalid family %d>", addr->sa_family); 310f2a7fa84SDmitri Tikhonov break; 311f2a7fa84SDmitri Tikhonov } 312f2a7fa84SDmitri Tikhonov 313f2a7fa84SDmitri Tikhonov len = strlen(buf); 314f2a7fa84SDmitri Tikhonov if (len < (int) sz) 315f2a7fa84SDmitri Tikhonov snprintf(buf + len, sz - (size_t) len, ":%hu", port); 316f2a7fa84SDmitri Tikhonov} 317a500a209SDmitri Tikhonov 318a500a209SDmitri Tikhonov 319a500a209SDmitri Tikhonov#ifdef _MSC_VER 320a500a209SDmitri Tikhonovchar * 321a500a209SDmitri Tikhonovlsquic_strndup (const char *s, size_t n) 322a500a209SDmitri Tikhonov{ 323a500a209SDmitri Tikhonov size_t len; 324a500a209SDmitri Tikhonov char *copy; 325a500a209SDmitri Tikhonov 326a500a209SDmitri Tikhonov len = strnlen(s, n); 327a500a209SDmitri Tikhonov copy = malloc(n + 1); 328a500a209SDmitri Tikhonov if (copy) 329a500a209SDmitri Tikhonov { 330a500a209SDmitri Tikhonov memcpy(copy, s, len); 331a500a209SDmitri Tikhonov copy[len] = '\0'; 332a500a209SDmitri Tikhonov } 333a500a209SDmitri Tikhonov 334a500a209SDmitri Tikhonov return copy; 335a500a209SDmitri Tikhonov} 336a500a209SDmitri Tikhonov#endif 337