xref: /aosp_15_r20/external/libwebsockets/lib/plat/unix/unix-init.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
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 #if !defined(_GNU_SOURCE)
26 #define _GNU_SOURCE
27 #endif
28 #include "private-lib-core.h"
29 
30 #include <pwd.h>
31 #include <grp.h>
32 
33 #ifdef LWS_WITH_PLUGINS
34 #include <dlfcn.h>
35 #endif
36 #include <dirent.h>
37 
38 #if defined(LWS_WITH_NETWORK)
39 static void
lws_sul_plat_unix(lws_sorted_usec_list_t * sul)40 lws_sul_plat_unix(lws_sorted_usec_list_t *sul)
41 {
42 	struct lws_context_per_thread *pt =
43 		lws_container_of(sul, struct lws_context_per_thread, sul_plat);
44 	struct lws_context *context = pt->context;
45 	int n = 0, m = 0;
46 
47 #if !defined(LWS_NO_DAEMONIZE)
48 	/* if our parent went down, don't linger around */
49 	if (pt->context->started_with_parent &&
50 	    kill(pt->context->started_with_parent, 0) < 0)
51 		kill(getpid(), SIGTERM);
52 #endif
53 
54 	for (n = 0; n < context->count_threads; n++)
55 		m = m | (int)pt->fds_count;
56 
57 	if (context->deprecated && !m) {
58 		lwsl_notice("%s: ending deprecated context\n", __func__);
59 		kill(getpid(), SIGINT);
60 		return;
61 	}
62 
63 #if defined(LWS_WITH_SERVER)
64 	lws_context_lock(context, "periodic checks");
65 	lws_start_foreach_llp(struct lws_vhost **, pv,
66 			      context->no_listener_vhost_list) {
67 		struct lws_vhost *v = *pv;
68 		lwsl_debug("deferred iface: checking if on vh %s\n", (*pv)->name);
69 		if (_lws_vhost_init_server(NULL, *pv) == 0) {
70 			/* became happy */
71 			lwsl_notice("vh %s: became connected\n", v->name);
72 			*pv = v->no_listener_vhost_list;
73 			v->no_listener_vhost_list = NULL;
74 			break;
75 		}
76 	} lws_end_foreach_llp(pv, no_listener_vhost_list);
77 	lws_context_unlock(context);
78 #endif
79 
80 	__lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
81 			    &pt->sul_plat, 30 * LWS_US_PER_SEC);
82 }
83 #endif
84 
85 #if defined(LWS_WITH_PLUGINS)
86 static int
protocol_plugin_cb(struct lws_plugin * pin,void * each_user)87 protocol_plugin_cb(struct lws_plugin *pin, void *each_user)
88 {
89 	struct lws_context *context = (struct lws_context *)each_user;
90 	const lws_plugin_protocol_t *plpr =
91 			(const lws_plugin_protocol_t *)pin->hdr;
92 
93 	context->plugin_protocol_count = (short)(context->plugin_protocol_count +
94 						 plpr->count_protocols);
95 	context->plugin_extension_count = (short)(context->plugin_extension_count +
96 						  plpr->count_extensions);
97 
98 	return 0;
99 }
100 #endif
101 
102 int
lws_plat_init(struct lws_context * context,const struct lws_context_creation_info * info)103 lws_plat_init(struct lws_context *context,
104 	      const struct lws_context_creation_info *info)
105 {
106 	int fd;
107 #if defined(LWS_WITH_NETWORK)
108 	/*
109 	 * context has the process-global fd lookup array.  This can be
110 	 * done two different ways now; one or the other is done depending on if
111 	 * info->fd_limit_per_thread was snonzero
112 	 *
113 	 *  - default: allocate a worst-case lookup array sized for ulimit -n
114 	 *             and use the fd directly as an index into it
115 	 *
116 	 *  - slow:    allocate context->max_fds entries only (which can be
117 	 *             forced at context creation time to be
118 	 *             info->fd_limit_per_thread * the number of threads)
119 	 *             and search the array to lookup fds
120 	 *
121 	 * the default way is optimized for server, if you only use one or two
122 	 * client wsi the slow way may save a lot of memory.
123 	 *
124 	 * Both ways allocate an array of struct lws *... one allocates it for
125 	 * all possible fd indexes the process could produce and uses it as a
126 	 * map, the other allocates for an amount of wsi the lws context is
127 	 * expected to use and searches through it to manipulate it.
128 	 */
129 
130 	context->lws_lookup = lws_zalloc(sizeof(struct lws *) *
131 					 context->max_fds, "lws_lookup");
132 
133 	if (!context->lws_lookup) {
134 		lwsl_cx_err(context, "OOM on alloc lws_lookup array for %d conn",
135 			 context->max_fds);
136 		return 1;
137 	}
138 
139 #if defined(LWS_WITH_MBEDTLS)
140 	{
141 		int n;
142 
143 		/* initialize platform random through mbedtls */
144 		mbedtls_entropy_init(&context->mec);
145 		mbedtls_ctr_drbg_init(&context->mcdc);
146 
147 		n = mbedtls_ctr_drbg_seed(&context->mcdc, mbedtls_entropy_func,
148 					  &context->mec, NULL, 0);
149 		if (n)
150 			lwsl_err("%s: mbedtls_ctr_drbg_seed() returned 0x%x\n",
151 				 __func__, n);
152 #if 0
153 		else {
154 			uint8_t rtest[16];
155 			lwsl_notice("%s: started drbg\n", __func__);
156 			if (mbedtls_ctr_drbg_random(&context->mcdc, rtest,
157 							sizeof(rtest)))
158 				lwsl_err("%s: get random failed\n", __func__);
159 			else
160 				lwsl_hexdump_notice(rtest, sizeof(rtest));
161 		}
162 #endif
163 	}
164 #endif
165 
166 	lwsl_cx_info(context, " mem: platform fd map: %5lu B",
167 		    (unsigned long)(sizeof(struct lws *) * context->max_fds));
168 #endif
169 #if defined(LWS_WITH_FILE_OPS)
170 	fd = lws_open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
171 #else
172 	fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
173 #endif
174 	context->fd_random = fd;
175 	if (context->fd_random < 0) {
176 		lwsl_err("Unable to open random device %s %d, errno %d\n",
177 			 SYSTEM_RANDOM_FILEPATH, context->fd_random, errno);
178 		return 1;
179 	}
180 
181 #if defined(LWS_WITH_PLUGINS)
182 	{
183 		char *ld_env = getenv("LD_LIBRARY_PATH");
184 
185 		if (ld_env) {
186 			const char *pp[2] = { ld_env, NULL };
187 
188 			lws_plugins_init(&context->plugin_list, pp,
189 					 "lws_protocol_plugin", NULL,
190 					 protocol_plugin_cb, context);
191 		}
192 
193 		if (info->plugin_dirs)
194 			lws_plugins_init(&context->plugin_list,
195 					 info->plugin_dirs,
196 					 "lws_protocol_plugin", NULL,
197 					 protocol_plugin_cb, context);
198 	}
199 #endif
200 
201 
202 #if defined(LWS_WITH_NETWORK)
203 	/* we only need to do this on pt[0] */
204 
205 	context->pt[0].sul_plat.cb = lws_sul_plat_unix;
206 	__lws_sul_insert_us(&context->pt[0].pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
207 			    &context->pt[0].sul_plat, 30 * LWS_US_PER_SEC);
208 #endif
209 
210 	return 0;
211 }
212 
213 int
lws_plat_context_early_init(void)214 lws_plat_context_early_init(void)
215 {
216 #if !defined(LWS_AVOID_SIGPIPE_IGN)
217 	signal(SIGPIPE, SIG_IGN);
218 #endif
219 
220 	return 0;
221 }
222 
223 void
lws_plat_context_early_destroy(struct lws_context * context)224 lws_plat_context_early_destroy(struct lws_context *context)
225 {
226 }
227 
228 void
lws_plat_context_late_destroy(struct lws_context * context)229 lws_plat_context_late_destroy(struct lws_context *context)
230 {
231 #if defined(LWS_WITH_PLUGINS)
232 	if (context->plugin_list)
233 		lws_plugins_destroy(&context->plugin_list, NULL, NULL);
234 #endif
235 #if defined(LWS_WITH_NETWORK)
236 	if (context->lws_lookup)
237 		lws_free_set_NULL(context->lws_lookup);
238 #endif
239 	if (!context->fd_random)
240 		lwsl_err("ZERO RANDOM FD\n");
241 	if (context->fd_random != LWS_INVALID_FILE)
242 		close(context->fd_random);
243 }
244