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