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