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