1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 250aadb33SDmitri Tikhonov/* 350aadb33SDmitri Tikhonov * LSQUIC Logger implementation. 450aadb33SDmitri Tikhonov */ 550aadb33SDmitri Tikhonov 6560db45bSDmitri Tikhonov#include <assert.h> 750aadb33SDmitri Tikhonov#include <errno.h> 850aadb33SDmitri Tikhonov#include <inttypes.h> 950aadb33SDmitri Tikhonov#include <stdarg.h> 1050aadb33SDmitri Tikhonov#include <stdio.h> 1150aadb33SDmitri Tikhonov#include <stdlib.h> 1250aadb33SDmitri Tikhonov#include <string.h> 13461e84d8SAmol Deshpande#ifndef WIN32 1450aadb33SDmitri Tikhonov#include <sys/time.h> 15461e84d8SAmol Deshpande#endif 1650aadb33SDmitri Tikhonov#include <time.h> 1750aadb33SDmitri Tikhonov 1850aadb33SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_LOGGER /* Quis custodiet ipsos custodes? */ 1950aadb33SDmitri Tikhonov#include "lsquic.h" 205392f7a3SLiteSpeed Tech#include "lsquic_logger.h" 2150aadb33SDmitri Tikhonov 225392f7a3SLiteSpeed Tech#define MAX_LINE_LEN 8192 2355f8042dSDmitri Tikhonov/* Expanded TRUNC_FMT should not exceed TRUNC_SZ bytes. At the same time, 2455f8042dSDmitri Tikhonov * TRUNC_SZ should be significantly smaller than MAX_LINE_LEN. 2555f8042dSDmitri Tikhonov */ 2655f8042dSDmitri Tikhonov#define TRUNC_FMT "<truncated, need %d bytes>" 2755f8042dSDmitri Tikhonov#define TRUNC_SZ 40 2855f8042dSDmitri Tikhonov#define FORMAT_PROBLEM(lb, len, max) ((lb < 0) || (lb + len >= max)) 295392f7a3SLiteSpeed Tech 305392f7a3SLiteSpeed Tech/* TODO: display GQUIC CIDs in Chrome-compatible format */ 313229dd11SDmitri Tikhonov 3250aadb33SDmitri Tikhonovstatic enum lsquic_logger_timestamp_style g_llts = LLTS_NONE; 3350aadb33SDmitri Tikhonov 3450aadb33SDmitri Tikhonovstatic int 355392f7a3SLiteSpeed Technull_log_buf (void *ctx, const char *buf, size_t len) 3650aadb33SDmitri Tikhonov{ 3750aadb33SDmitri Tikhonov return 0; 3850aadb33SDmitri Tikhonov} 3950aadb33SDmitri Tikhonov 4050aadb33SDmitri Tikhonovstatic int 415392f7a3SLiteSpeed Techfile_log_buf (void *ctx, const char *buf, size_t len) 4250aadb33SDmitri Tikhonov{ 435392f7a3SLiteSpeed Tech return (int)fwrite(buf, sizeof(char), len, (FILE *) ctx); 4450aadb33SDmitri Tikhonov} 4550aadb33SDmitri Tikhonov 4650aadb33SDmitri Tikhonovstatic const struct lsquic_logger_if file_logger_if = { 475392f7a3SLiteSpeed Tech .log_buf = file_log_buf, 4850aadb33SDmitri Tikhonov}; 4950aadb33SDmitri Tikhonov 5050aadb33SDmitri Tikhonovstatic const struct lsquic_logger_if null_logger_if = { 515392f7a3SLiteSpeed Tech .log_buf = null_log_buf, 5250aadb33SDmitri Tikhonov}; 5350aadb33SDmitri Tikhonov 5450aadb33SDmitri Tikhonovstatic void *logger_ctx = NULL; 5550aadb33SDmitri Tikhonovstatic const struct lsquic_logger_if *logger_if = &null_logger_if; 5650aadb33SDmitri Tikhonov 5750aadb33SDmitri Tikhonovenum lsq_log_level lsq_log_levels[N_LSQUIC_LOGGER_MODULES] = { 5850aadb33SDmitri Tikhonov [LSQLM_NOMODULE] = LSQ_LOG_WARN, 5950aadb33SDmitri Tikhonov [LSQLM_LOGGER] = LSQ_LOG_WARN, 6050aadb33SDmitri Tikhonov [LSQLM_EVENT] = LSQ_LOG_WARN, 6150aadb33SDmitri Tikhonov [LSQLM_ENGINE] = LSQ_LOG_WARN, 6250aadb33SDmitri Tikhonov [LSQLM_CONN] = LSQ_LOG_WARN, 6350aadb33SDmitri Tikhonov [LSQLM_STREAM] = LSQ_LOG_WARN, 6450aadb33SDmitri Tikhonov [LSQLM_PARSE] = LSQ_LOG_WARN, 6550aadb33SDmitri Tikhonov [LSQLM_CFCW] = LSQ_LOG_WARN, 6650aadb33SDmitri Tikhonov [LSQLM_SFCW] = LSQ_LOG_WARN, 6750aadb33SDmitri Tikhonov [LSQLM_SENDCTL] = LSQ_LOG_WARN, 6850aadb33SDmitri Tikhonov [LSQLM_ALARMSET] = LSQ_LOG_WARN, 6950aadb33SDmitri Tikhonov [LSQLM_CRYPTO] = LSQ_LOG_WARN, 7050aadb33SDmitri Tikhonov [LSQLM_HANDSHAKE] = LSQ_LOG_WARN, 7150aadb33SDmitri Tikhonov [LSQLM_HSK_ADAPTER] = LSQ_LOG_WARN, 725392f7a3SLiteSpeed Tech [LSQLM_BBR] = LSQ_LOG_WARN, 7350aadb33SDmitri Tikhonov [LSQLM_CUBIC] = LSQ_LOG_WARN, 74b1a7c3f9SDmitri Tikhonov [LSQLM_ADAPTIVE_CC] = LSQ_LOG_WARN, 7550aadb33SDmitri Tikhonov [LSQLM_HEADERS] = LSQ_LOG_WARN, 7650aadb33SDmitri Tikhonov [LSQLM_FRAME_READER]= LSQ_LOG_WARN, 7750aadb33SDmitri Tikhonov [LSQLM_FRAME_WRITER]= LSQ_LOG_WARN, 785392f7a3SLiteSpeed Tech [LSQLM_MINI_CONN] = LSQ_LOG_WARN, 795392f7a3SLiteSpeed Tech [LSQLM_TOKGEN] = LSQ_LOG_WARN, 8050aadb33SDmitri Tikhonov [LSQLM_ENG_HIST] = LSQ_LOG_WARN, 8150aadb33SDmitri Tikhonov [LSQLM_SPI] = LSQ_LOG_WARN, 82fbc6cc04SDmitri Tikhonov [LSQLM_HPI] = LSQ_LOG_WARN, 8350aadb33SDmitri Tikhonov [LSQLM_DI] = LSQ_LOG_WARN, 845392f7a3SLiteSpeed Tech [LSQLM_PRQ] = LSQ_LOG_WARN, 8550aadb33SDmitri Tikhonov [LSQLM_PACER] = LSQ_LOG_WARN, 863b55e6aeSDmitri Tikhonov [LSQLM_HTTP1X] = LSQ_LOG_WARN, 8755cd0b38SDmitri Tikhonov [LSQLM_QLOG] = LSQ_LOG_WARN, 885392f7a3SLiteSpeed Tech [LSQLM_TRAPA] = LSQ_LOG_WARN, 895392f7a3SLiteSpeed Tech [LSQLM_PURGA] = LSQ_LOG_WARN, 905392f7a3SLiteSpeed Tech [LSQLM_HCSI_READER] = LSQ_LOG_WARN, 915392f7a3SLiteSpeed Tech [LSQLM_HCSO_WRITER] = LSQ_LOG_WARN, 925392f7a3SLiteSpeed Tech [LSQLM_QENC_HDL] = LSQ_LOG_WARN, 935392f7a3SLiteSpeed Tech [LSQLM_QDEC_HDL] = LSQ_LOG_WARN, 945392f7a3SLiteSpeed Tech [LSQLM_QPACK_ENC] = LSQ_LOG_WARN, 955392f7a3SLiteSpeed Tech [LSQLM_QPACK_DEC] = LSQ_LOG_WARN, 965392f7a3SLiteSpeed Tech [LSQLM_PRIO] = LSQ_LOG_WARN, 975392f7a3SLiteSpeed Tech [LSQLM_BW_SAMPLER] = LSQ_LOG_WARN, 98b8fa6195SDmitri Tikhonov [LSQLM_PACKET_RESIZE] = LSQ_LOG_WARN, 99758aff32SDmitri Tikhonov [LSQLM_CONN_STATS] = LSQ_LOG_WARN, 10050aadb33SDmitri Tikhonov}; 10150aadb33SDmitri Tikhonov 10250aadb33SDmitri Tikhonovconst char *const lsqlm_to_str[N_LSQUIC_LOGGER_MODULES] = { 10350aadb33SDmitri Tikhonov [LSQLM_NOMODULE] = "", 10450aadb33SDmitri Tikhonov [LSQLM_LOGGER] = "logger", 10550aadb33SDmitri Tikhonov [LSQLM_EVENT] = "event", 10650aadb33SDmitri Tikhonov [LSQLM_ENGINE] = "engine", 10750aadb33SDmitri Tikhonov [LSQLM_CONN] = "conn", 10850aadb33SDmitri Tikhonov [LSQLM_STREAM] = "stream", 10950aadb33SDmitri Tikhonov [LSQLM_PARSE] = "parse", 11050aadb33SDmitri Tikhonov [LSQLM_CFCW] = "cfcw", 11150aadb33SDmitri Tikhonov [LSQLM_SFCW] = "sfcw", 11250aadb33SDmitri Tikhonov [LSQLM_SENDCTL] = "sendctl", 11350aadb33SDmitri Tikhonov [LSQLM_ALARMSET] = "alarmset", 11450aadb33SDmitri Tikhonov [LSQLM_CRYPTO] = "crypto", 11550aadb33SDmitri Tikhonov [LSQLM_HANDSHAKE] = "handshake", 11650aadb33SDmitri Tikhonov [LSQLM_HSK_ADAPTER] = "hsk-adapter", 1175392f7a3SLiteSpeed Tech [LSQLM_BBR] = "bbr", 11850aadb33SDmitri Tikhonov [LSQLM_CUBIC] = "cubic", 119b1a7c3f9SDmitri Tikhonov [LSQLM_ADAPTIVE_CC] = "adaptive-cc", 12050aadb33SDmitri Tikhonov [LSQLM_HEADERS] = "headers", 12150aadb33SDmitri Tikhonov [LSQLM_FRAME_READER]= "frame-reader", 12250aadb33SDmitri Tikhonov [LSQLM_FRAME_WRITER]= "frame-writer", 1235392f7a3SLiteSpeed Tech [LSQLM_MINI_CONN] = "mini-conn", 1245392f7a3SLiteSpeed Tech [LSQLM_TOKGEN] = "tokgen", 12550aadb33SDmitri Tikhonov [LSQLM_ENG_HIST] = "eng-hist", 12650aadb33SDmitri Tikhonov [LSQLM_SPI] = "spi", 127fbc6cc04SDmitri Tikhonov [LSQLM_HPI] = "hpi", 12850aadb33SDmitri Tikhonov [LSQLM_DI] = "di", 1295392f7a3SLiteSpeed Tech [LSQLM_PRQ] = "prq", 13050aadb33SDmitri Tikhonov [LSQLM_PACER] = "pacer", 1313b55e6aeSDmitri Tikhonov [LSQLM_HTTP1X] = "http1x", 13255cd0b38SDmitri Tikhonov [LSQLM_QLOG] = "qlog", 1335392f7a3SLiteSpeed Tech [LSQLM_TRAPA] = "trapa", 1345392f7a3SLiteSpeed Tech [LSQLM_PURGA] = "purga", 1355392f7a3SLiteSpeed Tech [LSQLM_HCSI_READER] = "hcsi-reader", 1365392f7a3SLiteSpeed Tech [LSQLM_HCSO_WRITER] = "hcso-writer", 1375392f7a3SLiteSpeed Tech [LSQLM_QENC_HDL] = "qenc-hdl", 1385392f7a3SLiteSpeed Tech [LSQLM_QDEC_HDL] = "qdec-hdl", 1395392f7a3SLiteSpeed Tech [LSQLM_QPACK_ENC] = "qpack-enc", 1405392f7a3SLiteSpeed Tech [LSQLM_QPACK_DEC] = "qpack-dec", 1415392f7a3SLiteSpeed Tech [LSQLM_PRIO] = "prio", 1425392f7a3SLiteSpeed Tech [LSQLM_BW_SAMPLER] = "bw-sampler", 143b8fa6195SDmitri Tikhonov [LSQLM_PACKET_RESIZE] = "packet-resize", 144758aff32SDmitri Tikhonov [LSQLM_CONN_STATS] = "conn-stats", 14550aadb33SDmitri Tikhonov}; 14650aadb33SDmitri Tikhonov 14750aadb33SDmitri Tikhonovconst char *const lsq_loglevel2str[N_LSQUIC_LOG_LEVELS] = { 14850aadb33SDmitri Tikhonov [LSQ_LOG_ALERT] = "ALERT", 14950aadb33SDmitri Tikhonov [LSQ_LOG_CRIT] = "CRIT", 15050aadb33SDmitri Tikhonov [LSQ_LOG_DEBUG] = "DEBUG", 15150aadb33SDmitri Tikhonov [LSQ_LOG_EMERG] = "EMERG", 15250aadb33SDmitri Tikhonov [LSQ_LOG_ERROR] = "ERROR", 15350aadb33SDmitri Tikhonov [LSQ_LOG_INFO] = "INFO", 15450aadb33SDmitri Tikhonov [LSQ_LOG_NOTICE] = "NOTICE", 15550aadb33SDmitri Tikhonov [LSQ_LOG_WARN] = "WARN", 15650aadb33SDmitri Tikhonov}; 15750aadb33SDmitri Tikhonov 15850aadb33SDmitri Tikhonov 159b93f59beSBob Perper#ifdef WIN32 160560db45bSDmitri Tikhonov#define DELTA_EPOCH_IN_TICKS 116444736000000000Ui64 161b93f59beSBob Perperstruct timezone 162b93f59beSBob Perper{ 163ab5c8df2SBob Perper time_t tz_minuteswest; /* minutes W of Greenwich */ 164ab5c8df2SBob Perper time_t tz_dsttime; /* type of dst correction */ 165b93f59beSBob Perper}; 166b93f59beSBob Perper 167b93f59beSBob Perperstatic int 168b93f59beSBob Perpergettimeofday (struct timeval *tv, struct timezone *tz) 169b93f59beSBob Perper{ 170b93f59beSBob Perper FILETIME ft; 171560db45bSDmitri Tikhonov uint64_t tmpres; 172b93f59beSBob Perper static int tzflag; 173b93f59beSBob Perper 174b93f59beSBob Perper if (NULL != tv) 175b93f59beSBob Perper { 176b93f59beSBob Perper GetSystemTimeAsFileTime(&ft); 177b93f59beSBob Perper 178560db45bSDmitri Tikhonov tmpres = ((uint64_t) ft.dwHighDateTime << 32) 179560db45bSDmitri Tikhonov | (ft.dwLowDateTime); 180b93f59beSBob Perper 181560db45bSDmitri Tikhonov tmpres -= DELTA_EPOCH_IN_TICKS; 182560db45bSDmitri Tikhonov tv->tv_sec = tmpres / 10000000; 183560db45bSDmitri Tikhonov tv->tv_usec = tmpres % 1000000; 184b93f59beSBob Perper } 185b93f59beSBob Perper 186b93f59beSBob Perper if (NULL != tz) 187b93f59beSBob Perper { 188b93f59beSBob Perper if (!tzflag) 189b93f59beSBob Perper { 190b93f59beSBob Perper _tzset(); 191b93f59beSBob Perper tzflag++; 192b93f59beSBob Perper } 193b93f59beSBob Perper tz->tz_minuteswest = _timezone / 60; 194b93f59beSBob Perper tz->tz_dsttime = _daylight; 195b93f59beSBob Perper } 196b93f59beSBob Perper 197b93f59beSBob Perper return 0; 198b93f59beSBob Perper} 199b93f59beSBob Perper#endif 200b93f59beSBob Perper 201b93f59beSBob Perper 2025392f7a3SLiteSpeed Techstatic size_t 2035392f7a3SLiteSpeed Techprint_timestamp (char *buf, size_t max) 20450aadb33SDmitri Tikhonov{ 20550aadb33SDmitri Tikhonov struct tm tm; 20650aadb33SDmitri Tikhonov struct timeval tv; 2075392f7a3SLiteSpeed Tech size_t len = 0; 2085392f7a3SLiteSpeed Tech 20950aadb33SDmitri Tikhonov gettimeofday(&tv, NULL); 210ab5c8df2SBob Perper#ifdef WIN32 211ab5c8df2SBob Perper { 2127b1586ddSDmitri Tikhonov time_t t = tv.tv_sec; 213560db45bSDmitri Tikhonov#ifndef NDEBUG 2147b1586ddSDmitri Tikhonov errno_t e = 215560db45bSDmitri Tikhonov#endif 2167b1586ddSDmitri Tikhonov localtime_s(&tm, &t); 217560db45bSDmitri Tikhonov assert(!e); 218ab5c8df2SBob Perper } 219ab5c8df2SBob Perper#else 22050aadb33SDmitri Tikhonov localtime_r(&tv.tv_sec, &tm); 221ab5c8df2SBob Perper#endif 222bfc7bfd8SDmitri Tikhonov if (g_llts == LLTS_YYYYMMDD_HHMMSSUS) 2235392f7a3SLiteSpeed Tech len = snprintf(buf, max, "%04d-%02d-%02d %02d:%02d:%02d.%06d ", 224bfc7bfd8SDmitri Tikhonov tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 225bfc7bfd8SDmitri Tikhonov tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec)); 226bfc7bfd8SDmitri Tikhonov else if (g_llts == LLTS_YYYYMMDD_HHMMSSMS) 2275392f7a3SLiteSpeed Tech len = snprintf(buf, max, "%04d-%02d-%02d %02d:%02d:%02d.%03d ", 22850aadb33SDmitri Tikhonov tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 22950aadb33SDmitri Tikhonov tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000)); 23050aadb33SDmitri Tikhonov else if (g_llts == LLTS_HHMMSSMS) 2315392f7a3SLiteSpeed Tech len = snprintf(buf, max, "%02d:%02d:%02d.%03d ", 2325392f7a3SLiteSpeed Tech tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000)); 23350aadb33SDmitri Tikhonov else if (g_llts == LLTS_HHMMSSUS) 2345392f7a3SLiteSpeed Tech len = snprintf(buf, max, "%02d:%02d:%02d.%06d ", 2355392f7a3SLiteSpeed Tech tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec); 23650aadb33SDmitri Tikhonov else if (g_llts == LLTS_CHROMELIKE) 2375392f7a3SLiteSpeed Tech len = snprintf(buf, max, "%02d%02d/%02d%02d%02d.%06d ", 2385392f7a3SLiteSpeed Tech tm.tm_mon + 1, tm.tm_mday,tm.tm_hour, tm.tm_min, 2395392f7a3SLiteSpeed Tech tm.tm_sec, (int) tv.tv_usec); 2405392f7a3SLiteSpeed Tech return len; 24150aadb33SDmitri Tikhonov} 24250aadb33SDmitri Tikhonov 24350aadb33SDmitri Tikhonov 24450aadb33SDmitri Tikhonovvoid 24550aadb33SDmitri Tikhonovlsquic_logger_log3 (enum lsq_log_level log_level, 24650aadb33SDmitri Tikhonov enum lsquic_logger_module module, 2475392f7a3SLiteSpeed Tech const lsquic_cid_t *conn_id, lsquic_stream_id_t stream_id, 2485392f7a3SLiteSpeed Tech const char *fmt, ...) 24950aadb33SDmitri Tikhonov{ 25050aadb33SDmitri Tikhonov const int saved_errno = errno; 2515392f7a3SLiteSpeed Tech char cidbuf_[MAX_CID_LEN * 2 + 1]; 2525392f7a3SLiteSpeed Tech size_t len = 0; 25355f8042dSDmitri Tikhonov int lb; 2545392f7a3SLiteSpeed Tech size_t max = MAX_LINE_LEN; 2555392f7a3SLiteSpeed Tech char buf[MAX_LINE_LEN]; 25650aadb33SDmitri Tikhonov 25750aadb33SDmitri Tikhonov if (g_llts != LLTS_NONE) 2585392f7a3SLiteSpeed Tech { 2595392f7a3SLiteSpeed Tech lb = print_timestamp(buf, max); 2605392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 2615392f7a3SLiteSpeed Tech goto end; 2625392f7a3SLiteSpeed Tech len += lb; 2635392f7a3SLiteSpeed Tech } 2645392f7a3SLiteSpeed Tech lb = snprintf(buf + len, max - len, "[%s] [QUIC:%"CID_FMT"-%"PRIu64"] %s: ", 2655392f7a3SLiteSpeed Tech lsq_loglevel2str[log_level], CID_BITS(conn_id), 2665392f7a3SLiteSpeed Tech stream_id, lsqlm_to_str[module]); 2675392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 2685392f7a3SLiteSpeed Tech goto end; 2695392f7a3SLiteSpeed Tech len += lb; 27050aadb33SDmitri Tikhonov va_list ap; 27150aadb33SDmitri Tikhonov va_start(ap, fmt); 2725392f7a3SLiteSpeed Tech lb = vsnprintf(buf + len, max - len, fmt, ap); 273a0e1aeeeSDmitri Tikhonov va_end(ap); 27455f8042dSDmitri Tikhonov if (lb > 0 && (size_t) lb >= max - len && max - len >= TRUNC_SZ) 27555f8042dSDmitri Tikhonov { 27655f8042dSDmitri Tikhonov len = max - TRUNC_SZ; 27755f8042dSDmitri Tikhonov lb = snprintf(buf + max - TRUNC_SZ, TRUNC_SZ, TRUNC_FMT, lb); 27855f8042dSDmitri Tikhonov } 2795392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 2805392f7a3SLiteSpeed Tech goto end; 2815392f7a3SLiteSpeed Tech len += lb; 2825392f7a3SLiteSpeed Tech lb = snprintf(buf + len, max - len, "\n"); 2835392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 2845392f7a3SLiteSpeed Tech goto end; 2855392f7a3SLiteSpeed Tech len += lb; 2865392f7a3SLiteSpeed Tech logger_if->log_buf(logger_ctx, buf, len); 2875392f7a3SLiteSpeed Techend: 28850aadb33SDmitri Tikhonov errno = saved_errno; 28950aadb33SDmitri Tikhonov} 29050aadb33SDmitri Tikhonov 29150aadb33SDmitri Tikhonov 29250aadb33SDmitri Tikhonovvoid 29350aadb33SDmitri Tikhonovlsquic_logger_log2 (enum lsq_log_level log_level, 29450aadb33SDmitri Tikhonov enum lsquic_logger_module module, 2955392f7a3SLiteSpeed Tech const struct lsquic_cid *conn_id, const char *fmt, ...) 29650aadb33SDmitri Tikhonov{ 29750aadb33SDmitri Tikhonov const int saved_errno = errno; 2985392f7a3SLiteSpeed Tech char cidbuf_[MAX_CID_LEN * 2 + 1]; 2995392f7a3SLiteSpeed Tech size_t len = 0; 30055f8042dSDmitri Tikhonov int lb; 3015392f7a3SLiteSpeed Tech size_t max = MAX_LINE_LEN; 3025392f7a3SLiteSpeed Tech char buf[MAX_LINE_LEN]; 30350aadb33SDmitri Tikhonov 30450aadb33SDmitri Tikhonov if (g_llts != LLTS_NONE) 3055392f7a3SLiteSpeed Tech { 3065392f7a3SLiteSpeed Tech lb = print_timestamp(buf, max); 3075392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 3085392f7a3SLiteSpeed Tech goto end; 3095392f7a3SLiteSpeed Tech len += lb; 3105392f7a3SLiteSpeed Tech } 31150aadb33SDmitri Tikhonov 3125392f7a3SLiteSpeed Tech lb = snprintf(buf + len, max - len, "[%s] [QUIC:%"CID_FMT"] %s: ", 3135392f7a3SLiteSpeed Tech lsq_loglevel2str[log_level], CID_BITS(conn_id), lsqlm_to_str[module]); 3145392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 3155392f7a3SLiteSpeed Tech goto end; 3165392f7a3SLiteSpeed Tech len += lb; 31750aadb33SDmitri Tikhonov va_list ap; 31850aadb33SDmitri Tikhonov va_start(ap, fmt); 3195392f7a3SLiteSpeed Tech lb = vsnprintf(buf + len, max - len, fmt, ap); 320a0e1aeeeSDmitri Tikhonov va_end(ap); 32155f8042dSDmitri Tikhonov if (lb > 0 && (size_t) lb >= max - len && max - len >= TRUNC_SZ) 32255f8042dSDmitri Tikhonov { 32355f8042dSDmitri Tikhonov len = max - TRUNC_SZ; 32455f8042dSDmitri Tikhonov lb = snprintf(buf + max - TRUNC_SZ, TRUNC_SZ, TRUNC_FMT, lb); 32555f8042dSDmitri Tikhonov } 3265392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 3275392f7a3SLiteSpeed Tech goto end; 3285392f7a3SLiteSpeed Tech len += lb; 3295392f7a3SLiteSpeed Tech lb = snprintf(buf + len, max - len, "\n"); 3305392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 3315392f7a3SLiteSpeed Tech goto end; 3325392f7a3SLiteSpeed Tech len += lb; 3335392f7a3SLiteSpeed Tech logger_if->log_buf(logger_ctx, buf, len); 3345392f7a3SLiteSpeed Techend: 33550aadb33SDmitri Tikhonov errno = saved_errno; 33650aadb33SDmitri Tikhonov} 33750aadb33SDmitri Tikhonov 33850aadb33SDmitri Tikhonov 33950aadb33SDmitri Tikhonovvoid 34050aadb33SDmitri Tikhonovlsquic_logger_log1 (enum lsq_log_level log_level, 34150aadb33SDmitri Tikhonov enum lsquic_logger_module module, 34250aadb33SDmitri Tikhonov const char *fmt, ...) 34350aadb33SDmitri Tikhonov{ 34450aadb33SDmitri Tikhonov const int saved_errno = errno; 3455392f7a3SLiteSpeed Tech size_t len = 0; 34655f8042dSDmitri Tikhonov int lb; 3475392f7a3SLiteSpeed Tech size_t max = MAX_LINE_LEN; 3485392f7a3SLiteSpeed Tech char buf[MAX_LINE_LEN]; 34950aadb33SDmitri Tikhonov 35050aadb33SDmitri Tikhonov if (g_llts != LLTS_NONE) 3515392f7a3SLiteSpeed Tech { 3525392f7a3SLiteSpeed Tech lb = print_timestamp(buf, max); 3535392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 3545392f7a3SLiteSpeed Tech goto end; 3555392f7a3SLiteSpeed Tech len += lb; 3565392f7a3SLiteSpeed Tech } 3575392f7a3SLiteSpeed Tech lb = snprintf(buf + len, max - len, "[%s] %s: ", lsq_loglevel2str[log_level], 35850aadb33SDmitri Tikhonov lsqlm_to_str[module]); 3595392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 3605392f7a3SLiteSpeed Tech goto end; 3615392f7a3SLiteSpeed Tech len += lb; 36250aadb33SDmitri Tikhonov va_list ap; 36350aadb33SDmitri Tikhonov va_start(ap, fmt); 3645392f7a3SLiteSpeed Tech lb = vsnprintf(buf + len, max - len, fmt, ap); 365a0e1aeeeSDmitri Tikhonov va_end(ap); 36655f8042dSDmitri Tikhonov if (lb > 0 && (size_t) lb >= max - len && max - len >= TRUNC_SZ) 36755f8042dSDmitri Tikhonov { 36855f8042dSDmitri Tikhonov len = max - TRUNC_SZ; 36955f8042dSDmitri Tikhonov lb = snprintf(buf + max - TRUNC_SZ, TRUNC_SZ, TRUNC_FMT, lb); 37055f8042dSDmitri Tikhonov } 3715392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 3725392f7a3SLiteSpeed Tech goto end; 3735392f7a3SLiteSpeed Tech len += lb; 3745392f7a3SLiteSpeed Tech lb = snprintf(buf + len, max - len, "\n"); 3755392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 3765392f7a3SLiteSpeed Tech goto end; 3775392f7a3SLiteSpeed Tech len += lb; 3785392f7a3SLiteSpeed Tech logger_if->log_buf(logger_ctx, buf, len); 3795392f7a3SLiteSpeed Techend: 38050aadb33SDmitri Tikhonov errno = saved_errno; 38150aadb33SDmitri Tikhonov} 38250aadb33SDmitri Tikhonov 38350aadb33SDmitri Tikhonov 38450aadb33SDmitri Tikhonovvoid 38550aadb33SDmitri Tikhonovlsquic_logger_log0 (enum lsq_log_level log_level, const char *fmt, ...) 38650aadb33SDmitri Tikhonov{ 38750aadb33SDmitri Tikhonov const int saved_errno = errno; 3885392f7a3SLiteSpeed Tech size_t len = 0; 38955f8042dSDmitri Tikhonov int lb; 3905392f7a3SLiteSpeed Tech size_t max = MAX_LINE_LEN; 3915392f7a3SLiteSpeed Tech char buf[MAX_LINE_LEN]; 39250aadb33SDmitri Tikhonov 39350aadb33SDmitri Tikhonov if (g_llts != LLTS_NONE) 3945392f7a3SLiteSpeed Tech { 3955392f7a3SLiteSpeed Tech lb = print_timestamp(buf, max); 3965392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 3975392f7a3SLiteSpeed Tech goto end; 3985392f7a3SLiteSpeed Tech len += lb; 3995392f7a3SLiteSpeed Tech } 40050aadb33SDmitri Tikhonov 4015392f7a3SLiteSpeed Tech lb = snprintf(buf + len, max - len, "[%s] ", lsq_loglevel2str[log_level]); 4025392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 4035392f7a3SLiteSpeed Tech goto end; 4045392f7a3SLiteSpeed Tech len += lb; 40550aadb33SDmitri Tikhonov va_list ap; 40650aadb33SDmitri Tikhonov va_start(ap, fmt); 4075392f7a3SLiteSpeed Tech lb = vsnprintf(buf + len, max - len, fmt, ap); 40850aadb33SDmitri Tikhonov va_end(ap); 40955f8042dSDmitri Tikhonov if (lb > 0 && (size_t) lb >= max - len && max - len >= TRUNC_SZ) 41055f8042dSDmitri Tikhonov { 41155f8042dSDmitri Tikhonov len = max - TRUNC_SZ; 41255f8042dSDmitri Tikhonov lb = snprintf(buf + max - TRUNC_SZ, TRUNC_SZ, TRUNC_FMT, lb); 41355f8042dSDmitri Tikhonov } 4145392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 4155392f7a3SLiteSpeed Tech goto end; 4165392f7a3SLiteSpeed Tech len += lb; 4175392f7a3SLiteSpeed Tech lb = snprintf(buf + len, max - len, "\n"); 4185392f7a3SLiteSpeed Tech if (FORMAT_PROBLEM(lb, len, max)) 4195392f7a3SLiteSpeed Tech goto end; 4205392f7a3SLiteSpeed Tech len += lb; 4215392f7a3SLiteSpeed Tech logger_if->log_buf(logger_ctx, buf, len); 4225392f7a3SLiteSpeed Techend: 42350aadb33SDmitri Tikhonov errno = saved_errno; 42450aadb33SDmitri Tikhonov} 42550aadb33SDmitri Tikhonov 42650aadb33SDmitri Tikhonov 42750aadb33SDmitri Tikhonovvoid 42850aadb33SDmitri Tikhonovlsquic_logger_init (const struct lsquic_logger_if *lif, void *lctx, 42950aadb33SDmitri Tikhonov unsigned llts) 43050aadb33SDmitri Tikhonov{ 43150aadb33SDmitri Tikhonov logger_if = lif; 43250aadb33SDmitri Tikhonov logger_ctx = lctx; 43350aadb33SDmitri Tikhonov if (llts < N_LLTS) 43450aadb33SDmitri Tikhonov g_llts = llts; 43550aadb33SDmitri Tikhonov LSQ_DEBUG("%s called", __func__); 43650aadb33SDmitri Tikhonov} 43750aadb33SDmitri Tikhonov 43850aadb33SDmitri Tikhonov 43950aadb33SDmitri Tikhonovenum lsquic_logger_module 44050aadb33SDmitri Tikhonovlsquic_str_to_logger_module (const char *str) 44150aadb33SDmitri Tikhonov{ 44250aadb33SDmitri Tikhonov enum lsquic_logger_module i; 44350aadb33SDmitri Tikhonov for (i = 0; i < sizeof(lsqlm_to_str) / sizeof(lsqlm_to_str[0]); ++i) 44450aadb33SDmitri Tikhonov if (0 == strcasecmp(lsqlm_to_str[i], str)) 44550aadb33SDmitri Tikhonov return i; 44650aadb33SDmitri Tikhonov return -1; 44750aadb33SDmitri Tikhonov} 44850aadb33SDmitri Tikhonov 44950aadb33SDmitri Tikhonov 45050aadb33SDmitri Tikhonovenum lsq_log_level 45150aadb33SDmitri Tikhonovlsquic_str_to_log_level (const char *str) 45250aadb33SDmitri Tikhonov{ 45350aadb33SDmitri Tikhonov if (0 == strcasecmp(str, "emerg")) 45450aadb33SDmitri Tikhonov return LSQ_LOG_EMERG; 45550aadb33SDmitri Tikhonov if (0 == strcasecmp(str, "alert")) 45650aadb33SDmitri Tikhonov return LSQ_LOG_ALERT; 45750aadb33SDmitri Tikhonov if (0 == strcasecmp(str, "crit")) 45850aadb33SDmitri Tikhonov return LSQ_LOG_CRIT; 45950aadb33SDmitri Tikhonov if (0 == strcasecmp(str, "error")) 46050aadb33SDmitri Tikhonov return LSQ_LOG_ERROR; 46150aadb33SDmitri Tikhonov if (0 == strcasecmp(str, "warn")) 46250aadb33SDmitri Tikhonov return LSQ_LOG_WARN; 46350aadb33SDmitri Tikhonov if (0 == strcasecmp(str, "notice")) 46450aadb33SDmitri Tikhonov return LSQ_LOG_NOTICE; 46550aadb33SDmitri Tikhonov if (0 == strcasecmp(str, "info")) 46650aadb33SDmitri Tikhonov return LSQ_LOG_INFO; 46750aadb33SDmitri Tikhonov if (0 == strcasecmp(str, "debug")) 46850aadb33SDmitri Tikhonov return LSQ_LOG_DEBUG; 46950aadb33SDmitri Tikhonov return -1; 47050aadb33SDmitri Tikhonov} 47150aadb33SDmitri Tikhonov 47250aadb33SDmitri Tikhonov 47350aadb33SDmitri Tikhonovvoid 47450aadb33SDmitri Tikhonovlsquic_log_to_fstream (FILE *file, unsigned llts) 47550aadb33SDmitri Tikhonov{ 47650aadb33SDmitri Tikhonov lsquic_logger_init(&file_logger_if, file, llts); 47750aadb33SDmitri Tikhonov} 47850aadb33SDmitri Tikhonov 47950aadb33SDmitri Tikhonov 48050aadb33SDmitri Tikhonovint 48150aadb33SDmitri Tikhonovlsquic_logger_lopt (const char *optarg_orig) 48250aadb33SDmitri Tikhonov{ 48350aadb33SDmitri Tikhonov char *const optarg = strdup(optarg_orig); 48450aadb33SDmitri Tikhonov char *mod_str; 48550aadb33SDmitri Tikhonov int i; 48650aadb33SDmitri Tikhonov for (i = 0; (mod_str = strtok(i ? NULL : optarg, ",")); ++i) { 48750aadb33SDmitri Tikhonov char *level_str = strchr(mod_str, '='); 48850aadb33SDmitri Tikhonov if (!level_str) { 48950aadb33SDmitri Tikhonov fprintf(stderr, "Invalid module specification `%s'\n", mod_str); 49050aadb33SDmitri Tikhonov break; 49150aadb33SDmitri Tikhonov } 49250aadb33SDmitri Tikhonov *level_str = '\0'; 49350aadb33SDmitri Tikhonov ++level_str; 49450aadb33SDmitri Tikhonov enum lsquic_logger_module mod = lsquic_str_to_logger_module(mod_str); 49550aadb33SDmitri Tikhonov if (-1 == (int) mod) { 49650aadb33SDmitri Tikhonov fprintf(stderr, "`%s' is not a valid module name\n", mod_str); 49750aadb33SDmitri Tikhonov break; 49850aadb33SDmitri Tikhonov } 49950aadb33SDmitri Tikhonov enum lsq_log_level level = lsquic_str_to_log_level(level_str); 50050aadb33SDmitri Tikhonov if (-1 == (int) level) { 50150aadb33SDmitri Tikhonov fprintf(stderr, "`%s' is not a valid level\n", level_str); 50250aadb33SDmitri Tikhonov break; 50350aadb33SDmitri Tikhonov } 50450aadb33SDmitri Tikhonov lsq_log_levels[mod] = level; 50550aadb33SDmitri Tikhonov LSQ_INFO("set %s to %s", mod_str, level_str); 50650aadb33SDmitri Tikhonov } 50750aadb33SDmitri Tikhonov free(optarg); 50850aadb33SDmitri Tikhonov return mod_str == NULL ? 0 : -1; 50950aadb33SDmitri Tikhonov} 51050aadb33SDmitri Tikhonov 51150aadb33SDmitri Tikhonov 51250aadb33SDmitri Tikhonovint 51350aadb33SDmitri Tikhonovlsquic_set_log_level (const char *level_str) 51450aadb33SDmitri Tikhonov{ 51550aadb33SDmitri Tikhonov enum lsq_log_level level; 51650aadb33SDmitri Tikhonov unsigned i; 51750aadb33SDmitri Tikhonov 51850aadb33SDmitri Tikhonov level = lsquic_str_to_log_level(level_str); 51950aadb33SDmitri Tikhonov if ((int) level >= 0) 52050aadb33SDmitri Tikhonov { 52150aadb33SDmitri Tikhonov for (i = 0; i < sizeof(lsq_log_levels) / sizeof(lsq_log_levels[0]); ++i) 52250aadb33SDmitri Tikhonov lsq_log_levels[i] = level; 52350aadb33SDmitri Tikhonov return 0; 52450aadb33SDmitri Tikhonov } 52550aadb33SDmitri Tikhonov else 52650aadb33SDmitri Tikhonov return -1; 52750aadb33SDmitri Tikhonov} 5285392f7a3SLiteSpeed Tech 5295392f7a3SLiteSpeed Tech 5305392f7a3SLiteSpeed Tech/* `out' must be at least MAX_CID_LEN * 2 + 1 characters long */ 5315392f7a3SLiteSpeed Techvoid 5325392f7a3SLiteSpeed Techlsquic_cid2str (const lsquic_cid_t *cid, char *out) 5335392f7a3SLiteSpeed Tech{ 5345392f7a3SLiteSpeed Tech static const char hex[] = "0123456789ABCDEF"; 5355392f7a3SLiteSpeed Tech int i; 5365392f7a3SLiteSpeed Tech 5375392f7a3SLiteSpeed Tech for (i = 0; i < (int) cid->len; ++i) 5385392f7a3SLiteSpeed Tech { 5395392f7a3SLiteSpeed Tech *out++ = hex[ cid->idbuf[i] >> 4 ]; 5405392f7a3SLiteSpeed Tech *out++ = hex[ cid->idbuf[i] & 0xF ]; 5415392f7a3SLiteSpeed Tech } 5425392f7a3SLiteSpeed Tech *out = '\0'; 5435392f7a3SLiteSpeed Tech} 544