1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 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#include <errno.h>
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
29d4afb5ceSopenharmony_cistatic int
30d4afb5ceSopenharmony_ciinterface_to_sa(struct lws_vhost *vh, const char *ifname,
31d4afb5ceSopenharmony_ci		struct sockaddr_in *addr, size_t addrlen, int allow_ipv6)
32d4afb5ceSopenharmony_ci{
33d4afb5ceSopenharmony_ci	int ipv6 = 0;
34d4afb5ceSopenharmony_ci#ifdef LWS_WITH_IPV6
35d4afb5ceSopenharmony_ci	if (allow_ipv6)
36d4afb5ceSopenharmony_ci		ipv6 = LWS_IPV6_ENABLED(vh);
37d4afb5ceSopenharmony_ci#endif
38d4afb5ceSopenharmony_ci	(void)vh;
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci	return lws_interface_to_sa(ipv6, ifname, addr, addrlen);
41d4afb5ceSopenharmony_ci}
42d4afb5ceSopenharmony_ci#endif
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ci#ifndef LWS_PLAT_OPTEE
45d4afb5ceSopenharmony_cistatic int
46d4afb5ceSopenharmony_cilws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
47d4afb5ceSopenharmony_ci		  int name_len, char *rip, int rip_len)
48d4afb5ceSopenharmony_ci{
49d4afb5ceSopenharmony_ci	struct addrinfo ai, *res;
50d4afb5ceSopenharmony_ci	struct sockaddr_in addr4;
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_ci	rip[0] = '\0';
53d4afb5ceSopenharmony_ci	name[0] = '\0';
54d4afb5ceSopenharmony_ci	addr4.sin_family = AF_UNSPEC;
55d4afb5ceSopenharmony_ci
56d4afb5ceSopenharmony_ci#ifdef LWS_WITH_IPV6
57d4afb5ceSopenharmony_ci	if (LWS_IPV6_ENABLED(vh)) {
58d4afb5ceSopenharmony_ci		if (!lws_plat_inet_ntop(AF_INET6,
59d4afb5ceSopenharmony_ci					&((struct sockaddr_in6 *)ads)->sin6_addr,
60d4afb5ceSopenharmony_ci					rip, (socklen_t)rip_len)) {
61d4afb5ceSopenharmony_ci			lwsl_vhost_err(vh, "inet_ntop: %s", strerror(LWS_ERRNO));
62d4afb5ceSopenharmony_ci			return -1;
63d4afb5ceSopenharmony_ci		}
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ci		// Strip off the IPv4 to IPv6 header if one exists
66d4afb5ceSopenharmony_ci		if (strncmp(rip, "::ffff:", 7) == 0)
67d4afb5ceSopenharmony_ci			memmove(rip, rip + 7, strlen(rip) - 6);
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_ci		getnameinfo((struct sockaddr *)ads, sizeof(struct sockaddr_in6),
70d4afb5ceSopenharmony_ci			    name,
71d4afb5ceSopenharmony_ci#if defined(__ANDROID__)
72d4afb5ceSopenharmony_ci			    (size_t)name_len,
73d4afb5ceSopenharmony_ci#else
74d4afb5ceSopenharmony_ci			    (socklen_t)name_len,
75d4afb5ceSopenharmony_ci#endif
76d4afb5ceSopenharmony_ci			    NULL, 0, 0);
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci		return 0;
79d4afb5ceSopenharmony_ci	} else
80d4afb5ceSopenharmony_ci#endif
81d4afb5ceSopenharmony_ci	{
82d4afb5ceSopenharmony_ci		struct addrinfo *result;
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci		memset(&ai, 0, sizeof ai);
85d4afb5ceSopenharmony_ci		ai.ai_family = PF_UNSPEC;
86d4afb5ceSopenharmony_ci		ai.ai_socktype = SOCK_STREAM;
87d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS)
88d4afb5ceSopenharmony_ci		if (getnameinfo((struct sockaddr *)ads,
89d4afb5ceSopenharmony_ci				sizeof(struct sockaddr_in),
90d4afb5ceSopenharmony_ci				name,
91d4afb5ceSopenharmony_ci#if defined(__ANDROID__)
92d4afb5ceSopenharmony_ci				(size_t)name_len,
93d4afb5ceSopenharmony_ci#else
94d4afb5ceSopenharmony_ci				(socklen_t)name_len,
95d4afb5ceSopenharmony_ci#endif
96d4afb5ceSopenharmony_ci				NULL, 0, 0))
97d4afb5ceSopenharmony_ci			return -1;
98d4afb5ceSopenharmony_ci#endif
99d4afb5ceSopenharmony_ci
100d4afb5ceSopenharmony_ci		if (getaddrinfo(name, NULL, &ai, &result))
101d4afb5ceSopenharmony_ci			return -1;
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_ci		res = result;
104d4afb5ceSopenharmony_ci		while (addr4.sin_family == AF_UNSPEC && res) {
105d4afb5ceSopenharmony_ci			switch (res->ai_family) {
106d4afb5ceSopenharmony_ci			case AF_INET:
107d4afb5ceSopenharmony_ci				addr4.sin_addr =
108d4afb5ceSopenharmony_ci				 ((struct sockaddr_in *)res->ai_addr)->sin_addr;
109d4afb5ceSopenharmony_ci				addr4.sin_family = AF_INET;
110d4afb5ceSopenharmony_ci				break;
111d4afb5ceSopenharmony_ci			}
112d4afb5ceSopenharmony_ci
113d4afb5ceSopenharmony_ci			res = res->ai_next;
114d4afb5ceSopenharmony_ci		}
115d4afb5ceSopenharmony_ci		freeaddrinfo(result);
116d4afb5ceSopenharmony_ci	}
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci	if (addr4.sin_family == AF_UNSPEC)
119d4afb5ceSopenharmony_ci		return -1;
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci	if (lws_plat_inet_ntop(AF_INET, &addr4.sin_addr, rip,
122d4afb5ceSopenharmony_ci			       (socklen_t)rip_len) == NULL)
123d4afb5ceSopenharmony_ci		return -1;
124d4afb5ceSopenharmony_ci
125d4afb5ceSopenharmony_ci	return 0;
126d4afb5ceSopenharmony_ci}
127d4afb5ceSopenharmony_ci
128d4afb5ceSopenharmony_ciconst char *
129d4afb5ceSopenharmony_cilws_get_peer_simple_fd(lws_sockfd_type fd, char *name, size_t namelen)
130d4afb5ceSopenharmony_ci{
131d4afb5ceSopenharmony_ci	lws_sockaddr46 sa46;
132d4afb5ceSopenharmony_ci	socklen_t len = sizeof(sa46);
133d4afb5ceSopenharmony_ci
134d4afb5ceSopenharmony_ci	if (getpeername(fd, (struct sockaddr *)&sa46, &len) < 0) {
135d4afb5ceSopenharmony_ci		lws_snprintf(name, namelen, "getpeername: %s",
136d4afb5ceSopenharmony_ci				strerror(LWS_ERRNO));
137d4afb5ceSopenharmony_ci		return name;
138d4afb5ceSopenharmony_ci	}
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci	lws_sa46_write_numeric_address(&sa46, name, namelen);
141d4afb5ceSopenharmony_ci
142d4afb5ceSopenharmony_ci	return name;
143d4afb5ceSopenharmony_ci}
144d4afb5ceSopenharmony_ci
145d4afb5ceSopenharmony_ciconst char *
146d4afb5ceSopenharmony_cilws_get_peer_simple(struct lws *wsi, char *name, size_t namelen)
147d4afb5ceSopenharmony_ci{
148d4afb5ceSopenharmony_ci	wsi = lws_get_network_wsi(wsi);
149d4afb5ceSopenharmony_ci	return lws_get_peer_simple_fd(wsi->desc.sockfd, name, namelen);
150d4afb5ceSopenharmony_ci}
151d4afb5ceSopenharmony_ci#endif
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_civoid
154d4afb5ceSopenharmony_cilws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
155d4afb5ceSopenharmony_ci		       int name_len, char *rip, int rip_len)
156d4afb5ceSopenharmony_ci{
157d4afb5ceSopenharmony_ci#ifndef LWS_PLAT_OPTEE
158d4afb5ceSopenharmony_ci	socklen_t len;
159d4afb5ceSopenharmony_ci#ifdef LWS_WITH_IPV6
160d4afb5ceSopenharmony_ci	struct sockaddr_in6 sin6;
161d4afb5ceSopenharmony_ci#endif
162d4afb5ceSopenharmony_ci	struct sockaddr_in sin4;
163d4afb5ceSopenharmony_ci	void *p;
164d4afb5ceSopenharmony_ci
165d4afb5ceSopenharmony_ci	rip[0] = '\0';
166d4afb5ceSopenharmony_ci	name[0] = '\0';
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci#ifdef LWS_WITH_IPV6
169d4afb5ceSopenharmony_ci	if (LWS_IPV6_ENABLED(wsi->a.vhost)) {
170d4afb5ceSopenharmony_ci		len = sizeof(sin6);
171d4afb5ceSopenharmony_ci		p = &sin6;
172d4afb5ceSopenharmony_ci	} else
173d4afb5ceSopenharmony_ci#endif
174d4afb5ceSopenharmony_ci	{
175d4afb5ceSopenharmony_ci		len = sizeof(sin4);
176d4afb5ceSopenharmony_ci		p = &sin4;
177d4afb5ceSopenharmony_ci	}
178d4afb5ceSopenharmony_ci
179d4afb5ceSopenharmony_ci	if (getpeername(fd, p, &len) < 0) {
180d4afb5ceSopenharmony_ci		lwsl_wsi_warn(wsi, "getpeername: %s", strerror(LWS_ERRNO));
181d4afb5ceSopenharmony_ci		goto bail;
182d4afb5ceSopenharmony_ci	}
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_ci	lws_get_addresses(wsi->a.vhost, p, name, name_len, rip, rip_len);
185d4afb5ceSopenharmony_ci
186d4afb5ceSopenharmony_cibail:
187d4afb5ceSopenharmony_ci#endif
188d4afb5ceSopenharmony_ci	(void)wsi;
189d4afb5ceSopenharmony_ci	(void)fd;
190d4afb5ceSopenharmony_ci	(void)name;
191d4afb5ceSopenharmony_ci	(void)name_len;
192d4afb5ceSopenharmony_ci	(void)rip;
193d4afb5ceSopenharmony_ci	(void)rip_len;
194d4afb5ceSopenharmony_ci}
195d4afb5ceSopenharmony_ci
196d4afb5ceSopenharmony_ci
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ci/* note: this returns a random port, or one of these <= 0 return codes:
199d4afb5ceSopenharmony_ci *
200d4afb5ceSopenharmony_ci * LWS_ITOSA_USABLE:     the interface is usable, returned if so and sockfd invalid
201d4afb5ceSopenharmony_ci * LWS_ITOSA_NOT_EXIST:  the requested iface does not even exist
202d4afb5ceSopenharmony_ci * LWS_ITOSA_NOT_USABLE: the requested iface exists but is not usable (eg, no IP)
203d4afb5ceSopenharmony_ci * LWS_ITOSA_BUSY:       the port at the requested iface + port is already in use
204d4afb5ceSopenharmony_ci */
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ciint
207d4afb5ceSopenharmony_cilws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
208d4afb5ceSopenharmony_ci		lws_sockfd_type sockfd, int port, const char *iface,
209d4afb5ceSopenharmony_ci		int af)
210d4afb5ceSopenharmony_ci{
211d4afb5ceSopenharmony_ci#ifdef LWS_WITH_UNIX_SOCK
212d4afb5ceSopenharmony_ci	struct sockaddr_un serv_unix;
213d4afb5ceSopenharmony_ci#endif
214d4afb5ceSopenharmony_ci#ifdef LWS_WITH_IPV6
215d4afb5ceSopenharmony_ci	struct sockaddr_in6 serv_addr6;
216d4afb5ceSopenharmony_ci#endif
217d4afb5ceSopenharmony_ci	struct sockaddr_in serv_addr4;
218d4afb5ceSopenharmony_ci#ifndef LWS_PLAT_OPTEE
219d4afb5ceSopenharmony_ci	socklen_t len = sizeof(struct sockaddr_storage);
220d4afb5ceSopenharmony_ci#endif
221d4afb5ceSopenharmony_ci	int n = 0;
222d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
223d4afb5ceSopenharmony_ci	int m;
224d4afb5ceSopenharmony_ci#endif
225d4afb5ceSopenharmony_ci	struct sockaddr_storage sin, *psin = &sin;
226d4afb5ceSopenharmony_ci	struct sockaddr *v;
227d4afb5ceSopenharmony_ci
228d4afb5ceSopenharmony_ci	memset(&sin, 0, sizeof(sin));
229d4afb5ceSopenharmony_ci
230d4afb5ceSopenharmony_ci	/* if there's a wsi, we want to mark it with our source ads:port */
231d4afb5ceSopenharmony_ci	if (wsi)
232d4afb5ceSopenharmony_ci		psin = (struct sockaddr_storage *)&wsi->sa46_local;
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci	switch (af) {
235d4afb5ceSopenharmony_ci#if defined(LWS_WITH_UNIX_SOCK)
236d4afb5ceSopenharmony_ci	case AF_UNIX:
237d4afb5ceSopenharmony_ci		v = (struct sockaddr *)&serv_unix;
238d4afb5ceSopenharmony_ci		memset(&serv_unix, 0, sizeof(serv_unix));
239d4afb5ceSopenharmony_ci		serv_unix.sun_family = AF_UNIX;
240d4afb5ceSopenharmony_ci		if (!iface)
241d4afb5ceSopenharmony_ci			return LWS_ITOSA_NOT_EXIST;
242d4afb5ceSopenharmony_ci		if (sizeof(serv_unix.sun_path) <= strlen(iface)) {
243d4afb5ceSopenharmony_ci			lwsl_wsi_err(wsi, "\"%s\" too long for UNIX domain socket",
244d4afb5ceSopenharmony_ci			         iface);
245d4afb5ceSopenharmony_ci			return LWS_ITOSA_NOT_EXIST;
246d4afb5ceSopenharmony_ci		}
247d4afb5ceSopenharmony_ci		n = (int)(sizeof(uint16_t) + strlen(iface));
248d4afb5ceSopenharmony_ci		strcpy(serv_unix.sun_path, iface);
249d4afb5ceSopenharmony_ci		if (serv_unix.sun_path[0] == '@')
250d4afb5ceSopenharmony_ci			serv_unix.sun_path[0] = '\0';
251d4afb5ceSopenharmony_ci		else
252d4afb5ceSopenharmony_ci			unlink(serv_unix.sun_path);
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ci		// lwsl_hexdump_notice(v, n);
255d4afb5ceSopenharmony_ci		break;
256d4afb5ceSopenharmony_ci#endif
257d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) && !defined(LWS_PLAT_FREERTOS)
258d4afb5ceSopenharmony_ci	case AF_INET6:
259d4afb5ceSopenharmony_ci		v = (struct sockaddr *)&serv_addr6;
260d4afb5ceSopenharmony_ci		n = sizeof(struct sockaddr_in6);
261d4afb5ceSopenharmony_ci
262d4afb5ceSopenharmony_ci		memset(&serv_addr6, 0, sizeof(serv_addr6));
263d4afb5ceSopenharmony_ci		serv_addr6.sin6_family = AF_INET6;
264d4afb5ceSopenharmony_ci		if (iface) {
265d4afb5ceSopenharmony_ci			m = interface_to_sa(vhost, iface,
266d4afb5ceSopenharmony_ci				    (struct sockaddr_in *)v, (unsigned int)n, 1);
267d4afb5ceSopenharmony_ci			if (m == LWS_ITOSA_NOT_USABLE) {
268d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "netif %s: Not usable",
269d4afb5ceSopenharmony_ci						   iface);
270d4afb5ceSopenharmony_ci				return m;
271d4afb5ceSopenharmony_ci			}
272d4afb5ceSopenharmony_ci			if (m == LWS_ITOSA_NOT_EXIST) {
273d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "netif %s: Does not exist",
274d4afb5ceSopenharmony_ci						   iface);
275d4afb5ceSopenharmony_ci				return m;
276d4afb5ceSopenharmony_ci			}
277d4afb5ceSopenharmony_ci			serv_addr6.sin6_scope_id = (unsigned int)htonl((uint32_t)
278d4afb5ceSopenharmony_ci					lws_get_addr_scope(wsi, iface));
279d4afb5ceSopenharmony_ci		}
280d4afb5ceSopenharmony_ci
281d4afb5ceSopenharmony_ci		serv_addr6.sin6_port = (uint16_t)htons((uint16_t)port);
282d4afb5ceSopenharmony_ci		break;
283d4afb5ceSopenharmony_ci#endif
284d4afb5ceSopenharmony_ci
285d4afb5ceSopenharmony_ci	case AF_INET:
286d4afb5ceSopenharmony_ci		v = (struct sockaddr *)&serv_addr4;
287d4afb5ceSopenharmony_ci		n = sizeof(serv_addr4);
288d4afb5ceSopenharmony_ci		memset(&serv_addr4, 0, sizeof(serv_addr4));
289d4afb5ceSopenharmony_ci		serv_addr4.sin_addr.s_addr = INADDR_ANY;
290d4afb5ceSopenharmony_ci		serv_addr4.sin_family = AF_INET;
291d4afb5ceSopenharmony_ci
292d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
293d4afb5ceSopenharmony_ci		if (iface) {
294d4afb5ceSopenharmony_ci		    m = interface_to_sa(vhost, iface,
295d4afb5ceSopenharmony_ci				    (struct sockaddr_in *)v, (unsigned int)n, 0);
296d4afb5ceSopenharmony_ci			if (m == LWS_ITOSA_NOT_USABLE) {
297d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "netif %s: Not usable",
298d4afb5ceSopenharmony_ci						   iface);
299d4afb5ceSopenharmony_ci				return m;
300d4afb5ceSopenharmony_ci			}
301d4afb5ceSopenharmony_ci			if (m == LWS_ITOSA_NOT_EXIST) {
302d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "netif %s: Does not exist",
303d4afb5ceSopenharmony_ci						   iface);
304d4afb5ceSopenharmony_ci				return m;
305d4afb5ceSopenharmony_ci			}
306d4afb5ceSopenharmony_ci		}
307d4afb5ceSopenharmony_ci#endif
308d4afb5ceSopenharmony_ci		serv_addr4.sin_port = htons((uint16_t)(unsigned int)port);
309d4afb5ceSopenharmony_ci		break;
310d4afb5ceSopenharmony_ci	default:
311d4afb5ceSopenharmony_ci		return -1;
312d4afb5ceSopenharmony_ci	} /* switch */
313d4afb5ceSopenharmony_ci
314d4afb5ceSopenharmony_ci	/* just checking for the interface extant */
315d4afb5ceSopenharmony_ci	if (sockfd == LWS_SOCK_INVALID)
316d4afb5ceSopenharmony_ci		return LWS_ITOSA_USABLE;
317d4afb5ceSopenharmony_ci
318d4afb5ceSopenharmony_ci	n = bind(sockfd, v, (socklen_t)n);
319d4afb5ceSopenharmony_ci#ifdef LWS_WITH_UNIX_SOCK
320d4afb5ceSopenharmony_ci	if (n < 0 && af == AF_UNIX) {
321d4afb5ceSopenharmony_ci		lwsl_wsi_err(wsi, "ERROR on binding fd %d to \"%s\" (%d %d)",
322d4afb5ceSopenharmony_ci				  sockfd, iface, n, LWS_ERRNO);
323d4afb5ceSopenharmony_ci
324d4afb5ceSopenharmony_ci		return LWS_ITOSA_NOT_EXIST;
325d4afb5ceSopenharmony_ci	} else
326d4afb5ceSopenharmony_ci#endif
327d4afb5ceSopenharmony_ci	if (n < 0) {
328d4afb5ceSopenharmony_ci		int _lws_errno = LWS_ERRNO;
329d4afb5ceSopenharmony_ci
330d4afb5ceSopenharmony_ci		lwsl_wsi_err(wsi, "ERROR on binding fd %d to port %d (%d %d)",
331d4afb5ceSopenharmony_ci				  sockfd, port, n, _lws_errno);
332d4afb5ceSopenharmony_ci
333d4afb5ceSopenharmony_ci		/* if something already listening, tell caller to fail permanently */
334d4afb5ceSopenharmony_ci
335d4afb5ceSopenharmony_ci		if (_lws_errno == LWS_EADDRINUSE)
336d4afb5ceSopenharmony_ci			return LWS_ITOSA_BUSY;
337d4afb5ceSopenharmony_ci
338d4afb5ceSopenharmony_ci		/* otherwise ask caller to retry later */
339d4afb5ceSopenharmony_ci
340d4afb5ceSopenharmony_ci		return LWS_ITOSA_NOT_EXIST;
341d4afb5ceSopenharmony_ci	}
342d4afb5ceSopenharmony_ci
343d4afb5ceSopenharmony_ci#if defined(LWS_WITH_UNIX_SOCK) && !defined(WIN32)
344d4afb5ceSopenharmony_ci	if (af == AF_UNIX) {
345d4afb5ceSopenharmony_ci		uid_t uid = vhost->context->uid;
346d4afb5ceSopenharmony_ci		gid_t gid = vhost->context->gid;
347d4afb5ceSopenharmony_ci
348d4afb5ceSopenharmony_ci		if (vhost->unix_socket_perms) {
349d4afb5ceSopenharmony_ci			if (lws_plat_user_colon_group_to_ids(
350d4afb5ceSopenharmony_ci				vhost->unix_socket_perms, &uid, &gid)) {
351d4afb5ceSopenharmony_ci				lwsl_wsi_err(wsi, "Failed to translate %s",
352d4afb5ceSopenharmony_ci						   vhost->unix_socket_perms);
353d4afb5ceSopenharmony_ci				return LWS_ITOSA_NOT_EXIST;
354d4afb5ceSopenharmony_ci			}
355d4afb5ceSopenharmony_ci		}
356d4afb5ceSopenharmony_ci		if (iface && iface[0] != '@' && uid && gid) {
357d4afb5ceSopenharmony_ci			if (chown(iface, uid, gid)) {
358d4afb5ceSopenharmony_ci				lwsl_wsi_err(wsi, "failed to set %s perms %u:%u",
359d4afb5ceSopenharmony_ci						  iface, (unsigned int)uid,
360d4afb5ceSopenharmony_ci						  (unsigned int)gid);
361d4afb5ceSopenharmony_ci
362d4afb5ceSopenharmony_ci				return LWS_ITOSA_NOT_EXIST;
363d4afb5ceSopenharmony_ci			}
364d4afb5ceSopenharmony_ci			lwsl_wsi_notice(wsi, "vh %s unix skt %s perms %u:%u",
365d4afb5ceSopenharmony_ci					      vhost->name, iface,
366d4afb5ceSopenharmony_ci					      (unsigned int)uid,
367d4afb5ceSopenharmony_ci					      (unsigned int)gid);
368d4afb5ceSopenharmony_ci
369d4afb5ceSopenharmony_ci			if (chmod(iface, 0660)) {
370d4afb5ceSopenharmony_ci				lwsl_wsi_err(wsi, "0600 mode on %s fail", iface);
371d4afb5ceSopenharmony_ci
372d4afb5ceSopenharmony_ci				return LWS_ITOSA_NOT_EXIST;
373d4afb5ceSopenharmony_ci			}
374d4afb5ceSopenharmony_ci		}
375d4afb5ceSopenharmony_ci	}
376d4afb5ceSopenharmony_ci#endif
377d4afb5ceSopenharmony_ci
378d4afb5ceSopenharmony_ci#ifndef LWS_PLAT_OPTEE
379d4afb5ceSopenharmony_ci	if (getsockname(sockfd, (struct sockaddr *)psin, &len) == -1)
380d4afb5ceSopenharmony_ci		lwsl_wsi_warn(wsi, "getsockname: %s", strerror(LWS_ERRNO));
381d4afb5ceSopenharmony_ci	else
382d4afb5ceSopenharmony_ci#endif
383d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
384d4afb5ceSopenharmony_ci		port = (sin.ss_family == AF_INET6) ?
385d4afb5ceSopenharmony_ci			ntohs(((struct sockaddr_in6 *)psin)->sin6_port) :
386d4afb5ceSopenharmony_ci			ntohs(((struct sockaddr_in *)psin)->sin_port);
387d4afb5ceSopenharmony_ci#else
388d4afb5ceSopenharmony_ci		{
389d4afb5ceSopenharmony_ci			struct sockaddr_in sain;
390d4afb5ceSopenharmony_ci			memcpy(&sain, psin, sizeof(sain));
391d4afb5ceSopenharmony_ci			port = ntohs(sain.sin_port);
392d4afb5ceSopenharmony_ci		}
393d4afb5ceSopenharmony_ci#endif
394d4afb5ceSopenharmony_ci
395d4afb5ceSopenharmony_ci		{
396d4afb5ceSopenharmony_ci			char buf[72];
397d4afb5ceSopenharmony_ci			lws_sa46_write_numeric_address((lws_sockaddr46 *)psin,
398d4afb5ceSopenharmony_ci							buf, sizeof(buf));
399d4afb5ceSopenharmony_ci
400d4afb5ceSopenharmony_ci			lwsl_vhost_notice(vhost, "source ads %s", buf);
401d4afb5ceSopenharmony_ci		}
402d4afb5ceSopenharmony_ci
403d4afb5ceSopenharmony_ci	return port;
404d4afb5ceSopenharmony_ci}
405d4afb5ceSopenharmony_ci
406d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_ciunsigned int
409d4afb5ceSopenharmony_cilws_retry_get_delay_ms(struct lws_context *context,
410d4afb5ceSopenharmony_ci		       const lws_retry_bo_t *retry, uint16_t *ctry,
411d4afb5ceSopenharmony_ci		       char *conceal)
412d4afb5ceSopenharmony_ci{
413d4afb5ceSopenharmony_ci	uint64_t ms = 3000, pc = 30; /* sane-ish defaults if no retry table */
414d4afb5ceSopenharmony_ci	uint16_t ra;
415d4afb5ceSopenharmony_ci
416d4afb5ceSopenharmony_ci	if (conceal)
417d4afb5ceSopenharmony_ci		*conceal = 0;
418d4afb5ceSopenharmony_ci
419d4afb5ceSopenharmony_ci	if (retry) {
420d4afb5ceSopenharmony_ci		if (retry->retry_ms_table_count) {
421d4afb5ceSopenharmony_ci			if (*ctry < retry->retry_ms_table_count)
422d4afb5ceSopenharmony_ci				ms = retry->retry_ms_table[*ctry];
423d4afb5ceSopenharmony_ci			else
424d4afb5ceSopenharmony_ci				ms = retry->retry_ms_table[
425d4afb5ceSopenharmony_ci					retry->retry_ms_table_count - 1];
426d4afb5ceSopenharmony_ci		}
427d4afb5ceSopenharmony_ci
428d4afb5ceSopenharmony_ci		/* if no percent given, use the default 30% */
429d4afb5ceSopenharmony_ci		if (retry->jitter_percent)
430d4afb5ceSopenharmony_ci			pc = retry->jitter_percent;
431d4afb5ceSopenharmony_ci	}
432d4afb5ceSopenharmony_ci
433d4afb5ceSopenharmony_ci	if (lws_get_random(context, &ra, sizeof(ra)) == sizeof(ra))
434d4afb5ceSopenharmony_ci		ms += ((ms * pc * ra) >> 16) / 100;
435d4afb5ceSopenharmony_ci	else
436d4afb5ceSopenharmony_ci		assert(0);
437d4afb5ceSopenharmony_ci
438d4afb5ceSopenharmony_ci	if (*ctry < 0xffff)
439d4afb5ceSopenharmony_ci		(*ctry)++;
440d4afb5ceSopenharmony_ci
441d4afb5ceSopenharmony_ci	if (retry && conceal)
442d4afb5ceSopenharmony_ci		*conceal = (int)*ctry <= retry->conceal_count;
443d4afb5ceSopenharmony_ci
444d4afb5ceSopenharmony_ci	return (unsigned int)ms;
445d4afb5ceSopenharmony_ci}
446d4afb5ceSopenharmony_ci
447d4afb5ceSopenharmony_ciint
448d4afb5ceSopenharmony_cilws_retry_sul_schedule(struct lws_context *context, int tid,
449d4afb5ceSopenharmony_ci		       lws_sorted_usec_list_t *sul,
450d4afb5ceSopenharmony_ci		       const lws_retry_bo_t *retry, sul_cb_t cb, uint16_t *ctry)
451d4afb5ceSopenharmony_ci{
452d4afb5ceSopenharmony_ci	char conceal;
453d4afb5ceSopenharmony_ci	uint64_t ms = lws_retry_get_delay_ms(context, retry, ctry, &conceal);
454d4afb5ceSopenharmony_ci
455d4afb5ceSopenharmony_ci	if (!conceal)
456d4afb5ceSopenharmony_ci		return 1;
457d4afb5ceSopenharmony_ci
458d4afb5ceSopenharmony_ci	lwsl_cx_info(context, "sul %p: scheduling retry in %dms", sul, (int)ms);
459d4afb5ceSopenharmony_ci
460d4afb5ceSopenharmony_ci	lws_sul_schedule(context, tid, sul, cb, (int64_t)(ms * 1000));
461d4afb5ceSopenharmony_ci
462d4afb5ceSopenharmony_ci	return 0;
463d4afb5ceSopenharmony_ci}
464d4afb5ceSopenharmony_ci
465d4afb5ceSopenharmony_ciint
466d4afb5ceSopenharmony_cilws_retry_sul_schedule_retry_wsi(struct lws *wsi, lws_sorted_usec_list_t *sul,
467d4afb5ceSopenharmony_ci				 sul_cb_t cb, uint16_t *ctry)
468d4afb5ceSopenharmony_ci{
469d4afb5ceSopenharmony_ci	char conceal;
470d4afb5ceSopenharmony_ci	lws_usec_t us = lws_retry_get_delay_ms(wsi->a.context,
471d4afb5ceSopenharmony_ci					       wsi->retry_policy, ctry,
472d4afb5ceSopenharmony_ci					       &conceal) * LWS_US_PER_MS;
473d4afb5ceSopenharmony_ci
474d4afb5ceSopenharmony_ci	if (!conceal)
475d4afb5ceSopenharmony_ci		/* if our reties are up, they're up... */
476d4afb5ceSopenharmony_ci		return 1;
477d4afb5ceSopenharmony_ci
478d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
479d4afb5ceSopenharmony_ci	if (
480d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1)
481d4afb5ceSopenharmony_ci		wsi->role_ops == &role_ops_h1
482d4afb5ceSopenharmony_ci#endif
483d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) && defined(LWS_ROLE_H2)
484d4afb5ceSopenharmony_ci		||
485d4afb5ceSopenharmony_ci#endif
486d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2)
487d4afb5ceSopenharmony_ci		wsi->role_ops == &role_ops_h2
488d4afb5ceSopenharmony_ci#endif
489d4afb5ceSopenharmony_ci		)
490d4afb5ceSopenharmony_ci		/*
491d4afb5ceSopenharmony_ci		 * Since we're doing it by wsi, we're in a position to check for
492d4afb5ceSopenharmony_ci		 * http retry-after, it will increase us accordingly if found
493d4afb5ceSopenharmony_ci		 */
494d4afb5ceSopenharmony_ci		lws_http_check_retry_after(wsi, &us);
495d4afb5ceSopenharmony_ci#endif
496d4afb5ceSopenharmony_ci	lws_sul_schedule(wsi->a.context, wsi->tsi, sul, cb, us);
497d4afb5ceSopenharmony_ci
498d4afb5ceSopenharmony_ci	return 0;
499d4afb5ceSopenharmony_ci}
500d4afb5ceSopenharmony_ci
501d4afb5ceSopenharmony_ci#endif
502d4afb5ceSopenharmony_ci
503d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
504d4afb5ceSopenharmony_ciunsigned long
505d4afb5ceSopenharmony_cilws_get_addr_scope(struct lws *wsi, const char *ifname_or_ipaddr)
506d4afb5ceSopenharmony_ci{
507d4afb5ceSopenharmony_ci	unsigned long scope;
508d4afb5ceSopenharmony_ci	char ip[NI_MAXHOST];
509d4afb5ceSopenharmony_ci	unsigned int i;
510d4afb5ceSopenharmony_ci#if !defined(WIN32)
511d4afb5ceSopenharmony_ci	struct ifaddrs *addrs, *addr;
512d4afb5ceSopenharmony_ci#else
513d4afb5ceSopenharmony_ci	PIP_ADAPTER_ADDRESSES adapter, addrs = NULL;
514d4afb5ceSopenharmony_ci	PIP_ADAPTER_UNICAST_ADDRESS addr;
515d4afb5ceSopenharmony_ci	struct sockaddr_in6 *sockaddr;
516d4afb5ceSopenharmony_ci	ULONG size = 0;
517d4afb5ceSopenharmony_ci	int found = 0;
518d4afb5ceSopenharmony_ci	DWORD ret;
519d4afb5ceSopenharmony_ci#endif
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci	/*
522d4afb5ceSopenharmony_ci	 * First see if we can look the string up as a network interface name...
523d4afb5ceSopenharmony_ci	 * windows vista+ also has this
524d4afb5ceSopenharmony_ci	 */
525d4afb5ceSopenharmony_ci
526d4afb5ceSopenharmony_ci	scope = if_nametoindex(ifname_or_ipaddr);
527d4afb5ceSopenharmony_ci	if (scope > 0)
528d4afb5ceSopenharmony_ci		/* we found it from the interface name lookup */
529d4afb5ceSopenharmony_ci		return scope;
530d4afb5ceSopenharmony_ci
531d4afb5ceSopenharmony_ci	/*
532d4afb5ceSopenharmony_ci	 * if not, try to look it up as an IP -> interface -> interface index
533d4afb5ceSopenharmony_ci	 */
534d4afb5ceSopenharmony_ci
535d4afb5ceSopenharmony_ci	scope = 0;
536d4afb5ceSopenharmony_ci
537d4afb5ceSopenharmony_ci#if !defined(WIN32)
538d4afb5ceSopenharmony_ci
539d4afb5ceSopenharmony_ci	getifaddrs(&addrs);
540d4afb5ceSopenharmony_ci	for (addr = addrs; addr; addr = addr->ifa_next) {
541d4afb5ceSopenharmony_ci		if (!addr->ifa_addr ||
542d4afb5ceSopenharmony_ci			addr->ifa_addr->sa_family != AF_INET6)
543d4afb5ceSopenharmony_ci			continue;
544d4afb5ceSopenharmony_ci
545d4afb5ceSopenharmony_ci		ip[0] = '\0';
546d4afb5ceSopenharmony_ci		getnameinfo(addr->ifa_addr, sizeof(struct sockaddr_in6),
547d4afb5ceSopenharmony_ci			    ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
548d4afb5ceSopenharmony_ci
549d4afb5ceSopenharmony_ci		i = 0;
550d4afb5ceSopenharmony_ci		while (ip[i])
551d4afb5ceSopenharmony_ci			if (ip[i++] == '%') {
552d4afb5ceSopenharmony_ci				ip[i - 1] = '\0';
553d4afb5ceSopenharmony_ci				break;
554d4afb5ceSopenharmony_ci			}
555d4afb5ceSopenharmony_ci
556d4afb5ceSopenharmony_ci		if (!strcmp(ip, ifname_or_ipaddr)) {
557d4afb5ceSopenharmony_ci			scope = if_nametoindex(addr->ifa_name);
558d4afb5ceSopenharmony_ci			break;
559d4afb5ceSopenharmony_ci		}
560d4afb5ceSopenharmony_ci	}
561d4afb5ceSopenharmony_ci	freeifaddrs(addrs);
562d4afb5ceSopenharmony_ci#else
563d4afb5ceSopenharmony_ci
564d4afb5ceSopenharmony_ci	for (i = 0; i < 5; i++) {
565d4afb5ceSopenharmony_ci		ret = GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX,
566d4afb5ceSopenharmony_ci					   NULL, addrs, &size);
567d4afb5ceSopenharmony_ci		if (ret == NO_ERROR || ret == ERROR_NO_DATA)
568d4afb5ceSopenharmony_ci			break;
569d4afb5ceSopenharmony_ci
570d4afb5ceSopenharmony_ci		if (addrs)
571d4afb5ceSopenharmony_ci			free(addrs);
572d4afb5ceSopenharmony_ci
573d4afb5ceSopenharmony_ci		if (ret != ERROR_BUFFER_OVERFLOW) {
574d4afb5ceSopenharmony_ci			addrs = NULL;
575d4afb5ceSopenharmony_ci			lwsl_wsi_err(wsi, "Get IPv6 ads table fail (%d)", ret);
576d4afb5ceSopenharmony_ci			break;
577d4afb5ceSopenharmony_ci		}
578d4afb5ceSopenharmony_ci
579d4afb5ceSopenharmony_ci		addrs = (IP_ADAPTER_ADDRESSES *)malloc(size);
580d4afb5ceSopenharmony_ci	}
581d4afb5ceSopenharmony_ci
582d4afb5ceSopenharmony_ci	if ((ret == NO_ERROR) && (addrs)) {
583d4afb5ceSopenharmony_ci		adapter = addrs;
584d4afb5ceSopenharmony_ci		while (adapter && !found) {
585d4afb5ceSopenharmony_ci			addr = adapter->FirstUnicastAddress;
586d4afb5ceSopenharmony_ci			while (addr && !found) {
587d4afb5ceSopenharmony_ci				if (addr->Address.lpSockaddr->sa_family ==
588d4afb5ceSopenharmony_ci				    AF_INET6) {
589d4afb5ceSopenharmony_ci					sockaddr = (struct sockaddr_in6 *)
590d4afb5ceSopenharmony_ci						(addr->Address.lpSockaddr);
591d4afb5ceSopenharmony_ci
592d4afb5ceSopenharmony_ci					lws_plat_inet_ntop(sockaddr->sin6_family,
593d4afb5ceSopenharmony_ci							&sockaddr->sin6_addr,
594d4afb5ceSopenharmony_ci							ip, sizeof(ip));
595d4afb5ceSopenharmony_ci
596d4afb5ceSopenharmony_ci					if (!strcmp(ip, ifname_or_ipaddr)) {
597d4afb5ceSopenharmony_ci						scope = sockaddr->sin6_scope_id;
598d4afb5ceSopenharmony_ci						found = 1;
599d4afb5ceSopenharmony_ci						break;
600d4afb5ceSopenharmony_ci					}
601d4afb5ceSopenharmony_ci				}
602d4afb5ceSopenharmony_ci				addr = addr->Next;
603d4afb5ceSopenharmony_ci			}
604d4afb5ceSopenharmony_ci			adapter = adapter->Next;
605d4afb5ceSopenharmony_ci		}
606d4afb5ceSopenharmony_ci	}
607d4afb5ceSopenharmony_ci	if (addrs)
608d4afb5ceSopenharmony_ci		free(addrs);
609d4afb5ceSopenharmony_ci#endif
610d4afb5ceSopenharmony_ci
611d4afb5ceSopenharmony_ci	return scope;
612d4afb5ceSopenharmony_ci}
613d4afb5ceSopenharmony_ci#endif
614d4afb5ceSopenharmony_ci
615d4afb5ceSopenharmony_ci/*
616d4afb5ceSopenharmony_ci * https://en.wikipedia.org/wiki/IPv6_address
617d4afb5ceSopenharmony_ci *
618d4afb5ceSopenharmony_ci * An IPv6 address is represented as eight groups of four hexadecimal digits,
619d4afb5ceSopenharmony_ci * each group representing 16 bits (two octets, a group sometimes also called a
620d4afb5ceSopenharmony_ci * hextet[6][7]). The groups are separated by colons (:). An example of an IPv6
621d4afb5ceSopenharmony_ci * address is:
622d4afb5ceSopenharmony_ci *
623d4afb5ceSopenharmony_ci *    2001:0db8:85a3:0000:0000:8a2e:0370:7334
624d4afb5ceSopenharmony_ci *
625d4afb5ceSopenharmony_ci * The hexadecimal digits are case-insensitive, but IETF recommendations suggest
626d4afb5ceSopenharmony_ci * the use of lower case letters. The full representation of eight 4-digit
627d4afb5ceSopenharmony_ci * groups may be simplified by several techniques, eliminating parts of the
628d4afb5ceSopenharmony_ci * representation.
629d4afb5ceSopenharmony_ci *
630d4afb5ceSopenharmony_ci * Leading zeroes in a group may be omitted, but each group must retain at least
631d4afb5ceSopenharmony_ci * one hexadecimal digit.[1] Thus, the example address may be written as:
632d4afb5ceSopenharmony_ci *
633d4afb5ceSopenharmony_ci *    2001:db8:85a3:0:0:8a2e:370:7334
634d4afb5ceSopenharmony_ci *
635d4afb5ceSopenharmony_ci * One or more consecutive groups containing zeros only may be replaced with a
636d4afb5ceSopenharmony_ci * single empty group, using two consecutive colons (::).[1] The substitution
637d4afb5ceSopenharmony_ci * may only be applied once in the address, however, because multiple
638d4afb5ceSopenharmony_ci * occurrences would create an ambiguous representation. Thus, the example
639d4afb5ceSopenharmony_ci * address can be further simplified:
640d4afb5ceSopenharmony_ci *
641d4afb5ceSopenharmony_ci *    2001:db8:85a3::8a2e:370:7334
642d4afb5ceSopenharmony_ci *
643d4afb5ceSopenharmony_ci * The localhost (loopback) address, 0:0:0:0:0:0:0:1, and the IPv6 unspecified
644d4afb5ceSopenharmony_ci * address, 0:0:0:0:0:0:0:0, are reduced to ::1 and ::, respectively.
645d4afb5ceSopenharmony_ci *
646d4afb5ceSopenharmony_ci * During the transition of the Internet from IPv4 to IPv6, it is typical to
647d4afb5ceSopenharmony_ci * operate in a mixed addressing environment. For such use cases, a special
648d4afb5ceSopenharmony_ci * notation has been introduced, which expresses IPv4-mapped and IPv4-compatible
649d4afb5ceSopenharmony_ci * IPv6 addresses by writing the least-significant 32 bits of an address in the
650d4afb5ceSopenharmony_ci * familiar IPv4 dot-decimal notation, whereas the other 96 (most significant)
651d4afb5ceSopenharmony_ci * bits are written in IPv6 format. For example, the IPv4-mapped IPv6 address
652d4afb5ceSopenharmony_ci * ::ffff:c000:0280 is written as ::ffff:192.0.2.128, thus expressing clearly
653d4afb5ceSopenharmony_ci * the original IPv4 address that was mapped to IPv6.
654d4afb5ceSopenharmony_ci */
655d4afb5ceSopenharmony_ci
656d4afb5ceSopenharmony_ciint
657d4afb5ceSopenharmony_cilws_parse_numeric_address(const char *ads, uint8_t *result, size_t max_len)
658d4afb5ceSopenharmony_ci{
659d4afb5ceSopenharmony_ci	struct lws_tokenize ts;
660d4afb5ceSopenharmony_ci	uint8_t *orig = result, temp[16];
661d4afb5ceSopenharmony_ci	int sects = 0, ipv6 = !!strchr(ads, ':'), skip_point = -1, dm = 0;
662d4afb5ceSopenharmony_ci	char t[5];
663d4afb5ceSopenharmony_ci	size_t n;
664d4afb5ceSopenharmony_ci	long u;
665d4afb5ceSopenharmony_ci
666d4afb5ceSopenharmony_ci	lws_tokenize_init(&ts, ads, LWS_TOKENIZE_F_NO_INTEGERS |
667d4afb5ceSopenharmony_ci				    LWS_TOKENIZE_F_MINUS_NONTERM);
668d4afb5ceSopenharmony_ci	ts.len = strlen(ads);
669d4afb5ceSopenharmony_ci	if (!ipv6 && ts.len < 7)
670d4afb5ceSopenharmony_ci		return -1;
671d4afb5ceSopenharmony_ci
672d4afb5ceSopenharmony_ci	if (ipv6 && ts.len < 2)
673d4afb5ceSopenharmony_ci		return -2;
674d4afb5ceSopenharmony_ci
675d4afb5ceSopenharmony_ci	if (!ipv6 && max_len < 4)
676d4afb5ceSopenharmony_ci		return -3;
677d4afb5ceSopenharmony_ci
678d4afb5ceSopenharmony_ci	if (ipv6 && max_len < 16)
679d4afb5ceSopenharmony_ci		return -4;
680d4afb5ceSopenharmony_ci
681d4afb5ceSopenharmony_ci	if (ipv6)
682d4afb5ceSopenharmony_ci		memset(result, 0, max_len);
683d4afb5ceSopenharmony_ci
684d4afb5ceSopenharmony_ci	do {
685d4afb5ceSopenharmony_ci		ts.e = (int8_t)lws_tokenize(&ts);
686d4afb5ceSopenharmony_ci		switch (ts.e) {
687d4afb5ceSopenharmony_ci		case LWS_TOKZE_TOKEN:
688d4afb5ceSopenharmony_ci			dm = 0;
689d4afb5ceSopenharmony_ci			if (ipv6) {
690d4afb5ceSopenharmony_ci				if (ts.token_len > 4)
691d4afb5ceSopenharmony_ci					return -1;
692d4afb5ceSopenharmony_ci				memcpy(t, ts.token, ts.token_len);
693d4afb5ceSopenharmony_ci				t[ts.token_len] = '\0';
694d4afb5ceSopenharmony_ci				for (n = 0; n < ts.token_len; n++)
695d4afb5ceSopenharmony_ci					if (t[n] < '0' || t[n] > 'f' ||
696d4afb5ceSopenharmony_ci					    (t[n] > '9' && t[n] < 'A') ||
697d4afb5ceSopenharmony_ci					    (t[n] > 'F' && t[n] < 'a'))
698d4afb5ceSopenharmony_ci						return -1;
699d4afb5ceSopenharmony_ci				u = strtol(t, NULL, 16);
700d4afb5ceSopenharmony_ci				if (u > 0xffff)
701d4afb5ceSopenharmony_ci					return -5;
702d4afb5ceSopenharmony_ci				*result++ = (uint8_t)(u >> 8);
703d4afb5ceSopenharmony_ci			} else {
704d4afb5ceSopenharmony_ci				if (ts.token_len > 3)
705d4afb5ceSopenharmony_ci					return -1;
706d4afb5ceSopenharmony_ci				memcpy(t, ts.token, ts.token_len);
707d4afb5ceSopenharmony_ci				t[ts.token_len] = '\0';
708d4afb5ceSopenharmony_ci				for (n = 0; n < ts.token_len; n++)
709d4afb5ceSopenharmony_ci					if (t[n] < '0' || t[n] > '9')
710d4afb5ceSopenharmony_ci						return -1;
711d4afb5ceSopenharmony_ci				u = strtol(t, NULL, 10);
712d4afb5ceSopenharmony_ci				if (u > 0xff)
713d4afb5ceSopenharmony_ci					return -6;
714d4afb5ceSopenharmony_ci			}
715d4afb5ceSopenharmony_ci			if (u < 0)
716d4afb5ceSopenharmony_ci				return -7;
717d4afb5ceSopenharmony_ci			*result++ = (uint8_t)u;
718d4afb5ceSopenharmony_ci			sects++;
719d4afb5ceSopenharmony_ci			break;
720d4afb5ceSopenharmony_ci
721d4afb5ceSopenharmony_ci		case LWS_TOKZE_DELIMITER:
722d4afb5ceSopenharmony_ci			if (dm++) {
723d4afb5ceSopenharmony_ci				if (dm > 2)
724d4afb5ceSopenharmony_ci					return -8;
725d4afb5ceSopenharmony_ci				if (*ts.token != ':')
726d4afb5ceSopenharmony_ci					return -9;
727d4afb5ceSopenharmony_ci				/* back to back : */
728d4afb5ceSopenharmony_ci				*result++ = 0;
729d4afb5ceSopenharmony_ci				*result++ = 0;
730d4afb5ceSopenharmony_ci				skip_point = lws_ptr_diff(result, orig);
731d4afb5ceSopenharmony_ci				break;
732d4afb5ceSopenharmony_ci			}
733d4afb5ceSopenharmony_ci			if (ipv6 && orig[2] == 0xff && orig[3] == 0xff &&
734d4afb5ceSopenharmony_ci			    skip_point == 2) {
735d4afb5ceSopenharmony_ci				/* ipv4 backwards compatible format */
736d4afb5ceSopenharmony_ci				ipv6 = 0;
737d4afb5ceSopenharmony_ci				memset(orig, 0, max_len);
738d4afb5ceSopenharmony_ci				orig[10] = 0xff;
739d4afb5ceSopenharmony_ci				orig[11] = 0xff;
740d4afb5ceSopenharmony_ci				skip_point = -1;
741d4afb5ceSopenharmony_ci				result = &orig[12];
742d4afb5ceSopenharmony_ci				sects = 0;
743d4afb5ceSopenharmony_ci				break;
744d4afb5ceSopenharmony_ci			}
745d4afb5ceSopenharmony_ci			if (ipv6 && *ts.token != ':')
746d4afb5ceSopenharmony_ci				return -10;
747d4afb5ceSopenharmony_ci			if (!ipv6 && *ts.token != '.')
748d4afb5ceSopenharmony_ci				return -11;
749d4afb5ceSopenharmony_ci			break;
750d4afb5ceSopenharmony_ci
751d4afb5ceSopenharmony_ci		case LWS_TOKZE_ENDED:
752d4afb5ceSopenharmony_ci			if (!ipv6 && sects == 4)
753d4afb5ceSopenharmony_ci				return lws_ptr_diff(result, orig);
754d4afb5ceSopenharmony_ci			if (ipv6 && sects == 8)
755d4afb5ceSopenharmony_ci				return lws_ptr_diff(result, orig);
756d4afb5ceSopenharmony_ci			if (skip_point != -1) {
757d4afb5ceSopenharmony_ci				int ow = lws_ptr_diff(result, orig);
758d4afb5ceSopenharmony_ci				/*
759d4afb5ceSopenharmony_ci				 * contains ...::...
760d4afb5ceSopenharmony_ci				 */
761d4afb5ceSopenharmony_ci				if (ow == 16)
762d4afb5ceSopenharmony_ci					return 16;
763d4afb5ceSopenharmony_ci				memcpy(temp, &orig[skip_point], (unsigned int)(ow - skip_point));
764d4afb5ceSopenharmony_ci				memset(&orig[skip_point], 0, (unsigned int)(16 - skip_point));
765d4afb5ceSopenharmony_ci				memcpy(&orig[16 - (ow - skip_point)], temp,
766d4afb5ceSopenharmony_ci						   (unsigned int)(ow - skip_point));
767d4afb5ceSopenharmony_ci
768d4afb5ceSopenharmony_ci				return 16;
769d4afb5ceSopenharmony_ci			}
770d4afb5ceSopenharmony_ci			return -12;
771d4afb5ceSopenharmony_ci
772d4afb5ceSopenharmony_ci		default: /* includes ENDED */
773d4afb5ceSopenharmony_ci			lwsl_err("%s: malformed ip address\n",
774d4afb5ceSopenharmony_ci				 __func__);
775d4afb5ceSopenharmony_ci
776d4afb5ceSopenharmony_ci			return -13;
777d4afb5ceSopenharmony_ci		}
778d4afb5ceSopenharmony_ci	} while (ts.e > 0 && result - orig <= (int)max_len);
779d4afb5ceSopenharmony_ci
780d4afb5ceSopenharmony_ci	lwsl_err("%s: ended on e %d\n", __func__, ts.e);
781d4afb5ceSopenharmony_ci
782d4afb5ceSopenharmony_ci	return -14;
783d4afb5ceSopenharmony_ci}
784d4afb5ceSopenharmony_ci
785d4afb5ceSopenharmony_ciint
786d4afb5ceSopenharmony_cilws_sa46_parse_numeric_address(const char *ads, lws_sockaddr46 *sa46)
787d4afb5ceSopenharmony_ci{
788d4afb5ceSopenharmony_ci	uint8_t a[16];
789d4afb5ceSopenharmony_ci	int n;
790d4afb5ceSopenharmony_ci
791d4afb5ceSopenharmony_ci	n = lws_parse_numeric_address(ads, a, sizeof(a));
792d4afb5ceSopenharmony_ci	if (n < 0)
793d4afb5ceSopenharmony_ci		return -1;
794d4afb5ceSopenharmony_ci
795d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
796d4afb5ceSopenharmony_ci	if (n == 16) {
797d4afb5ceSopenharmony_ci		sa46->sa6.sin6_family = AF_INET6;
798d4afb5ceSopenharmony_ci		memcpy(sa46->sa6.sin6_addr.s6_addr, a,
799d4afb5ceSopenharmony_ci		       sizeof(sa46->sa6.sin6_addr.s6_addr));
800d4afb5ceSopenharmony_ci
801d4afb5ceSopenharmony_ci		return 0;
802d4afb5ceSopenharmony_ci	}
803d4afb5ceSopenharmony_ci#endif
804d4afb5ceSopenharmony_ci
805d4afb5ceSopenharmony_ci	if (n != 4)
806d4afb5ceSopenharmony_ci		return -1;
807d4afb5ceSopenharmony_ci
808d4afb5ceSopenharmony_ci	sa46->sa4.sin_family = AF_INET;
809d4afb5ceSopenharmony_ci	memcpy(&sa46->sa4.sin_addr.s_addr, a,
810d4afb5ceSopenharmony_ci	       sizeof(sa46->sa4.sin_addr.s_addr));
811d4afb5ceSopenharmony_ci
812d4afb5ceSopenharmony_ci	return 0;
813d4afb5ceSopenharmony_ci}
814d4afb5ceSopenharmony_ci
815d4afb5ceSopenharmony_ciint
816d4afb5ceSopenharmony_cilws_write_numeric_address(const uint8_t *ads, int size, char *buf, size_t len)
817d4afb5ceSopenharmony_ci{
818d4afb5ceSopenharmony_ci	char c, elided = 0, soe = 0, zb = (char)-1, n, ipv4 = 0;
819d4afb5ceSopenharmony_ci	const char *e = buf + len;
820d4afb5ceSopenharmony_ci	char *obuf = buf;
821d4afb5ceSopenharmony_ci	int q = 0;
822d4afb5ceSopenharmony_ci
823d4afb5ceSopenharmony_ci	if (size == 4)
824d4afb5ceSopenharmony_ci		return lws_snprintf(buf, len, "%u.%u.%u.%u",
825d4afb5ceSopenharmony_ci				    ads[0], ads[1], ads[2], ads[3]);
826d4afb5ceSopenharmony_ci
827d4afb5ceSopenharmony_ci	if (size != 16)
828d4afb5ceSopenharmony_ci		return -1;
829d4afb5ceSopenharmony_ci
830d4afb5ceSopenharmony_ci	for (c = 0; c < (char)size / 2; c++) {
831d4afb5ceSopenharmony_ci		uint16_t v = (uint16_t)((ads[q] << 8) | ads[q + 1]);
832d4afb5ceSopenharmony_ci
833d4afb5ceSopenharmony_ci		if (buf + 8 > e)
834d4afb5ceSopenharmony_ci			return -1;
835d4afb5ceSopenharmony_ci
836d4afb5ceSopenharmony_ci		q += 2;
837d4afb5ceSopenharmony_ci		if (soe) {
838d4afb5ceSopenharmony_ci			if (v)
839d4afb5ceSopenharmony_ci				*buf++ = ':';
840d4afb5ceSopenharmony_ci				/* fall thru to print hex value */
841d4afb5ceSopenharmony_ci		} else
842d4afb5ceSopenharmony_ci			if (!elided && !soe && !v) {
843d4afb5ceSopenharmony_ci				elided = soe = 1;
844d4afb5ceSopenharmony_ci				zb = c;
845d4afb5ceSopenharmony_ci				continue;
846d4afb5ceSopenharmony_ci			}
847d4afb5ceSopenharmony_ci
848d4afb5ceSopenharmony_ci		if (ipv4) {
849d4afb5ceSopenharmony_ci			n = (char)lws_snprintf(buf, lws_ptr_diff_size_t(e, buf), "%u.%u",
850d4afb5ceSopenharmony_ci					ads[q - 2], ads[q - 1]);
851d4afb5ceSopenharmony_ci			buf += n;
852d4afb5ceSopenharmony_ci			if (c == 6)
853d4afb5ceSopenharmony_ci				*buf++ = '.';
854d4afb5ceSopenharmony_ci		} else {
855d4afb5ceSopenharmony_ci			if (soe && !v)
856d4afb5ceSopenharmony_ci				continue;
857d4afb5ceSopenharmony_ci			if (c)
858d4afb5ceSopenharmony_ci				*buf++ = ':';
859d4afb5ceSopenharmony_ci
860d4afb5ceSopenharmony_ci			buf += lws_snprintf(buf, lws_ptr_diff_size_t(e, buf), "%x", v);
861d4afb5ceSopenharmony_ci
862d4afb5ceSopenharmony_ci			if (soe && v) {
863d4afb5ceSopenharmony_ci				soe = 0;
864d4afb5ceSopenharmony_ci				if (c == 5 && v == 0xffff && !zb) {
865d4afb5ceSopenharmony_ci					ipv4 = 1;
866d4afb5ceSopenharmony_ci					*buf++ = ':';
867d4afb5ceSopenharmony_ci				}
868d4afb5ceSopenharmony_ci			}
869d4afb5ceSopenharmony_ci		}
870d4afb5ceSopenharmony_ci	}
871d4afb5ceSopenharmony_ci	if (buf + 3 > e)
872d4afb5ceSopenharmony_ci		return -1;
873d4afb5ceSopenharmony_ci
874d4afb5ceSopenharmony_ci	if (soe) { /* as is the case for all zeros */
875d4afb5ceSopenharmony_ci		*buf++ = ':';
876d4afb5ceSopenharmony_ci		*buf++ = ':';
877d4afb5ceSopenharmony_ci		*buf = '\0';
878d4afb5ceSopenharmony_ci	}
879d4afb5ceSopenharmony_ci
880d4afb5ceSopenharmony_ci	return lws_ptr_diff(buf, obuf);
881d4afb5ceSopenharmony_ci}
882d4afb5ceSopenharmony_ci
883d4afb5ceSopenharmony_ciint
884d4afb5ceSopenharmony_cilws_sa46_write_numeric_address(lws_sockaddr46 *sa46, char *buf, size_t len)
885d4afb5ceSopenharmony_ci{
886d4afb5ceSopenharmony_ci	*buf = '\0';
887d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
888d4afb5ceSopenharmony_ci	if (sa46->sa4.sin_family == AF_INET6)
889d4afb5ceSopenharmony_ci		return lws_write_numeric_address(
890d4afb5ceSopenharmony_ci				(uint8_t *)&sa46->sa6.sin6_addr, 16, buf, len);
891d4afb5ceSopenharmony_ci#endif
892d4afb5ceSopenharmony_ci	if (sa46->sa4.sin_family == AF_INET)
893d4afb5ceSopenharmony_ci		return lws_write_numeric_address(
894d4afb5ceSopenharmony_ci				(uint8_t *)&sa46->sa4.sin_addr, 4, buf, len);
895d4afb5ceSopenharmony_ci
896d4afb5ceSopenharmony_ci#if defined(LWS_WITH_UNIX_SOCK)
897d4afb5ceSopenharmony_ci	if (sa46->sa4.sin_family == AF_UNIX)
898d4afb5ceSopenharmony_ci		return lws_snprintf(buf, len, "(unix skt)");
899d4afb5ceSopenharmony_ci#endif
900d4afb5ceSopenharmony_ci
901d4afb5ceSopenharmony_ci	if (!sa46->sa4.sin_family)
902d4afb5ceSopenharmony_ci		return lws_snprintf(buf, len, "(unset)");
903d4afb5ceSopenharmony_ci
904d4afb5ceSopenharmony_ci	if (sa46->sa4.sin_family == AF_INET6)
905d4afb5ceSopenharmony_ci		return lws_snprintf(buf, len, "(ipv6 unsupp)");
906d4afb5ceSopenharmony_ci
907d4afb5ceSopenharmony_ci	lws_snprintf(buf, len, "(AF%d unsupp)", (int)sa46->sa4.sin_family);
908d4afb5ceSopenharmony_ci
909d4afb5ceSopenharmony_ci	return -1;
910d4afb5ceSopenharmony_ci}
911d4afb5ceSopenharmony_ci
912d4afb5ceSopenharmony_ciint
913d4afb5ceSopenharmony_cilws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b)
914d4afb5ceSopenharmony_ci{
915d4afb5ceSopenharmony_ci	if (sa46a->sa4.sin_family != sa46b->sa4.sin_family)
916d4afb5ceSopenharmony_ci		return 1;
917d4afb5ceSopenharmony_ci
918d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
919d4afb5ceSopenharmony_ci	if (sa46a->sa4.sin_family == AF_INET6)
920d4afb5ceSopenharmony_ci		return memcmp(&sa46a->sa6.sin6_addr, &sa46b->sa6.sin6_addr, 16);
921d4afb5ceSopenharmony_ci#endif
922d4afb5ceSopenharmony_ci
923d4afb5ceSopenharmony_ci	if (sa46a->sa4.sin_family == AF_INET)
924d4afb5ceSopenharmony_ci		return sa46a->sa4.sin_addr.s_addr != sa46b->sa4.sin_addr.s_addr;
925d4afb5ceSopenharmony_ci
926d4afb5ceSopenharmony_ci	return 0;
927d4afb5ceSopenharmony_ci}
928d4afb5ceSopenharmony_ci
929d4afb5ceSopenharmony_civoid
930d4afb5ceSopenharmony_cilws_4to6(uint8_t *v6addr, const uint8_t *v4addr)
931d4afb5ceSopenharmony_ci{
932d4afb5ceSopenharmony_ci	v6addr[12] = v4addr[0];
933d4afb5ceSopenharmony_ci	v6addr[13] = v4addr[1];
934d4afb5ceSopenharmony_ci	v6addr[14] = v4addr[2];
935d4afb5ceSopenharmony_ci	v6addr[15] = v4addr[3];
936d4afb5ceSopenharmony_ci
937d4afb5ceSopenharmony_ci	memset(v6addr, 0, 10);
938d4afb5ceSopenharmony_ci
939d4afb5ceSopenharmony_ci	v6addr[10] = v6addr[11] = 0xff;
940d4afb5ceSopenharmony_ci}
941d4afb5ceSopenharmony_ci
942d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
943d4afb5ceSopenharmony_civoid
944d4afb5ceSopenharmony_cilws_sa46_4to6(lws_sockaddr46 *sa46, const uint8_t *v4addr, uint16_t port)
945d4afb5ceSopenharmony_ci{
946d4afb5ceSopenharmony_ci	sa46->sa4.sin_family = AF_INET6;
947d4afb5ceSopenharmony_ci
948d4afb5ceSopenharmony_ci	lws_4to6((uint8_t *)&sa46->sa6.sin6_addr.s6_addr[0], v4addr);
949d4afb5ceSopenharmony_ci
950d4afb5ceSopenharmony_ci	sa46->sa6.sin6_port = htons(port);
951d4afb5ceSopenharmony_ci}
952d4afb5ceSopenharmony_ci#endif
953d4afb5ceSopenharmony_ci
954d4afb5ceSopenharmony_ciint
955d4afb5ceSopenharmony_cilws_sa46_on_net(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46_net,
956d4afb5ceSopenharmony_ci		int net_len)
957d4afb5ceSopenharmony_ci{
958d4afb5ceSopenharmony_ci	uint8_t mask = 0xff, norm[16];
959d4afb5ceSopenharmony_ci	const uint8_t *p1, *p2;
960d4afb5ceSopenharmony_ci
961d4afb5ceSopenharmony_ci	if (sa46a->sa4.sin_family == AF_INET) {
962d4afb5ceSopenharmony_ci		p1 = (uint8_t *)&sa46a->sa4.sin_addr;
963d4afb5ceSopenharmony_ci		if (sa46_net->sa4.sin_family == AF_INET6) {
964d4afb5ceSopenharmony_ci			/* ip is v4, net is v6, promote ip to v6 */
965d4afb5ceSopenharmony_ci
966d4afb5ceSopenharmony_ci			lws_4to6(norm, p1);
967d4afb5ceSopenharmony_ci			p1 = norm;
968d4afb5ceSopenharmony_ci		}
969d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
970d4afb5ceSopenharmony_ci	} else
971d4afb5ceSopenharmony_ci		if (sa46a->sa4.sin_family == AF_INET6) {
972d4afb5ceSopenharmony_ci			p1 = (uint8_t *)&sa46a->sa6.sin6_addr;
973d4afb5ceSopenharmony_ci#endif
974d4afb5ceSopenharmony_ci		} else
975d4afb5ceSopenharmony_ci			return 1;
976d4afb5ceSopenharmony_ci
977d4afb5ceSopenharmony_ci	if (sa46_net->sa4.sin_family == AF_INET) {
978d4afb5ceSopenharmony_ci		p2 = (uint8_t *)&sa46_net->sa4.sin_addr;
979d4afb5ceSopenharmony_ci		if (sa46a->sa4.sin_family == AF_INET6) {
980d4afb5ceSopenharmony_ci			/* ip is v6, net is v4, promote net to v6 */
981d4afb5ceSopenharmony_ci
982d4afb5ceSopenharmony_ci			lws_4to6(norm, p2);
983d4afb5ceSopenharmony_ci			p2 = norm;
984d4afb5ceSopenharmony_ci			/* because the mask length is for net v4 address */
985d4afb5ceSopenharmony_ci			net_len += 12 * 8;
986d4afb5ceSopenharmony_ci		}
987d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
988d4afb5ceSopenharmony_ci	} else
989d4afb5ceSopenharmony_ci		if (sa46a->sa4.sin_family == AF_INET6) {
990d4afb5ceSopenharmony_ci			p2 = (uint8_t *)&sa46_net->sa6.sin6_addr;
991d4afb5ceSopenharmony_ci#endif
992d4afb5ceSopenharmony_ci		} else
993d4afb5ceSopenharmony_ci			return 1;
994d4afb5ceSopenharmony_ci
995d4afb5ceSopenharmony_ci	while (net_len > 0) {
996d4afb5ceSopenharmony_ci		if (net_len < 8)
997d4afb5ceSopenharmony_ci			mask = (uint8_t)(mask << (8 - net_len));
998d4afb5ceSopenharmony_ci
999d4afb5ceSopenharmony_ci		if (((*p1++) & mask) != ((*p2++) & mask))
1000d4afb5ceSopenharmony_ci			return 1;
1001d4afb5ceSopenharmony_ci
1002d4afb5ceSopenharmony_ci		net_len -= 8;
1003d4afb5ceSopenharmony_ci	}
1004d4afb5ceSopenharmony_ci
1005d4afb5ceSopenharmony_ci	return 0;
1006d4afb5ceSopenharmony_ci}
1007d4afb5ceSopenharmony_ci
1008d4afb5ceSopenharmony_civoid
1009d4afb5ceSopenharmony_cilws_sa46_copy_address(lws_sockaddr46 *sa46a, const void *in, int af)
1010d4afb5ceSopenharmony_ci{
1011d4afb5ceSopenharmony_ci	sa46a->sa4.sin_family = (sa_family_t)af;
1012d4afb5ceSopenharmony_ci
1013d4afb5ceSopenharmony_ci	if (af == AF_INET)
1014d4afb5ceSopenharmony_ci		memcpy(&sa46a->sa4.sin_addr, in, 4);
1015d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
1016d4afb5ceSopenharmony_ci	else if (af == AF_INET6)
1017d4afb5ceSopenharmony_ci		memcpy(&sa46a->sa6.sin6_addr, in, sizeof(sa46a->sa6.sin6_addr));
1018d4afb5ceSopenharmony_ci#endif
1019d4afb5ceSopenharmony_ci}
1020d4afb5ceSopenharmony_ci
1021d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_STATE)
1022d4afb5ceSopenharmony_cilws_state_manager_t *
1023d4afb5ceSopenharmony_cilws_system_get_state_manager(struct lws_context *context)
1024d4afb5ceSopenharmony_ci{
1025d4afb5ceSopenharmony_ci	return &context->mgr_system;
1026d4afb5ceSopenharmony_ci}
1027d4afb5ceSopenharmony_ci#endif
1028