lsquic_util.c revision 5392f7a3
1/* Copyright (c) 2017 - 2019 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