1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci#ifdef LWS_HAVE_SYS_TYPES_H
28d4afb5ceSopenharmony_ci#include <sys/types.h>
29d4afb5ceSopenharmony_ci#endif
30d4afb5ceSopenharmony_ci
31d4afb5ceSopenharmony_ci#if defined(LWS_PLAT_OPTEE)
32d4afb5ceSopenharmony_civoid lwsl_emit_optee(int level, const char *line);
33d4afb5ceSopenharmony_ci#endif
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_cilws_log_cx_t log_cx = {
36d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE)
37d4afb5ceSopenharmony_ci	.u.emit				= lwsl_emit_stderr,
38d4afb5ceSopenharmony_ci#else
39d4afb5ceSopenharmony_ci	.u.emit				= lwsl_emit_optee,
40d4afb5ceSopenharmony_ci#endif
41d4afb5ceSopenharmony_ci	.lll_flags			= LLL_ERR | LLL_WARN | LLL_NOTICE,
42d4afb5ceSopenharmony_ci};
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NO_LOGS)
45d4afb5ceSopenharmony_cistatic const char * log_level_names ="EWNIDPHXCLUT??";
46d4afb5ceSopenharmony_ci#endif
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_ci/*
49d4afb5ceSopenharmony_ci * Name an instance tag and attach to a group
50d4afb5ceSopenharmony_ci */
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_civoid
53d4afb5ceSopenharmony_ci__lws_lc_tag(struct lws_context *context, lws_lifecycle_group_t *grp,
54d4afb5ceSopenharmony_ci	     lws_lifecycle_t *lc, const char *format, ...)
55d4afb5ceSopenharmony_ci{
56d4afb5ceSopenharmony_ci	va_list ap;
57d4afb5ceSopenharmony_ci	int n = 1;
58d4afb5ceSopenharmony_ci
59d4afb5ceSopenharmony_ci	if (*lc->gutag == '[') {
60d4afb5ceSopenharmony_ci		/* appending inside [] */
61d4afb5ceSopenharmony_ci
62d4afb5ceSopenharmony_ci		char *cp = strchr(lc->gutag, ']');
63d4afb5ceSopenharmony_ci		char rend[96];
64d4afb5ceSopenharmony_ci		size_t ll, k;
65d4afb5ceSopenharmony_ci		int n;
66d4afb5ceSopenharmony_ci
67d4afb5ceSopenharmony_ci		if (!cp)
68d4afb5ceSopenharmony_ci			return;
69d4afb5ceSopenharmony_ci
70d4afb5ceSopenharmony_ci		/* length of closing brace and anything else after it */
71d4afb5ceSopenharmony_ci		k = strlen(cp);
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci		/* compute the remaining gutag unused */
74d4afb5ceSopenharmony_ci		ll = sizeof(lc->gutag) - lws_ptr_diff_size_t(cp, lc->gutag) - k - 1;
75d4afb5ceSopenharmony_ci		if (ll > sizeof(rend) - 1)
76d4afb5ceSopenharmony_ci			ll = sizeof(rend) - 1;
77d4afb5ceSopenharmony_ci		va_start(ap, format);
78d4afb5ceSopenharmony_ci		n = vsnprintf(rend, ll, format, ap);
79d4afb5ceSopenharmony_ci		va_end(ap);
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_ci		if ((unsigned int)n > ll)
82d4afb5ceSopenharmony_ci			n = (int)ll;
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci		/* shove the trailer up by what we added */
85d4afb5ceSopenharmony_ci		memmove(cp + n, cp, k);
86d4afb5ceSopenharmony_ci		assert(k + (unsigned int)n < sizeof(lc->gutag));
87d4afb5ceSopenharmony_ci		cp[k + (unsigned int)n] = '\0';
88d4afb5ceSopenharmony_ci		/* copy what we added into place */
89d4afb5ceSopenharmony_ci		memcpy(cp, rend, (unsigned int)n);
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci		return;
92d4afb5ceSopenharmony_ci	}
93d4afb5ceSopenharmony_ci
94d4afb5ceSopenharmony_ci	assert(grp);
95d4afb5ceSopenharmony_ci	assert(grp->tag_prefix); /* lc group must have a tag prefix string */
96d4afb5ceSopenharmony_ci
97d4afb5ceSopenharmony_ci	lc->gutag[0] = '[';
98d4afb5ceSopenharmony_ci
99d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) /* ie, will have getpid if set */
100d4afb5ceSopenharmony_ci	n += lws_snprintf(&lc->gutag[n], sizeof(lc->gutag) -
101d4afb5ceSopenharmony_ci					 (unsigned int)n - 1u, "%u|", getpid());
102d4afb5ceSopenharmony_ci#endif
103d4afb5ceSopenharmony_ci	n += lws_snprintf(&lc->gutag[n], sizeof(lc->gutag) -
104d4afb5ceSopenharmony_ci					 (unsigned int)n - 1u, "%s|%lx|",
105d4afb5ceSopenharmony_ci					 grp->tag_prefix,
106d4afb5ceSopenharmony_ci					 (unsigned long)grp->ordinal++);
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci	va_start(ap, format);
109d4afb5ceSopenharmony_ci	n += vsnprintf(&lc->gutag[n], sizeof(lc->gutag) - (unsigned int)n -
110d4afb5ceSopenharmony_ci			1u, format, ap);
111d4afb5ceSopenharmony_ci	va_end(ap);
112d4afb5ceSopenharmony_ci
113d4afb5ceSopenharmony_ci	if (n < (int)sizeof(lc->gutag) - 2) {
114d4afb5ceSopenharmony_ci		lc->gutag[n++] = ']';
115d4afb5ceSopenharmony_ci		lc->gutag[n++] = '\0';
116d4afb5ceSopenharmony_ci	} else {
117d4afb5ceSopenharmony_ci		lc->gutag[sizeof(lc->gutag) - 2] = ']';
118d4afb5ceSopenharmony_ci		lc->gutag[sizeof(lc->gutag) - 1] = '\0';
119d4afb5ceSopenharmony_ci	}
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci	lc->us_creation = (uint64_t)lws_now_usecs();
122d4afb5ceSopenharmony_ci	lws_dll2_add_tail(&lc->list, &grp->owner);
123d4afb5ceSopenharmony_ci
124d4afb5ceSopenharmony_ci	lwsl_refcount_cx(lc->log_cx, 1);
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci#if defined(LWS_LOG_TAG_LIFECYCLE)
127d4afb5ceSopenharmony_ci	lwsl_cx_notice(context, " ++ %s (%d)", lc->gutag, (int)grp->owner.count);
128d4afb5ceSopenharmony_ci#endif
129d4afb5ceSopenharmony_ci}
130d4afb5ceSopenharmony_ci
131d4afb5ceSopenharmony_ci/*
132d4afb5ceSopenharmony_ci * Normally we want to set the tag one time at creation.  But sometimes we
133d4afb5ceSopenharmony_ci * don't have enough information at that point to give it a meaningful tag, eg,
134d4afb5ceSopenharmony_ci * it's an accepted, served connection but we haven't read data from it yet
135d4afb5ceSopenharmony_ci * to find out what it wants to be.
136d4afb5ceSopenharmony_ci *
137d4afb5ceSopenharmony_ci * This allows you to append some extra info to the tag in those cases, the
138d4afb5ceSopenharmony_ci * initial tag remains the same on the lhs so it can be tracked correctly.
139d4afb5ceSopenharmony_ci */
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_civoid
142d4afb5ceSopenharmony_ci__lws_lc_tag_append(lws_lifecycle_t *lc, const char *app)
143d4afb5ceSopenharmony_ci{
144d4afb5ceSopenharmony_ci	int n = (int)strlen(lc->gutag);
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_ci	if (n && lc->gutag[n - 1] == ']')
147d4afb5ceSopenharmony_ci		n--;
148d4afb5ceSopenharmony_ci
149d4afb5ceSopenharmony_ci	n += lws_snprintf(&lc->gutag[n], sizeof(lc->gutag) - 2u -
150d4afb5ceSopenharmony_ci					 (unsigned int)n, "|%s]", app);
151d4afb5ceSopenharmony_ci
152d4afb5ceSopenharmony_ci	if ((unsigned int)n >= sizeof(lc->gutag) - 2u) {
153d4afb5ceSopenharmony_ci		lc->gutag[sizeof(lc->gutag) - 2] = ']';
154d4afb5ceSopenharmony_ci		lc->gutag[sizeof(lc->gutag) - 1] = '\0';
155d4afb5ceSopenharmony_ci	}
156d4afb5ceSopenharmony_ci}
157d4afb5ceSopenharmony_ci
158d4afb5ceSopenharmony_ci/*
159d4afb5ceSopenharmony_ci * Remove instance from group
160d4afb5ceSopenharmony_ci */
161d4afb5ceSopenharmony_ci
162d4afb5ceSopenharmony_civoid
163d4afb5ceSopenharmony_ci__lws_lc_untag(struct lws_context *context, lws_lifecycle_t *lc)
164d4afb5ceSopenharmony_ci{
165d4afb5ceSopenharmony_ci	//lws_lifecycle_group_t *grp;
166d4afb5ceSopenharmony_ci	char buf[24];
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci	if (!lc->gutag[0]) { /* we never tagged this object... */
169d4afb5ceSopenharmony_ci		lwsl_cx_err(context, "%s never tagged", lc->gutag);
170d4afb5ceSopenharmony_ci		assert(0);
171d4afb5ceSopenharmony_ci		return;
172d4afb5ceSopenharmony_ci	}
173d4afb5ceSopenharmony_ci
174d4afb5ceSopenharmony_ci	if (!lc->list.owner) { /* we already untagged this object... */
175d4afb5ceSopenharmony_ci		lwsl_cx_err(context, "%s untagged twice", lc->gutag);
176d4afb5ceSopenharmony_ci		assert(0);
177d4afb5ceSopenharmony_ci		return;
178d4afb5ceSopenharmony_ci	}
179d4afb5ceSopenharmony_ci
180d4afb5ceSopenharmony_ci	//grp = lws_container_of(lc->list.owner, lws_lifecycle_group_t, owner);
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci	lws_humanize(buf, sizeof(buf),
183d4afb5ceSopenharmony_ci		     (uint64_t)lws_now_usecs() - lc->us_creation,
184d4afb5ceSopenharmony_ci		     humanize_schema_us);
185d4afb5ceSopenharmony_ci
186d4afb5ceSopenharmony_ci#if defined(LWS_LOG_TAG_LIFECYCLE)
187d4afb5ceSopenharmony_ci	lwsl_cx_notice(context, " -- %s (%d) %s", lc->gutag,
188d4afb5ceSopenharmony_ci		    (int)lc->list.owner->count - 1, buf);
189d4afb5ceSopenharmony_ci#endif
190d4afb5ceSopenharmony_ci
191d4afb5ceSopenharmony_ci	lws_dll2_remove(&lc->list);
192d4afb5ceSopenharmony_ci
193d4afb5ceSopenharmony_ci	lwsl_refcount_cx(lc->log_cx, -1);
194d4afb5ceSopenharmony_ci}
195d4afb5ceSopenharmony_ci
196d4afb5ceSopenharmony_ciconst char *
197d4afb5ceSopenharmony_cilws_lc_tag(lws_lifecycle_t *lc)
198d4afb5ceSopenharmony_ci{
199d4afb5ceSopenharmony_ci	return lc->gutag;
200d4afb5ceSopenharmony_ci}
201d4afb5ceSopenharmony_ci
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ciint
204d4afb5ceSopenharmony_cilwsl_timestamp(int level, char *p, size_t len)
205d4afb5ceSopenharmony_ci{
206d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NO_LOGS)
207d4afb5ceSopenharmony_ci	time_t o_now;
208d4afb5ceSopenharmony_ci	unsigned long long now;
209d4afb5ceSopenharmony_ci	struct timeval tv;
210d4afb5ceSopenharmony_ci	struct tm *ptm = NULL;
211d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_LOCALTIME_R)
212d4afb5ceSopenharmony_ci	struct tm tm;
213d4afb5ceSopenharmony_ci#endif
214d4afb5ceSopenharmony_ci	int n;
215d4afb5ceSopenharmony_ci
216d4afb5ceSopenharmony_ci	gettimeofday(&tv, NULL);
217d4afb5ceSopenharmony_ci	o_now = tv.tv_sec;
218d4afb5ceSopenharmony_ci	now = ((unsigned long long)tv.tv_sec * 10000) +
219d4afb5ceSopenharmony_ci				(unsigned int)(tv.tv_usec / 100);
220d4afb5ceSopenharmony_ci
221d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_LOCALTIME_R)
222d4afb5ceSopenharmony_ci	ptm = localtime_r(&o_now, &tm);
223d4afb5ceSopenharmony_ci#else
224d4afb5ceSopenharmony_ci	ptm = localtime(&o_now);
225d4afb5ceSopenharmony_ci#endif
226d4afb5ceSopenharmony_ci	p[0] = '\0';
227d4afb5ceSopenharmony_ci	for (n = 0; n < LLL_COUNT; n++) {
228d4afb5ceSopenharmony_ci		if (level != (1 << n))
229d4afb5ceSopenharmony_ci			continue;
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci		if (ptm)
232d4afb5ceSopenharmony_ci			n = lws_snprintf(p, len,
233d4afb5ceSopenharmony_ci				"[%04d/%02d/%02d %02d:%02d:%02d:%04d] %c: ",
234d4afb5ceSopenharmony_ci				ptm->tm_year + 1900,
235d4afb5ceSopenharmony_ci				ptm->tm_mon + 1,
236d4afb5ceSopenharmony_ci				ptm->tm_mday,
237d4afb5ceSopenharmony_ci				ptm->tm_hour,
238d4afb5ceSopenharmony_ci				ptm->tm_min,
239d4afb5ceSopenharmony_ci				ptm->tm_sec,
240d4afb5ceSopenharmony_ci				(int)(now % 10000), log_level_names[n]);
241d4afb5ceSopenharmony_ci		else
242d4afb5ceSopenharmony_ci			n = lws_snprintf(p, len, "[%llu:%04d] %c: ",
243d4afb5ceSopenharmony_ci					(unsigned long long) now / 10000,
244d4afb5ceSopenharmony_ci					(int)(now % 10000), log_level_names[n]);
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci#if defined(LWS_PLAT_FREERTOS)
247d4afb5ceSopenharmony_ci		n += lws_snprintf(p + n, len - n, "%6u: ",
248d4afb5ceSopenharmony_ci#if defined(LWS_AMAZON_RTOS)
249d4afb5ceSopenharmony_ci				  (unsigned int)xPortGetFreeHeapSize());
250d4afb5ceSopenharmony_ci#else
251d4afb5ceSopenharmony_ci				  (unsigned int)esp_get_free_heap_size());
252d4afb5ceSopenharmony_ci#endif
253d4afb5ceSopenharmony_ci#endif
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_ci		return n;
256d4afb5ceSopenharmony_ci	}
257d4afb5ceSopenharmony_ci#else
258d4afb5ceSopenharmony_ci	p[0] = '\0';
259d4afb5ceSopenharmony_ci#endif
260d4afb5ceSopenharmony_ci
261d4afb5ceSopenharmony_ci	return 0;
262d4afb5ceSopenharmony_ci}
263d4afb5ceSopenharmony_ci
264d4afb5ceSopenharmony_ci#ifndef LWS_PLAT_OPTEE
265d4afb5ceSopenharmony_cistatic const char * const colours[] = {
266d4afb5ceSopenharmony_ci	"[31;1m", /* LLL_ERR */
267d4afb5ceSopenharmony_ci	"[36;1m", /* LLL_WARN */
268d4afb5ceSopenharmony_ci	"[35;1m", /* LLL_NOTICE */
269d4afb5ceSopenharmony_ci	"[32;1m", /* LLL_INFO */
270d4afb5ceSopenharmony_ci	"[34;1m", /* LLL_DEBUG */
271d4afb5ceSopenharmony_ci	"[33;1m", /* LLL_PARSER */
272d4afb5ceSopenharmony_ci	"[33m", /* LLL_HEADER */
273d4afb5ceSopenharmony_ci	"[33m", /* LLL_EXT */
274d4afb5ceSopenharmony_ci	"[33m", /* LLL_CLIENT */
275d4afb5ceSopenharmony_ci	"[33;1m", /* LLL_LATENCY */
276d4afb5ceSopenharmony_ci        "[0;1m", /* LLL_USER */
277d4afb5ceSopenharmony_ci	"[31m", /* LLL_THREAD */
278d4afb5ceSopenharmony_ci};
279d4afb5ceSopenharmony_ci
280d4afb5ceSopenharmony_cistatic char tty;
281d4afb5ceSopenharmony_ci
282d4afb5ceSopenharmony_cistatic void
283d4afb5ceSopenharmony_ci_lwsl_emit_stderr(int level, const char *line)
284d4afb5ceSopenharmony_ci{
285d4afb5ceSopenharmony_ci	int n, m = LWS_ARRAY_SIZE(colours) - 1;
286d4afb5ceSopenharmony_ci
287d4afb5ceSopenharmony_ci	if (!tty)
288d4afb5ceSopenharmony_ci		tty = (char)(isatty(2) | 2);
289d4afb5ceSopenharmony_ci
290d4afb5ceSopenharmony_ci	if (tty == 3) {
291d4afb5ceSopenharmony_ci		n = 1 << (LWS_ARRAY_SIZE(colours) - 1);
292d4afb5ceSopenharmony_ci		while (n) {
293d4afb5ceSopenharmony_ci			if (level & n)
294d4afb5ceSopenharmony_ci				break;
295d4afb5ceSopenharmony_ci			m--;
296d4afb5ceSopenharmony_ci			n >>= 1;
297d4afb5ceSopenharmony_ci		}
298d4afb5ceSopenharmony_ci		fprintf(stderr, "%c%s%s%c[0m", 27, colours[m], line, 27);
299d4afb5ceSopenharmony_ci	} else
300d4afb5ceSopenharmony_ci		fprintf(stderr, "%s", line);
301d4afb5ceSopenharmony_ci}
302d4afb5ceSopenharmony_ci
303d4afb5ceSopenharmony_civoid
304d4afb5ceSopenharmony_cilwsl_emit_stderr(int level, const char *line)
305d4afb5ceSopenharmony_ci{
306d4afb5ceSopenharmony_ci	_lwsl_emit_stderr(level, line);
307d4afb5ceSopenharmony_ci}
308d4afb5ceSopenharmony_ci
309d4afb5ceSopenharmony_civoid
310d4afb5ceSopenharmony_cilwsl_emit_stderr_notimestamp(int level, const char *line)
311d4afb5ceSopenharmony_ci{
312d4afb5ceSopenharmony_ci	_lwsl_emit_stderr(level, line);
313d4afb5ceSopenharmony_ci}
314d4afb5ceSopenharmony_ci
315d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
316d4afb5ceSopenharmony_ci
317d4afb5ceSopenharmony_ci/*
318d4afb5ceSopenharmony_ci * Helper to emit to a file
319d4afb5ceSopenharmony_ci */
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_civoid
322d4afb5ceSopenharmony_cilws_log_emit_cx_file(struct lws_log_cx *cx, int level, const char *line,
323d4afb5ceSopenharmony_ci			size_t len)
324d4afb5ceSopenharmony_ci{
325d4afb5ceSopenharmony_ci	int fd = (int)(intptr_t)cx->stg;
326d4afb5ceSopenharmony_ci
327d4afb5ceSopenharmony_ci	if (fd >= 0)
328d4afb5ceSopenharmony_ci		if (write(fd, line, (unsigned int)len) != (ssize_t)len)
329d4afb5ceSopenharmony_ci			fprintf(stderr, "Unable to write log to file\n");
330d4afb5ceSopenharmony_ci}
331d4afb5ceSopenharmony_ci
332d4afb5ceSopenharmony_ci/*
333d4afb5ceSopenharmony_ci * Helper to use a .refcount_cb to store logs in a file
334d4afb5ceSopenharmony_ci */
335d4afb5ceSopenharmony_ci
336d4afb5ceSopenharmony_civoid
337d4afb5ceSopenharmony_cilws_log_use_cx_file(struct lws_log_cx *cx, int _new)
338d4afb5ceSopenharmony_ci{
339d4afb5ceSopenharmony_ci	int fd;
340d4afb5ceSopenharmony_ci
341d4afb5ceSopenharmony_ci	if (_new > 0 && cx->refcount == 1) {
342d4afb5ceSopenharmony_ci		fd = open((const char *)cx->opaque,
343d4afb5ceSopenharmony_ci				LWS_O_CREAT | LWS_O_TRUNC | LWS_O_WRONLY, 0600);
344d4afb5ceSopenharmony_ci		if (fd < 0)
345d4afb5ceSopenharmony_ci			fprintf(stderr, "Unable to open log %s: errno %d\n",
346d4afb5ceSopenharmony_ci				(const char *)cx->opaque, errno);
347d4afb5ceSopenharmony_ci		cx->stg = (void *)(intptr_t)fd;
348d4afb5ceSopenharmony_ci
349d4afb5ceSopenharmony_ci		return;
350d4afb5ceSopenharmony_ci	}
351d4afb5ceSopenharmony_ci
352d4afb5ceSopenharmony_ci	fd = (int)(intptr_t)cx->stg;
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci	if (_new <= 0 && cx->refcount == 0 && fd >= 0) {
355d4afb5ceSopenharmony_ci		close(fd);
356d4afb5ceSopenharmony_ci		cx->stg = (void *)(intptr_t)-1;
357d4afb5ceSopenharmony_ci	}
358d4afb5ceSopenharmony_ci}
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci#endif
361d4afb5ceSopenharmony_ci
362d4afb5ceSopenharmony_ci#endif
363d4afb5ceSopenharmony_ci
364d4afb5ceSopenharmony_ci#if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK))
365d4afb5ceSopenharmony_civoid
366d4afb5ceSopenharmony_ci__lws_logv(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
367d4afb5ceSopenharmony_ci	   int filter, const char *_fun, const char *format, va_list vl)
368d4afb5ceSopenharmony_ci{
369d4afb5ceSopenharmony_ci#if LWS_MAX_SMP == 1 && !defined(LWS_WITH_THREADPOOL)
370d4afb5ceSopenharmony_ci	/* this is incompatible with multithreaded logging */
371d4afb5ceSopenharmony_ci	static char buf[256];
372d4afb5ceSopenharmony_ci#else
373d4afb5ceSopenharmony_ci	char buf[1024];
374d4afb5ceSopenharmony_ci#endif
375d4afb5ceSopenharmony_ci	char *p = buf, *end = p + sizeof(buf) - 1;
376d4afb5ceSopenharmony_ci	lws_log_cx_t *cxp;
377d4afb5ceSopenharmony_ci	int n, back = 0;
378d4afb5ceSopenharmony_ci
379d4afb5ceSopenharmony_ci	/*
380d4afb5ceSopenharmony_ci	 * We need to handle NULL wsi etc at the wrappers as gracefully as
381d4afb5ceSopenharmony_ci	 * possible
382d4afb5ceSopenharmony_ci	 */
383d4afb5ceSopenharmony_ci
384d4afb5ceSopenharmony_ci	if (!cx) {
385d4afb5ceSopenharmony_ci		lws_strncpy(p, "NULL log cx: ", sizeof(buf) - 1);
386d4afb5ceSopenharmony_ci		p += 13;
387d4afb5ceSopenharmony_ci		/* use the processwide one for lack of anything better */
388d4afb5ceSopenharmony_ci		cx = &log_cx;
389d4afb5ceSopenharmony_ci	}
390d4afb5ceSopenharmony_ci
391d4afb5ceSopenharmony_ci	cxp = cx;
392d4afb5ceSopenharmony_ci
393d4afb5ceSopenharmony_ci	if (!(cx->lll_flags & (uint32_t)filter))
394d4afb5ceSopenharmony_ci		/*
395d4afb5ceSopenharmony_ci		 * logs may be produced and built in to the code but disabled
396d4afb5ceSopenharmony_ci		 * at runtime
397d4afb5ceSopenharmony_ci		 */
398d4afb5ceSopenharmony_ci		return;
399d4afb5ceSopenharmony_ci
400d4afb5ceSopenharmony_ci#if !defined(LWS_LOGS_TIMESTAMP)
401d4afb5ceSopenharmony_ci	if (cx->lll_flags & LLLF_LOG_TIMESTAMP)
402d4afb5ceSopenharmony_ci#endif
403d4afb5ceSopenharmony_ci	{
404d4afb5ceSopenharmony_ci		buf[0] = '\0';
405d4afb5ceSopenharmony_ci		lwsl_timestamp(filter, buf, sizeof(buf));
406d4afb5ceSopenharmony_ci		p += strlen(buf);
407d4afb5ceSopenharmony_ci	}
408d4afb5ceSopenharmony_ci
409d4afb5ceSopenharmony_ci	/*
410d4afb5ceSopenharmony_ci	 * prepend parent log ctx content first
411d4afb5ceSopenharmony_ci	 * top level cx also gets an opportunity to prepend
412d4afb5ceSopenharmony_ci	 */
413d4afb5ceSopenharmony_ci
414d4afb5ceSopenharmony_ci	while (cxp->parent) {
415d4afb5ceSopenharmony_ci		cxp = cxp->parent;
416d4afb5ceSopenharmony_ci		back++;
417d4afb5ceSopenharmony_ci	}
418d4afb5ceSopenharmony_ci
419d4afb5ceSopenharmony_ci	do {
420d4afb5ceSopenharmony_ci		int b = back;
421d4afb5ceSopenharmony_ci
422d4afb5ceSopenharmony_ci		cxp = cx;
423d4afb5ceSopenharmony_ci		while (b--)
424d4afb5ceSopenharmony_ci			cxp = cxp->parent;
425d4afb5ceSopenharmony_ci		if (cxp->prepend)
426d4afb5ceSopenharmony_ci			cxp->prepend(cxp, NULL, &p, end);
427d4afb5ceSopenharmony_ci
428d4afb5ceSopenharmony_ci		back--;
429d4afb5ceSopenharmony_ci	} while (back > 0);
430d4afb5ceSopenharmony_ci
431d4afb5ceSopenharmony_ci	if (prep)
432d4afb5ceSopenharmony_ci		prep(cxp, obj, &p, end);
433d4afb5ceSopenharmony_ci
434d4afb5ceSopenharmony_ci	if (_fun)
435d4afb5ceSopenharmony_ci		p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s: ", _fun);
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_ci	/*
438d4afb5ceSopenharmony_ci	 * The actual log content
439d4afb5ceSopenharmony_ci	 */
440d4afb5ceSopenharmony_ci
441d4afb5ceSopenharmony_ci	n = vsnprintf(p, lws_ptr_diff_size_t(end, p), format, vl);
442d4afb5ceSopenharmony_ci
443d4afb5ceSopenharmony_ci	/* vnsprintf returns what it would have written, even if truncated */
444d4afb5ceSopenharmony_ci	if (p + n > end - 2) {
445d4afb5ceSopenharmony_ci		p = end - 5;
446d4afb5ceSopenharmony_ci		*p++ = '.';
447d4afb5ceSopenharmony_ci		*p++ = '.';
448d4afb5ceSopenharmony_ci		*p++ = '.';
449d4afb5ceSopenharmony_ci		*p++ = '\n';
450d4afb5ceSopenharmony_ci		*p++ = '\0';
451d4afb5ceSopenharmony_ci	} else
452d4afb5ceSopenharmony_ci		if (n > 0) {
453d4afb5ceSopenharmony_ci			p += n;
454d4afb5ceSopenharmony_ci			if (p[-1] != '\n')
455d4afb5ceSopenharmony_ci				*p++ = '\n';
456d4afb5ceSopenharmony_ci			*p = '\0';
457d4afb5ceSopenharmony_ci		}
458d4afb5ceSopenharmony_ci
459d4afb5ceSopenharmony_ci	/*
460d4afb5ceSopenharmony_ci	 * The actual emit
461d4afb5ceSopenharmony_ci	 */
462d4afb5ceSopenharmony_ci
463d4afb5ceSopenharmony_ci	if (cx->lll_flags & LLLF_LOG_CONTEXT_AWARE)
464d4afb5ceSopenharmony_ci		cx->u.emit_cx(cx, filter, buf, lws_ptr_diff_size_t(p, buf));
465d4afb5ceSopenharmony_ci	else
466d4afb5ceSopenharmony_ci		cx->u.emit(filter, buf);
467d4afb5ceSopenharmony_ci}
468d4afb5ceSopenharmony_ci
469d4afb5ceSopenharmony_civoid _lws_logv(int filter, const char *format, va_list vl)
470d4afb5ceSopenharmony_ci{
471d4afb5ceSopenharmony_ci	__lws_logv(&log_cx, NULL, NULL, filter, NULL, format, vl);
472d4afb5ceSopenharmony_ci}
473d4afb5ceSopenharmony_ci
474d4afb5ceSopenharmony_civoid _lws_log(int filter, const char *format, ...)
475d4afb5ceSopenharmony_ci{
476d4afb5ceSopenharmony_ci	va_list ap;
477d4afb5ceSopenharmony_ci
478d4afb5ceSopenharmony_ci	va_start(ap, format);
479d4afb5ceSopenharmony_ci	__lws_logv(&log_cx, NULL, NULL, filter, NULL, format, ap);
480d4afb5ceSopenharmony_ci	va_end(ap);
481d4afb5ceSopenharmony_ci}
482d4afb5ceSopenharmony_ci
483d4afb5ceSopenharmony_civoid _lws_log_cx(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
484d4afb5ceSopenharmony_ci		 int filter, const char *_fun, const char *format, ...)
485d4afb5ceSopenharmony_ci{
486d4afb5ceSopenharmony_ci	va_list ap;
487d4afb5ceSopenharmony_ci
488d4afb5ceSopenharmony_ci	if (!cx)
489d4afb5ceSopenharmony_ci		cx = &log_cx;
490d4afb5ceSopenharmony_ci
491d4afb5ceSopenharmony_ci	va_start(ap, format);
492d4afb5ceSopenharmony_ci	__lws_logv(cx, prep, obj, filter, _fun, format, ap);
493d4afb5ceSopenharmony_ci	va_end(ap);
494d4afb5ceSopenharmony_ci}
495d4afb5ceSopenharmony_ci#endif
496d4afb5ceSopenharmony_ci
497d4afb5ceSopenharmony_civoid
498d4afb5ceSopenharmony_cilws_set_log_level(int flags, lws_log_emit_t func)
499d4afb5ceSopenharmony_ci{
500d4afb5ceSopenharmony_ci	log_cx.lll_flags = (uint32_t)(flags & (~LLLF_LOG_CONTEXT_AWARE));
501d4afb5ceSopenharmony_ci
502d4afb5ceSopenharmony_ci	if (func)
503d4afb5ceSopenharmony_ci		log_cx.u.emit = func;
504d4afb5ceSopenharmony_ci}
505d4afb5ceSopenharmony_ci
506d4afb5ceSopenharmony_ciint lwsl_visible(int level)
507d4afb5ceSopenharmony_ci{
508d4afb5ceSopenharmony_ci	return !!(log_cx.lll_flags & (uint32_t)level);
509d4afb5ceSopenharmony_ci}
510d4afb5ceSopenharmony_ci
511d4afb5ceSopenharmony_ciint lwsl_visible_cx(lws_log_cx_t *cx, int level)
512d4afb5ceSopenharmony_ci{
513d4afb5ceSopenharmony_ci	return !!(cx->lll_flags & (uint32_t)level);
514d4afb5ceSopenharmony_ci}
515d4afb5ceSopenharmony_ci
516d4afb5ceSopenharmony_civoid
517d4afb5ceSopenharmony_cilwsl_refcount_cx(lws_log_cx_t *cx, int _new)
518d4afb5ceSopenharmony_ci{
519d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1
520d4afb5ceSopenharmony_ci	volatile lws_log_cx_t *vcx = (volatile lws_log_cx_t *)cx;
521d4afb5ceSopenharmony_ci#endif
522d4afb5ceSopenharmony_ci
523d4afb5ceSopenharmony_ci	if (!cx)
524d4afb5ceSopenharmony_ci		return;
525d4afb5ceSopenharmony_ci
526d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1
527d4afb5ceSopenharmony_ci	if (!vcx->inited) {
528d4afb5ceSopenharmony_ci		vcx->inited = 1;
529d4afb5ceSopenharmony_ci		lws_pthread_mutex_init(&cx->refcount_lock);
530d4afb5ceSopenharmony_ci		vcx->inited = 2;
531d4afb5ceSopenharmony_ci	}
532d4afb5ceSopenharmony_ci	while (vcx->inited != 2)
533d4afb5ceSopenharmony_ci		;
534d4afb5ceSopenharmony_ci	lws_pthread_mutex_lock(&cx->refcount_lock);
535d4afb5ceSopenharmony_ci#endif
536d4afb5ceSopenharmony_ci
537d4afb5ceSopenharmony_ci	if (_new > 0)
538d4afb5ceSopenharmony_ci		cx->refcount++;
539d4afb5ceSopenharmony_ci	else {
540d4afb5ceSopenharmony_ci		assert(cx->refcount);
541d4afb5ceSopenharmony_ci		cx->refcount--;
542d4afb5ceSopenharmony_ci	}
543d4afb5ceSopenharmony_ci
544d4afb5ceSopenharmony_ci	if (cx->refcount_cb)
545d4afb5ceSopenharmony_ci		cx->refcount_cb(cx, _new);
546d4afb5ceSopenharmony_ci
547d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1
548d4afb5ceSopenharmony_ci	lws_pthread_mutex_unlock(&cx->refcount_lock);
549d4afb5ceSopenharmony_ci#endif
550d4afb5ceSopenharmony_ci}
551d4afb5ceSopenharmony_ci
552d4afb5ceSopenharmony_civoid
553d4afb5ceSopenharmony_cilwsl_hexdump_level_cx(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
554d4afb5ceSopenharmony_ci		      int hexdump_level, const void *vbuf, size_t len)
555d4afb5ceSopenharmony_ci{
556d4afb5ceSopenharmony_ci	unsigned char *buf = (unsigned char *)vbuf;
557d4afb5ceSopenharmony_ci	unsigned int n;
558d4afb5ceSopenharmony_ci
559d4afb5ceSopenharmony_ci	if (!lwsl_visible_cx(cx, hexdump_level))
560d4afb5ceSopenharmony_ci		return;
561d4afb5ceSopenharmony_ci
562d4afb5ceSopenharmony_ci	if (!len) {
563d4afb5ceSopenharmony_ci		_lws_log_cx(cx, prep, obj, hexdump_level, NULL,
564d4afb5ceSopenharmony_ci					"(hexdump: zero length)\n");
565d4afb5ceSopenharmony_ci		return;
566d4afb5ceSopenharmony_ci	}
567d4afb5ceSopenharmony_ci
568d4afb5ceSopenharmony_ci	if (!vbuf) {
569d4afb5ceSopenharmony_ci		_lws_log_cx(cx, prep, obj, hexdump_level, NULL,
570d4afb5ceSopenharmony_ci					"(hexdump: NULL ptr)\n");
571d4afb5ceSopenharmony_ci		return;
572d4afb5ceSopenharmony_ci	}
573d4afb5ceSopenharmony_ci
574d4afb5ceSopenharmony_ci	_lws_log_cx(cx, prep, obj, hexdump_level, NULL, "\n");
575d4afb5ceSopenharmony_ci
576d4afb5ceSopenharmony_ci	for (n = 0; n < len;) {
577d4afb5ceSopenharmony_ci		unsigned int start = n, m;
578d4afb5ceSopenharmony_ci		char line[80], *p = line;
579d4afb5ceSopenharmony_ci
580d4afb5ceSopenharmony_ci		p += lws_snprintf(p, 10, "%04X: ", start);
581d4afb5ceSopenharmony_ci
582d4afb5ceSopenharmony_ci		for (m = 0; m < 16 && n < len; m++)
583d4afb5ceSopenharmony_ci			p += lws_snprintf(p, 5, "%02X ", buf[n++]);
584d4afb5ceSopenharmony_ci		while (m++ < 16)
585d4afb5ceSopenharmony_ci			p += lws_snprintf(p, 5, "   ");
586d4afb5ceSopenharmony_ci
587d4afb5ceSopenharmony_ci		p += lws_snprintf(p, 6, "   ");
588d4afb5ceSopenharmony_ci
589d4afb5ceSopenharmony_ci		for (m = 0; m < 16 && (start + m) < len; m++) {
590d4afb5ceSopenharmony_ci			if (buf[start + m] >= ' ' && buf[start + m] < 127)
591d4afb5ceSopenharmony_ci				*p++ = (char)buf[start + m];
592d4afb5ceSopenharmony_ci			else
593d4afb5ceSopenharmony_ci				*p++ = '.';
594d4afb5ceSopenharmony_ci		}
595d4afb5ceSopenharmony_ci		while (m++ < 16)
596d4afb5ceSopenharmony_ci			*p++ = ' ';
597d4afb5ceSopenharmony_ci
598d4afb5ceSopenharmony_ci		*p++ = '\n';
599d4afb5ceSopenharmony_ci		*p = '\0';
600d4afb5ceSopenharmony_ci		_lws_log_cx(cx, prep, obj, hexdump_level, NULL, "%s", line);
601d4afb5ceSopenharmony_ci		(void)line;
602d4afb5ceSopenharmony_ci	}
603d4afb5ceSopenharmony_ci
604d4afb5ceSopenharmony_ci	_lws_log_cx(cx, prep, obj, hexdump_level, NULL, "\n");
605d4afb5ceSopenharmony_ci}
606d4afb5ceSopenharmony_ci
607d4afb5ceSopenharmony_civoid
608d4afb5ceSopenharmony_cilwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)
609d4afb5ceSopenharmony_ci{
610d4afb5ceSopenharmony_ci	lwsl_hexdump_level_cx(&log_cx, NULL, NULL, hexdump_level, vbuf, len);
611d4afb5ceSopenharmony_ci}
612d4afb5ceSopenharmony_ci
613d4afb5ceSopenharmony_civoid
614d4afb5ceSopenharmony_cilwsl_hexdump(const void *vbuf, size_t len)
615d4afb5ceSopenharmony_ci{
616d4afb5ceSopenharmony_ci#if defined(_DEBUG)
617d4afb5ceSopenharmony_ci	lwsl_hexdump_level(LLL_DEBUG, vbuf, len);
618d4afb5ceSopenharmony_ci#endif
619d4afb5ceSopenharmony_ci}
620