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