/src/libwebsockets/lib/core/context.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * libwebsockets - small server side websockets and web server implementation |
3 | | * |
4 | | * Copyright (C) 2010 - 2020 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 | | #ifndef LWS_BUILD_HASH |
28 | | #define LWS_BUILD_HASH "unknown-build-hash" |
29 | | #endif |
30 | | |
31 | | static const char *library_version = LWS_LIBRARY_VERSION; |
32 | | |
33 | | #if defined(LWS_WITH_MBEDTLS) |
34 | | extern const char *mbedtls_client_preload_filepath; |
35 | | #endif |
36 | | |
37 | | #if defined(LWS_HAVE_SYS_RESOURCE_H) |
38 | | /* for setrlimit */ |
39 | | #include <sys/resource.h> |
40 | | #endif |
41 | | |
42 | | #if defined(LWS_WITH_NETWORK) |
43 | | /* in ms */ |
44 | | static uint32_t default_backoff_table[] = { 1000, 3000, 9000, 17000 }; |
45 | | #endif |
46 | | |
47 | | /** |
48 | | * lws_get_library_version: get version and git hash library built from |
49 | | * |
50 | | * returns a const char * to a string like "1.1 178d78c" |
51 | | * representing the library version followed by the git head hash it |
52 | | * was built from |
53 | | */ |
54 | | const char * |
55 | | lws_get_library_version(void) |
56 | 0 | { |
57 | 0 | return library_version; |
58 | 0 | } |
59 | | |
60 | | #if defined(LWS_WITH_NETWORK) |
61 | | |
62 | | #if defined(LWS_WITH_SYS_STATE) |
63 | | |
64 | | static const char * system_state_names[] = { |
65 | | "undef", |
66 | | "CONTEXT_CREATED", |
67 | | "INITIALIZED", |
68 | | "IFACE_COLDPLUG", |
69 | | "DHCP", |
70 | | "CPD_PRE_TIME", |
71 | | "TIME_VALID", |
72 | | "CPD_POST_TIME", |
73 | | "POLICY_VALID", |
74 | | "REGISTERED", |
75 | | "AUTH1", |
76 | | "AUTH2", |
77 | | "ONE_TIME_UPDATES", |
78 | | "OPERATIONAL", |
79 | | "POLICY_INVALID", |
80 | | "DESTROYING", |
81 | | "AWAITING_MODAL_UPDATING", |
82 | | "MODAL_UPDATING" |
83 | | }; |
84 | | |
85 | | |
86 | | /* |
87 | | * Handle provoking protocol init when we pass through the right system state |
88 | | */ |
89 | | |
90 | | static int |
91 | | lws_state_notify_protocol_init(struct lws_state_manager *mgr, |
92 | | struct lws_state_notify_link *link, int current, |
93 | | int target) |
94 | 0 | { |
95 | 0 | struct lws_context *context = lws_container_of(mgr, struct lws_context, |
96 | 0 | mgr_system); |
97 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) && \ |
98 | 0 | defined(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM) |
99 | 0 | lws_system_blob_t *ab0, *ab1; |
100 | 0 | #endif |
101 | 0 | int n; |
102 | | |
103 | | /* |
104 | | * Deal with any attachments that were waiting for the right state |
105 | | * to come along |
106 | | */ |
107 | |
|
108 | 0 | for (n = 0; n < context->count_threads; n++) |
109 | 0 | lws_system_do_attach(&context->pt[n]); |
110 | |
|
111 | | #if defined(LWS_WITH_SYS_DHCP_CLIENT) |
112 | | if (target == LWS_SYSTATE_DHCP) { |
113 | | /* |
114 | | * Don't let it past here until at least one iface has been |
115 | | * configured for operation with DHCP |
116 | | */ |
117 | | |
118 | | if (!lws_dhcpc_status(context, NULL)) |
119 | | return 1; |
120 | | } |
121 | | #endif |
122 | |
|
123 | | #if defined(LWS_WITH_SYS_NTPCLIENT) |
124 | | if (target == LWS_SYSTATE_TIME_VALID && |
125 | | lws_now_secs() < 1594017754) /* 06:42 Mon Jul 6 2020 UTC */ { |
126 | | lws_ntpc_trigger(context); |
127 | | |
128 | | return 1; |
129 | | } |
130 | | #endif |
131 | |
|
132 | | #if defined(LWS_WITH_OTA) |
133 | | if (target == LWS_SYSTATE_OPERATIONAL) { |
134 | | uint16_t b; |
135 | | |
136 | | /* |
137 | | * We add jitter, so possibly large numbers of devices don't |
138 | | * all wake up and check for updates at the same moment after a |
139 | | * power outage |
140 | | */ |
141 | | |
142 | | lws_get_random(context, &b, 2); |
143 | | lws_sul_schedule(context, 0, &context->sul_ota_periodic, |
144 | | lws_ota_periodic_cb, (/* 30 + */ (b % 1000) * |
145 | | LWS_US_PER_MS)); |
146 | | } |
147 | | #endif |
148 | |
|
149 | 0 | #if defined(LWS_WITH_NETLINK) |
150 | | /* |
151 | | * If we're going to use netlink routing data for DNS, we have to |
152 | | * wait to collect it asynchronously from the platform first. Netlink |
153 | | * role init starts a ctx sul for 350ms (reset to 100ms each time some |
154 | | * new netlink data comes) that sets nl_initial_done and tries to move |
155 | | * us to OPERATIONAL |
156 | | */ |
157 | |
|
158 | 0 | if (target == LWS_SYSTATE_IFACE_COLDPLUG && |
159 | 0 | context->netlink && |
160 | 0 | !context->nl_initial_done) { |
161 | 0 | lwsl_cx_info(context, "waiting for netlink coldplug"); |
162 | |
|
163 | 0 | return 1; |
164 | 0 | } |
165 | 0 | #endif |
166 | | |
167 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) && \ |
168 | 0 | defined(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM) |
169 | | /* |
170 | | * Skip this if we are running something without the policy for it |
171 | | * |
172 | | * If root token is empty, skip too. |
173 | | */ |
174 | | |
175 | 0 | ab0 = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, 0); |
176 | 0 | ab1 = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, 1); |
177 | |
|
178 | 0 | if (target == LWS_SYSTATE_AUTH1 && |
179 | 0 | context->pss_policies && ab0 && ab1 && |
180 | 0 | !lws_system_blob_get_size(ab0) && |
181 | 0 | lws_system_blob_get_size(ab1)) { |
182 | 0 | lwsl_cx_info(context, |
183 | 0 | "AUTH1 state triggering api.amazon.com auth"); |
184 | | /* |
185 | | * Start trying to acquire it if it's not already in progress |
186 | | * returns nonzero if we determine it's not needed |
187 | | */ |
188 | 0 | if (!lws_ss_sys_auth_api_amazon_com(context)) |
189 | 0 | return 1; |
190 | 0 | } |
191 | 0 | #endif |
192 | | |
193 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) |
194 | | #if defined(LWS_WITH_DRIVERS) |
195 | | /* |
196 | | * See if we should do the SS Captive Portal Detection |
197 | | */ |
198 | | if (target == LWS_SYSTATE_CPD_PRE_TIME) { |
199 | | if (lws_system_cpd_state_get(context) == LWS_CPD_INTERNET_OK) |
200 | | return 0; /* allow it */ |
201 | | |
202 | | /* |
203 | | * Don't allow it to move past here until we get an IP and |
204 | | * CPD passes, driven by SMD |
205 | | */ |
206 | | |
207 | | return 1; |
208 | | } |
209 | | #endif |
210 | | |
211 | 0 | #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
212 | | /* |
213 | | * Skip this if we are running something without the policy for it |
214 | | */ |
215 | 0 | if (target == LWS_SYSTATE_POLICY_VALID && |
216 | 0 | context->pss_policies && !context->policy_updated) { |
217 | |
|
218 | 0 | if (context->hss_fetch_policy) |
219 | 0 | return 1; |
220 | | |
221 | 0 | lwsl_cx_debug(context, "starting policy fetch"); |
222 | | /* |
223 | | * Start trying to acquire it if it's not already in progress |
224 | | * returns nonzero if we determine it's not needed |
225 | | */ |
226 | 0 | if (!lws_ss_sys_fetch_policy(context)) |
227 | | /* we have it */ |
228 | 0 | return 0; |
229 | | |
230 | | /* deny while we fetch it */ |
231 | | |
232 | 0 | return 1; |
233 | 0 | } |
234 | 0 | #endif |
235 | 0 | #endif |
236 | | |
237 | | /* protocol part */ |
238 | | |
239 | 0 | if (context->protocol_init_done) |
240 | 0 | return 0; |
241 | | |
242 | 0 | if (target != LWS_SYSTATE_POLICY_VALID) |
243 | 0 | return 0; |
244 | | |
245 | 0 | lwsl_cx_info(context, "doing protocol init on POLICY_VALID\n"); |
246 | |
|
247 | 0 | return lws_protocol_init(context); |
248 | 0 | } |
249 | | |
250 | | static void |
251 | | lws_context_creation_completion_cb(lws_sorted_usec_list_t *sul) |
252 | 0 | { |
253 | 0 | struct lws_context *context = lws_container_of(sul, struct lws_context, |
254 | 0 | sul_system_state); |
255 | | |
256 | | /* if nothing is there to intercept anything, go all the way */ |
257 | 0 | lws_state_transition_steps(&context->mgr_system, |
258 | 0 | LWS_SYSTATE_OPERATIONAL); |
259 | 0 | } |
260 | | #endif /* WITH_SYS_STATE */ |
261 | | |
262 | | #if defined(LWS_WITH_SYS_SMD) |
263 | | static int |
264 | | lws_system_smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp, |
265 | | void *buf, size_t len) |
266 | 0 | { |
267 | 0 | struct lws_context *cx = (struct lws_context *)opaque; |
268 | |
|
269 | 0 | if (_class != LWSSMDCL_NETWORK) |
270 | 0 | return 0; |
271 | | |
272 | | /* something external requested CPD check */ |
273 | | |
274 | 0 | if (!lws_json_simple_strcmp(buf, len, "\"trigger\":", "cpdcheck")) |
275 | 0 | lws_system_cpd_start(cx); |
276 | 0 | else |
277 | | /* |
278 | | * IP acquisition on any interface triggers captive portal |
279 | | * check on default route |
280 | | */ |
281 | 0 | if (!lws_json_simple_strcmp(buf, len, "\"type\":", "ipacq")) |
282 | 0 | lws_system_cpd_start(cx); |
283 | |
|
284 | | #if defined(LWS_WITH_SYS_NTPCLIENT) |
285 | | /* |
286 | | * Captive portal detect showing internet workable triggers NTP Client |
287 | | */ |
288 | | if (!lws_json_simple_strcmp(buf, len, "\"type\":", "cps") && |
289 | | !lws_json_simple_strcmp(buf, len, "\"result\":", "OK") && |
290 | | lws_now_secs() < 1594017754) /* 06:42 Mon Jul 6 2020 UTC */ |
291 | | lws_ntpc_trigger(cx); |
292 | | #endif |
293 | |
|
294 | | #if defined(LWS_WITH_SYS_DHCP_CLIENT) && 0 |
295 | | /* |
296 | | * Any network interface linkup triggers DHCP |
297 | | */ |
298 | | if (!lws_json_simple_strcmp(buf, len, "\"type\":", "linkup")) |
299 | | lws_ntpc_trigger(cx); |
300 | | |
301 | | #endif |
302 | |
|
303 | | #if defined(LWS_WITH_DRIVERS) && defined(LWS_WITH_NETWORK) |
304 | | lws_netdev_smd_cb(opaque, _class, timestamp, buf, len); |
305 | | #endif |
306 | |
|
307 | 0 | return 0; |
308 | 0 | } |
309 | | #endif |
310 | | |
311 | | |
312 | | |
313 | | #endif /* NETWORK */ |
314 | | |
315 | | #if !defined(LWS_WITH_NO_LOGS) |
316 | | |
317 | | static const char * const opts_str = |
318 | | #if defined(LWS_WITH_NETWORK) |
319 | | "NET " |
320 | | #else |
321 | | "NoNET " |
322 | | #endif |
323 | | #if defined(LWS_WITH_CLIENT) |
324 | | "CLI " |
325 | | #endif |
326 | | #if defined(LWS_WITH_SERVER) |
327 | | "SRV " |
328 | | #endif |
329 | | #if defined(LWS_ROLE_H1) |
330 | | "H1 " |
331 | | #endif |
332 | | #if defined(LWS_ROLE_H2) |
333 | | "H2 " |
334 | | #endif |
335 | | #if defined(LWS_ROLE_WS) |
336 | | "WS " |
337 | | #endif |
338 | | #if defined(LWS_ROLE_MQTT) |
339 | | "MQTT " |
340 | | #endif |
341 | | #if defined(LWS_WITH_SECURE_STREAMS) && !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
342 | | "SS-JSON-POL " |
343 | | #endif |
344 | | #if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
345 | | "SS-STATIC-POL " |
346 | | #endif |
347 | | #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) |
348 | | "SSPROX " |
349 | | #endif |
350 | | #if defined(LWS_WITH_CONMON) |
351 | | "ConMon " |
352 | | #endif |
353 | | #if defined(LWS_WITH_SYS_FAULT_INJECTION) |
354 | | "FLTINJ " |
355 | | #endif |
356 | | #if defined(LWS_WITH_SYS_ASYNC_DNS) |
357 | | "ASYNC_DNS " |
358 | | #endif |
359 | | #if defined(LWS_WITH_SYS_NTPCLIENT) |
360 | | "NTPCLIENT " |
361 | | #endif |
362 | | #if defined(LWS_WITH_SYS_DHCP_CLIENT) |
363 | | "DHCP_CLIENT " |
364 | | #endif |
365 | | ; |
366 | | |
367 | | #endif |
368 | | |
369 | | #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) |
370 | | static const struct lws_evlib_map { |
371 | | uint64_t flag; |
372 | | const char *name; |
373 | | } map[] = { |
374 | | { LWS_SERVER_OPTION_LIBUV, "evlib_uv" }, |
375 | | { LWS_SERVER_OPTION_LIBEVENT, "evlib_event" }, |
376 | | { LWS_SERVER_OPTION_GLIB, "evlib_glib" }, |
377 | | { LWS_SERVER_OPTION_LIBEV, "evlib_ev" }, |
378 | | { LWS_SERVER_OPTION_SDEVENT, "evlib_sd" }, |
379 | | { LWS_SERVER_OPTION_ULOOP, "evlib_uloop" }, |
380 | | }; |
381 | | static const char * const dlist[] = { |
382 | | ".", /* Priority 1: plugins in cwd */ |
383 | | LWS_INSTALL_LIBDIR, /* Priority 2: plugins in install dir */ |
384 | | NULL |
385 | | }; |
386 | | #endif |
387 | | |
388 | | struct lws_context * |
389 | | lws_create_context(const struct lws_context_creation_info *info) |
390 | 0 | { |
391 | 0 | struct lws_context *context = NULL; |
392 | 0 | #if !defined(LWS_WITH_NO_LOGS) |
393 | 0 | const char *s = "IPv6-absent"; |
394 | 0 | #endif |
395 | 0 | #if defined(LWS_WITH_FILE_OPS) |
396 | 0 | struct lws_plat_file_ops *prev; |
397 | 0 | #endif |
398 | | #ifndef LWS_NO_DAEMONIZE |
399 | | pid_t pid_daemon = get_daemonize_pid(); |
400 | | #endif |
401 | 0 | #if defined(LWS_WITH_NETWORK) |
402 | 0 | const lws_plugin_evlib_t *plev = NULL; |
403 | 0 | unsigned short count_threads = 1; |
404 | 0 | uint8_t *u; |
405 | 0 | uint16_t us_wait_resolution = 0; |
406 | 0 | #if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT) |
407 | 0 | struct lws_cache_creation_info ci; |
408 | 0 | #endif |
409 | |
|
410 | | #if defined(__ANDROID__) |
411 | | struct rlimit rt; |
412 | | #endif |
413 | 0 | size_t |
414 | | #if defined(LWS_PLAT_FREERTOS) |
415 | | /* smaller default, can set in info->pt_serv_buf_size */ |
416 | | s1 = 2048, |
417 | | #else |
418 | 0 | s1 = 4096, |
419 | 0 | #endif |
420 | 0 | size = sizeof(struct lws_context); |
421 | 0 | #endif |
422 | 0 | #if !defined(LWS_PLAT_BAREMETAL) && defined(LWS_WITH_NETWORK) |
423 | 0 | int n; |
424 | 0 | #endif |
425 | 0 | unsigned int lpf = info->fd_limit_per_thread; |
426 | | #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) |
427 | | struct lws_plugin *evlib_plugin_list = NULL; |
428 | | #if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS) |
429 | | char *ld_env; |
430 | | #endif |
431 | | #endif |
432 | | #if defined(LWS_WITH_LIBUV) |
433 | | char fatal_exit_defer = 0; |
434 | | #endif |
435 | | |
436 | |
|
437 | 0 | if (lws_fi(&info->fic, "ctx_createfail1")) |
438 | 0 | goto early_bail; |
439 | | |
440 | 0 | if (lpf) { |
441 | 0 | lpf+= 2; |
442 | | #if defined(LWS_WITH_SYS_ASYNC_DNS) |
443 | | lpf++; |
444 | | #endif |
445 | | #if defined(LWS_WITH_SYS_NTPCLIENT) |
446 | | lpf++; |
447 | | #endif |
448 | | #if defined(LWS_WITH_SYS_DHCP_CLIENT) |
449 | | lpf++; |
450 | | #endif |
451 | 0 | } |
452 | |
|
453 | | #if defined(LWS_WITH_IPV6) && !defined(LWS_WITH_NO_LOGS) |
454 | | if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6)) |
455 | | s = "IPV6-on"; |
456 | | else |
457 | | s = "IPV6-off"; |
458 | | #endif |
459 | |
|
460 | 0 | if (lws_plat_context_early_init()) |
461 | 0 | goto early_bail; |
462 | | |
463 | 0 | #if defined(LWS_WITH_NETWORK) |
464 | 0 | if (info->count_threads) |
465 | 0 | count_threads = (unsigned short)info->count_threads; |
466 | |
|
467 | 0 | if (count_threads > LWS_MAX_SMP) |
468 | 0 | count_threads = LWS_MAX_SMP; |
469 | |
|
470 | 0 | if (info->pt_serv_buf_size) |
471 | 0 | s1 = info->pt_serv_buf_size; |
472 | | |
473 | | /* pt fakewsi and the pt serv buf allocations ride after the context */ |
474 | 0 | size += count_threads * s1; |
475 | 0 | #if !defined(LWS_PLAT_FREERTOS) |
476 | 0 | size += (count_threads * sizeof(struct lws)); |
477 | 0 | #endif |
478 | |
|
479 | 0 | if (info->event_lib_custom) { |
480 | 0 | plev = info->event_lib_custom; |
481 | 0 | us_wait_resolution = 0; |
482 | 0 | } |
483 | 0 | #if defined(LWS_WITH_POLL) |
484 | 0 | else { |
485 | 0 | extern const lws_plugin_evlib_t evlib_poll; |
486 | 0 | plev = &evlib_poll; |
487 | 0 | #if !defined(LWS_PLAT_FREERTOS) |
488 | | /* |
489 | | * ... freertos has us-resolution select()... |
490 | | * others are to ms-resolution poll() |
491 | | */ |
492 | 0 | us_wait_resolution = 1000; |
493 | 0 | #endif |
494 | 0 | } |
495 | 0 | #endif |
496 | |
|
497 | | #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) |
498 | | |
499 | | /* |
500 | | * New style dynamically loaded event lib support |
501 | | * |
502 | | * We have to pick and load the event lib plugin before we allocate |
503 | | * the context object, so we can overallocate it correctly |
504 | | */ |
505 | | |
506 | | #if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS) |
507 | | ld_env = getenv("LD_LIBRARY_PATH"); |
508 | | lwsl_info("%s: ev lib path %s, '%s'\n", __func__, |
509 | | LWS_INSTALL_LIBDIR, ld_env); |
510 | | #endif |
511 | | |
512 | | for (n = 0; n < (int)LWS_ARRAY_SIZE(map); n++) { |
513 | | char ok = 0; |
514 | | |
515 | | if (!lws_check_opt(info->options, map[n].flag)) |
516 | | continue; |
517 | | |
518 | | if (!lws_plugins_init(&evlib_plugin_list, |
519 | | dlist, "lws_evlib_plugin", |
520 | | map[n].name, NULL, NULL)) |
521 | | ok = 1; |
522 | | |
523 | | if (!ok || lws_fi(&info->fic, "ctx_createfail_plugin_init")) { |
524 | | lwsl_err("%s: failed to load %s\n", __func__, |
525 | | map[n].name); |
526 | | goto bail; |
527 | | } |
528 | | |
529 | | #if defined(LWS_WITH_LIBUV) |
530 | | if (!n) /* libuv */ |
531 | | fatal_exit_defer = !!info->foreign_loops; |
532 | | #endif |
533 | | |
534 | | if (!evlib_plugin_list || |
535 | | lws_fi(&info->fic, "ctx_createfail_evlib_plugin")) { |
536 | | lwsl_err("%s: unable to load evlib plugin %s\n", |
537 | | __func__, map[n].name); |
538 | | |
539 | | goto bail; |
540 | | } |
541 | | plev = (const lws_plugin_evlib_t *)evlib_plugin_list->hdr; |
542 | | break; |
543 | | } |
544 | | #else |
545 | | #if defined(LWS_WITH_EVENT_LIBS) |
546 | | /* |
547 | | * set the context event loops ops struct |
548 | | * |
549 | | * after this, all event_loop actions use the generic ops |
550 | | */ |
551 | | |
552 | | /* |
553 | | * oldstyle built-in event lib support |
554 | | * |
555 | | * We have composed them into the libwebsockets lib itself, we can |
556 | | * just pick the ops we want and done |
557 | | */ |
558 | | |
559 | | #if defined(LWS_WITH_LIBUV) |
560 | | if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV)) { |
561 | | extern const lws_plugin_evlib_t evlib_uv; |
562 | | plev = &evlib_uv; |
563 | | fatal_exit_defer = !!info->foreign_loops; |
564 | | us_wait_resolution = 0; |
565 | | } |
566 | | #endif |
567 | | |
568 | | #if defined(LWS_WITH_LIBEVENT) |
569 | | if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEVENT)) { |
570 | | extern const lws_plugin_evlib_t evlib_event; |
571 | | plev = &evlib_event; |
572 | | us_wait_resolution = 0; |
573 | | } |
574 | | #endif |
575 | | |
576 | | #if defined(LWS_WITH_GLIB) |
577 | | if (lws_check_opt(info->options, LWS_SERVER_OPTION_GLIB)) { |
578 | | extern const lws_plugin_evlib_t evlib_glib; |
579 | | plev = &evlib_glib; |
580 | | us_wait_resolution = 0; |
581 | | } |
582 | | #endif |
583 | | |
584 | | #if defined(LWS_WITH_LIBEV) |
585 | | if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEV)) { |
586 | | extern const lws_plugin_evlib_t evlib_ev; |
587 | | plev = &evlib_ev; |
588 | | us_wait_resolution = 0; |
589 | | } |
590 | | #endif |
591 | | |
592 | | #if defined(LWS_WITH_SDEVENT) |
593 | | if (lws_check_opt(info->options, LWS_SERVER_OPTION_SDEVENT)) { |
594 | | extern const lws_plugin_evlib_t evlib_sd; |
595 | | plev = &evlib_sd; |
596 | | us_wait_resolution = 0; |
597 | | } |
598 | | #endif |
599 | | |
600 | | #if defined(LWS_WITH_ULOOP) |
601 | | if (lws_check_opt(info->options, LWS_SERVER_OPTION_ULOOP)) { |
602 | | extern const lws_plugin_evlib_t evlib_uloop; |
603 | | plev = &evlib_uloop; |
604 | | us_wait_resolution = 0; |
605 | | } |
606 | | #endif |
607 | | |
608 | | #endif /* with event libs */ |
609 | |
|
610 | 0 | #endif /* not with ev plugins */ |
611 | |
|
612 | 0 | if (!plev || lws_fi(&info->fic, "ctx_createfail_evlib_sel")) |
613 | 0 | goto fail_event_libs; |
614 | | |
615 | 0 | #if defined(LWS_WITH_NETWORK) |
616 | 0 | size += (size_t)plev->ops->evlib_size_ctx /* the ctx evlib priv */ + |
617 | 0 | (count_threads * (size_t)plev->ops->evlib_size_pt) /* the pt evlib priv */; |
618 | 0 | #endif |
619 | |
|
620 | 0 | context = lws_zalloc(size, "context"); |
621 | 0 | if (!context || lws_fi(&info->fic, "ctx_createfail_oom_ctx")) { |
622 | | #if defined(LWS_WITH_SYS_FAULT_INJECTION) |
623 | | lws_free(context); |
624 | | #endif |
625 | 0 | lwsl_err("OOM"); |
626 | 0 | goto early_bail; |
627 | 0 | } |
628 | | |
629 | 0 | #if defined(LWS_WITH_SYS_STATE) |
630 | | // NOTE: we need to init this fields because they may be used in logger when context destroying |
631 | 0 | context->mgr_system.state_names = system_state_names; |
632 | 0 | context->mgr_system.context = context; |
633 | 0 | #endif |
634 | |
|
635 | 0 | #if defined(LWS_WITH_NETWORK) |
636 | 0 | context->event_loop_ops = plev->ops; |
637 | 0 | context->us_wait_resolution = us_wait_resolution; |
638 | | #if defined(LWS_WITH_TLS_JIT_TRUST) |
639 | | { |
640 | | struct lws_cache_creation_info ci; |
641 | | |
642 | | memset(&ci, 0, sizeof(ci)); |
643 | | ci.cx = context; |
644 | | ci.ops = &lws_cache_ops_heap; |
645 | | ci.name = "jitt"; |
646 | | ci.max_footprint = info->jitt_cache_max_footprint; |
647 | | context->trust_cache = lws_cache_create(&ci); |
648 | | } |
649 | | #endif |
650 | 0 | #endif |
651 | | #if defined(LWS_WITH_EVENT_LIBS) |
652 | | /* at the very end */ |
653 | | context->evlib_ctx = (uint8_t *)context + size - |
654 | | plev->ops->evlib_size_ctx; |
655 | | #endif |
656 | | #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) |
657 | | context->evlib_plugin_list = evlib_plugin_list; |
658 | | #endif |
659 | |
|
660 | 0 | #if !defined(LWS_PLAT_FREERTOS) |
661 | 0 | context->uid = info->uid; |
662 | 0 | context->gid = info->gid; |
663 | 0 | context->username = info->username; |
664 | 0 | context->groupname = info->groupname; |
665 | 0 | #endif |
666 | 0 | context->name = info->vhost_name; |
667 | 0 | if (info->log_cx) |
668 | 0 | context->log_cx = info->log_cx; |
669 | 0 | else |
670 | 0 | context->log_cx = &log_cx; |
671 | 0 | lwsl_refcount_cx(context->log_cx, 1); |
672 | |
|
673 | 0 | context->system_ops = info->system_ops; |
674 | 0 | context->pt_serv_buf_size = (unsigned int)s1; |
675 | 0 | context->protocols_copy = info->protocols; |
676 | | #if defined(LWS_WITH_TLS_JIT_TRUST) |
677 | | context->vh_idle_grace_ms = info->vh_idle_grace_ms ? |
678 | | info->vh_idle_grace_ms : 5000; |
679 | | #endif |
680 | |
|
681 | | #if defined(LWS_WITH_SYS_FAULT_INJECTION) |
682 | | context->fic.name = "ctx"; |
683 | | if (info->fic.fi_owner.count) |
684 | | /* |
685 | | * This moves all the lws_fi_t from info->fi to the context fi, |
686 | | * leaving it empty, so no injection added to default vhost |
687 | | */ |
688 | | lws_fi_import(&context->fic, &info->fic); |
689 | | #endif |
690 | | |
691 | |
|
692 | 0 | #if defined(LWS_WITH_SYS_SMD) |
693 | 0 | context->smd_ttl_us = info->smd_ttl_us ? info->smd_ttl_us : |
694 | | #if defined(LWS_PLAT_FREERTOS) |
695 | | 5000000; |
696 | | #else |
697 | 0 | 2000000; |
698 | 0 | #endif |
699 | 0 | context->smd_queue_depth = (uint16_t)(info->smd_queue_depth ? |
700 | 0 | info->smd_queue_depth : |
701 | | #if defined(LWS_PLAT_FREERTOS) |
702 | | 20); |
703 | | #else |
704 | 0 | 40); |
705 | 0 | #endif |
706 | 0 | #endif |
707 | |
|
708 | 0 | #if defined(LWS_WITH_NETWORK) |
709 | 0 | context->lcg[LWSLCG_WSI].tag_prefix = "wsi"; |
710 | 0 | context->lcg[LWSLCG_VHOST].tag_prefix = "vh"; |
711 | 0 | context->lcg[LWSLCG_WSI_SERVER].tag_prefix = "wsisrv"; /* adopted */ |
712 | |
|
713 | 0 | #if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT) |
714 | 0 | context->lcg[LWSLCG_WSI_MUX].tag_prefix = "mux"; /* a mux child wsi */ |
715 | 0 | #endif |
716 | |
|
717 | 0 | #if defined(LWS_WITH_CLIENT) |
718 | 0 | context->lcg[LWSLCG_WSI_CLIENT].tag_prefix = "wsicli"; |
719 | 0 | #endif |
720 | |
|
721 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) |
722 | 0 | #if defined(LWS_WITH_CLIENT) |
723 | 0 | context->lcg[LWSLCG_SS_CLIENT].tag_prefix = "SScli"; |
724 | 0 | #endif |
725 | 0 | #if defined(LWS_WITH_SERVER) |
726 | 0 | context->lcg[LWSLCG_SS_SERVER].tag_prefix = "SSsrv"; |
727 | 0 | #endif |
728 | 0 | #if defined(LWS_WITH_CLIENT) |
729 | 0 | context->lcg[LWSLCG_WSI_SS_CLIENT].tag_prefix = "wsiSScli"; |
730 | 0 | #endif |
731 | 0 | #if defined(LWS_WITH_SERVER) |
732 | 0 | context->lcg[LWSLCG_WSI_SS_SERVER].tag_prefix = "wsiSSsrv"; |
733 | 0 | #endif |
734 | 0 | #endif |
735 | 0 | #endif |
736 | |
|
737 | | #if defined(LWS_WITH_SYS_METRICS) |
738 | | /* |
739 | | * If we're not using secure streams, we can still pass in a linked- |
740 | | * list of metrics policies |
741 | | */ |
742 | | context->metrics_policies = info->metrics_policies; |
743 | | context->metrics_prefix = info->metrics_prefix; |
744 | | |
745 | | context->mt_service = lws_metric_create(context, |
746 | | LWSMTFL_REPORT_DUTY_WALLCLOCK_US | |
747 | | LWSMTFL_REPORT_ONLY_GO, "cpu.svc"); |
748 | | |
749 | | #if defined(LWS_WITH_CLIENT) |
750 | | |
751 | | context->mt_conn_dns = lws_metric_create(context, |
752 | | LWSMTFL_REPORT_MEAN | |
753 | | LWSMTFL_REPORT_DUTY_WALLCLOCK_US, |
754 | | "n.cn.dns"); |
755 | | context->mt_conn_tcp = lws_metric_create(context, |
756 | | LWSMTFL_REPORT_MEAN | |
757 | | LWSMTFL_REPORT_DUTY_WALLCLOCK_US, |
758 | | "n.cn.tcp"); |
759 | | context->mt_conn_tls = lws_metric_create(context, |
760 | | LWSMTFL_REPORT_MEAN | |
761 | | LWSMTFL_REPORT_DUTY_WALLCLOCK_US, |
762 | | "n.cn.tls"); |
763 | | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) |
764 | | context->mt_http_txn = lws_metric_create(context, |
765 | | LWSMTFL_REPORT_MEAN | |
766 | | LWSMTFL_REPORT_DUTY_WALLCLOCK_US, |
767 | | "n.http.txn"); |
768 | | #endif |
769 | | |
770 | | context->mth_conn_failures = lws_metric_create(context, |
771 | | LWSMTFL_REPORT_HIST, "n.cn.failures"); |
772 | | |
773 | | #if defined(LWS_WITH_SYS_ASYNC_DNS) |
774 | | context->mt_adns_cache = lws_metric_create(context, |
775 | | LWSMTFL_REPORT_MEAN | |
776 | | LWSMTFL_REPORT_DUTY_WALLCLOCK_US, |
777 | | "n.cn.adns"); |
778 | | #endif |
779 | | #if defined(LWS_WITH_SECURE_STREAMS) |
780 | | context->mth_ss_conn = lws_metric_create(context, LWSMTFL_REPORT_HIST, |
781 | | "n.ss.conn"); |
782 | | #endif |
783 | | #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) |
784 | | context->mt_ss_cliprox_conn = lws_metric_create(context, |
785 | | LWSMTFL_REPORT_HIST, |
786 | | "n.ss.cliprox.conn"); |
787 | | context->mt_ss_cliprox_paylat = lws_metric_create(context, |
788 | | LWSMTFL_REPORT_MEAN | |
789 | | LWSMTFL_REPORT_DUTY_WALLCLOCK_US, |
790 | | "n.ss.cliprox.paylat"); |
791 | | context->mt_ss_proxcli_paylat = lws_metric_create(context, |
792 | | LWSMTFL_REPORT_MEAN | |
793 | | LWSMTFL_REPORT_DUTY_WALLCLOCK_US, |
794 | | "n.ss.proxcli.paylat"); |
795 | | #endif |
796 | | |
797 | | #endif /* network + metrics + client */ |
798 | | |
799 | | #if defined(LWS_WITH_SERVER) |
800 | | context->mth_srv = lws_metric_create(context, |
801 | | LWSMTFL_REPORT_HIST, "n.srv"); |
802 | | #endif /* network + metrics + server */ |
803 | | |
804 | | #endif /* network + metrics */ |
805 | |
|
806 | 0 | #endif /* network */ |
807 | |
|
808 | | #if defined(LWS_WITH_MBEDTLS) |
809 | | { |
810 | | char mbedtls_version[32]; |
811 | | |
812 | | #if defined(MBEDTLS_VERSION_C) |
813 | | mbedtls_version_get_string(mbedtls_version); |
814 | | #else |
815 | | lws_snprintf(mbedtls_version, sizeof(mbedtls_version), "%s", MBEDTLS_VERSION_STRING); |
816 | | #endif |
817 | | lwsl_cx_notice(context, "LWS: %s, MbedTLS-%s %s%s", library_version, mbedtls_version, opts_str, s); |
818 | | } |
819 | | #else |
820 | 0 | lwsl_cx_notice(context, "LWS: %s, %s%s", library_version, opts_str, s); |
821 | 0 | #endif |
822 | |
|
823 | 0 | #if defined(LWS_WITH_NETWORK) |
824 | 0 | lwsl_cx_info(context, "Event loop: %s", plev->ops->name); |
825 | 0 | #endif |
826 | | |
827 | | /* |
828 | | * Proxy group |
829 | | */ |
830 | |
|
831 | | #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) |
832 | | #if defined(LWS_WITH_CLIENT) |
833 | | context->lcg[LWSLCG_SSP_CLIENT].tag_prefix = "SSPcli"; |
834 | | #endif |
835 | | #if defined(LWS_WITH_SERVER) |
836 | | context->lcg[LWSLCG_SSP_ONWARD].tag_prefix = "SSPonw"; |
837 | | #endif |
838 | | #if defined(LWS_WITH_CLIENT) |
839 | | context->lcg[LWSLCG_WSI_SSP_CLIENT].tag_prefix = "wsiSSPcli"; |
840 | | #endif |
841 | | #if defined(LWS_WITH_SERVER) |
842 | | context->lcg[LWSLCG_WSI_SSP_ONWARD].tag_prefix = "wsiSSPonw"; |
843 | | #endif |
844 | | #endif |
845 | |
|
846 | 0 | #if defined(LWS_WITH_SERVER) |
847 | 0 | context->lcg[LWSLCG_WSI_SSP_SINK].tag_prefix = "SSsink"; |
848 | 0 | context->lcg[LWSLCG_WSI_SSP_SOURCE].tag_prefix = "SSsrc"; |
849 | 0 | #endif |
850 | |
|
851 | | #if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
852 | | /* directly use the user-provided policy object list */ |
853 | | context->pss_policies = info->pss_policies; |
854 | | #endif |
855 | |
|
856 | | #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) && defined(LWS_WITH_CLIENT) |
857 | | context->ss_proxy_bind = info->ss_proxy_bind; |
858 | | context->ss_proxy_port = info->ss_proxy_port; |
859 | | context->ss_proxy_address = info->ss_proxy_address; |
860 | | |
861 | | if (info->txp_ops_ssproxy) |
862 | | context->txp_ppath.ops_onw = info->txp_ops_ssproxy; |
863 | | else |
864 | | context->txp_ppath.ops_onw = &txp_ops_ssproxy_wsi; |
865 | | if (info->txp_ops_sspc) |
866 | | context->txp_cpath.ops_onw = info->txp_ops_sspc; |
867 | | else |
868 | | context->txp_cpath.ops_onw = &txp_ops_sspc_wsi; |
869 | | |
870 | | context->txp_ssproxy_info = info->txp_ssproxy_info; |
871 | | |
872 | | if (context->ss_proxy_bind && context->ss_proxy_address) |
873 | | lwsl_cx_notice(context, "ss proxy bind '%s', port %d, ads '%s'", |
874 | | context->ss_proxy_bind, context->ss_proxy_port, |
875 | | context->ss_proxy_address); |
876 | | #endif |
877 | |
|
878 | 0 | #if defined(LWS_WITH_NETWORK) |
879 | 0 | context->undestroyed_threads = count_threads; |
880 | 0 | context->count_threads = count_threads; |
881 | |
|
882 | 0 | #if defined(LWS_ROLE_WS) && defined(LWS_WITHOUT_EXTENSIONS) |
883 | 0 | if (info->extensions) |
884 | 0 | lwsl_cx_warn(context, "WITHOUT_EXTENSIONS but exts ptr set"); |
885 | 0 | #endif |
886 | 0 | #endif /* network */ |
887 | |
|
888 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) |
889 | 0 | #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
890 | 0 | context->pss_policies_json = info->pss_policies_json; |
891 | 0 | #endif |
892 | 0 | #endif |
893 | | |
894 | | /* if he gave us names, set the uid / gid */ |
895 | 0 | if (lws_plat_drop_app_privileges(context, 0) || |
896 | 0 | lws_fi(&context->fic, "ctx_createfail_privdrop")) |
897 | 0 | goto free_context_fail2; |
898 | | |
899 | 0 | #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK) |
900 | | #if defined(LWS_WITH_MBEDTLS) |
901 | | context->tls_ops = &tls_ops_mbedtls; |
902 | | |
903 | | mbedtls_client_preload_filepath = info->mbedtls_client_preload_filepath; |
904 | | #else |
905 | 0 | context->tls_ops = &tls_ops_openssl; |
906 | 0 | #endif |
907 | 0 | #endif |
908 | |
|
909 | | #if LWS_MAX_SMP > 1 |
910 | | lws_mutex_refcount_init(&context->mr); |
911 | | #endif |
912 | |
|
913 | | #if defined(LWS_PLAT_FREERTOS) |
914 | | #if defined(LWS_AMAZON_RTOS) |
915 | | context->last_free_heap = xPortGetFreeHeapSize(); |
916 | | #else |
917 | | context->last_free_heap = esp_get_free_heap_size(); |
918 | | #endif |
919 | | #endif |
920 | |
|
921 | 0 | #if defined(LWS_WITH_FILE_OPS) |
922 | | /* default to just the platform fops implementation */ |
923 | |
|
924 | 0 | context->fops_platform.LWS_FOP_OPEN = _lws_plat_file_open; |
925 | 0 | context->fops_platform.LWS_FOP_CLOSE = _lws_plat_file_close; |
926 | 0 | context->fops_platform.LWS_FOP_SEEK_CUR = _lws_plat_file_seek_cur; |
927 | 0 | context->fops_platform.LWS_FOP_READ = _lws_plat_file_read; |
928 | 0 | context->fops_platform.LWS_FOP_WRITE = _lws_plat_file_write; |
929 | 0 | context->fops_platform.fi[0].sig = NULL; |
930 | 0 | context->fops_platform.cx = context; |
931 | | |
932 | | /* |
933 | | * arrange a linear linked-list of fops starting from context->fops |
934 | | * |
935 | | * platform fops |
936 | | * [ -> fops_zip (copied into context so .next settable) ] |
937 | | * [ -> info->fops ] |
938 | | */ |
939 | |
|
940 | 0 | context->fops = &context->fops_platform; |
941 | 0 | prev = (struct lws_plat_file_ops *)context->fops; |
942 | |
|
943 | | #if defined(LWS_WITH_ZIP_FOPS) |
944 | | /* make a soft copy so we can set .next */ |
945 | | context->fops_zip = fops_zip; |
946 | | prev->next = &context->fops_zip; |
947 | | context->fops_zip.cx = context; |
948 | | prev = (struct lws_plat_file_ops *)prev->next; |
949 | | #endif |
950 | | |
951 | | /* if user provided fops, tack them on the end of the list */ |
952 | 0 | if (info->fops) |
953 | 0 | prev->next = info->fops; |
954 | 0 | #endif |
955 | |
|
956 | 0 | #if defined(LWS_WITH_SERVER) |
957 | 0 | context->reject_service_keywords = info->reject_service_keywords; |
958 | 0 | #endif |
959 | 0 | if (info->external_baggage_free_on_destroy) |
960 | 0 | context->external_baggage_free_on_destroy = |
961 | 0 | info->external_baggage_free_on_destroy; |
962 | 0 | #if defined(LWS_WITH_NETWORK) |
963 | 0 | context->time_up = lws_now_usecs(); |
964 | 0 | #endif |
965 | 0 | context->pcontext_finalize = info->pcontext; |
966 | |
|
967 | 0 | #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK) |
968 | 0 | context->simultaneous_ssl_restriction = |
969 | 0 | info->simultaneous_ssl_restriction; |
970 | 0 | context->simultaneous_ssl_handshake_restriction = |
971 | 0 | info->simultaneous_ssl_handshake_restriction; |
972 | 0 | #endif |
973 | |
|
974 | 0 | context->options = info->options; |
975 | |
|
976 | 0 | #if defined(LWS_HAVE_SYS_RESOURCE_H) && !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE) && !defined(WIN32) && !defined(LWS_PLAT_BAREMETAL) |
977 | | /* |
978 | | * If asked, try to set the rlimit / ulimit for process sockets / files. |
979 | | * We read the effective limit in a moment, so we will find out the |
980 | | * real limit according to system constraints then. |
981 | | */ |
982 | 0 | if (info->rlimit_nofile) { |
983 | 0 | struct rlimit rl; |
984 | |
|
985 | 0 | rl.rlim_cur = (unsigned int)info->rlimit_nofile; |
986 | 0 | rl.rlim_max = (unsigned int)info->rlimit_nofile; |
987 | 0 | setrlimit(RLIMIT_NOFILE, &rl); |
988 | 0 | } |
989 | 0 | #endif |
990 | |
|
991 | | #ifndef LWS_NO_DAEMONIZE |
992 | | if (pid_daemon) { |
993 | | context->started_with_parent = pid_daemon; |
994 | | lwsl_cx_info(context, " Started with daemon pid %u", |
995 | | (unsigned int)pid_daemon); |
996 | | } |
997 | | #endif |
998 | | #if defined(__ANDROID__) |
999 | | n = getrlimit(RLIMIT_NOFILE, &rt); |
1000 | | if (n == -1) { |
1001 | | lwsl_cx_err(context, "Get RLIMIT_NOFILE failed!"); |
1002 | | |
1003 | | goto free_context_fail2; |
1004 | | } |
1005 | | context->max_fds = (unsigned int)rt.rlim_cur; |
1006 | | #else |
1007 | | #if defined(WIN32) || defined(_WIN32) || defined(LWS_AMAZON_RTOS) || defined(LWS_ESP_PLATFORM) |
1008 | | context->max_fds = getdtablesize(); |
1009 | | #else |
1010 | 0 | { |
1011 | 0 | long l = sysconf(_SC_OPEN_MAX); |
1012 | |
|
1013 | 0 | context->max_fds = 2560; |
1014 | |
|
1015 | 0 | if (l > 10000000) |
1016 | 0 | lwsl_cx_warn(context, "unreasonable ulimit -n workaround"); |
1017 | 0 | else |
1018 | 0 | if (l != -1l) |
1019 | 0 | context->max_fds = (unsigned int)l; |
1020 | 0 | } |
1021 | 0 | #endif |
1022 | 0 | if ((int)context->max_fds < 0 || |
1023 | 0 | lws_fi(&context->fic, "ctx_createfail_maxfds")) { |
1024 | 0 | lwsl_cx_err(context, "problem getting process max files"); |
1025 | |
|
1026 | 0 | goto free_context_fail2; |
1027 | 0 | } |
1028 | 0 | #endif |
1029 | | |
1030 | | /* |
1031 | | * deal with any max_fds override, if it's reducing (setting it to |
1032 | | * more than ulimit -n is meaningless). The platform init will |
1033 | | * figure out what if this is something it can deal with. |
1034 | | */ |
1035 | 0 | if (info->fd_limit_per_thread) { |
1036 | 0 | unsigned int mf = lpf * context->count_threads; |
1037 | |
|
1038 | 0 | if (mf < context->max_fds) { |
1039 | 0 | context->max_fds_unrelated_to_ulimit = 1; |
1040 | 0 | context->max_fds = mf; |
1041 | 0 | } |
1042 | 0 | } |
1043 | |
|
1044 | 0 | #if defined(LWS_WITH_NETWORK) |
1045 | 0 | context->token_limits = info->token_limits; |
1046 | 0 | #endif |
1047 | | |
1048 | |
|
1049 | 0 | #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK) |
1050 | 0 | time(&context->tls.last_cert_check_s); |
1051 | 0 | if (info->alpn) |
1052 | 0 | context->tls.alpn_default = info->alpn; |
1053 | 0 | else { |
1054 | 0 | char *p = context->tls.alpn_discovered, first = 1; |
1055 | |
|
1056 | 0 | LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) { |
1057 | 0 | if (ar->alpn) { |
1058 | 0 | if (!first) |
1059 | 0 | *p++ = ','; |
1060 | 0 | p += lws_snprintf(p, (unsigned int)( |
1061 | 0 | (context->tls.alpn_discovered + |
1062 | 0 | sizeof(context->tls.alpn_discovered) - |
1063 | 0 | 2) - p), "%s", ar->alpn); |
1064 | 0 | first = 0; |
1065 | 0 | } |
1066 | 0 | } LWS_FOR_EVERY_AVAILABLE_ROLE_END; |
1067 | |
|
1068 | 0 | context->tls.alpn_default = context->tls.alpn_discovered; |
1069 | 0 | } |
1070 | |
|
1071 | 0 | #endif |
1072 | |
|
1073 | 0 | context->timeout_secs = 15; |
1074 | |
|
1075 | 0 | #if defined(LWS_WITH_NETWORK) |
1076 | | #if defined(WIN32) |
1077 | | if (!info->win32_connect_check_interval_usec) |
1078 | | context->win32_connect_check_interval_usec = 1000; |
1079 | | else |
1080 | | context->win32_connect_check_interval_usec = |
1081 | | info->win32_connect_check_interval_usec; |
1082 | | #endif |
1083 | 0 | if (info->timeout_secs) |
1084 | 0 | context->timeout_secs = info->timeout_secs; |
1085 | 0 | #endif /* WITH_NETWORK */ |
1086 | |
|
1087 | 0 | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) |
1088 | 0 | if (info->max_http_header_data) |
1089 | 0 | context->max_http_header_data = info->max_http_header_data; |
1090 | 0 | else |
1091 | 0 | if (info->max_http_header_data2) |
1092 | 0 | context->max_http_header_data = |
1093 | 0 | (unsigned short)info->max_http_header_data2; |
1094 | 0 | else |
1095 | 0 | context->max_http_header_data = LWS_DEF_HEADER_LEN; |
1096 | |
|
1097 | 0 | if (info->max_http_header_pool) |
1098 | 0 | context->max_http_header_pool = info->max_http_header_pool; |
1099 | 0 | else |
1100 | 0 | if (info->max_http_header_pool2) |
1101 | 0 | context->max_http_header_pool = |
1102 | 0 | (unsigned short)info->max_http_header_pool2; |
1103 | 0 | else |
1104 | 0 | context->max_http_header_pool = context->max_fds; |
1105 | 0 | #endif |
1106 | |
|
1107 | 0 | if (info->fd_limit_per_thread) |
1108 | 0 | context->fd_limit_per_thread = lpf; |
1109 | 0 | else |
1110 | 0 | if (context->count_threads) |
1111 | 0 | context->fd_limit_per_thread = context->max_fds / |
1112 | 0 | context->count_threads; |
1113 | |
|
1114 | 0 | #if defined(LWS_WITH_SYS_SMD) |
1115 | 0 | lws_mutex_init(context->smd.lock_messages); |
1116 | 0 | lws_mutex_init(context->smd.lock_peers); |
1117 | | |
1118 | | /* lws_system smd participant */ |
1119 | |
|
1120 | 0 | if (!lws_smd_register(context, context, 0, LWSSMDCL_NETWORK, |
1121 | 0 | lws_system_smd_cb)) { |
1122 | 0 | lwsl_cx_err(context, "early smd register failed"); |
1123 | 0 | } |
1124 | | |
1125 | | /* user smd participant */ |
1126 | |
|
1127 | 0 | if (info->early_smd_cb && |
1128 | 0 | !lws_smd_register(context, info->early_smd_opaque, 0, |
1129 | 0 | info->early_smd_class_filter, |
1130 | 0 | info->early_smd_cb)) { |
1131 | 0 | lwsl_cx_err(context, "early smd register failed"); |
1132 | 0 | } |
1133 | 0 | #endif |
1134 | |
|
1135 | 0 | #if !defined(LWS_PLAT_BAREMETAL) && defined(LWS_WITH_NETWORK) |
1136 | 0 | n = 0; |
1137 | 0 | #endif |
1138 | 0 | #if defined(LWS_WITH_NETWORK) |
1139 | |
|
1140 | 0 | context->default_retry.retry_ms_table = default_backoff_table; |
1141 | 0 | context->default_retry.conceal_count = |
1142 | 0 | context->default_retry.retry_ms_table_count = |
1143 | 0 | LWS_ARRAY_SIZE(default_backoff_table); |
1144 | 0 | context->default_retry.jitter_percent = 20; |
1145 | 0 | context->default_retry.secs_since_valid_ping = 300; |
1146 | 0 | context->default_retry.secs_since_valid_hangup = 310; |
1147 | |
|
1148 | 0 | if (info->retry_and_idle_policy && |
1149 | 0 | info->retry_and_idle_policy->secs_since_valid_ping) { |
1150 | 0 | context->default_retry.secs_since_valid_ping = |
1151 | 0 | info->retry_and_idle_policy->secs_since_valid_ping; |
1152 | 0 | context->default_retry.secs_since_valid_hangup = |
1153 | 0 | info->retry_and_idle_policy->secs_since_valid_hangup; |
1154 | 0 | } |
1155 | | |
1156 | | /* |
1157 | | * Allocate the per-thread storage for scratchpad buffers, |
1158 | | * and header data pool |
1159 | | */ |
1160 | 0 | u = (uint8_t *)&context[1]; |
1161 | 0 | for (n = 0; n < context->count_threads; n++) { |
1162 | 0 | context->pt[n].serv_buf = u; |
1163 | 0 | u += context->pt_serv_buf_size; |
1164 | |
|
1165 | 0 | context->pt[n].context = context; |
1166 | 0 | context->pt[n].tid = (uint8_t)n; |
1167 | |
|
1168 | 0 | #if !defined(LWS_PLAT_FREERTOS) |
1169 | | /* |
1170 | | * We overallocated for a fakewsi (can't compose it in the |
1171 | | * pt because size isn't known at that time). point to it |
1172 | | * and zero it down. Fakewsis are needed to make callbacks work |
1173 | | * when the source of the callback is not actually from a wsi |
1174 | | * context. |
1175 | | */ |
1176 | 0 | context->pt[n].fake_wsi = (struct lws *)u; |
1177 | 0 | u += sizeof(struct lws); |
1178 | |
|
1179 | 0 | memset(context->pt[n].fake_wsi, 0, sizeof(struct lws)); |
1180 | 0 | #endif |
1181 | |
|
1182 | 0 | context->pt[n].evlib_pt = u; |
1183 | 0 | u += plev->ops->evlib_size_pt; |
1184 | |
|
1185 | 0 | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) |
1186 | 0 | context->pt[n].http.ah_list = NULL; |
1187 | 0 | context->pt[n].http.ah_pool_length = 0; |
1188 | 0 | #endif |
1189 | 0 | lws_pt_mutex_init(&context->pt[n]); |
1190 | |
|
1191 | | #if defined(LWS_WITH_CGI) |
1192 | | if (lws_rops_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy)) |
1193 | | (lws_rops_func_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy)). |
1194 | | pt_init_destroy(context, info, |
1195 | | &context->pt[n], 0); |
1196 | | #endif |
1197 | 0 | } |
1198 | |
|
1199 | 0 | if (!info->ka_interval && info->ka_time > 0) { |
1200 | 0 | lwsl_cx_err(context, "info->ka_interval can't be 0 if ka_time used"); |
1201 | 0 | goto free_context_fail; |
1202 | 0 | } |
1203 | | |
1204 | | #if defined(LWS_WITH_PEER_LIMITS) |
1205 | | /* scale the peer hash table according to the max fds for the process, |
1206 | | * so that the max list depth averages 16. Eg, 1024 fd -> 64, |
1207 | | * 102400 fd -> 6400 |
1208 | | */ |
1209 | | |
1210 | | context->pl_hash_elements = |
1211 | | (context->count_threads * context->fd_limit_per_thread) / 16; |
1212 | | context->pl_hash_table = lws_zalloc(sizeof(struct lws_peer *) * |
1213 | | context->pl_hash_elements, "peer limits hash table"); |
1214 | | |
1215 | | context->ip_limit_ah = info->ip_limit_ah; |
1216 | | context->ip_limit_wsi = info->ip_limit_wsi; |
1217 | | context->pl_notify_cb = info->pl_notify_cb; |
1218 | | #endif |
1219 | | |
1220 | | /* |
1221 | | * fds table contains pollfd structs for as many pollfds as we can |
1222 | | * handle... spread across as many service threads as we have going |
1223 | | */ |
1224 | 0 | n = (int)(sizeof(struct lws_pollfd) * context->count_threads * |
1225 | 0 | context->fd_limit_per_thread); |
1226 | 0 | context->pt[0].fds = lws_zalloc((unsigned int)n, "fds table"); |
1227 | 0 | if (context->pt[0].fds == NULL || |
1228 | 0 | lws_fi(&context->fic, "ctx_createfail_oom_fds")) { |
1229 | | #if defined(LWS_WITH_SYS_FAULT_INJECTION) |
1230 | | lws_free(context->pt[0].fds); |
1231 | | #endif |
1232 | 0 | lwsl_cx_err(context, "OOM allocating %d fds\n", context->max_fds); |
1233 | 0 | goto free_context_fail; |
1234 | 0 | } |
1235 | 0 | #endif |
1236 | | |
1237 | 0 | lwsl_cx_info(context, "ctx: %5luB (%ld ctx + pt(%ld thr x %d)), " |
1238 | 0 | "pt-fds: %d", |
1239 | 0 | (long)sizeof(struct lws_context) + |
1240 | 0 | (context->count_threads * context->pt_serv_buf_size), |
1241 | 0 | (long)sizeof(struct lws_context), |
1242 | 0 | (long)context->count_threads, |
1243 | 0 | context->pt_serv_buf_size, |
1244 | 0 | context->fd_limit_per_thread); |
1245 | |
|
1246 | 0 | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) |
1247 | 0 | lwsl_cx_info(context, " http: ah_data: %u, ah: %lu, max count %u", |
1248 | 0 | context->max_http_header_data, |
1249 | 0 | (long)sizeof(struct allocated_headers), |
1250 | 0 | context->max_http_header_pool); |
1251 | 0 | #endif |
1252 | |
|
1253 | 0 | #if defined(LWS_WITH_SERVER) |
1254 | 0 | if (info->server_string) { |
1255 | 0 | context->server_string = info->server_string; |
1256 | 0 | context->server_string_len = (short) |
1257 | 0 | strlen(context->server_string); |
1258 | 0 | } |
1259 | 0 | #endif |
1260 | |
|
1261 | | #if LWS_MAX_SMP > 1 |
1262 | | /* each thread serves his own chunk of fds */ |
1263 | | for (n = 1; n < (int)context->count_threads; n++) |
1264 | | context->pt[n].fds = context->pt[n - 1].fds + |
1265 | | context->fd_limit_per_thread; |
1266 | | #endif |
1267 | | |
1268 | | |
1269 | | /* |
1270 | | * Past here, we may have added handles to the event lib |
1271 | | * loop and if libuv, have to take care about how to unpick them... |
1272 | | */ |
1273 | |
|
1274 | 0 | if (lws_plat_init(context, info) || |
1275 | 0 | lws_fi(&context->fic, "ctx_createfail_plat_init")) |
1276 | 0 | goto bail_libuv_aware; |
1277 | | |
1278 | 0 | #if defined(LWS_WITH_NETWORK) |
1279 | | |
1280 | 0 | if (lws_fi(&context->fic, "ctx_createfail_evlib_init")) |
1281 | 0 | goto bail_libuv_aware; |
1282 | | |
1283 | 0 | if (context->event_loop_ops->init_context) |
1284 | 0 | if (context->event_loop_ops->init_context(context, info)) |
1285 | 0 | goto bail_libuv_aware; |
1286 | | |
1287 | 0 | if (lws_fi(&context->fic, "ctx_createfail_evlib_pt")) |
1288 | 0 | goto bail_libuv_aware; |
1289 | | |
1290 | 0 | if (context->event_loop_ops->init_pt) |
1291 | 0 | for (n = 0; n < context->count_threads; n++) { |
1292 | 0 | void *lp = NULL; |
1293 | |
|
1294 | 0 | if (info->foreign_loops) |
1295 | 0 | lp = info->foreign_loops[n]; |
1296 | |
|
1297 | 0 | if (context->event_loop_ops->init_pt(context, lp, n)) |
1298 | 0 | goto bail_libuv_aware; |
1299 | 0 | } |
1300 | | |
1301 | 0 | lws_context_lock(context, __func__); |
1302 | 0 | n = __lws_create_event_pipes(context); |
1303 | 0 | lws_context_unlock(context); |
1304 | 0 | if (n) |
1305 | 0 | goto bail_libuv_aware; |
1306 | | |
1307 | 0 | for (n = 0; n < context->count_threads; n++) { |
1308 | 0 | LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) { |
1309 | 0 | if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy)) |
1310 | 0 | (lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)). |
1311 | 0 | pt_init_destroy(context, info, |
1312 | 0 | &context->pt[n], 0); |
1313 | 0 | } LWS_FOR_EVERY_AVAILABLE_ROLE_END; |
1314 | 0 | } |
1315 | 0 | #endif |
1316 | |
|
1317 | 0 | lws_context_init_ssl_library(context, info); |
1318 | |
|
1319 | 0 | context->user_space = info->user; |
1320 | |
|
1321 | 0 | #if defined(LWS_WITH_SERVER) |
1322 | 0 | strcpy(context->canonical_hostname, "unknown"); |
1323 | 0 | #if defined(LWS_WITH_NETWORK) |
1324 | 0 | lws_server_get_canonical_hostname(context, info); |
1325 | 0 | #endif |
1326 | 0 | #endif |
1327 | |
|
1328 | | #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) |
1329 | | memcpy(context->caps, info->caps, sizeof(context->caps)); |
1330 | | context->count_caps = info->count_caps; |
1331 | | #endif |
1332 | | |
1333 | |
|
1334 | 0 | #if defined(LWS_WITH_NETWORK) |
1335 | |
|
1336 | | #if defined(LWS_WITH_SYS_ASYNC_DNS) || defined(LWS_WITH_SYS_NTPCLIENT) || \ |
1337 | | defined(LWS_WITH_SYS_DHCP_CLIENT) |
1338 | | { |
1339 | | /* |
1340 | | * system vhost |
1341 | | */ |
1342 | | |
1343 | | struct lws_context_creation_info ii; |
1344 | | const struct lws_protocols *pp[4]; |
1345 | | struct lws_vhost *vh; |
1346 | | #if defined(LWS_WITH_SYS_ASYNC_DNS) |
1347 | | extern const struct lws_protocols lws_async_dns_protocol; |
1348 | | #endif |
1349 | | #if defined(LWS_WITH_SYS_NTPCLIENT) |
1350 | | extern const struct lws_protocols lws_system_protocol_ntpc; |
1351 | | #endif |
1352 | | #if defined(LWS_WITH_SYS_DHCP_CLIENT) |
1353 | | extern const struct lws_protocols lws_system_protocol_dhcpc4; |
1354 | | #endif |
1355 | | |
1356 | | n = 0; |
1357 | | #if defined(LWS_WITH_SYS_ASYNC_DNS) |
1358 | | pp[n++] = &lws_async_dns_protocol; |
1359 | | #endif |
1360 | | #if defined(LWS_WITH_SYS_NTPCLIENT) |
1361 | | pp[n++] = &lws_system_protocol_ntpc; |
1362 | | #endif |
1363 | | #if defined(LWS_WITH_SYS_DHCP_CLIENT) |
1364 | | pp[n++] = &lws_system_protocol_dhcpc4; |
1365 | | #endif |
1366 | | pp[n] = NULL; |
1367 | | |
1368 | | memset(&ii, 0, sizeof(ii)); |
1369 | | ii.vhost_name = "system"; |
1370 | | ii.pprotocols = pp; |
1371 | | ii.port = CONTEXT_PORT_NO_LISTEN; |
1372 | | |
1373 | | if (lws_fi(&context->fic, "ctx_createfail_sys_vh")) |
1374 | | vh = NULL; |
1375 | | else |
1376 | | vh = lws_create_vhost(context, &ii); |
1377 | | if (!vh) { |
1378 | | lwsl_cx_err(context, "failed to create system vhost"); |
1379 | | goto bail_libuv_aware; |
1380 | | } |
1381 | | |
1382 | | context->vhost_system = vh; |
1383 | | |
1384 | | if (lws_protocol_init_vhost(vh, NULL) || |
1385 | | lws_fi(&context->fic, "ctx_createfail_sys_vh_init")) { |
1386 | | lwsl_cx_err(context, "failed to init system vhost"); |
1387 | | goto bail_libuv_aware; |
1388 | | } |
1389 | | #if defined(LWS_WITH_SYS_ASYNC_DNS) |
1390 | | lws_async_dns_init(context); |
1391 | | //goto bail_libuv_aware; |
1392 | | #endif |
1393 | | } |
1394 | | |
1395 | | #endif |
1396 | |
|
1397 | 0 | #if defined(LWS_WITH_SYS_STATE) |
1398 | | /* |
1399 | | * init the lws_state mgr for the system state |
1400 | | */ |
1401 | |
|
1402 | 0 | context->mgr_system.name = "system"; |
1403 | 0 | context->mgr_system.state = LWS_SYSTATE_CONTEXT_CREATED; |
1404 | 0 | context->mgr_system.parent = context; |
1405 | 0 | #if defined(LWS_WITH_SYS_SMD) |
1406 | 0 | context->mgr_system.smd_class = LWSSMDCL_SYSTEM_STATE; |
1407 | 0 | #endif |
1408 | |
|
1409 | 0 | context->protocols_notify.name = "prot_init"; |
1410 | 0 | context->protocols_notify.notify_cb = lws_state_notify_protocol_init; |
1411 | |
|
1412 | 0 | lws_state_reg_notifier(&context->mgr_system, &context->protocols_notify); |
1413 | | |
1414 | | /* |
1415 | | * insert user notifiers here so they can participate with vetoing us |
1416 | | * trying to jump straight to operational, or at least observe us |
1417 | | * reaching 'operational', before we returned from context creation. |
1418 | | */ |
1419 | |
|
1420 | 0 | lws_state_reg_notifier_list(&context->mgr_system, |
1421 | 0 | info->register_notifier_list); |
1422 | 0 | #endif |
1423 | | |
1424 | | /* |
1425 | | * if he's not saying he'll make his own vhosts later then act |
1426 | | * compatibly and make a default vhost using the data in the info |
1427 | | */ |
1428 | 0 | if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS) |
1429 | 0 | || info->pprotocols) { |
1430 | 0 | if (!lws_create_vhost(context, info) || |
1431 | 0 | lws_fi(&context->fic, "ctx_createfail_def_vh")) { |
1432 | 0 | lwsl_cx_err(context, "Failed to create default vhost"); |
1433 | |
|
1434 | | #if defined(LWS_WITH_PEER_LIMITS) |
1435 | | lws_free_set_NULL(context->pl_hash_table); |
1436 | | #endif |
1437 | 0 | goto bail; |
1438 | 0 | } |
1439 | 0 | } |
1440 | | |
1441 | 0 | #if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT) |
1442 | 0 | if (info->http_nsc_filepath) { |
1443 | 0 | memset(&ci, 0, sizeof(ci)); |
1444 | |
|
1445 | 0 | ci.cx = context; |
1446 | 0 | ci.ops = &lws_cache_ops_nscookiejar; |
1447 | 0 | ci.name = "NSC"; |
1448 | 0 | ci.u.nscookiejar.filepath = info->http_nsc_filepath; |
1449 | |
|
1450 | 0 | context->nsc = lws_cache_create(&ci); |
1451 | 0 | if (!context->nsc) |
1452 | 0 | goto bail; |
1453 | | |
1454 | 0 | ci.ops = &lws_cache_ops_heap; |
1455 | 0 | ci.name = "L1"; |
1456 | 0 | ci.parent = context->nsc; |
1457 | 0 | ci.max_footprint = info->http_nsc_heap_max_footprint; |
1458 | 0 | ci.max_items = info->http_nsc_heap_max_items; |
1459 | 0 | ci.max_payload = info->http_nsc_heap_max_payload; |
1460 | |
|
1461 | 0 | context->l1 = lws_cache_create(&ci); |
1462 | 0 | if (!context->l1) { |
1463 | 0 | lwsl_cx_err(context, "Failed to init cookiejar"); |
1464 | 0 | goto bail; |
1465 | 0 | } |
1466 | 0 | } |
1467 | 0 | #endif |
1468 | | |
1469 | | #if defined(LWS_WITH_SYS_ASYNC_DNS) |
1470 | | if (info->async_dns_servers) { |
1471 | | const char **dsrv = info->async_dns_servers; |
1472 | | while (*dsrv) { |
1473 | | lws_sockaddr46 sa46; |
1474 | | if (!lws_sa46_parse_numeric_address(*dsrv, &sa46)) { |
1475 | | lwsl_cx_info(context, "Adding DNS %s", *dsrv); |
1476 | | lws_async_dns_server_add(context, &sa46); |
1477 | | } |
1478 | | dsrv++; |
1479 | | } |
1480 | | } |
1481 | | #endif |
1482 | | |
1483 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) |
1484 | | |
1485 | 0 | #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
1486 | | |
1487 | | /* |
1488 | | * You must create your context with the explicit vhosts flag |
1489 | | * in order to use secure streams |
1490 | | */ |
1491 | 0 | if (lws_check_opt(info->options, |
1492 | 0 | LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) { |
1493 | |
|
1494 | 0 | if (!context->pss_policies_json) |
1495 | 0 | context->pss_policies_json = |
1496 | 0 | "{\n" |
1497 | 0 | "\"release\": \"1\",\n" |
1498 | 0 | "\"product\": \"lws_default\",\n" |
1499 | 0 | "\"schema-version\": 1,\n" |
1500 | 0 | "\"retry\": [{\n" |
1501 | 0 | "\"default\": {\n" |
1502 | 0 | "\"backoff\": [1000, 2000, 3000, 5000, 10000],\n" |
1503 | 0 | "\"conceal\": 5,\n" |
1504 | 0 | "\"jitterpc\": 20,\n" |
1505 | 0 | "\"svalidping\": 30,\n" |
1506 | 0 | "\"svalidhup\": 35\n" |
1507 | 0 | "}\n" |
1508 | 0 | "}],\n" |
1509 | 0 | "\"s\": [\n" |
1510 | 0 | "{\n" |
1511 | 0 | "\"__default\": {\n" |
1512 | 0 | "\"endpoint\": \"${endpoint}\",\n" |
1513 | 0 | "\"port\": 443,\n" |
1514 | 0 | #if defined(LWS_WITH_HTTP2) |
1515 | 0 | "\"protocol\": \"h2\",\n" |
1516 | | #else |
1517 | | "\"protocol\": \"h1\",\n" |
1518 | | #endif |
1519 | 0 | "\"http_method\": \"GET\",\n" |
1520 | 0 | "\"http_url\": \"\",\n" |
1521 | 0 | "\"metadata\": [{\n" |
1522 | 0 | "\"endpoint\":" "\"\",\n" |
1523 | 0 | "\"acc\":" "\"accept\",\n" |
1524 | 0 | "\"ua\":" "\"user-agent\"\n" |
1525 | 0 | "}],\n" |
1526 | 0 | "\"tls\": true,\n" |
1527 | 0 | "\"allow_redirects\": true,\n" |
1528 | 0 | "\"nghttp2_quirk_end_stream\": true,\n" |
1529 | 0 | "\"h2q_oflow_txcr\": true,\n" |
1530 | 0 | "\"direct_proto_str\": true,\n" |
1531 | 0 | "\"opportunistic\": true,\n" |
1532 | 0 | "\"retry\": \"default\",\n" |
1533 | 0 | "\"timeout_ms\": 2000\n" |
1534 | 0 | "},\n" |
1535 | 0 | "\"captive_portal_detect\": {" |
1536 | 0 | "\"endpoint\":" "\"connectivitycheck.android.com\"," |
1537 | 0 | "\"http_url\":" "\"generate_204\"," |
1538 | 0 | "\"port\":" "80," |
1539 | 0 | "\"protocol\":" "\"h1\"," |
1540 | 0 | "\"http_method\":" "\"GET\"," |
1541 | 0 | "\"opportunistic\":" "true," |
1542 | 0 | "\"http_expect\":" "204," |
1543 | 0 | "\"http_fail_redirect\": true\n" |
1544 | 0 | "}\n" |
1545 | 0 | "}\n" |
1546 | 0 | "]\n" |
1547 | 0 | "}\n"; |
1548 | |
|
1549 | 0 | if (lws_ss_policy_parse_begin(context, 0) || |
1550 | 0 | lws_fi(&context->fic, "ctx_createfail_ss_pol1")) { |
1551 | | #if defined(LWS_WITH_SYS_FAULT_INJECTION) |
1552 | | lws_ss_policy_parse_abandon(context); |
1553 | | #endif |
1554 | 0 | goto bail_libuv_aware; |
1555 | 0 | } |
1556 | | |
1557 | 0 | n = lws_ss_policy_parse(context, |
1558 | 0 | (uint8_t *)context->pss_policies_json, |
1559 | 0 | strlen(context->pss_policies_json)); |
1560 | 0 | if ((n != LEJP_CONTINUE && n < 0) || |
1561 | 0 | lws_fi(&context->fic, "ctx_createfail_ss_pol2")) { |
1562 | 0 | lws_ss_policy_parse_abandon(context); |
1563 | 0 | goto bail_libuv_aware; |
1564 | 0 | } |
1565 | | |
1566 | 0 | if (lws_ss_policy_set(context, "hardcoded") || |
1567 | 0 | lws_fi(&context->fic, "ctx_createfail_ss_pol3")) { |
1568 | 0 | lwsl_cx_err(context, "policy set failed"); |
1569 | 0 | goto bail_libuv_aware; |
1570 | 0 | } |
1571 | 0 | } |
1572 | | #else |
1573 | | if (context->pss_policies) { |
1574 | | /* user code set the policy objects directly, no parsing step */ |
1575 | | |
1576 | | /* you must set this content option to use SS */ |
1577 | | assert(lws_check_opt(info->options, |
1578 | | LWS_SERVER_OPTION_EXPLICIT_VHOSTS)); |
1579 | | |
1580 | | if (lws_ss_policy_set(context, "hardcoded") || |
1581 | | lws_fi(&context->fic, "ctx_createfail_ss_pol3")) { |
1582 | | lwsl_cx_err(context, "policy set failed"); |
1583 | | goto bail_libuv_aware; |
1584 | | } |
1585 | | } |
1586 | | #endif |
1587 | 0 | #endif |
1588 | | |
1589 | 0 | lws_context_init_extensions(info, context); |
1590 | |
|
1591 | 0 | lwsl_cx_info(context, " mem: per-conn: %5lu bytes + protocol rx buf", |
1592 | 0 | (unsigned long)sizeof(struct lws)); |
1593 | | |
1594 | | /* |
1595 | | * drop any root privs for this process |
1596 | | * to listen on port < 1023 we would have needed root, but now we are |
1597 | | * listening, we don't want the power for anything else |
1598 | | */ |
1599 | 0 | if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) |
1600 | 0 | if (lws_plat_drop_app_privileges(context, 1) || |
1601 | 0 | lws_fi(&context->fic, "ctx_createfail_privdrop")) |
1602 | 0 | goto bail_libuv_aware; |
1603 | | |
1604 | 0 | #if defined(LWS_WITH_SYS_STATE) |
1605 | | /* |
1606 | | * We want to move on the syste, state as far as it can go towards |
1607 | | * OPERATIONAL now. But we have to return from here first so the user |
1608 | | * code that called us can set its copy of context, which it may be |
1609 | | * relying on to perform operations triggered by the state change. |
1610 | | * |
1611 | | * We set up a sul to come back immediately and do the state change. |
1612 | | */ |
1613 | | |
1614 | 0 | lws_sul_schedule(context, 0, &context->sul_system_state, |
1615 | 0 | lws_context_creation_completion_cb, 1); |
1616 | 0 | #endif |
1617 | | |
1618 | | /* expedite post-context init (eg, protocols) */ |
1619 | 0 | lws_cancel_service(context); |
1620 | 0 | #endif |
1621 | |
|
1622 | 0 | return context; |
1623 | | |
1624 | 0 | early_bail: |
1625 | 0 | lws_fi_destroy(&info->fic); |
1626 | |
|
1627 | 0 | return NULL; |
1628 | | |
1629 | 0 | #if defined(LWS_WITH_NETWORK) |
1630 | 0 | bail: |
1631 | 0 | lws_fi_destroy(&info->fic); |
1632 | 0 | lws_context_destroy(context); |
1633 | |
|
1634 | 0 | return NULL; |
1635 | 0 | #endif |
1636 | | |
1637 | 0 | bail_libuv_aware: |
1638 | 0 | lws_context_destroy(context); |
1639 | | #if defined(LWS_WITH_LIBUV) |
1640 | | return fatal_exit_defer ? context : NULL; |
1641 | | #else |
1642 | 0 | return NULL; |
1643 | 0 | #endif |
1644 | | |
1645 | 0 | #if defined(LWS_WITH_NETWORK) |
1646 | 0 | fail_event_libs: |
1647 | 0 | if (context) |
1648 | 0 | lwsl_cx_err(context, "Requested event library support not configured"); |
1649 | 0 | #endif |
1650 | |
|
1651 | 0 | #if defined(LWS_WITH_NETWORK) |
1652 | 0 | free_context_fail: |
1653 | 0 | if (context) { |
1654 | 0 | #if defined(LWS_WITH_SYS_SMD) |
1655 | 0 | _lws_smd_destroy(context); |
1656 | 0 | #endif |
1657 | 0 | } |
1658 | 0 | #endif |
1659 | 0 | free_context_fail2: |
1660 | 0 | if (context) { |
1661 | | #if defined(LWS_WITH_SYS_METRICS) |
1662 | | lws_metrics_destroy(context); |
1663 | | #endif |
1664 | 0 | lws_fi_destroy(&context->fic); |
1665 | 0 | } |
1666 | 0 | lws_fi_destroy(&info->fic); |
1667 | 0 | if (context) { |
1668 | 0 | lwsl_refcount_cx(context->log_cx, -1); |
1669 | 0 | lws_free(context); |
1670 | 0 | } |
1671 | |
|
1672 | 0 | return NULL; |
1673 | 0 | } |
1674 | | |
1675 | | #if defined(LWS_WITH_NETWORK) |
1676 | | int |
1677 | | lws_system_cpd_start(struct lws_context *cx) |
1678 | 0 | { |
1679 | 0 | cx->captive_portal_detect = LWS_CPD_UNKNOWN; |
1680 | | |
1681 | | /* if there's a platform implementation, use it */ |
1682 | |
|
1683 | 0 | if (lws_system_get_ops(cx) && |
1684 | 0 | lws_system_get_ops(cx)->captive_portal_detect_request) |
1685 | 0 | return lws_system_get_ops(cx)->captive_portal_detect_request(cx); |
1686 | | |
1687 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) |
1688 | | /* |
1689 | | * Otherwise try to use SS "captive_portal_detect" if that's enabled |
1690 | | */ |
1691 | 0 | return lws_ss_sys_cpd(cx); |
1692 | | #else |
1693 | | return 0; |
1694 | | #endif |
1695 | 0 | } |
1696 | | |
1697 | | static void |
1698 | | lws_system_deferred_cb(lws_sorted_usec_list_t *sul) |
1699 | 0 | { |
1700 | 0 | struct lws_context *cx = |
1701 | 0 | lws_container_of(sul, struct lws_context, sul_cpd_defer); |
1702 | |
|
1703 | 0 | lws_system_cpd_start(cx); |
1704 | 0 | } |
1705 | | |
1706 | | void |
1707 | | lws_system_cpd_start_defer(struct lws_context *cx, lws_usec_t defer_us) |
1708 | 0 | { |
1709 | 0 | lws_sul_schedule(cx, 0, &cx->sul_cpd_defer, |
1710 | 0 | lws_system_deferred_cb, defer_us); |
1711 | 0 | } |
1712 | | |
1713 | | #if (defined(LWS_WITH_SYS_STATE) && defined(LWS_WITH_SYS_SMD)) || !defined(LWS_WITH_NO_LOGS) |
1714 | | static const char *cname[] = { "Unknown", "OK", "Captive", "No internet" }; |
1715 | | #endif |
1716 | | |
1717 | | void |
1718 | | lws_system_cpd_set(struct lws_context *cx, lws_cpd_result_t result) |
1719 | 0 | { |
1720 | 0 | if (cx->captive_portal_detect != LWS_CPD_UNKNOWN) |
1721 | 0 | return; |
1722 | | |
1723 | 0 | #if !defined(LWS_WITH_NO_LOGS) |
1724 | 0 | lwsl_cx_notice(cx, "setting CPD result %s", cname[result]); |
1725 | 0 | #endif |
1726 | |
|
1727 | 0 | cx->captive_portal_detect = (uint8_t)result; |
1728 | |
|
1729 | 0 | #if defined(LWS_WITH_SYS_STATE) |
1730 | 0 | #if defined(LWS_WITH_SYS_SMD) |
1731 | 0 | lws_smd_msg_printf(cx, LWSSMDCL_NETWORK, |
1732 | 0 | "{\"type\":\"cpd\",\"result\":\"%s\"}", |
1733 | 0 | cname[cx->captive_portal_detect]); |
1734 | 0 | #endif |
1735 | | |
1736 | | /* if nothing is there to intercept anything, go all the way */ |
1737 | 0 | if (cx->mgr_system.state != LWS_SYSTATE_POLICY_INVALID) |
1738 | 0 | lws_state_transition_steps(&cx->mgr_system, |
1739 | 0 | LWS_SYSTATE_OPERATIONAL); |
1740 | 0 | #endif |
1741 | 0 | } |
1742 | | |
1743 | | lws_cpd_result_t |
1744 | | lws_system_cpd_state_get(struct lws_context *cx) |
1745 | 0 | { |
1746 | 0 | return (lws_cpd_result_t)cx->captive_portal_detect; |
1747 | 0 | } |
1748 | | |
1749 | | #endif |
1750 | | |
1751 | | int |
1752 | | lws_context_is_deprecated(struct lws_context *cx) |
1753 | 0 | { |
1754 | 0 | return cx->deprecated; |
1755 | 0 | } |
1756 | | |
1757 | | /* |
1758 | | * When using an event loop, the context destruction is in three separate |
1759 | | * parts. This is to cover both internal and foreign event loops cleanly. |
1760 | | * |
1761 | | * - lws_context_destroy() simply starts a soft close of all wsi and |
1762 | | * related allocations. The event loop continues. |
1763 | | * |
1764 | | * As the closes complete in the event loop, reference counting is used |
1765 | | * to determine when everything is closed. It then calls |
1766 | | * lws_context_destroy2(). |
1767 | | * |
1768 | | * - lws_context_destroy2() cleans up the rest of the higher-level logical |
1769 | | * lws pieces like vhosts. If the loop was foreign, it then proceeds to |
1770 | | * lws_context_destroy3(). If it the loop is internal, it stops the |
1771 | | * internal loops and waits for lws_context_destroy() to be called again |
1772 | | * outside the event loop (since we cannot destroy the loop from |
1773 | | * within the loop). That will cause lws_context_destroy3() to run |
1774 | | * directly. |
1775 | | * |
1776 | | * - lws_context_destroy3() destroys any internal event loops and then |
1777 | | * destroys the context itself, setting what was info.pcontext to NULL. |
1778 | | */ |
1779 | | |
1780 | | |
1781 | | #if defined(LWS_WITH_NETWORK) |
1782 | | static void |
1783 | | lws_pt_destroy(struct lws_context_per_thread *pt) |
1784 | 0 | { |
1785 | 0 | volatile struct lws_foreign_thread_pollfd *ftp, *next; |
1786 | 0 | volatile struct lws_context_per_thread *vpt; |
1787 | | #if defined(LWS_WITH_CGI) |
1788 | | lws_ctx_t ctx = pt->context; |
1789 | | |
1790 | | if (lws_rops_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy)) |
1791 | | (lws_rops_func_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy)). |
1792 | | pt_init_destroy(ctx, NULL, pt, 1); |
1793 | | #endif |
1794 | 0 | vpt = (volatile struct lws_context_per_thread *)pt; |
1795 | 0 | ftp = vpt->foreign_pfd_list; |
1796 | 0 | while (ftp) { |
1797 | 0 | next = ftp->next; |
1798 | 0 | lws_free((void *)ftp); |
1799 | 0 | ftp = next; |
1800 | 0 | } |
1801 | 0 | vpt->foreign_pfd_list = NULL; |
1802 | |
|
1803 | 0 | lws_pt_lock(pt, __func__); |
1804 | |
|
1805 | 0 | if (pt->pipe_wsi) { |
1806 | 0 | lws_destroy_event_pipe(pt->pipe_wsi); |
1807 | 0 | pt->pipe_wsi = NULL; |
1808 | 0 | } |
1809 | |
|
1810 | 0 | if ((pt->dummy_pipe_fds[0] || pt->dummy_pipe_fds[1]) |
1811 | 0 | #if !defined(WIN32) |
1812 | 0 | && ((int)pt->dummy_pipe_fds[0] != -1 || (int)pt->dummy_pipe_fds[1] != -1) |
1813 | 0 | #endif |
1814 | 0 | ) { |
1815 | 0 | struct lws wsi; |
1816 | |
|
1817 | 0 | memset(&wsi, 0, sizeof(wsi)); |
1818 | 0 | wsi.a.context = pt->context; |
1819 | 0 | wsi.tsi = (char)pt->tid; |
1820 | 0 | lws_plat_pipe_close(&wsi); |
1821 | 0 | } |
1822 | |
|
1823 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) |
1824 | 0 | while (pt->ss_owner.head) |
1825 | 0 | lws_ss_destroy_dll(pt->ss_owner.head, NULL); |
1826 | |
|
1827 | | #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) && defined(LWS_WITH_CLIENT) |
1828 | | lws_dll2_foreach_safe(&pt->ss_client_owner, NULL, lws_sspc_destroy_dll); |
1829 | | #endif |
1830 | |
|
1831 | 0 | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) |
1832 | 0 | while (pt->http.ah_list) |
1833 | 0 | _lws_destroy_ah(pt, pt->http.ah_list); |
1834 | 0 | #endif |
1835 | |
|
1836 | 0 | #endif |
1837 | |
|
1838 | 0 | lws_pt_unlock(pt); |
1839 | 0 | pt->pipe_wsi = NULL; |
1840 | |
|
1841 | 0 | } |
1842 | | #endif |
1843 | | |
1844 | | /* |
1845 | | * Context destruction is now a state machine that's aware of SMP pts and |
1846 | | * various event lib approaches. |
1847 | | * |
1848 | | * lws_context_destroy() expects to be called at the end of the user code's |
1849 | | * usage of it. But it can also be called non-finally, as a way to stop |
1850 | | * service and exit the outer user service loop, and then complete in the |
1851 | | * final call. |
1852 | | * |
1853 | | * For libuv, with async close, it must decide by refcounting the hamdles on |
1854 | | * the loop if it has extricated itself from the loop and can be destroyed. |
1855 | | * |
1856 | | * The various entry states for the staged destroy |
1857 | | * |
1858 | | * LWSCD_NO_DESTROY: begin destroy process |
1859 | | * - mark context as starting destroy process |
1860 | | * - start vhost destroy |
1861 | | * - stop any further user protocol service |
1862 | | * |
1863 | | * LWSCD_PT_WAS_DEFERRED: come back here if any pt inside service |
1864 | | * - Check for pts that are inside service loop, mark deferral needed if so |
1865 | | * - If not, close all wsi on the pt loop and start logical pt destroy |
1866 | | * - If any deferred, set state to LWSCD_PT_WAS_DEFERRED and exit |
1867 | | * |
1868 | | * LWSCD_PT_WAIT_ALL_DESTROYED: come back here for async loop / pt closes |
1869 | | * - exit if any pt not marked as unused, or destroyed |
1870 | | * - if all pt down, call into evlib to advance context destroy |
1871 | | * - finalize vhost destruction |
1872 | | * - finalize pt destruction |
1873 | | * - if foreign loops, set state to LWSCD_FINALIZATION and exit |
1874 | | * |
1875 | | * LWSCD_FINALIZATION: come back here at final lws_destroy_context() call |
1876 | | * - destroy sundries |
1877 | | * - destroy and free the actual context |
1878 | | */ |
1879 | | |
1880 | | void |
1881 | | lws_context_destroy(struct lws_context *context) |
1882 | 0 | { |
1883 | 0 | struct lws_context **pcontext_finalize; |
1884 | 0 | #if defined(LWS_WITH_NETWORK) |
1885 | 0 | struct lws_context_per_thread *pt; |
1886 | 0 | struct lws_vhost *vh = NULL, *vh1; |
1887 | 0 | int alive = 0, deferred_pt = 0; |
1888 | 0 | #endif |
1889 | | #if defined(LWS_WITH_PEER_LIMITS) |
1890 | | uint32_t nu; |
1891 | | #endif |
1892 | 0 | int n; |
1893 | |
|
1894 | 0 | if (!context || context->inside_context_destroy) |
1895 | 0 | return; |
1896 | | |
1897 | 0 | pcontext_finalize = context->pcontext_finalize; |
1898 | |
|
1899 | 0 | lws_context_lock(context, __func__); |
1900 | 0 | context->inside_context_destroy = 1; |
1901 | |
|
1902 | 0 | lwsl_cx_info(context, "destroy_state %d", context->destroy_state); |
1903 | |
|
1904 | 0 | switch (context->destroy_state) { |
1905 | 0 | case LWSCD_NO_DESTROY: |
1906 | | /* |
1907 | | * We're getting started |
1908 | | */ |
1909 | |
|
1910 | 0 | lwsl_cx_info(context, "starting context destroy flow"); |
1911 | 0 | context->being_destroyed = 1; |
1912 | |
|
1913 | 0 | #if defined(LWS_WITH_NETWORK) |
1914 | | |
1915 | | /* |
1916 | | * Close any vhost listen wsi |
1917 | | * |
1918 | | * inform all the protocols that they are done and will have no |
1919 | | * more callbacks. |
1920 | | * |
1921 | | * We can't free things until after the event loop shuts down. |
1922 | | */ |
1923 | |
|
1924 | 0 | if (context->protocol_init_done) |
1925 | 0 | vh = context->vhost_list; |
1926 | |
|
1927 | 0 | while (vh) { |
1928 | 0 | lwsl_vhost_info(vh, "start close"); |
1929 | 0 | vh1 = vh->vhost_next; |
1930 | 0 | lws_vhost_destroy1(vh); |
1931 | 0 | vh = vh1; |
1932 | 0 | } |
1933 | 0 | #endif |
1934 | |
|
1935 | 0 | lws_plat_context_early_destroy(context); |
1936 | |
|
1937 | 0 | context->service_no_longer_possible = 1; |
1938 | 0 | context->requested_stop_internal_loops = 1; |
1939 | | |
1940 | | /* fallthru */ |
1941 | |
|
1942 | 0 | case LWSCD_PT_WAS_DEFERRED: |
1943 | |
|
1944 | 0 | #if defined(LWS_WITH_NETWORK) |
1945 | | |
1946 | | /* |
1947 | | * We want to mark the pts as their destruction having been |
1948 | | * initiated, so they will reject any new wsi, and iterate all |
1949 | | * existing pt wsi starting to close them. |
1950 | | * |
1951 | | * If the event loop has async close, we have to return after |
1952 | | * this and try again when all the loops stop after all the |
1953 | | * refcounted wsi are gone. |
1954 | | */ |
1955 | |
|
1956 | 0 | pt = context->pt; |
1957 | 0 | for (n = 0; n < context->count_threads; n++) { |
1958 | 0 | lws_pt_lock(pt, __func__); |
1959 | | |
1960 | | /* evlib will realize it needs to destroy pt */ |
1961 | 0 | pt->destroy_self = 1; |
1962 | |
|
1963 | 0 | if (pt->inside_lws_service) { |
1964 | 0 | pt->event_loop_pt_unused = 1; |
1965 | 0 | deferred_pt = 1; |
1966 | 0 | goto next; |
1967 | 0 | } |
1968 | | |
1969 | | /* |
1970 | | * Close every handle in the fds |
1971 | | */ |
1972 | | |
1973 | 0 | while (pt->fds_count) { |
1974 | 0 | struct lws *wsi = wsi_from_fd(context, |
1975 | 0 | pt->fds[0].fd); |
1976 | |
|
1977 | 0 | if (wsi) { |
1978 | |
|
1979 | 0 | lwsl_cx_debug(context, |
1980 | 0 | "pt %d: closing wsi %p: role %s", |
1981 | 0 | n, wsi, wsi->role_ops->name); |
1982 | |
|
1983 | 0 | lws_close_free_wsi(wsi, |
1984 | 0 | LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY, |
1985 | 0 | "ctx destroy" |
1986 | 0 | /* no protocol close */); |
1987 | |
|
1988 | 0 | if (pt->pipe_wsi == wsi) |
1989 | 0 | pt->pipe_wsi = NULL; |
1990 | 0 | } |
1991 | 0 | } |
1992 | |
|
1993 | | #if defined(LWS_WITH_CGI) |
1994 | | (lws_rops_func_fidx(&role_ops_cgi, |
1995 | | LWS_ROPS_pt_init_destroy)). |
1996 | | pt_init_destroy(context, NULL, |
1997 | | pt, 1); |
1998 | | #endif |
1999 | | |
2000 | | /* |
2001 | | * This closes handles that belong to the evlib pt |
2002 | | * footprint, eg, timers, idle |
2003 | | */ |
2004 | |
|
2005 | 0 | if (context->event_loop_ops->destroy_pt) { |
2006 | 0 | lwsl_cx_info(context, |
2007 | 0 | "calling evlib destroy_pt %d\n", n); |
2008 | 0 | context->event_loop_ops->destroy_pt(context, n); |
2009 | 0 | } |
2010 | |
|
2011 | 0 | next: |
2012 | 0 | lws_pt_unlock(pt); |
2013 | |
|
2014 | 0 | pt++; |
2015 | 0 | } |
2016 | | |
2017 | 0 | if (deferred_pt) { |
2018 | 0 | context->destroy_state = LWSCD_PT_WAS_DEFERRED; |
2019 | 0 | lwsl_cx_notice(context, "destroy from inside service"); |
2020 | 0 | lws_cancel_service(context); |
2021 | 0 | goto bail; |
2022 | 0 | } |
2023 | 0 | #endif |
2024 | 0 | context->destroy_state = LWSCD_PT_WAIT_ALL_DESTROYED; |
2025 | | |
2026 | | /* |
2027 | | * We have different needs depending if foreign loop or not. |
2028 | | * |
2029 | | * 1) If foreign loop, we really want to advance the |
2030 | | * destroy_context() past here, and block only for libuv- |
2031 | | * style async close completion. |
2032 | | * |
2033 | | * 2a) If poll, and we exited by ourselves and are calling a |
2034 | | * final destroy_context() outside of any service already, |
2035 | | * we want to advance all the way in one step. |
2036 | | * |
2037 | | * 2b) If poll, and we are reacting to a SIGINT, service |
2038 | | * thread(s) may be in poll wait or servicing. We can't |
2039 | | * advance the destroy_context() to the point it's freeing |
2040 | | * things; we have to leave that for the final |
2041 | | * destroy_context() after the service thread(s) are |
2042 | | * finished calling for service. |
2043 | | */ |
2044 | |
|
2045 | 0 | #if defined(LWS_WITH_NETWORK) |
2046 | |
|
2047 | | #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) |
2048 | | lws_ss_proxy_destroy(context); |
2049 | | #endif |
2050 | |
|
2051 | 0 | if (context->event_loop_ops->destroy_context1) { |
2052 | 0 | lwsl_cx_info(context, "do evlib destroy_context1 and wait"); |
2053 | 0 | context->event_loop_ops->destroy_context1(context); |
2054 | |
|
2055 | 0 | goto bail; |
2056 | 0 | } |
2057 | | |
2058 | | /* |
2059 | | * ...if the more typical sync close, we can clean up the pts |
2060 | | * now ourselves... |
2061 | | */ |
2062 | | |
2063 | 0 | lwsl_cx_info(context, "manually destroying pts"); |
2064 | |
|
2065 | 0 | pt = context->pt; |
2066 | 0 | for (n = 0; n < context->count_threads; n++, pt++) { |
2067 | 0 | pt->event_loop_pt_unused = 1; |
2068 | 0 | lws_pt_destroy(pt); |
2069 | 0 | } |
2070 | 0 | #endif |
2071 | | /* fallthru */ |
2072 | |
|
2073 | 0 | case LWSCD_PT_WAIT_ALL_DESTROYED: |
2074 | |
|
2075 | 0 | #if defined(LWS_WITH_NETWORK) |
2076 | |
|
2077 | 0 | for (n = 0; n < context->count_threads; n++) |
2078 | 0 | if (!context->pt[n].is_destroyed && |
2079 | 0 | !context->pt[n].event_loop_pt_unused) |
2080 | 0 | alive++; |
2081 | |
|
2082 | 0 | lwsl_cx_info(context, "PT_WAIT_ALL_DESTROYED: %d alive", alive); |
2083 | |
|
2084 | 0 | if (alive) |
2085 | 0 | break; |
2086 | | |
2087 | | /* |
2088 | | * With foreign loops, removing all our fds from the loop |
2089 | | * means there are no more ways for the foreign loop to give |
2090 | | * us any further CPU once we leave here... so we must make |
2091 | | * sure related service threads are exiting so we can pick up |
2092 | | * again at the original app thread and do the context |
2093 | | * destroy completion |
2094 | | */ |
2095 | | |
2096 | | /* |
2097 | | * evlib specific loop destroy? |
2098 | | */ |
2099 | 0 | if (context->event_loop_ops->destroy_context2) |
2100 | | /* |
2101 | | * He returns nonzero to indicate the evlib must |
2102 | | * continue around the loop before destroy of it is |
2103 | | * completed so it can be freed |
2104 | | */ |
2105 | 0 | context->event_loop_ops->destroy_context2(context); |
2106 | 0 | context->requested_stop_internal_loops = 1; |
2107 | 0 | #endif |
2108 | | |
2109 | | /* |
2110 | | * Every pt and wsi that may depend on the logical vhosts |
2111 | | * is destroyed. We can remove the logical vhosts. |
2112 | | */ |
2113 | |
|
2114 | 0 | #if defined(LWS_WITH_SYS_STATE) && defined(LWS_WITH_NETWORK) |
2115 | 0 | lws_state_transition(&context->mgr_system, LWS_SYSTATE_POLICY_INVALID); |
2116 | 0 | #endif |
2117 | |
|
2118 | 0 | #if defined(LWS_WITH_NETWORK) |
2119 | | /* |
2120 | | * free all the per-vhost allocations |
2121 | | */ |
2122 | |
|
2123 | 0 | vh = context->vhost_list; |
2124 | 0 | while (vh) { |
2125 | 0 | vh1 = vh->vhost_next; |
2126 | | // lwsl_vhost_debug(vh, "vh %s destroy2", vh->name); |
2127 | 0 | __lws_vhost_destroy2(vh); |
2128 | 0 | vh = vh1; |
2129 | 0 | } |
2130 | | |
2131 | | /* remove ourselves from the pending destruction list */ |
2132 | |
|
2133 | 0 | while (context->vhost_pending_destruction_list) |
2134 | | /* removes itself from list */ |
2135 | 0 | __lws_vhost_destroy2(context->vhost_pending_destruction_list); |
2136 | 0 | #endif |
2137 | |
|
2138 | 0 | #if defined(LWS_WITH_NETWORK) |
2139 | 0 | lws_ssl_context_destroy(context); |
2140 | 0 | #endif |
2141 | 0 | lws_plat_context_late_destroy(context); |
2142 | |
|
2143 | | #if defined(LWS_WITH_PEER_LIMITS) |
2144 | | if (context->pl_hash_table) |
2145 | | for (nu = 0; nu < context->pl_hash_elements; nu++) { |
2146 | | if (!context->pl_hash_table[nu]) |
2147 | | continue; |
2148 | | lws_start_foreach_llp(struct lws_peer **, peer, |
2149 | | context->pl_hash_table[nu]) { |
2150 | | struct lws_peer *df = *peer; |
2151 | | *peer = df->next; |
2152 | | lws_free(df); |
2153 | | continue; |
2154 | | } lws_end_foreach_llp(peer, next); |
2155 | | } |
2156 | | lws_free(context->pl_hash_table); |
2157 | | #endif |
2158 | |
|
2159 | 0 | #if defined(LWS_WITH_NETWORK) |
2160 | |
|
2161 | 0 | for (n = 0; n < context->count_threads; n++) { |
2162 | 0 | struct lws_context_per_thread *pt = &context->pt[n]; |
2163 | |
|
2164 | 0 | (void)pt; |
2165 | |
|
2166 | 0 | LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) { |
2167 | 0 | if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy)) |
2168 | 0 | (lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)). |
2169 | 0 | pt_init_destroy(context, NULL, pt, 1); |
2170 | 0 | } LWS_FOR_EVERY_AVAILABLE_ROLE_END; |
2171 | |
|
2172 | | #if defined(LWS_WITH_CGI) |
2173 | | lws_rops_func_fidx(&role_ops_cgi, |
2174 | | LWS_ROPS_pt_init_destroy). |
2175 | | pt_init_destroy(context, NULL, |
2176 | | pt, 1); |
2177 | | #endif |
2178 | |
|
2179 | 0 | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) |
2180 | 0 | while (pt->http.ah_list) |
2181 | 0 | _lws_destroy_ah(pt, pt->http.ah_list); |
2182 | 0 | #endif |
2183 | 0 | lwsl_cx_info(context, "pt destroy %d", n); |
2184 | 0 | lws_pt_destroy(pt); |
2185 | 0 | } |
2186 | 0 | #endif /* NETWORK */ |
2187 | |
|
2188 | 0 | context->destroy_state = LWSCD_FINALIZATION; |
2189 | |
|
2190 | 0 | #if defined(LWS_WITH_NETWORK) |
2191 | |
|
2192 | 0 | if (context->pt[0].event_loop_foreign && |
2193 | 0 | context->event_loop_ops->destroy_context1) { |
2194 | |
|
2195 | 0 | lwsl_cx_info(context, |
2196 | 0 | "leaving final context destruction" |
2197 | 0 | " for final call"); |
2198 | 0 | goto bail; |
2199 | 0 | } |
2200 | | |
2201 | 0 | if (context->event_loop_ops->destroy_context1 && |
2202 | 0 | !context->pt[0].event_loop_foreign) { |
2203 | 0 | lwsl_cx_notice(context, "waiting for internal loop exit"); |
2204 | |
|
2205 | 0 | goto bail; |
2206 | 0 | } |
2207 | 0 | #endif |
2208 | | /* fallthru */ |
2209 | | |
2210 | 0 | case LWSCD_FINALIZATION: |
2211 | |
|
2212 | | #if defined(LWS_WITH_SYS_METRICS) |
2213 | | lws_metrics_dump(context); |
2214 | | #endif |
2215 | |
|
2216 | 0 | context->evlib_finalize_destroy_after_int_loops_stop = 1; |
2217 | |
|
2218 | 0 | #if defined(LWS_WITH_NETWORK) |
2219 | 0 | if (context->event_loop_ops->destroy_context2) |
2220 | 0 | context->event_loop_ops->destroy_context2(context); |
2221 | 0 | #if defined(LWS_WITH_SYS_STATE) |
2222 | 0 | lws_state_transition_steps(&context->mgr_system, |
2223 | 0 | LWS_SYSTATE_CONTEXT_DESTROYING); |
2224 | 0 | #endif |
2225 | | /* |
2226 | | * finalize destroy of pt and things hanging off it |
2227 | | */ |
2228 | |
|
2229 | 0 | for (n = 0; n < context->count_threads; n++) { |
2230 | 0 | struct lws_context_per_thread *pt = &context->pt[n]; |
2231 | | |
2232 | | /* |
2233 | | * Destroy the pt-roles |
2234 | | */ |
2235 | |
|
2236 | 0 | LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) { |
2237 | 0 | if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy)) |
2238 | 0 | (lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)). |
2239 | 0 | pt_init_destroy(context, NULL, pt, 1); |
2240 | 0 | } LWS_FOR_EVERY_AVAILABLE_ROLE_END; |
2241 | |
|
2242 | | #if defined(LWS_WITH_CGI) |
2243 | | lws_rops_func_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy). |
2244 | | pt_init_destroy(context, NULL, pt, 1); |
2245 | | #endif |
2246 | |
|
2247 | 0 | lws_pt_mutex_destroy(pt); |
2248 | 0 | assert(!pt->is_destroyed); |
2249 | 0 | pt->destroy_self = 0; |
2250 | 0 | pt->is_destroyed = 1; |
2251 | |
|
2252 | 0 | lwsl_cx_info(context, "pt %d fully destroyed", |
2253 | 0 | (int)(pt - pt->context->pt)); |
2254 | 0 | } |
2255 | | |
2256 | | /* |
2257 | | * wsis are gone, pts are gone, vhosts are gone. |
2258 | | * |
2259 | | * clean up the context and things hanging off it |
2260 | | */ |
2261 | | |
2262 | | #if defined(LWS_WITH_TLS_JIT_TRUST) |
2263 | | lws_cache_destroy(&context->trust_cache); |
2264 | | lws_tls_jit_trust_inflight_destroy_all(context); |
2265 | | #endif |
2266 | | |
2267 | 0 | #if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT) |
2268 | 0 | lws_cache_destroy(&context->nsc); |
2269 | 0 | lws_cache_destroy(&context->l1); |
2270 | 0 | #endif |
2271 | |
|
2272 | 0 | #if defined(LWS_WITH_SYS_SMD) |
2273 | 0 | _lws_smd_destroy(context); |
2274 | 0 | #endif |
2275 | |
|
2276 | | #if defined(LWS_WITH_SYS_ASYNC_DNS) |
2277 | | lws_async_dns_deinit(&context->async_dns); |
2278 | | #endif |
2279 | | #if defined(LWS_WITH_SYS_DHCP_CLIENT) |
2280 | | lws_dhcpc_remove(context, NULL); |
2281 | | #endif |
2282 | |
|
2283 | 0 | #if defined(LWS_WITH_DLO) |
2284 | 0 | lws_fonts_destroy(context); |
2285 | 0 | lws_dlo_file_destroy(context); |
2286 | 0 | #endif |
2287 | |
|
2288 | 0 | if (context->pt[0].fds) |
2289 | 0 | lws_free_set_NULL(context->pt[0].fds); |
2290 | 0 | #endif |
2291 | 0 | lws_context_deinit_ssl_library(context); |
2292 | |
|
2293 | | #if defined(LWS_WITH_DETAILED_LATENCIES) |
2294 | | if (context->latencies_fd != -1) |
2295 | | compatible_close(context->latencies_fd); |
2296 | | #endif |
2297 | |
|
2298 | 0 | for (n = 0; n < LWS_SYSBLOB_TYPE_COUNT; n++) |
2299 | 0 | lws_system_blob_destroy( |
2300 | 0 | lws_system_get_blob(context, (lws_system_blob_item_t)n, 0)); |
2301 | |
|
2302 | 0 | #if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_SECURE_STREAMS) && \ |
2303 | 0 | !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
2304 | |
|
2305 | 0 | while (context->server_der_list) { |
2306 | 0 | struct lws_ss_x509 *x = context->server_der_list; |
2307 | |
|
2308 | 0 | context->server_der_list = x->next; |
2309 | 0 | lws_free((void *)x->ca_der); |
2310 | 0 | } |
2311 | |
|
2312 | 0 | if (context->ac_policy) |
2313 | 0 | lwsac_free(&context->ac_policy); |
2314 | |
|
2315 | 0 | #if defined(LWS_WITH_SERVER) |
2316 | | /* ... for every sink... */ |
2317 | 0 | lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, |
2318 | 0 | lws_dll2_get_head(&context->sinks)) { |
2319 | 0 | lws_ss_sinks_t *sn = lws_container_of(d, lws_ss_sinks_t, |
2320 | 0 | list); |
2321 | |
|
2322 | 0 | assert(!sn->accepts.count); |
2323 | | |
2324 | 0 | lws_dll2_remove(&sn->list); |
2325 | 0 | lws_free(sn); |
2326 | |
|
2327 | 0 | } lws_end_foreach_dll_safe(d, d1); |
2328 | 0 | #endif |
2329 | 0 | #endif |
2330 | | |
2331 | | /* |
2332 | | * Context lock is about to go away |
2333 | | */ |
2334 | |
|
2335 | 0 | lws_context_unlock(context); |
2336 | |
|
2337 | | #if LWS_MAX_SMP > 1 |
2338 | | lws_mutex_refcount_destroy(&context->mr); |
2339 | | #endif |
2340 | |
|
2341 | | #if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_NETWORK) |
2342 | | lws_metrics_destroy(context); |
2343 | | #endif |
2344 | |
|
2345 | 0 | if (context->external_baggage_free_on_destroy) |
2346 | 0 | free(context->external_baggage_free_on_destroy); |
2347 | |
|
2348 | | #if defined(LWS_PLAT_FREERTOS) |
2349 | | #if defined(LWS_AMAZON_RTOS) |
2350 | | context->last_free_heap = xPortGetFreeHeapSize(); |
2351 | | #else |
2352 | | context->last_free_heap = esp_get_free_heap_size(); |
2353 | | #endif |
2354 | | #endif |
2355 | |
|
2356 | | #if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) |
2357 | | if (context->evlib_plugin_list) |
2358 | | lws_plugins_destroy(&context->evlib_plugin_list, |
2359 | | NULL, NULL); |
2360 | | #endif |
2361 | |
|
2362 | | #if defined(LWS_WITH_SYS_FAULT_INJECTION) |
2363 | | lws_fi_destroy(&context->fic); |
2364 | | #endif |
2365 | |
|
2366 | 0 | lwsl_refcount_cx(context->log_cx, -1); |
2367 | |
|
2368 | 0 | lws_free(context); |
2369 | |
|
2370 | 0 | if (pcontext_finalize) |
2371 | 0 | *pcontext_finalize = NULL; |
2372 | |
|
2373 | 0 | return; |
2374 | 0 | } |
2375 | | |
2376 | 0 | #if defined(LWS_WITH_NETWORK) |
2377 | 0 | bail: |
2378 | 0 | #endif |
2379 | 0 | lwsl_cx_info(context, "leaving"); |
2380 | 0 | context->inside_context_destroy = 0; |
2381 | 0 | lws_context_unlock(context); |
2382 | 0 | } |
2383 | | |
2384 | | int |
2385 | | lws_context_is_being_destroyed(struct lws_context *context) |
2386 | 0 | { |
2387 | 0 | return !!context->being_destroyed; |
2388 | 0 | } |
2389 | | |
2390 | | #if defined(LWS_WITH_SYS_STATE) |
2391 | | struct lws_context * |
2392 | | lws_system_context_from_system_mgr(lws_state_manager_t *mgr) |
2393 | 0 | { |
2394 | 0 | #if defined(LWS_WITH_NETWORK) |
2395 | 0 | return mgr->context; |
2396 | | #else |
2397 | | return NULL; |
2398 | | #endif |
2399 | 0 | } |
2400 | | #endif |
2401 | | |
2402 | | void |
2403 | | lws_log_prepend_context(struct lws_log_cx *cx, void *obj, char **p, char *e) |
2404 | 0 | { |
2405 | 0 | struct lws_context *lcx = (struct lws_context *)obj; |
2406 | |
|
2407 | 0 | if (lcx->name) |
2408 | 0 | *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ", |
2409 | 0 | lcx->name); |
2410 | 0 | } |
2411 | | |
2412 | | struct lws_log_cx * |
2413 | | lwsl_context_get_cx(struct lws_context *cx) |
2414 | 0 | { |
2415 | 0 | if (!cx) |
2416 | 0 | return NULL; |
2417 | | |
2418 | 0 | return cx->log_cx; |
2419 | 0 | } |