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