Packages
hackney
3.0.0
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Retired package: Release invalid - Use 3.0.1 instead
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/lsquic/src/liblsquic/lsquic_logger.c
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
/*
* LSQUIC Logger implementation.
*/
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <sys/time.h>
#endif
#include <time.h>
#define LSQUIC_LOGGER_MODULE LSQLM_LOGGER /* Quis custodiet ipsos custodes? */
#include "lsquic.h"
#include "lsquic_logger.h"
#define MAX_LINE_LEN 8192
/* Expanded TRUNC_FMT should not exceed TRUNC_SZ bytes. At the same time,
* TRUNC_SZ should be significantly smaller than MAX_LINE_LEN.
*/
#define TRUNC_FMT "<truncated, need %d bytes>"
#define TRUNC_SZ 40
#define FORMAT_PROBLEM(lb, len, max) ((lb < 0) || (lb + len >= max))
/* TODO: display GQUIC CIDs in Chrome-compatible format */
static enum lsquic_logger_timestamp_style g_llts = LLTS_NONE;
static int
null_log_buf (void *ctx, const char *buf, size_t len)
{
return 0;
}
static int
file_log_buf (void *ctx, const char *buf, size_t len)
{
return (int)fwrite(buf, sizeof(char), len, (FILE *) ctx);
}
static const struct lsquic_logger_if file_logger_if = {
.log_buf = file_log_buf,
};
static const struct lsquic_logger_if null_logger_if = {
.log_buf = null_log_buf,
};
static void *logger_ctx = NULL;
static const struct lsquic_logger_if *logger_if = &null_logger_if;
enum lsq_log_level lsq_log_levels[N_LSQUIC_LOGGER_MODULES] = {
[LSQLM_NOMODULE] = LSQ_LOG_WARN,
[LSQLM_LOGGER] = LSQ_LOG_WARN,
[LSQLM_EVENT] = LSQ_LOG_WARN,
[LSQLM_ENGINE] = LSQ_LOG_WARN,
[LSQLM_CONN] = LSQ_LOG_WARN,
[LSQLM_STREAM] = LSQ_LOG_WARN,
[LSQLM_PARSE] = LSQ_LOG_WARN,
[LSQLM_CFCW] = LSQ_LOG_WARN,
[LSQLM_SFCW] = LSQ_LOG_WARN,
[LSQLM_SENDCTL] = LSQ_LOG_WARN,
[LSQLM_ALARMSET] = LSQ_LOG_WARN,
[LSQLM_CRYPTO] = LSQ_LOG_WARN,
[LSQLM_HANDSHAKE] = LSQ_LOG_WARN,
[LSQLM_HSK_ADAPTER] = LSQ_LOG_WARN,
[LSQLM_BBR] = LSQ_LOG_WARN,
[LSQLM_CUBIC] = LSQ_LOG_WARN,
[LSQLM_ADAPTIVE_CC] = LSQ_LOG_WARN,
[LSQLM_HEADERS] = LSQ_LOG_WARN,
[LSQLM_FRAME_READER]= LSQ_LOG_WARN,
[LSQLM_FRAME_WRITER]= LSQ_LOG_WARN,
[LSQLM_MINI_CONN] = LSQ_LOG_WARN,
[LSQLM_TOKGEN] = LSQ_LOG_WARN,
[LSQLM_ENG_HIST] = LSQ_LOG_WARN,
[LSQLM_SPI] = LSQ_LOG_WARN,
[LSQLM_HPI] = LSQ_LOG_WARN,
[LSQLM_DI] = LSQ_LOG_WARN,
[LSQLM_PRQ] = LSQ_LOG_WARN,
[LSQLM_PACER] = LSQ_LOG_WARN,
[LSQLM_HTTP1X] = LSQ_LOG_WARN,
[LSQLM_QLOG] = LSQ_LOG_WARN,
[LSQLM_TRAPA] = LSQ_LOG_WARN,
[LSQLM_PURGA] = LSQ_LOG_WARN,
[LSQLM_HCSI_READER] = LSQ_LOG_WARN,
[LSQLM_HCSO_WRITER] = LSQ_LOG_WARN,
[LSQLM_QENC_HDL] = LSQ_LOG_WARN,
[LSQLM_QDEC_HDL] = LSQ_LOG_WARN,
[LSQLM_QPACK_ENC] = LSQ_LOG_WARN,
[LSQLM_QPACK_DEC] = LSQ_LOG_WARN,
[LSQLM_PRIO] = LSQ_LOG_WARN,
[LSQLM_BW_SAMPLER] = LSQ_LOG_WARN,
[LSQLM_PACKET_RESIZE] = LSQ_LOG_WARN,
[LSQLM_CONN_STATS] = LSQ_LOG_WARN,
};
const char *const lsqlm_to_str[N_LSQUIC_LOGGER_MODULES] = {
[LSQLM_NOMODULE] = "",
[LSQLM_LOGGER] = "logger",
[LSQLM_EVENT] = "event",
[LSQLM_ENGINE] = "engine",
[LSQLM_CONN] = "conn",
[LSQLM_STREAM] = "stream",
[LSQLM_PARSE] = "parse",
[LSQLM_CFCW] = "cfcw",
[LSQLM_SFCW] = "sfcw",
[LSQLM_SENDCTL] = "sendctl",
[LSQLM_ALARMSET] = "alarmset",
[LSQLM_CRYPTO] = "crypto",
[LSQLM_HANDSHAKE] = "handshake",
[LSQLM_HSK_ADAPTER] = "hsk-adapter",
[LSQLM_BBR] = "bbr",
[LSQLM_CUBIC] = "cubic",
[LSQLM_ADAPTIVE_CC] = "adaptive-cc",
[LSQLM_HEADERS] = "headers",
[LSQLM_FRAME_READER]= "frame-reader",
[LSQLM_FRAME_WRITER]= "frame-writer",
[LSQLM_MINI_CONN] = "mini-conn",
[LSQLM_TOKGEN] = "tokgen",
[LSQLM_ENG_HIST] = "eng-hist",
[LSQLM_SPI] = "spi",
[LSQLM_HPI] = "hpi",
[LSQLM_DI] = "di",
[LSQLM_PRQ] = "prq",
[LSQLM_PACER] = "pacer",
[LSQLM_HTTP1X] = "http1x",
[LSQLM_QLOG] = "qlog",
[LSQLM_TRAPA] = "trapa",
[LSQLM_PURGA] = "purga",
[LSQLM_HCSI_READER] = "hcsi-reader",
[LSQLM_HCSO_WRITER] = "hcso-writer",
[LSQLM_QENC_HDL] = "qenc-hdl",
[LSQLM_QDEC_HDL] = "qdec-hdl",
[LSQLM_QPACK_ENC] = "qpack-enc",
[LSQLM_QPACK_DEC] = "qpack-dec",
[LSQLM_PRIO] = "prio",
[LSQLM_BW_SAMPLER] = "bw-sampler",
[LSQLM_PACKET_RESIZE] = "packet-resize",
[LSQLM_CONN_STATS] = "conn-stats",
};
const char *const lsq_loglevel2str[N_LSQUIC_LOG_LEVELS] = {
[LSQ_LOG_ALERT] = "ALERT",
[LSQ_LOG_CRIT] = "CRIT",
[LSQ_LOG_DEBUG] = "DEBUG",
[LSQ_LOG_EMERG] = "EMERG",
[LSQ_LOG_ERROR] = "ERROR",
[LSQ_LOG_INFO] = "INFO",
[LSQ_LOG_NOTICE] = "NOTICE",
[LSQ_LOG_WARN] = "WARN",
};
#ifdef WIN32
#define DELTA_EPOCH_IN_TICKS 116444736000000000Ui64
struct timezone
{
time_t tz_minuteswest; /* minutes W of Greenwich */
time_t tz_dsttime; /* type of dst correction */
};
static int
gettimeofday (struct timeval *tv, struct timezone *tz)
{
FILETIME ft;
uint64_t tmpres;
static int tzflag;
if (NULL != tv)
{
GetSystemTimeAsFileTime(&ft);
tmpres = ((uint64_t) ft.dwHighDateTime << 32)
| (ft.dwLowDateTime);
tmpres -= DELTA_EPOCH_IN_TICKS;
tv->tv_sec = tmpres / 10000000;
tv->tv_usec = tmpres % 1000000;
}
if (NULL != tz)
{
if (!tzflag)
{
_tzset();
tzflag++;
}
tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight;
}
return 0;
}
#endif
static size_t
print_timestamp (char *buf, size_t max)
{
struct tm tm;
struct timeval tv;
size_t len = 0;
gettimeofday(&tv, NULL);
#ifdef WIN32
{
time_t t = tv.tv_sec;
#ifndef NDEBUG
errno_t e =
#endif
localtime_s(&tm, &t);
assert(!e);
}
#else
localtime_r(&tv.tv_sec, &tm);
#endif
if (g_llts == LLTS_YYYYMMDD_HHMMSSUS)
len = snprintf(buf, max, "%04d-%02d-%02d %02d:%02d:%02d.%06d ",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec));
else if (g_llts == LLTS_YYYYMMDD_HHMMSSMS)
len = snprintf(buf, max, "%04d-%02d-%02d %02d:%02d:%02d.%03d ",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000));
else if (g_llts == LLTS_HHMMSSMS)
len = snprintf(buf, max, "%02d:%02d:%02d.%03d ",
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000));
else if (g_llts == LLTS_HHMMSSUS)
len = snprintf(buf, max, "%02d:%02d:%02d.%06d ",
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec);
else if (g_llts == LLTS_CHROMELIKE)
len = snprintf(buf, max, "%02d%02d/%02d%02d%02d.%06d ",
tm.tm_mon + 1, tm.tm_mday,tm.tm_hour, tm.tm_min,
tm.tm_sec, (int) tv.tv_usec);
return len;
}
void
lsquic_logger_log3 (enum lsq_log_level log_level,
enum lsquic_logger_module module,
const lsquic_cid_t *conn_id, lsquic_stream_id_t stream_id,
const char *fmt, ...)
{
const int saved_errno = errno;
char cidbuf_[MAX_CID_LEN * 2 + 1];
size_t len = 0;
int lb;
size_t max = MAX_LINE_LEN;
char buf[MAX_LINE_LEN];
if (g_llts != LLTS_NONE)
{
lb = print_timestamp(buf, max);
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
}
lb = snprintf(buf + len, max - len, "[%s] [QUIC:%"CID_FMT"-%"PRIu64"] %s: ",
lsq_loglevel2str[log_level], CID_BITS(conn_id),
stream_id, lsqlm_to_str[module]);
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
va_list ap;
va_start(ap, fmt);
lb = vsnprintf(buf + len, max - len, fmt, ap);
va_end(ap);
if (lb > 0 && (size_t) lb >= max - len && max - len >= TRUNC_SZ)
{
len = max - TRUNC_SZ;
lb = snprintf(buf + max - TRUNC_SZ, TRUNC_SZ, TRUNC_FMT, lb);
}
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
lb = snprintf(buf + len, max - len, "\n");
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
logger_if->log_buf(logger_ctx, buf, len);
end:
errno = saved_errno;
}
void
lsquic_logger_log2 (enum lsq_log_level log_level,
enum lsquic_logger_module module,
const struct lsquic_cid *conn_id, const char *fmt, ...)
{
const int saved_errno = errno;
char cidbuf_[MAX_CID_LEN * 2 + 1];
size_t len = 0;
int lb;
size_t max = MAX_LINE_LEN;
char buf[MAX_LINE_LEN];
if (g_llts != LLTS_NONE)
{
lb = print_timestamp(buf, max);
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
}
lb = snprintf(buf + len, max - len, "[%s] [QUIC:%"CID_FMT"] %s: ",
lsq_loglevel2str[log_level], CID_BITS(conn_id), lsqlm_to_str[module]);
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
va_list ap;
va_start(ap, fmt);
lb = vsnprintf(buf + len, max - len, fmt, ap);
va_end(ap);
if (lb > 0 && (size_t) lb >= max - len && max - len >= TRUNC_SZ)
{
len = max - TRUNC_SZ;
lb = snprintf(buf + max - TRUNC_SZ, TRUNC_SZ, TRUNC_FMT, lb);
}
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
lb = snprintf(buf + len, max - len, "\n");
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
logger_if->log_buf(logger_ctx, buf, len);
end:
errno = saved_errno;
}
void
lsquic_logger_log1 (enum lsq_log_level log_level,
enum lsquic_logger_module module,
const char *fmt, ...)
{
const int saved_errno = errno;
size_t len = 0;
int lb;
size_t max = MAX_LINE_LEN;
char buf[MAX_LINE_LEN];
if (g_llts != LLTS_NONE)
{
lb = print_timestamp(buf, max);
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
}
lb = snprintf(buf + len, max - len, "[%s] %s: ", lsq_loglevel2str[log_level],
lsqlm_to_str[module]);
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
va_list ap;
va_start(ap, fmt);
lb = vsnprintf(buf + len, max - len, fmt, ap);
va_end(ap);
if (lb > 0 && (size_t) lb >= max - len && max - len >= TRUNC_SZ)
{
len = max - TRUNC_SZ;
lb = snprintf(buf + max - TRUNC_SZ, TRUNC_SZ, TRUNC_FMT, lb);
}
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
lb = snprintf(buf + len, max - len, "\n");
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
logger_if->log_buf(logger_ctx, buf, len);
end:
errno = saved_errno;
}
void
lsquic_logger_log0 (enum lsq_log_level log_level, const char *fmt, ...)
{
const int saved_errno = errno;
size_t len = 0;
int lb;
size_t max = MAX_LINE_LEN;
char buf[MAX_LINE_LEN];
if (g_llts != LLTS_NONE)
{
lb = print_timestamp(buf, max);
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
}
lb = snprintf(buf + len, max - len, "[%s] ", lsq_loglevel2str[log_level]);
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
va_list ap;
va_start(ap, fmt);
lb = vsnprintf(buf + len, max - len, fmt, ap);
va_end(ap);
if (lb > 0 && (size_t) lb >= max - len && max - len >= TRUNC_SZ)
{
len = max - TRUNC_SZ;
lb = snprintf(buf + max - TRUNC_SZ, TRUNC_SZ, TRUNC_FMT, lb);
}
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
lb = snprintf(buf + len, max - len, "\n");
if (FORMAT_PROBLEM(lb, len, max))
goto end;
len += lb;
logger_if->log_buf(logger_ctx, buf, len);
end:
errno = saved_errno;
}
void
lsquic_logger_init (const struct lsquic_logger_if *lif, void *lctx,
unsigned llts)
{
logger_if = lif;
logger_ctx = lctx;
if (llts < N_LLTS)
g_llts = llts;
LSQ_DEBUG("%s called", __func__);
}
enum lsquic_logger_module
lsquic_str_to_logger_module (const char *str)
{
enum lsquic_logger_module i;
for (i = 0; i < sizeof(lsqlm_to_str) / sizeof(lsqlm_to_str[0]); ++i)
if (0 == strcasecmp(lsqlm_to_str[i], str))
return i;
return -1;
}
enum lsq_log_level
lsquic_str_to_log_level (const char *str)
{
if (0 == strcasecmp(str, "emerg"))
return LSQ_LOG_EMERG;
if (0 == strcasecmp(str, "alert"))
return LSQ_LOG_ALERT;
if (0 == strcasecmp(str, "crit"))
return LSQ_LOG_CRIT;
if (0 == strcasecmp(str, "error"))
return LSQ_LOG_ERROR;
if (0 == strcasecmp(str, "warn"))
return LSQ_LOG_WARN;
if (0 == strcasecmp(str, "notice"))
return LSQ_LOG_NOTICE;
if (0 == strcasecmp(str, "info"))
return LSQ_LOG_INFO;
if (0 == strcasecmp(str, "debug"))
return LSQ_LOG_DEBUG;
return -1;
}
void
lsquic_log_to_fstream (FILE *file, unsigned llts)
{
lsquic_logger_init(&file_logger_if, file, llts);
}
int
lsquic_logger_lopt (const char *optarg_orig)
{
char *const optarg = strdup(optarg_orig);
char *mod_str;
int i;
for (i = 0; (mod_str = strtok(i ? NULL : optarg, ",")); ++i) {
char *level_str = strchr(mod_str, '=');
if (!level_str) {
fprintf(stderr, "Invalid module specification `%s'\n", mod_str);
break;
}
*level_str = '\0';
++level_str;
enum lsquic_logger_module mod = lsquic_str_to_logger_module(mod_str);
if (-1 == (int) mod) {
fprintf(stderr, "`%s' is not a valid module name\n", mod_str);
break;
}
enum lsq_log_level level = lsquic_str_to_log_level(level_str);
if (-1 == (int) level) {
fprintf(stderr, "`%s' is not a valid level\n", level_str);
break;
}
lsq_log_levels[mod] = level;
LSQ_INFO("set %s to %s", mod_str, level_str);
}
free(optarg);
return mod_str == NULL ? 0 : -1;
}
int
lsquic_set_log_level (const char *level_str)
{
enum lsq_log_level level;
unsigned i;
level = lsquic_str_to_log_level(level_str);
if ((int) level >= 0)
{
for (i = 0; i < sizeof(lsq_log_levels) / sizeof(lsq_log_levels[0]); ++i)
lsq_log_levels[i] = level;
return 0;
}
else
return -1;
}
/* `out' must be at least MAX_CID_LEN * 2 + 1 characters long */
void
lsquic_cid2str (const lsquic_cid_t *cid, char *out)
{
static const char hex[] = "0123456789ABCDEF";
int i;
for (i = 0; i < (int) cid->len; ++i)
{
*out++ = hex[ cid->idbuf[i] >> 4 ];
*out++ = hex[ cid->idbuf[i] & 0xF ];
}
*out = '\0';
}