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