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