lsquic_util.c revision 83287402
1/* Copyright (c) 2017 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 <sys/time.h>
11#include <time.h>
12#include <unistd.h>
13
14#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__)
15#include <mach/mach_time.h>
16#endif
17
18#include "lsquic_int_types.h"
19#include "lsquic_util.h"
20
21
22#if defined(__APPLE__)
23static mach_timebase_info_data_t timebase;
24#endif
25
26void
27lsquic_init_timers (void)
28{
29#if defined(__APPLE__)
30    mach_timebase_info(&timebase);
31#endif
32}
33
34
35lsquic_time_t
36lsquic_time_now (void)
37{
38#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
39    struct timespec ts;
40    (void) clock_gettime(CLOCK_MONOTONIC, &ts);
41    return (lsquic_time_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
42#elif defined(__APPLE__)
43    lsquic_time_t t = mach_absolute_time();
44    t *= timebase.numer;
45    t /= timebase.denom;
46    t /= 1000;
47    return t;
48#else
49#   warn Monotonically increasing clock is not available on this platform
50    struct timeval tv;
51    (void) gettimeofday(&tv, NULL);
52    return (lsquic_time_t) tv.tv_sec * 1000000 + tv.tv_usec;
53#endif
54}
55
56
57int
58lsquic_is_zero (const void *pbuf, size_t bufsz)
59{
60    const unsigned char *buf, *end;
61    const unsigned long *buf_ul;
62    unsigned n_ul;
63    unsigned long n_non_zero;
64
65    buf = pbuf;
66    end = buf + bufsz;
67    buf_ul = (unsigned long *) buf;
68    n_ul = bufsz / sizeof(buf_ul[0]);
69    buf += n_ul * sizeof(buf_ul[0]);
70    n_non_zero = 0;
71
72    while (n_ul--)
73        n_non_zero |= buf_ul[n_ul];
74
75    while (buf < end)
76        n_non_zero |= *buf++;
77
78    return n_non_zero == 0;
79}
80
81
82/* XXX this function uses static buffer.  Replace it with hexdump() if possible */
83char *get_bin_str(const void *s, size_t len, size_t max_display_len)
84{
85    const unsigned char *p, *pEnd;
86    char *pOutput;
87    size_t lenOrg = len;
88    static char str[512 * 2 + 40] = {0};
89
90    /**
91     * We alloc fixed size buffer, at most max_display_len is 512
92     */
93    size_t fit_display_len = (max_display_len > 512 ? 512 : max_display_len);
94    if (len > fit_display_len)
95        len = fit_display_len;
96
97    pOutput = &str[0] + sprintf(str, "(%zd/%zd)=0x", len, lenOrg);
98
99    for(p = s, pEnd = s + len; p < pEnd; ++p)
100    {
101        sprintf(pOutput, "%02X", *p);
102        pOutput += 2;
103    }
104    if (lenOrg > len)
105    {
106        sprintf(pOutput, "...");
107        pOutput += 3;
108    }
109    return str;
110}
111
112
113size_t
114hexdump (const void *src_void, size_t src_sz, char *out, size_t out_sz)
115{
116/* Ruler:
117 *
118      6                       31                        57              73
119      |                        |                         |               |
1200000  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F  |................|
121 *
122 */
123#define LINE_SIZE (74 + 1 /* newline */)
124    const unsigned char       *src     = src_void;
125    const unsigned char *const src_end = src + src_sz;
126    char *const                out_end = out + out_sz;
127    unsigned line = 0;
128
129    while (src < src_end && out_end - out >= LINE_SIZE)
130    {
131        const unsigned char *limit = src + 16;
132        if (limit > src_end)
133            limit = src_end;
134        unsigned hex_off   = 6;
135        unsigned alpha_off = 57;
136        sprintf(out, "%04x", line++);
137        out[4] = ' ';
138        out[5] = ' ';
139        while (src < limit)
140        {
141            sprintf(out + hex_off, "%02X ", *src);
142            sprintf(out + alpha_off, "%c", isprint(*src) ? *src : '.');
143            hex_off += 3;
144            out[hex_off] = ' ';
145            hex_off += 30 == hex_off;
146            out[hex_off] = ' ';
147            ++alpha_off;
148            out[alpha_off] = ' ';
149            ++src;
150        }
151        memset(out + hex_off,   ' ', 56 - hex_off);
152        memset(out + alpha_off, '.', 73 - alpha_off);
153        out[56] = '|';
154        out[73] = '|';
155        out[74] = '\n';
156        out += LINE_SIZE;
157    }
158
159    if (out < out_end)
160        *out = '\0';
161    else
162        out_end[-1] = '\0';
163
164    return out + out_sz - out_end;
165}
166