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