1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov/*
350aadb33SDmitri Tikhonov * Utility functions
450aadb33SDmitri Tikhonov */
550aadb33SDmitri Tikhonov
650aadb33SDmitri Tikhonov#include <ctype.h>
750aadb33SDmitri Tikhonov#include <stdint.h>
850aadb33SDmitri Tikhonov#include <stdio.h>
9a500a209SDmitri Tikhonov#include <stdlib.h>
1050aadb33SDmitri Tikhonov#include <string.h>
1183287402SDmitri Tikhonov#include <time.h>
12461e84d8SAmol Deshpande#ifndef WIN32
13fb3e20e0SDmitri Tikhonov#include <netinet/in.h>
14fb3e20e0SDmitri Tikhonov#include <arpa/inet.h>
15fb3e20e0SDmitri Tikhonov#include <sys/socket.h>
16461e84d8SAmol Deshpande#include <sys/time.h>
1783287402SDmitri Tikhonov#include <unistd.h>
18461e84d8SAmol Deshpande#else
19461e84d8SAmol Deshpande#include <vc_compat.h>
20fb3e20e0SDmitri Tikhonov#include <ws2tcpip.h>
21461e84d8SAmol Deshpande#endif
2283287402SDmitri Tikhonov
2383287402SDmitri Tikhonov#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__)
2483287402SDmitri Tikhonov#include <mach/mach_time.h>
2583287402SDmitri Tikhonov#endif
2650aadb33SDmitri Tikhonov
2750aadb33SDmitri Tikhonov#include "lsquic_int_types.h"
2850aadb33SDmitri Tikhonov#include "lsquic_util.h"
295392f7a3SLiteSpeed Tech#if LSQUIC_COUNT_TIME_CALLS
305392f7a3SLiteSpeed Tech#include <stdlib.h>
315392f7a3SLiteSpeed Tech#include "lsquic_types.h"
325392f7a3SLiteSpeed Tech#include "lsquic_logger.h"
335392f7a3SLiteSpeed Tech#endif
3450aadb33SDmitri Tikhonov
3550aadb33SDmitri Tikhonov
3683287402SDmitri Tikhonov#if defined(__APPLE__)
3783287402SDmitri Tikhonovstatic mach_timebase_info_data_t timebase;
3883287402SDmitri Tikhonov#endif
39461e84d8SAmol Deshpande#if defined(WIN32)
40461e84d8SAmol Deshpandestatic LARGE_INTEGER perf_frequency;
41461e84d8SAmol Deshpande#endif
4283287402SDmitri Tikhonov
435392f7a3SLiteSpeed Tech
445392f7a3SLiteSpeed Tech#if LSQUIC_COUNT_TIME_CALLS
455392f7a3SLiteSpeed Techstatic volatile unsigned long n_time_now_calls;
465392f7a3SLiteSpeed Tech
475392f7a3SLiteSpeed Tech
485392f7a3SLiteSpeed Techstatic void
495392f7a3SLiteSpeed Techprint_call_stats (void)
505392f7a3SLiteSpeed Tech{
515392f7a3SLiteSpeed Tech    LSQ_NOTICE("number of lsquic_time_now() calls: %lu", n_time_now_calls);
525392f7a3SLiteSpeed Tech}
535392f7a3SLiteSpeed Tech#endif
545392f7a3SLiteSpeed Tech
555392f7a3SLiteSpeed Tech
5683287402SDmitri Tikhonovvoid
5783287402SDmitri Tikhonovlsquic_init_timers (void)
5883287402SDmitri Tikhonov{
595392f7a3SLiteSpeed Tech#if LSQUIC_COUNT_TIME_CALLS
605392f7a3SLiteSpeed Tech    atexit(print_call_stats);
615392f7a3SLiteSpeed Tech#endif
6283287402SDmitri Tikhonov#if defined(__APPLE__)
6383287402SDmitri Tikhonov    mach_timebase_info(&timebase);
6483287402SDmitri Tikhonov#endif
65461e84d8SAmol Deshpande#if defined(WIN32)
66461e84d8SAmol Deshpande    QueryPerformanceFrequency(&perf_frequency);
67461e84d8SAmol Deshpande#endif
6883287402SDmitri Tikhonov}
6983287402SDmitri Tikhonov
7083287402SDmitri Tikhonov
7150aadb33SDmitri Tikhonovlsquic_time_t
7250aadb33SDmitri Tikhonovlsquic_time_now (void)
7350aadb33SDmitri Tikhonov{
745392f7a3SLiteSpeed Tech#if LSQUIC_COUNT_TIME_CALLS
755392f7a3SLiteSpeed Tech    ++n_time_now_calls;
765392f7a3SLiteSpeed Tech#endif
7783287402SDmitri Tikhonov#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
7883287402SDmitri Tikhonov    struct timespec ts;
7983287402SDmitri Tikhonov    (void) clock_gettime(CLOCK_MONOTONIC, &ts);
8083287402SDmitri Tikhonov    return (lsquic_time_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
8183287402SDmitri Tikhonov#elif defined(__APPLE__)
8283287402SDmitri Tikhonov    lsquic_time_t t = mach_absolute_time();
8383287402SDmitri Tikhonov    t *= timebase.numer;
8483287402SDmitri Tikhonov    t /= timebase.denom;
8583287402SDmitri Tikhonov    t /= 1000;
8683287402SDmitri Tikhonov    return t;
87461e84d8SAmol Deshpande#elif defined(WIN32)
88461e84d8SAmol Deshpande    LARGE_INTEGER counter;
89461e84d8SAmol Deshpande    lsquic_time_t t;
90461e84d8SAmol Deshpande    QueryPerformanceCounter(&counter);
91461e84d8SAmol Deshpande    t = counter.QuadPart;
92461e84d8SAmol Deshpande    t *= 1000000;
93461e84d8SAmol Deshpande    t /= perf_frequency.QuadPart;
94461e84d8SAmol Deshpande    return t;
9583287402SDmitri Tikhonov#else
9683287402SDmitri Tikhonov#   warn Monotonically increasing clock is not available on this platform
9750aadb33SDmitri Tikhonov    struct timeval tv;
9850aadb33SDmitri Tikhonov    (void) gettimeofday(&tv, NULL);
9950aadb33SDmitri Tikhonov    return (lsquic_time_t) tv.tv_sec * 1000000 + tv.tv_usec;
10083287402SDmitri Tikhonov#endif
10150aadb33SDmitri Tikhonov}
10250aadb33SDmitri Tikhonov
10350aadb33SDmitri Tikhonov
10450aadb33SDmitri Tikhonovint
10550aadb33SDmitri Tikhonovlsquic_is_zero (const void *pbuf, size_t bufsz)
10650aadb33SDmitri Tikhonov{
10750aadb33SDmitri Tikhonov    const unsigned char *buf, *end;
10850aadb33SDmitri Tikhonov    const unsigned long *buf_ul;
10950aadb33SDmitri Tikhonov    unsigned n_ul;
11050aadb33SDmitri Tikhonov    unsigned long n_non_zero;
11150aadb33SDmitri Tikhonov
11250aadb33SDmitri Tikhonov    buf = pbuf;
11350aadb33SDmitri Tikhonov    end = buf + bufsz;
11450aadb33SDmitri Tikhonov    buf_ul = (unsigned long *) buf;
11550aadb33SDmitri Tikhonov    n_ul = bufsz / sizeof(buf_ul[0]);
11650aadb33SDmitri Tikhonov    buf += n_ul * sizeof(buf_ul[0]);
11750aadb33SDmitri Tikhonov    n_non_zero = 0;
11850aadb33SDmitri Tikhonov
11950aadb33SDmitri Tikhonov    while (n_ul--)
12050aadb33SDmitri Tikhonov        n_non_zero |= buf_ul[n_ul];
12150aadb33SDmitri Tikhonov
12250aadb33SDmitri Tikhonov    while (buf < end)
12350aadb33SDmitri Tikhonov        n_non_zero |= *buf++;
12450aadb33SDmitri Tikhonov
12550aadb33SDmitri Tikhonov    return n_non_zero == 0;
12650aadb33SDmitri Tikhonov}
12750aadb33SDmitri Tikhonov
12850aadb33SDmitri Tikhonov
1295392f7a3SLiteSpeed Tech/* XXX this function uses static buffer.  Replace it with lsquic_hexdump() if possible */
130a5fa05f9SDmitri Tikhonovchar *
131a5fa05f9SDmitri Tikhonovlsquic_get_bin_str (const void *s, size_t len, size_t max_display_len)
13250aadb33SDmitri Tikhonov{
13350aadb33SDmitri Tikhonov    const unsigned char *p, *pEnd;
13450aadb33SDmitri Tikhonov    char *pOutput;
13550aadb33SDmitri Tikhonov    size_t lenOrg = len;
13650aadb33SDmitri Tikhonov    static char str[512 * 2 + 40] = {0};
13750aadb33SDmitri Tikhonov
13850aadb33SDmitri Tikhonov    /**
13950aadb33SDmitri Tikhonov     * We alloc fixed size buffer, at most max_display_len is 512
14050aadb33SDmitri Tikhonov     */
14150aadb33SDmitri Tikhonov    size_t fit_display_len = (max_display_len > 512 ? 512 : max_display_len);
14250aadb33SDmitri Tikhonov    if (len > fit_display_len)
14350aadb33SDmitri Tikhonov        len = fit_display_len;
14450aadb33SDmitri Tikhonov
14550aadb33SDmitri Tikhonov    pOutput = &str[0] + sprintf(str, "(%zd/%zd)=0x", len, lenOrg);
14650aadb33SDmitri Tikhonov
147461e84d8SAmol Deshpande    for(p = s, pEnd = (unsigned char*)s + len; p < pEnd; ++p)
14850aadb33SDmitri Tikhonov    {
14950aadb33SDmitri Tikhonov        sprintf(pOutput, "%02X", *p);
15050aadb33SDmitri Tikhonov        pOutput += 2;
15150aadb33SDmitri Tikhonov    }
15250aadb33SDmitri Tikhonov    if (lenOrg > len)
15350aadb33SDmitri Tikhonov    {
15450aadb33SDmitri Tikhonov        sprintf(pOutput, "...");
15550aadb33SDmitri Tikhonov        pOutput += 3;
15650aadb33SDmitri Tikhonov    }
15750aadb33SDmitri Tikhonov    return str;
15850aadb33SDmitri Tikhonov}
15950aadb33SDmitri Tikhonov
16050aadb33SDmitri Tikhonov
16155cd0b38SDmitri Tikhonovstatic char
16255cd0b38SDmitri Tikhonovhex_digit(uint8_t n)
16355cd0b38SDmitri Tikhonov{
16455cd0b38SDmitri Tikhonov    return (n < 10) ? (n + '0') : ((n - 10) + 'a');
16555cd0b38SDmitri Tikhonov}
16655cd0b38SDmitri Tikhonov
16755cd0b38SDmitri Tikhonov
16855cd0b38SDmitri Tikhonovsize_t
16955cd0b38SDmitri Tikhonovlsquic_hex_encode (const void *src, size_t src_sz, void *dst, size_t dst_sz)
17055cd0b38SDmitri Tikhonov{
17155cd0b38SDmitri Tikhonov    size_t src_cur, dst_cur;
17255cd0b38SDmitri Tikhonov    const uint8_t *src_hex;
17355cd0b38SDmitri Tikhonov    char *dst_char;
17455cd0b38SDmitri Tikhonov
17555cd0b38SDmitri Tikhonov    src_hex = (const uint8_t *)src;
17655cd0b38SDmitri Tikhonov    dst_char = (char *)dst;
17755cd0b38SDmitri Tikhonov    src_cur = dst_cur = 0;
17855cd0b38SDmitri Tikhonov
17955cd0b38SDmitri Tikhonov    while (src_cur < src_sz && dst_cur < (dst_sz - 2))
18055cd0b38SDmitri Tikhonov    {
18155cd0b38SDmitri Tikhonov        dst_char[dst_cur++] = hex_digit((src_hex[src_cur] & 0xf0) >> 4);
18255cd0b38SDmitri Tikhonov        dst_char[dst_cur++] = hex_digit(src_hex[src_cur++] & 0x0f);
18355cd0b38SDmitri Tikhonov    }
18455cd0b38SDmitri Tikhonov    dst_char[dst_cur++] = '\0';
18555cd0b38SDmitri Tikhonov    return dst_cur;
18655cd0b38SDmitri Tikhonov}
18755cd0b38SDmitri Tikhonov
18855cd0b38SDmitri Tikhonov
1895392f7a3SLiteSpeed Techvoid
1905392f7a3SLiteSpeed Techlsquic_hexstr (const unsigned char *buf, size_t bufsz, char *out, size_t outsz)
1915392f7a3SLiteSpeed Tech{
1925392f7a3SLiteSpeed Tech    static const char b2c[16] = "0123456789ABCDEF";
1935392f7a3SLiteSpeed Tech    const unsigned char *const end_input = buf + bufsz;
1945392f7a3SLiteSpeed Tech    char *const end_output = out + outsz;
1955392f7a3SLiteSpeed Tech
1965392f7a3SLiteSpeed Tech    while (buf < end_input && out + 2 < end_output)
1975392f7a3SLiteSpeed Tech    {
1985392f7a3SLiteSpeed Tech        *out++ = b2c[ *buf >> 4 ];
1995392f7a3SLiteSpeed Tech        *out++ = b2c[ *buf & 0xF ];
2005392f7a3SLiteSpeed Tech        ++buf;
2015392f7a3SLiteSpeed Tech    }
2025392f7a3SLiteSpeed Tech
2035392f7a3SLiteSpeed Tech    if (buf < end_input)
2045392f7a3SLiteSpeed Tech        out[-1] = '!';
2055392f7a3SLiteSpeed Tech
2065392f7a3SLiteSpeed Tech    *out = '\0';
2075392f7a3SLiteSpeed Tech}
2085392f7a3SLiteSpeed Tech
2095392f7a3SLiteSpeed Tech
21050aadb33SDmitri Tikhonovsize_t
2115392f7a3SLiteSpeed Techlsquic_hexdump (const void *src_void, size_t src_sz, char *out, size_t out_sz)
21250aadb33SDmitri Tikhonov{
21350aadb33SDmitri Tikhonov/* Ruler:
21450aadb33SDmitri Tikhonov *
21550aadb33SDmitri Tikhonov      6                       31                        57              73
21650aadb33SDmitri Tikhonov      |                        |                         |               |
21750aadb33SDmitri Tikhonov0000  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F  |................|
21850aadb33SDmitri Tikhonov *
21950aadb33SDmitri Tikhonov */
22050aadb33SDmitri Tikhonov#define LINE_SIZE (74 + 1 /* newline */)
22150aadb33SDmitri Tikhonov    const unsigned char       *src     = src_void;
22250aadb33SDmitri Tikhonov    const unsigned char *const src_end = src + src_sz;
22350aadb33SDmitri Tikhonov    char *const                out_end = out + out_sz;
22450aadb33SDmitri Tikhonov    unsigned line = 0;
22550aadb33SDmitri Tikhonov
22650aadb33SDmitri Tikhonov    while (src < src_end && out_end - out >= LINE_SIZE)
22750aadb33SDmitri Tikhonov    {
22850aadb33SDmitri Tikhonov        const unsigned char *limit = src + 16;
22950aadb33SDmitri Tikhonov        if (limit > src_end)
23050aadb33SDmitri Tikhonov            limit = src_end;
23150aadb33SDmitri Tikhonov        unsigned hex_off   = 6;
23250aadb33SDmitri Tikhonov        unsigned alpha_off = 57;
2335392f7a3SLiteSpeed Tech        sprintf(out, "%03X0", line++);
23450aadb33SDmitri Tikhonov        out[4] = ' ';
23550aadb33SDmitri Tikhonov        out[5] = ' ';
23650aadb33SDmitri Tikhonov        while (src < limit)
23750aadb33SDmitri Tikhonov        {
23850aadb33SDmitri Tikhonov            sprintf(out + hex_off, "%02X ", *src);
23950aadb33SDmitri Tikhonov            sprintf(out + alpha_off, "%c", isprint(*src) ? *src : '.');
24050aadb33SDmitri Tikhonov            hex_off += 3;
24150aadb33SDmitri Tikhonov            out[hex_off] = ' ';
24250aadb33SDmitri Tikhonov            hex_off += 30 == hex_off;
24350aadb33SDmitri Tikhonov            out[hex_off] = ' ';
24450aadb33SDmitri Tikhonov            ++alpha_off;
24550aadb33SDmitri Tikhonov            out[alpha_off] = ' ';
24650aadb33SDmitri Tikhonov            ++src;
24750aadb33SDmitri Tikhonov        }
24850aadb33SDmitri Tikhonov        memset(out + hex_off,   ' ', 56 - hex_off);
24950aadb33SDmitri Tikhonov        memset(out + alpha_off, '.', 73 - alpha_off);
25050aadb33SDmitri Tikhonov        out[56] = '|';
25150aadb33SDmitri Tikhonov        out[73] = '|';
25250aadb33SDmitri Tikhonov        out[74] = '\n';
25350aadb33SDmitri Tikhonov        out += LINE_SIZE;
25450aadb33SDmitri Tikhonov    }
25550aadb33SDmitri Tikhonov
25650aadb33SDmitri Tikhonov    if (out < out_end)
25750aadb33SDmitri Tikhonov        *out = '\0';
25850aadb33SDmitri Tikhonov    else
25950aadb33SDmitri Tikhonov        out_end[-1] = '\0';
26050aadb33SDmitri Tikhonov
26150aadb33SDmitri Tikhonov    return out + out_sz - out_end;
26250aadb33SDmitri Tikhonov}
2638c1565cbSDmitri Tikhonov
2648c1565cbSDmitri Tikhonov
2658c1565cbSDmitri Tikhonov/* Returns true if socket addresses are equal, false otherwise.  Only
2668c1565cbSDmitri Tikhonov * families, IP addresses, and ports are compared.
2678c1565cbSDmitri Tikhonov */
2688c1565cbSDmitri Tikhonovint
2698c1565cbSDmitri Tikhonovlsquic_sockaddr_eq (const struct sockaddr *a, const struct sockaddr *b)
2708c1565cbSDmitri Tikhonov{
2718c1565cbSDmitri Tikhonov    if (a->sa_family == AF_INET)
2728c1565cbSDmitri Tikhonov        return a->sa_family == b->sa_family
2738c1565cbSDmitri Tikhonov            && ((struct sockaddr_in *) a)->sin_addr.s_addr
2748c1565cbSDmitri Tikhonov                            == ((struct sockaddr_in *) b)->sin_addr.s_addr
2758c1565cbSDmitri Tikhonov            && ((struct sockaddr_in *) a)->sin_port
2768c1565cbSDmitri Tikhonov                            == ((struct sockaddr_in *) b)->sin_port;
2778c1565cbSDmitri Tikhonov    else
2788c1565cbSDmitri Tikhonov        return a->sa_family == b->sa_family
2798c1565cbSDmitri Tikhonov            && ((struct sockaddr_in6 *) a)->sin6_port ==
2808c1565cbSDmitri Tikhonov                                ((struct sockaddr_in6 *) b)->sin6_port
2818c1565cbSDmitri Tikhonov            && 0 == memcmp(&((struct sockaddr_in6 *) a)->sin6_addr,
2828c1565cbSDmitri Tikhonov                            &((struct sockaddr_in6 *) b)->sin6_addr,
2838c1565cbSDmitri Tikhonov                            sizeof(((struct sockaddr_in6 *) b)->sin6_addr));
2848c1565cbSDmitri Tikhonov}
285f2a7fa84SDmitri Tikhonov
286f2a7fa84SDmitri Tikhonov
287f2a7fa84SDmitri Tikhonovvoid
288f2a7fa84SDmitri Tikhonovlsquic_sockaddr2str (const struct sockaddr *addr, char *buf, size_t sz)
289f2a7fa84SDmitri Tikhonov{
290f2a7fa84SDmitri Tikhonov    unsigned short port;
291f2a7fa84SDmitri Tikhonov    int len;
292f2a7fa84SDmitri Tikhonov
293f2a7fa84SDmitri Tikhonov    switch (addr->sa_family)
294f2a7fa84SDmitri Tikhonov    {
295f2a7fa84SDmitri Tikhonov    case AF_INET:
296f2a7fa84SDmitri Tikhonov        port = ntohs(((struct sockaddr_in *) addr)->sin_port);
297f2a7fa84SDmitri Tikhonov        if (!inet_ntop(AF_INET, &((struct sockaddr_in *) addr)->sin_addr,
298f2a7fa84SDmitri Tikhonov                                                                    buf, sz))
299f2a7fa84SDmitri Tikhonov            buf[0] = '\0';
300f2a7fa84SDmitri Tikhonov        break;
301f2a7fa84SDmitri Tikhonov    case AF_INET6:
302f2a7fa84SDmitri Tikhonov        port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
303f2a7fa84SDmitri Tikhonov        if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *) addr)->sin6_addr,
304f2a7fa84SDmitri Tikhonov                                                                    buf, sz))
305f2a7fa84SDmitri Tikhonov            buf[0] = '\0';
306f2a7fa84SDmitri Tikhonov        break;
307f2a7fa84SDmitri Tikhonov    default:
308f2a7fa84SDmitri Tikhonov        port = 0;
309f2a7fa84SDmitri Tikhonov        (void) snprintf(buf, sz, "<invalid family %d>", addr->sa_family);
310f2a7fa84SDmitri Tikhonov        break;
311f2a7fa84SDmitri Tikhonov    }
312f2a7fa84SDmitri Tikhonov
313f2a7fa84SDmitri Tikhonov    len = strlen(buf);
314f2a7fa84SDmitri Tikhonov    if (len < (int) sz)
315f2a7fa84SDmitri Tikhonov        snprintf(buf + len, sz - (size_t) len, ":%hu", port);
316f2a7fa84SDmitri Tikhonov}
317a500a209SDmitri Tikhonov
318a500a209SDmitri Tikhonov
319a500a209SDmitri Tikhonov#ifdef _MSC_VER
320a500a209SDmitri Tikhonovchar *
321a500a209SDmitri Tikhonovlsquic_strndup (const char *s, size_t n)
322a500a209SDmitri Tikhonov{
323a500a209SDmitri Tikhonov    size_t len;
324a500a209SDmitri Tikhonov    char *copy;
325a500a209SDmitri Tikhonov
326a500a209SDmitri Tikhonov    len = strnlen(s, n);
327a500a209SDmitri Tikhonov    copy = malloc(n + 1);
328a500a209SDmitri Tikhonov    if (copy)
329a500a209SDmitri Tikhonov    {
330a500a209SDmitri Tikhonov        memcpy(copy, s, len);
331a500a209SDmitri Tikhonov        copy[len] = '\0';
332a500a209SDmitri Tikhonov    }
333a500a209SDmitri Tikhonov
334a500a209SDmitri Tikhonov    return copy;
335a500a209SDmitri Tikhonov}
336a500a209SDmitri Tikhonov#endif
337