private.h: rename to contain dir
[platform/upstream/libwebsockets.git] / lib / core / context.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include "private-lib-core.h"
23
24 #ifndef LWS_BUILD_HASH
25 #define LWS_BUILD_HASH "unknown-build-hash"
26 #endif
27
28
29 static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
30
31 /**
32  * lws_get_library_version: get version and git hash library built from
33  *
34  *      returns a const char * to a string like "1.1 178d78c"
35  *      representing the library version followed by the git head hash it
36  *      was built from
37  */
38 LWS_VISIBLE const char *
39 lws_get_library_version(void)
40 {
41         return library_version;
42 }
43
44 #if defined(LWS_WITH_STATS)
45 static void
46 lws_sul_stats_cb(lws_sorted_usec_list_t *sul)
47 {
48         struct lws_context_per_thread *pt = lws_container_of(sul,
49                         struct lws_context_per_thread, sul_stats);
50
51         lws_stats_log_dump(pt->context);
52
53         __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_stats, 10 * LWS_US_PER_SEC);
54 }
55 #endif
56 #if defined(LWS_WITH_PEER_LIMITS)
57 static void
58 lws_sul_peer_limits_cb(lws_sorted_usec_list_t *sul)
59 {
60         struct lws_context_per_thread *pt = lws_container_of(sul,
61                         struct lws_context_per_thread, sul_peer_limits);
62
63         lws_peer_cull_peer_wait_list(pt->context);
64
65         __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_peer_limits, 10 * LWS_US_PER_SEC);
66 }
67 #endif
68
69
70 LWS_VISIBLE struct lws_context *
71 lws_create_context(const struct lws_context_creation_info *info)
72 {
73         struct lws_context *context = NULL;
74         struct lws_plat_file_ops *prev;
75 #ifndef LWS_NO_DAEMONIZE
76         pid_t pid_daemon = get_daemonize_pid();
77 #endif
78 #if defined(LWS_WITH_NETWORK)
79         int n;
80 #endif
81 #if defined(__ANDROID__)
82         struct rlimit rt;
83 #endif
84
85         lwsl_info("Initial logging level %d\n", log_level);
86         lwsl_info("Libwebsockets version: %s\n", library_version);
87
88 #ifdef LWS_WITH_IPV6
89         if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6))
90                 lwsl_info("IPV6 compiled in and enabled\n");
91         else
92                 lwsl_info("IPV6 compiled in but disabled\n");
93 #else
94         lwsl_info("IPV6 not compiled in\n");
95 #endif
96
97         lwsl_info(" LWS_DEF_HEADER_LEN    : %u\n", LWS_DEF_HEADER_LEN);
98         lwsl_info(" LWS_MAX_PROTOCOLS     : %u\n", LWS_MAX_PROTOCOLS);
99         lwsl_info(" LWS_MAX_SMP           : %u\n", LWS_MAX_SMP);
100         lwsl_info(" sizeof (*info)        : %ld\n", (long)sizeof(*info));
101 #if defined(LWS_WITH_STATS)
102         lwsl_info(" LWS_WITH_STATS        : on\n");
103 #endif
104         lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
105 #if defined(LWS_WITH_HTTP2)
106         lwsl_info(" HTTP2 support         : available\n");
107 #else
108         lwsl_info(" HTTP2 support         : not configured\n");
109 #endif
110         if (lws_plat_context_early_init())
111                 return NULL;
112
113         context = lws_zalloc(sizeof(struct lws_context), "context");
114         if (!context) {
115                 lwsl_err("No memory for websocket context\n");
116                 return NULL;
117         }
118
119         context->uid = info->uid;
120         context->gid = info->gid;
121         context->username = info->username;
122         context->groupname = info->groupname;
123         context->system_ops = info->system_ops;
124
125         /* if he gave us names, set the uid / gid */
126         if (lws_plat_drop_app_privileges(context, 0))
127                 goto bail;
128
129 lwsl_info("context created\n");
130 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
131 #if defined(LWS_WITH_MBEDTLS)
132         context->tls_ops = &tls_ops_mbedtls;
133 #else
134         context->tls_ops = &tls_ops_openssl;
135 #endif
136 #endif
137
138         if (info->pt_serv_buf_size)
139                 context->pt_serv_buf_size = info->pt_serv_buf_size;
140         else
141                 context->pt_serv_buf_size = 4096;
142
143 #if defined(LWS_ROLE_H2)
144         role_ops_h2.init_context(context, info);
145 #endif
146
147 #if LWS_MAX_SMP > 1
148         lws_mutex_refcount_init(&context->mr);
149 #endif
150
151 #if defined(LWS_WITH_ESP32)
152 #if defined(LWS_AMAZON_RTOS)
153         context->last_free_heap = xPortGetFreeHeapSize();
154 #else
155         context->last_free_heap = esp_get_free_heap_size();
156 #endif
157 #endif
158
159         /* default to just the platform fops implementation */
160
161         context->fops_platform.LWS_FOP_OPEN     = _lws_plat_file_open;
162         context->fops_platform.LWS_FOP_CLOSE    = _lws_plat_file_close;
163         context->fops_platform.LWS_FOP_SEEK_CUR = _lws_plat_file_seek_cur;
164         context->fops_platform.LWS_FOP_READ     = _lws_plat_file_read;
165         context->fops_platform.LWS_FOP_WRITE    = _lws_plat_file_write;
166         context->fops_platform.fi[0].sig        = NULL;
167
168         /*
169          *  arrange a linear linked-list of fops starting from context->fops
170          *
171          * platform fops
172          * [ -> fops_zip (copied into context so .next settable) ]
173          * [ -> info->fops ]
174          */
175
176         context->fops = &context->fops_platform;
177         prev = (struct lws_plat_file_ops *)context->fops;
178
179 #if defined(LWS_WITH_ZIP_FOPS)
180         /* make a soft copy so we can set .next */
181         context->fops_zip = fops_zip;
182         prev->next = &context->fops_zip;
183         prev = (struct lws_plat_file_ops *)prev->next;
184 #endif
185
186         /* if user provided fops, tack them on the end of the list */
187         if (info->fops)
188                 prev->next = info->fops;
189
190         context->reject_service_keywords = info->reject_service_keywords;
191         if (info->external_baggage_free_on_destroy)
192                 context->external_baggage_free_on_destroy =
193                         info->external_baggage_free_on_destroy;
194 #if defined(LWS_WITH_NETWORK)
195         context->time_up = lws_now_usecs();
196 #endif
197         context->pcontext_finalize = info->pcontext;
198
199         context->simultaneous_ssl_restriction =
200                         info->simultaneous_ssl_restriction;
201
202         context->options = info->options;
203
204 #ifndef LWS_NO_DAEMONIZE
205         if (pid_daemon) {
206                 context->started_with_parent = pid_daemon;
207                 lwsl_info(" Started with daemon pid %u\n", (unsigned int)pid_daemon);
208         }
209 #endif
210 #if defined(__ANDROID__)
211                 n = getrlimit(RLIMIT_NOFILE, &rt);
212                 if (n == -1) {
213                         lwsl_err("Get RLIMIT_NOFILE failed!\n");
214
215                         return NULL;
216                 }
217                 context->max_fds = rt.rlim_cur;
218 #else
219 #if defined(WIN32) || defined(_WIN32) || defined(LWS_AMAZON_RTOS)
220                 context->max_fds = getdtablesize();
221 #else
222                 context->max_fds = sysconf(_SC_OPEN_MAX);
223 #endif
224 #endif
225
226                 if (context->max_fds < 0) {
227                         lwsl_err("%s: problem getting process max files\n",
228                                  __func__);
229
230                         return NULL;
231                 }
232
233         if (info->count_threads)
234                 context->count_threads = info->count_threads;
235         else
236                 context->count_threads = 1;
237
238         if (context->count_threads > LWS_MAX_SMP)
239                 context->count_threads = LWS_MAX_SMP;
240
241         /*
242          * deal with any max_fds override, if it's reducing (setting it to
243          * more than ulimit -n is meaningless).  The platform init will
244          * figure out what if this is something it can deal with.
245          */
246         if (info->fd_limit_per_thread) {
247                 int mf = info->fd_limit_per_thread * context->count_threads;
248
249                 if (mf < context->max_fds) {
250                         context->max_fds_unrelated_to_ulimit = 1;
251                         context->max_fds = mf;
252                 }
253         }
254
255         context->token_limits = info->token_limits;
256
257 #if defined(LWS_WITH_NETWORK)
258
259         /*
260          * set the context event loops ops struct
261          *
262          * after this, all event_loop actions use the generic ops
263          */
264
265 #if defined(LWS_WITH_POLL)
266         context->event_loop_ops = &event_loop_ops_poll;
267 #endif
268
269         if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
270 #if defined(LWS_WITH_LIBUV)
271                 context->event_loop_ops = &event_loop_ops_uv;
272 #else
273                 goto fail_event_libs;
274 #endif
275
276         if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV))
277 #if defined(LWS_WITH_LIBEV)
278                 context->event_loop_ops = &event_loop_ops_ev;
279 #else
280                 goto fail_event_libs;
281 #endif
282
283         if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT))
284 #if defined(LWS_WITH_LIBEVENT)
285                 context->event_loop_ops = &event_loop_ops_event;
286 #else
287                 goto fail_event_libs;
288 #endif
289
290         if (!context->event_loop_ops)
291                 goto fail_event_libs;
292
293         lwsl_info("Using event loop: %s\n", context->event_loop_ops->name);
294 #endif
295
296 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
297         time(&context->tls.last_cert_check_s);
298         if (info->alpn)
299                 context->tls.alpn_default = info->alpn;
300         else {
301                 char *p = context->tls.alpn_discovered, first = 1;
302
303                 LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
304                         if (ar->alpn) {
305                                 if (!first)
306                                         *p++ = ',';
307                                 p += lws_snprintf(p,
308                                         context->tls.alpn_discovered +
309                                         sizeof(context->tls.alpn_discovered) -
310                                         2 - p, "%s", ar->alpn);
311                                 first = 0;
312                         }
313                 } LWS_FOR_EVERY_AVAILABLE_ROLE_END;
314
315                 context->tls.alpn_default = context->tls.alpn_discovered;
316         }
317
318         lwsl_info("Default ALPN advertisment: %s\n", context->tls.alpn_default);
319 #endif
320
321         if (info->timeout_secs)
322                 context->timeout_secs = info->timeout_secs;
323         else
324                 context->timeout_secs = AWAITING_TIMEOUT;
325
326         context->ws_ping_pong_interval = info->ws_ping_pong_interval;
327
328         lwsl_info(" default timeout (secs): %u\n", context->timeout_secs);
329
330         if (info->max_http_header_data)
331                 context->max_http_header_data = info->max_http_header_data;
332         else
333                 if (info->max_http_header_data2)
334                         context->max_http_header_data =
335                                         info->max_http_header_data2;
336                 else
337                         context->max_http_header_data = LWS_DEF_HEADER_LEN;
338
339         if (info->max_http_header_pool)
340                 context->max_http_header_pool = info->max_http_header_pool;
341         else
342                 if (info->max_http_header_pool2)
343                         context->max_http_header_pool =
344                                         info->max_http_header_pool2;
345                 else
346                         context->max_http_header_pool = context->max_fds;
347
348         if (info->fd_limit_per_thread)
349                 context->fd_limit_per_thread = info->fd_limit_per_thread;
350         else
351                 context->fd_limit_per_thread = context->max_fds /
352                                                context->count_threads;
353
354 #if defined(LWS_WITH_NETWORK)
355         /*
356          * Allocate the per-thread storage for scratchpad buffers,
357          * and header data pool
358          */
359         for (n = 0; n < context->count_threads; n++) {
360                 context->pt[n].serv_buf = lws_malloc(
361                                 context->pt_serv_buf_size + sizeof(struct lws),
362                                                      "pt_serv_buf");
363                 if (!context->pt[n].serv_buf) {
364                         lwsl_err("OOM\n");
365                         return NULL;
366                 }
367
368                 context->pt[n].context = context;
369                 context->pt[n].tid = n;
370
371                 /*
372                  * We overallocated for a fakewsi (can't compose it in the
373                  * pt because size isn't known at that time).  point to it
374                  * and zero it down.  Fakewsis are needed to make callbacks work
375                  * when the source of the callback is not actually from a wsi
376                  * context.
377                  */
378                 context->pt[n].fake_wsi = (struct lws *)(context->pt[n].serv_buf +
379                                                 context->pt_serv_buf_size);
380
381                 memset(context->pt[n].fake_wsi, 0, sizeof(struct lws));
382
383 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
384                 context->pt[n].http.ah_list = NULL;
385                 context->pt[n].http.ah_pool_length = 0;
386 #endif
387                 lws_pt_mutex_init(&context->pt[n]);
388 #if defined(LWS_WITH_SEQUENCER)
389                 lws_seq_pt_init(&context->pt[n]);
390 #endif
391         }
392
393         lwsl_info(" Threads: %d each %d fds\n", context->count_threads,
394                     context->fd_limit_per_thread);
395
396         if (!info->ka_interval && info->ka_time > 0) {
397                 lwsl_err("info->ka_interval can't be 0 if ka_time used\n");
398                 return NULL;
399         }
400
401 #if defined(LWS_WITH_PEER_LIMITS)
402         /* scale the peer hash table according to the max fds for the process,
403          * so that the max list depth averages 16.  Eg, 1024 fd -> 64,
404          * 102400 fd -> 6400
405          */
406
407         context->pl_hash_elements =
408                 (context->count_threads * context->fd_limit_per_thread) / 16;
409         context->pl_hash_table = lws_zalloc(sizeof(struct lws_peer *) *
410                         context->pl_hash_elements, "peer limits hash table");
411
412         context->ip_limit_ah = info->ip_limit_ah;
413         context->ip_limit_wsi = info->ip_limit_wsi;
414 #endif
415
416         lwsl_info(" mem: context:         %5lu B (%ld ctx + (%ld thr x %d))\n",
417                   (long)sizeof(struct lws_context) +
418                   (context->count_threads * context->pt_serv_buf_size),
419                   (long)sizeof(struct lws_context),
420                   (long)context->count_threads,
421                   context->pt_serv_buf_size);
422 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
423         lwsl_info(" mem: http hdr size:   (%u + %lu), max count %u\n",
424                     context->max_http_header_data,
425                     (long)sizeof(struct allocated_headers),
426                     context->max_http_header_pool);
427 #endif
428
429         /*
430          * fds table contains pollfd structs for as many pollfds as we can
431          * handle... spread across as many service threads as we have going
432          */
433         n = sizeof(struct lws_pollfd) * context->count_threads *
434             context->fd_limit_per_thread;
435         context->pt[0].fds = lws_zalloc(n, "fds table");
436         if (context->pt[0].fds == NULL) {
437                 lwsl_err("OOM allocating %d fds\n", context->max_fds);
438                 goto bail;
439         }
440         lwsl_info(" mem: pollfd map:      %5u B\n", n);
441 #endif
442         if (info->server_string) {
443                 context->server_string = info->server_string;
444                 context->server_string_len = (short)
445                                 strlen(context->server_string);
446         }
447
448 #if LWS_MAX_SMP > 1
449         /* each thread serves his own chunk of fds */
450         for (n = 1; n < (int)context->count_threads; n++)
451                 context->pt[n].fds = context->pt[n - 1].fds +
452                                      context->fd_limit_per_thread;
453 #endif
454
455         if (lws_plat_init(context, info))
456                 goto bail;
457
458 #if defined(LWS_WITH_NETWORK)
459         if (context->event_loop_ops->init_context)
460                 if (context->event_loop_ops->init_context(context, info))
461                         goto bail;
462
463
464         if (context->event_loop_ops->init_pt)
465                 for (n = 0; n < context->count_threads; n++) {
466                         void *lp = NULL;
467
468                         if (info->foreign_loops)
469                                 lp = info->foreign_loops[n];
470
471                         if (context->event_loop_ops->init_pt(context, lp, n))
472                                 goto bail;
473                 }
474
475 #if !defined(LWS_AMAZON_RTOS)
476         if (lws_create_event_pipes(context))
477                 goto bail;
478 #endif
479 #endif
480
481         lws_context_init_ssl_library(info);
482
483         context->user_space = info->user;
484 #if defined(LWS_WITH_NETWORK)
485         /*
486          * if he's not saying he'll make his own vhosts later then act
487          * compatibly and make a default vhost using the data in the info
488          */
489         if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
490                 if (!lws_create_vhost(context, info)) {
491                         lwsl_err("Failed to create default vhost\n");
492                         for (n = 0; n < context->count_threads; n++)
493                                 lws_free_set_NULL(context->pt[n].serv_buf);
494 #if defined(LWS_WITH_PEER_LIMITS)
495                         lws_free_set_NULL(context->pl_hash_table);
496 #endif
497                         lws_free_set_NULL(context->pt[0].fds);
498                         lws_plat_context_late_destroy(context);
499                         lws_free_set_NULL(context);
500                         return NULL;
501                 }
502
503         lws_context_init_extensions(info, context);
504
505         lwsl_info(" mem: per-conn:        %5lu bytes + protocol rx buf\n",
506                     (unsigned long)sizeof(struct lws));
507 #endif
508         strcpy(context->canonical_hostname, "unknown");
509 #if defined(LWS_WITH_NETWORK)
510         lws_server_get_canonical_hostname(context, info);
511 #endif
512
513 #if defined(LWS_WITH_STATS)
514         context->pt[0].sul_stats.cb = lws_sul_stats_cb;
515         __lws_sul_insert(&context->pt[0].pt_sul_owner, &context->pt[0].sul_stats,
516                          10 * LWS_US_PER_SEC);
517 #endif
518 #if defined(LWS_WITH_PEER_LIMITS)
519         context->pt[0].sul_peer_limits.cb = lws_sul_peer_limits_cb;
520         __lws_sul_insert(&context->pt[0].pt_sul_owner,
521                          &context->pt[0].sul_peer_limits, 10 * LWS_US_PER_SEC);
522 #endif
523
524 #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
525         memcpy(context->caps, info->caps, sizeof(context->caps));
526         context->count_caps = info->count_caps;
527 #endif
528
529         /*
530          * drop any root privs for this process
531          * to listen on port < 1023 we would have needed root, but now we are
532          * listening, we don't want the power for anything else
533          */
534         if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
535                 if (lws_plat_drop_app_privileges(context, 1))
536                         goto bail;
537
538 #if defined(LWS_WITH_NETWORK)
539         /* expedite post-context init (eg, protocols) */
540         lws_cancel_service(context);
541 #endif
542
543         return context;
544
545 bail:
546         lws_context_destroy(context);
547
548         return NULL;
549
550 #if defined(LWS_WITH_NETWORK)
551 fail_event_libs:
552         lwsl_err("Requested event library support not configured, available:\n");
553         {
554                 extern const struct lws_event_loop_ops *available_event_libs[];
555                 const struct lws_event_loop_ops **elops = available_event_libs;
556
557                 while (*elops) {
558                         lwsl_err("  - %s\n", (*elops)->name);
559                         elops++;
560                 }
561         }
562 #endif
563         lws_free(context);
564
565         return NULL;
566 }
567
568 LWS_VISIBLE LWS_EXTERN int
569 lws_context_is_deprecated(struct lws_context *context)
570 {
571         return context->deprecated;
572 }
573
574 /*
575  * When using an event loop, the context destruction is in three separate
576  * parts.  This is to cover both internal and foreign event loops cleanly.
577  *
578  *  - lws_context_destroy() simply starts a soft close of all wsi and
579  *     related allocations.  The event loop continues.
580  *
581  *     As the closes complete in the event loop, reference counting is used
582  *     to determine when everything is closed.  It then calls
583  *     lws_context_destroy2().
584  *
585  *  - lws_context_destroy2() cleans up the rest of the higher-level logical
586  *     lws pieces like vhosts.  If the loop was foreign, it then proceeds to
587  *     lws_context_destroy3().  If it the loop is internal, it stops the
588  *     internal loops and waits for lws_context_destroy() to be called again
589  *     outside the event loop (since we cannot destroy the loop from
590  *     within the loop).  That will cause lws_context_destroy3() to run
591  *     directly.
592  *
593  *  - lws_context_destroy3() destroys any internal event loops and then
594  *     destroys the context itself, setting what was info.pcontext to NULL.
595  */
596
597 /*
598  * destroy the actual context itself
599  */
600
601 static void
602 lws_context_destroy3(struct lws_context *context)
603 {
604         struct lws_context **pcontext_finalize = context->pcontext_finalize;
605 #if defined(LWS_WITH_NETWORK)
606         int n;
607
608         lwsl_debug("%s\n", __func__);
609
610         for (n = 0; n < context->count_threads; n++) {
611                 struct lws_context_per_thread *pt = &context->pt[n];
612                 (void)pt;
613 #if defined(LWS_WITH_SEQUENCER)
614                 lws_seq_destroy_all_on_pt(pt);
615 #endif
616
617                 if (context->event_loop_ops->destroy_pt)
618                         context->event_loop_ops->destroy_pt(context, n);
619
620                 lws_free_set_NULL(context->pt[n].serv_buf);
621
622 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
623                 while (pt->http.ah_list)
624                         _lws_destroy_ah(pt, pt->http.ah_list);
625 #endif
626         }
627
628         if (context->pt[0].fds)
629                 lws_free_set_NULL(context->pt[0].fds);
630 #endif
631         lws_context_deinit_ssl_library(context);
632
633         lws_free(context);
634         lwsl_info("%s: ctx %p freed\n", __func__, context);
635
636         if (pcontext_finalize)
637                 *pcontext_finalize = NULL;
638 }
639
640 /*
641  * really start destroying things
642  */
643
644 void
645 lws_context_destroy2(struct lws_context *context)
646 {
647 #if defined(LWS_WITH_NETWORK)
648         struct lws_vhost *vh = NULL, *vh1;
649 #endif
650 #if defined(LWS_WITH_PEER_LIMITS)
651         uint32_t nu;
652 #endif
653
654         lwsl_info("%s: ctx %p\n", __func__, context);
655
656         lws_context_lock(context, "context destroy 2"); /* ------ context { */
657
658         context->being_destroyed2 = 1;
659 #if defined(LWS_WITH_NETWORK)
660         /*
661          * free all the per-vhost allocations
662          */
663
664         vh = context->vhost_list;
665         while (vh) {
666                 vh1 = vh->vhost_next;
667                 __lws_vhost_destroy2(vh);
668                 vh = vh1;
669         }
670
671         lwsl_debug("%p: post vh listl\n", __func__);
672
673         /* remove ourselves from the pending destruction list */
674
675         while (context->vhost_pending_destruction_list)
676                 /* removes itself from list */
677                 __lws_vhost_destroy2(context->vhost_pending_destruction_list);
678 #endif
679
680         lwsl_debug("%p: post pdl\n", __func__);
681
682         lws_stats_log_dump(context);
683 #if defined(LWS_WITH_NETWORK)
684         lws_ssl_context_destroy(context);
685 #endif
686         lws_plat_context_late_destroy(context);
687
688 #if defined(LWS_WITH_PEER_LIMITS)
689         for (nu = 0; nu < context->pl_hash_elements; nu++)      {
690                 lws_start_foreach_llp(struct lws_peer **, peer,
691                                       context->pl_hash_table[nu]) {
692                         struct lws_peer *df = *peer;
693                         *peer = df->next;
694                         lws_free(df);
695                         continue;
696                 } lws_end_foreach_llp(peer, next);
697         }
698         lws_free(context->pl_hash_table);
699 #endif
700
701         lwsl_debug("%p: baggage\n", __func__);
702
703         if (context->external_baggage_free_on_destroy)
704                 free(context->external_baggage_free_on_destroy);
705
706 #if defined(LWS_WITH_NETWORK)
707         lws_check_deferred_free(context, 0, 1);
708 #endif
709
710 #if LWS_MAX_SMP > 1
711         lws_mutex_refcount_destroy(&context->mr);
712 #endif
713 #if defined(LWS_WITH_NETWORK)
714         if (context->event_loop_ops->destroy_context2)
715                 if (context->event_loop_ops->destroy_context2(context)) {
716                         lws_context_unlock(context); /* } context ----------- */
717                         context->finalize_destroy_after_internal_loops_stopped = 1;
718                         return;
719                 }
720
721         lwsl_debug("%p: post dc2\n", __func__);
722
723         if (!context->pt[0].event_loop_foreign) {
724                 int n;
725                 for (n = 0; n < context->count_threads; n++)
726                         if (context->pt[n].inside_service) {
727                                 lwsl_debug("%p: bailing as inside service\n", __func__);
728                                 lws_context_unlock(context); /* } context --- */
729                                 return;
730                         }
731         }
732 #endif
733         lws_context_unlock(context); /* } context ------------------- */
734
735         lws_context_destroy3(context);
736 }
737
738 /*
739  * Begin the context takedown
740  */
741
742 LWS_VISIBLE void
743 lws_context_destroy(struct lws_context *context)
744 {
745 #if defined(LWS_WITH_NETWORK)
746         volatile struct lws_foreign_thread_pollfd *ftp, *next;
747         volatile struct lws_context_per_thread *vpt;
748         struct lws_vhost *vh = NULL;
749         struct lws wsi;
750         int n, m;
751 #endif
752
753         if (!context)
754                 return;
755 #if defined(LWS_WITH_NETWORK)
756         if (context->finalize_destroy_after_internal_loops_stopped) {
757                 if (context->event_loop_ops->destroy_context2)
758                         context->event_loop_ops->destroy_context2(context);
759                 lws_context_destroy3(context);
760
761                 return;
762         }
763 #endif
764         if (context->being_destroyed1) {
765                 if (!context->being_destroyed2) {
766                         lws_context_destroy2(context);
767
768                         return;
769                 }
770                 lwsl_info("%s: ctx %p: already being destroyed\n",
771                             __func__, context);
772
773                 lws_context_destroy3(context);
774                 return;
775         }
776
777         lwsl_info("%s: ctx %p\n", __func__, context);
778
779         context->being_destroyed = 1;
780         context->being_destroyed1 = 1;
781         context->requested_kill = 1;
782
783 #if defined(LWS_WITH_NETWORK)
784         m = context->count_threads;
785         memset(&wsi, 0, sizeof(wsi));
786         wsi.context = context;
787
788 #ifdef LWS_LATENCY
789         if (context->worst_latency_info[0])
790                 lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
791 #endif
792
793         while (m--) {
794                 struct lws_context_per_thread *pt = &context->pt[m];
795                 vpt = (volatile struct lws_context_per_thread *)pt;
796
797                 ftp = vpt->foreign_pfd_list;
798                 while (ftp) {
799                         next = ftp->next;
800                         lws_free((void *)ftp);
801                         ftp = next;
802                 }
803                 vpt->foreign_pfd_list = NULL;
804
805                 for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
806                         struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
807                         if (!wsi)
808                                 continue;
809
810                         if (wsi->event_pipe)
811                                 lws_destroy_event_pipe(wsi);
812                         else
813                                 lws_close_free_wsi(wsi,
814                                         LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
815                                         "ctx destroy"
816                                         /* no protocol close */);
817                         n--;
818                 }
819                 lws_pt_mutex_destroy(pt);
820         }
821
822         /*
823          * inform all the protocols that they are done and will have no more
824          * callbacks.
825          *
826          * We can't free things until after the event loop shuts down.
827          */
828         if (context->protocol_init_done)
829                 vh = context->vhost_list;
830         while (vh) {
831                 struct lws_vhost *vhn = vh->vhost_next;
832                 lws_vhost_destroy1(vh);
833                 vh = vhn;
834         }
835 #endif
836
837         lws_plat_context_early_destroy(context);
838
839 #if defined(LWS_WITH_NETWORK)
840
841         /*
842          * We face two different needs depending if foreign loop or not.
843          *
844          * 1) If foreign loop, we really want to advance the destroy_context()
845          *    past here, and block only for libuv-style async close completion.
846          *
847          * 2a) If poll, and we exited by ourselves and are calling a final
848          *     destroy_context() outside of any service already, we want to
849          *     advance all the way in one step.
850          *
851          * 2b) If poll, and we are reacting to a SIGINT, service thread(s) may
852          *     be in poll wait or servicing.  We can't advance the
853          *     destroy_context() to the point it's freeing things; we have to
854          *     leave that for the final destroy_context() after the service
855          *     thread(s) are finished calling for service.
856          */
857
858         if (context->event_loop_ops->destroy_context1) {
859                 context->event_loop_ops->destroy_context1(context);
860
861                 return;
862         }
863 #endif
864
865 #if defined(LWS_WITH_ESP32)
866 #if defined(LWS_AMAZON_RTOS)
867         context->last_free_heap = xPortGetFreeHeapSize();
868 #else
869         context->last_free_heap = esp_get_free_heap_size();
870 #endif
871 #endif
872
873         lws_context_destroy2(context);
874 }
875