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