1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 #ifdef LWS_HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
30 
31 #if defined(LWS_PLAT_OPTEE)
32 void lwsl_emit_optee(int level, const char *line);
33 #endif
34 
35 int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE;
36 static void (*lwsl_emit)(int level, const char *line)
37 #ifndef LWS_PLAT_OPTEE
38 	= lwsl_emit_stderr
39 #else
40 	= lwsl_emit_optee;
41 #endif
42 	;
43 #ifndef LWS_PLAT_OPTEE
44 static const char * log_level_names ="EWNIDPHXCLUT??";
45 #endif
46 
47 #if defined(LWS_LOGS_TIMESTAMP)
48 int
lwsl_timestamp(int level,char * p,int len)49 lwsl_timestamp(int level, char *p, int len)
50 {
51 #ifndef LWS_PLAT_OPTEE
52 	time_t o_now;
53 	unsigned long long now;
54 	struct timeval tv;
55 	struct tm *ptm = NULL;
56 #ifndef WIN32
57 	struct tm tm;
58 #endif
59 	int n;
60 
61 	gettimeofday(&tv, NULL);
62 	o_now = tv.tv_sec;
63 	now = ((unsigned long long)tv.tv_sec * 10000) + (tv.tv_usec / 100);
64 
65 #ifndef _WIN32_WCE
66 #ifdef WIN32
67 	ptm = localtime(&o_now);
68 #else
69 	if (localtime_r(&o_now, &tm))
70 		ptm = &tm;
71 #endif
72 #endif
73 	p[0] = '\0';
74 	for (n = 0; n < LLL_COUNT; n++) {
75 		if (level != (1 << n))
76 			continue;
77 
78 		if (ptm)
79 			n = lws_snprintf(p, len,
80 				"[%04d/%02d/%02d %02d:%02d:%02d:%04d] %c: ",
81 				ptm->tm_year + 1900,
82 				ptm->tm_mon + 1,
83 				ptm->tm_mday,
84 				ptm->tm_hour,
85 				ptm->tm_min,
86 				ptm->tm_sec,
87 				(int)(now % 10000), log_level_names[n]);
88 		else
89 			n = lws_snprintf(p, len, "[%llu:%04d] %c: ",
90 					(unsigned long long) now / 10000,
91 					(int)(now % 10000), log_level_names[n]);
92 		return n;
93 	}
94 #else
95 	p[0] = '\0';
96 #endif
97 
98 	return 0;
99 }
100 #endif
101 
102 #ifndef LWS_PLAT_OPTEE
103 static const char * const colours[] = {
104 	"[31;1m", /* LLL_ERR */
105 	"[36;1m", /* LLL_WARN */
106 	"[35;1m", /* LLL_NOTICE */
107 	"[32;1m", /* LLL_INFO */
108 	"[34;1m", /* LLL_DEBUG */
109 	"[33;1m", /* LLL_PARSER */
110 	"[33m", /* LLL_HEADER */
111 	"[33m", /* LLL_EXT */
112 	"[33m", /* LLL_CLIENT */
113 	"[33;1m", /* LLL_LATENCY */
114         "[0;1m", /* LLL_USER */
115 	"[31m", /* LLL_THREAD */
116 };
117 
118 static char tty;
119 
120 static void
_lwsl_emit_stderr(int level,const char * line,int ts)121 _lwsl_emit_stderr(int level, const char *line, int ts)
122 {
123 	char buf[50];
124 	int n, m = LWS_ARRAY_SIZE(colours) - 1;
125 
126 	if (!tty)
127 		tty = isatty(2) | 2;
128 
129 	buf[0] = '\0';
130 #if defined(LWS_LOGS_TIMESTAMP)
131 	if (ts)
132 		lwsl_timestamp(level, buf, sizeof(buf));
133 #endif
134 
135 	if (tty == 3) {
136 		n = 1 << (LWS_ARRAY_SIZE(colours) - 1);
137 		while (n) {
138 			if (level & n)
139 				break;
140 			m--;
141 			n >>= 1;
142 		}
143 		fprintf(stderr, "%c%s%s%s%c[0m", 27, colours[m], buf, line, 27);
144 	} else
145 		fprintf(stderr, "%s%s", buf, line);
146 }
147 
148 void
lwsl_emit_stderr(int level,const char * line)149 lwsl_emit_stderr(int level, const char *line)
150 {
151 	_lwsl_emit_stderr(level, line, 1);
152 }
153 
154 void
lwsl_emit_stderr_notimestamp(int level,const char * line)155 lwsl_emit_stderr_notimestamp(int level, const char *line)
156 {
157 	_lwsl_emit_stderr(level, line, 0);
158 }
159 
160 #endif
161 
162 #if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK))
_lws_logv(int filter,const char * format,va_list vl)163 void _lws_logv(int filter, const char *format, va_list vl)
164 {
165 #if LWS_MAX_SMP == 1
166 	static char buf[256];
167 #else
168 	char buf[1024];
169 #endif
170 	int n;
171 
172 	if (!(log_level & filter))
173 		return;
174 
175 	n = vsnprintf(buf, sizeof(buf) - 1, format, vl);
176 	(void)n;
177 	/* vnsprintf returns what it would have written, even if truncated */
178 	if (n > (int)sizeof(buf) - 1) {
179 		n = sizeof(buf) - 5;
180 		buf[n++] = '.';
181 		buf[n++] = '.';
182 		buf[n++] = '.';
183 		buf[n++] = '\n';
184 		buf[n] = '\0';
185 	}
186 	if (n > 0)
187 		buf[n] = '\0';
188 	lwsl_emit(filter, buf);
189 }
190 
_lws_log(int filter,const char * format,...)191 void _lws_log(int filter, const char *format, ...)
192 {
193 	va_list ap;
194 
195 	va_start(ap, format);
196 	_lws_logv(filter, format, ap);
197 	va_end(ap);
198 }
199 #endif
lws_set_log_level(int level,void (* func)(int level,const char * line))200 void lws_set_log_level(int level, void (*func)(int level, const char *line))
201 {
202 	log_level = level;
203 	if (func)
204 		lwsl_emit = func;
205 }
206 
lwsl_visible(int level)207 int lwsl_visible(int level)
208 {
209 	return log_level & level;
210 }
211 
212 void
lwsl_hexdump_level(int hexdump_level,const void * vbuf,size_t len)213 lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)
214 {
215 	unsigned char *buf = (unsigned char *)vbuf;
216 	unsigned int n;
217 
218 	if (!lwsl_visible(hexdump_level))
219 		return;
220 
221 	if (!len) {
222 		_lws_log(hexdump_level, "(hexdump: zero length)\n");
223 		return;
224 	}
225 
226 	if (!vbuf) {
227 		_lws_log(hexdump_level, "(hexdump: NULL ptr)\n");
228 		return;
229 	}
230 
231 	_lws_log(hexdump_level, "\n");
232 
233 	for (n = 0; n < len;) {
234 		unsigned int start = n, m;
235 		char line[80], *p = line;
236 
237 		p += lws_snprintf(p, 10, "%04X: ", start);
238 
239 		for (m = 0; m < 16 && n < len; m++)
240 			p += lws_snprintf(p, 5, "%02X ", buf[n++]);
241 		while (m++ < 16)
242 			p += lws_snprintf(p, 5, "   ");
243 
244 		p += lws_snprintf(p, 6, "   ");
245 
246 		for (m = 0; m < 16 && (start + m) < len; m++) {
247 			if (buf[start + m] >= ' ' && buf[start + m] < 127)
248 				*p++ = buf[start + m];
249 			else
250 				*p++ = '.';
251 		}
252 		while (m++ < 16)
253 			*p++ = ' ';
254 
255 		*p++ = '\n';
256 		*p = '\0';
257 		_lws_log(hexdump_level, "%s", line);
258 		(void)line;
259 	}
260 
261 	_lws_log(hexdump_level, "\n");
262 }
263 
264 void
lwsl_hexdump(const void * vbuf,size_t len)265 lwsl_hexdump(const void *vbuf, size_t len)
266 {
267 #if defined(_DEBUG)
268 	lwsl_hexdump_level(LLL_DEBUG, vbuf, len);
269 #endif
270 }
271