/* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010 - 2019 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "private-lib-core.h" #ifdef LWS_HAVE_SYS_TYPES_H #include #endif #if defined(LWS_PLAT_OPTEE) void lwsl_emit_optee(int level, const char *line); #endif int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE; static void (*lwsl_emit)(int level, const char *line) #ifndef LWS_PLAT_OPTEE = lwsl_emit_stderr #else = lwsl_emit_optee; #endif ; #ifndef LWS_PLAT_OPTEE static const char * log_level_names ="EWNIDPHXCLUT??"; #endif #if defined(LWS_LOGS_TIMESTAMP) int lwsl_timestamp(int level, char *p, int len) { #ifndef LWS_PLAT_OPTEE time_t o_now; unsigned long long now; struct timeval tv; struct tm *ptm = NULL; #ifndef WIN32 struct tm tm; #endif int n; gettimeofday(&tv, NULL); o_now = tv.tv_sec; now = ((unsigned long long)tv.tv_sec * 10000) + (tv.tv_usec / 100); #ifndef _WIN32_WCE #ifdef WIN32 ptm = localtime(&o_now); #else if (localtime_r(&o_now, &tm)) ptm = &tm; #endif #endif p[0] = '\0'; for (n = 0; n < LLL_COUNT; n++) { if (level != (1 << n)) continue; if (ptm) n = lws_snprintf(p, len, "[%04d/%02d/%02d %02d:%02d:%02d:%04d] %c: ", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(now % 10000), log_level_names[n]); else n = lws_snprintf(p, len, "[%llu:%04d] %c: ", (unsigned long long) now / 10000, (int)(now % 10000), log_level_names[n]); return n; } #else p[0] = '\0'; #endif return 0; } #endif #ifndef LWS_PLAT_OPTEE static const char * const colours[] = { "[31;1m", /* LLL_ERR */ "[36;1m", /* LLL_WARN */ "[35;1m", /* LLL_NOTICE */ "[32;1m", /* LLL_INFO */ "[34;1m", /* LLL_DEBUG */ "[33;1m", /* LLL_PARSER */ "[33m", /* LLL_HEADER */ "[33m", /* LLL_EXT */ "[33m", /* LLL_CLIENT */ "[33;1m", /* LLL_LATENCY */ "[0;1m", /* LLL_USER */ "[31m", /* LLL_THREAD */ }; static char tty; static void _lwsl_emit_stderr(int level, const char *line, int ts) { char buf[50]; int n, m = LWS_ARRAY_SIZE(colours) - 1; if (!tty) tty = isatty(2) | 2; buf[0] = '\0'; #if defined(LWS_LOGS_TIMESTAMP) if (ts) lwsl_timestamp(level, buf, sizeof(buf)); #endif if (tty == 3) { n = 1 << (LWS_ARRAY_SIZE(colours) - 1); while (n) { if (level & n) break; m--; n >>= 1; } fprintf(stderr, "%c%s%s%s%c[0m", 27, colours[m], buf, line, 27); } else fprintf(stderr, "%s%s", buf, line); } void lwsl_emit_stderr(int level, const char *line) { _lwsl_emit_stderr(level, line, 1); } void lwsl_emit_stderr_notimestamp(int level, const char *line) { _lwsl_emit_stderr(level, line, 0); } #endif #if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK)) void _lws_logv(int filter, const char *format, va_list vl) { #if LWS_MAX_SMP == 1 static char buf[256]; #else char buf[1024]; #endif int n; if (!(log_level & filter)) return; n = vsnprintf(buf, sizeof(buf) - 1, format, vl); (void)n; /* vnsprintf returns what it would have written, even if truncated */ if (n > (int)sizeof(buf) - 1) { n = sizeof(buf) - 5; buf[n++] = '.'; buf[n++] = '.'; buf[n++] = '.'; buf[n++] = '\n'; buf[n] = '\0'; } if (n > 0) buf[n] = '\0'; lwsl_emit(filter, buf); } void _lws_log(int filter, const char *format, ...) { va_list ap; va_start(ap, format); _lws_logv(filter, format, ap); va_end(ap); } #endif void lws_set_log_level(int level, void (*func)(int level, const char *line)) { log_level = level; if (func) lwsl_emit = func; } int lwsl_visible(int level) { return log_level & level; } void lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len) { unsigned char *buf = (unsigned char *)vbuf; unsigned int n; if (!lwsl_visible(hexdump_level)) return; if (!len) { _lws_log(hexdump_level, "(hexdump: zero length)\n"); return; } if (!vbuf) { _lws_log(hexdump_level, "(hexdump: NULL ptr)\n"); return; } _lws_log(hexdump_level, "\n"); for (n = 0; n < len;) { unsigned int start = n, m; char line[80], *p = line; p += lws_snprintf(p, 10, "%04X: ", start); for (m = 0; m < 16 && n < len; m++) p += lws_snprintf(p, 5, "%02X ", buf[n++]); while (m++ < 16) p += lws_snprintf(p, 5, " "); p += lws_snprintf(p, 6, " "); for (m = 0; m < 16 && (start + m) < len; m++) { if (buf[start + m] >= ' ' && buf[start + m] < 127) *p++ = buf[start + m]; else *p++ = '.'; } while (m++ < 16) *p++ = ' '; *p++ = '\n'; *p = '\0'; _lws_log(hexdump_level, "%s", line); (void)line; } _lws_log(hexdump_level, "\n"); } void lwsl_hexdump(const void *vbuf, size_t len) { #if defined(_DEBUG) lwsl_hexdump_level(LLL_DEBUG, vbuf, len); #endif }