lwsws cgi integration
[platform/upstream/libwebsockets.git] / lib / context.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2015 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-libwebsockets.h"
23
24 #ifndef LWS_BUILD_HASH
25 #define LWS_BUILD_HASH "unknown-build-hash"
26 #endif
27
28 static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
29
30 /**
31  * lws_get_library_version: get version and git hash library built from
32  *
33  *      returns a const char * to a string like "1.1 178d78c"
34  *      representing the library version followed by the git head hash it
35  *      was built from
36  */
37 LWS_VISIBLE const char *
38 lws_get_library_version(void)
39 {
40         return library_version;
41 }
42
43 static const char * const mount_protocols[] = {
44         "http://",
45         "https://",
46         "file://",
47         "cgi://",
48         ">http://",
49         ">https://",
50 };
51
52 LWS_VISIBLE LWS_EXTERN int
53 lws_write_http_mount(struct lws_http_mount *next, struct lws_http_mount **res,
54                      void *store, const char *mountpoint, const char *origin,
55                      const char *def, struct lws_protocol_vhost_options *cgienv)
56 {
57         struct lws_http_mount *m;
58         void *orig = store;
59         unsigned long l = (unsigned long)store;
60         int n;
61
62         if (l & 15)
63                 l += 16 - (l & 15);
64
65         store = (void *)l;
66         m = (struct lws_http_mount *)store;
67         *res = m;
68
69         m->def = def;
70         m->mountpoint = mountpoint;
71         m->mountpoint_len = (unsigned char)strlen(mountpoint);
72         m->mount_next = NULL;
73         m->cgienv = cgienv;
74         if (next)
75                 next->mount_next = m;
76
77         for (n = 0; n < ARRAY_SIZE(mount_protocols); n++)
78                 if (!strncmp(origin, mount_protocols[n],
79                      strlen(mount_protocols[n]))) {
80                         m->origin_protocol = n;
81                         m->origin = origin + strlen(mount_protocols[n]);
82                         break;
83                 }
84
85         if (n == ARRAY_SIZE(mount_protocols)) {
86                 lwsl_err("unsupported protocol://\n");
87                 return 0; /* ie, fail */
88         }
89
90         return ((char *)store + sizeof(*m)) - (char *)orig;
91 }
92
93 LWS_VISIBLE void *
94 lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, const struct lws_protocols *prot,
95                             int size)
96 {
97         int n = 0;
98
99         /* allocate the vh priv array only on demand */
100         if (!vhost->protocol_vh_privs) {
101                 vhost->protocol_vh_privs = (void **)lws_zalloc(
102                                 vhost->count_protocols * sizeof(void *));
103                 if (!vhost->protocol_vh_privs)
104                         return NULL;
105         }
106
107         while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
108                 n++;
109
110         if (n == vhost->count_protocols)
111                 return NULL;
112
113         vhost->protocol_vh_privs[n] = lws_zalloc(size);
114         return vhost->protocol_vh_privs[n];
115 }
116
117 LWS_VISIBLE void *
118 lws_protocol_vh_priv_get(struct lws_vhost *vhost, const struct lws_protocols *prot)
119 {
120         int n = 0;
121
122         if (!vhost->protocol_vh_privs)
123                 return NULL;
124
125         while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
126                 n++;
127
128         if (n == vhost->count_protocols) {
129                 lwsl_err("%s: unknown protocol %p\n", __func__, prot);
130                 return NULL;
131         }
132
133         return vhost->protocol_vh_privs[n];
134 }
135
136 static struct lws_protocol_vhost_options *
137 lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
138 {
139         struct lws_protocol_vhost_options *pvo = vh->pvo;
140
141         while (pvo) {
142                 // lwsl_notice("%s: '%s' '%s'\n", __func__, pvo->name, name);
143                 if (!strcmp(pvo->name, name))
144                         return pvo;
145                 pvo = pvo->next;
146         }
147
148         return NULL;
149 }
150
151 int
152 lws_protocol_init(struct lws_context *context)
153 {
154         struct lws_vhost *vh = context->vhost_list;
155         struct lws_protocol_vhost_options *pvo;
156         struct lws wsi;
157         int n;
158
159         memset(&wsi, 0, sizeof(wsi));
160         wsi.context = context;
161
162         while (vh) {
163                 wsi.vhost = vh;
164
165                 /* initialize supported protocols on this vhost */
166
167                 for (n = 0; n < vh->count_protocols; n++) {
168                         wsi.protocol = &vh->protocols[n];
169
170                         pvo = lws_vhost_protocol_options(vh,
171                                                          vh->protocols[n].name);
172                         if (pvo)
173                                 /*
174                                  * linked list of options specific to
175                                  * vh + protocol
176                                  */
177                                 pvo = pvo->options;
178
179                         /*
180                          * inform all the protocols that they are doing their one-time
181                          * initialization if they want to.
182                          *
183                          * NOTE the wsi is all zeros except for the context, vh and
184                          * protocol ptrs so lws_get_context(wsi) etc can work
185                          */
186                         vh->protocols[n].callback(&wsi,
187                                 LWS_CALLBACK_PROTOCOL_INIT, NULL, pvo, 0);
188                 }
189
190                 vh = vh->vhost_next;
191         }
192
193         context->protocol_init_done = 1;
194
195         return 0;
196 }
197
198 LWS_VISIBLE struct lws_vhost *
199 lws_create_vhost(struct lws_context *context,
200                  struct lws_context_creation_info *info,
201                  struct lws_http_mount *mounts)
202 {
203         struct lws_vhost *vh = lws_zalloc(sizeof(*vh)),
204                          **vh1 = &context->vhost_list;
205 #ifdef LWS_WITH_PLUGINS
206         struct lws_plugin *plugin = context->plugin_list;
207         struct lws_protocols *lwsp;
208         int m, n, f = !info->pvo;
209 #endif
210         char *p;
211
212         if (!vh)
213                 return NULL;
214
215         vh->context = context;
216         if (!info->vhost_name)
217                 vh->name = "default";
218         else
219                 vh->name = info->vhost_name;
220
221         vh->iface = info->iface;
222         for (vh->count_protocols = 0;
223              info->protocols[vh->count_protocols].callback;
224              vh->count_protocols++)
225                 ;
226
227         vh->pvo = info->pvo;
228
229 #ifdef LWS_WITH_PLUGINS
230         if (plugin) {
231                 /*
232                  * give the vhost a unified list of protocols including the
233                  * ones that came from plugins
234                  */
235                 lwsp = lws_zalloc(sizeof(struct lws_protocols) *
236                                            (vh->count_protocols +
237                                            context->plugin_protocol_count + 1));
238                 if (!lwsp)
239                         return NULL;
240
241                 m = vh->count_protocols;
242                 memcpy(lwsp, info->protocols,
243                        sizeof(struct lws_protocols) * m);
244
245                 /* for compatibility, all protocols enabled on vhost if only
246                  * the default vhost exists.  Otherwise only vhosts who ask
247                  * for a protocol get it enabled.
248                  */
249
250                 if (info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
251                         f = 0;
252
253                 while (plugin) {
254                         for (n = 0; n < plugin->caps.count_protocols; n++) {
255                                 /*
256                                  * for compatibility's sake, no pvo implies
257                                  * allow all protocols
258                                  */
259                                 if (f || lws_vhost_protocol_options(vh,
260                                     plugin->caps.protocols[n].name)) {
261                                         memcpy(&lwsp[m],
262                                                &plugin->caps.protocols[n],
263                                                sizeof(struct lws_protocols));
264                                         m++;
265                                         vh->count_protocols++;
266                                 }
267                         }
268                         plugin = plugin->list;
269                 }
270                 vh->protocols = lwsp;
271         } else
272 #endif
273                 vh->protocols = info->protocols;
274
275         vh->mount_list = mounts;
276
277         lwsl_notice("Creating Vhost '%s' port %d, %d protocols\n",
278                         vh->name, info->port, vh->count_protocols);
279
280         while (mounts) {
281                 lwsl_notice("   mounting %s%s to %s\n",
282                                 mount_protocols[mounts->origin_protocol],
283                                 mounts->origin, mounts->mountpoint);
284                 mounts = mounts->mount_next;
285         }
286
287 #ifndef LWS_NO_EXTENSIONS
288 #ifdef LWS_WITH_PLUGINS
289         if (context->plugin_extension_count) {
290
291                 m = 0;
292                 while (info->extensions && info->extensions[m].callback)
293                         m++;
294
295                 /*
296                  * give the vhost a unified list of extensions including the
297                  * ones that came from plugins
298                  */
299                 vh->extensions = lws_zalloc(sizeof(struct lws_extension) *
300                                            (m +
301                                            context->plugin_extension_count + 1));
302                 if (!vh->extensions)
303                         return NULL;
304
305                 memcpy((struct lws_extension *)vh->extensions, info->extensions,
306                        sizeof(struct lws_extension) * m);
307                 while (plugin) {
308                         memcpy((struct lws_extension *)&vh->extensions[m], plugin->caps.extensions,
309                                sizeof(struct lws_extension) *
310                                plugin->caps.count_extensions);
311                         m += plugin->caps.count_extensions;
312                         plugin = plugin->list;
313                 }
314         } else
315 #endif
316                 vh->extensions = info->extensions;
317 #endif
318
319         vh->listen_port = info->port;
320         vh->http_proxy_port = 0;
321         vh->http_proxy_address[0] = '\0';
322
323         /* either use proxy from info, or try get it from env var */
324
325         if (info->http_proxy_address) {
326                 /* override for backwards compatibility */
327                 if (info->http_proxy_port)
328                         vh->http_proxy_port = info->http_proxy_port;
329                 lws_set_proxy(vh, info->http_proxy_address);
330         } else {
331 #ifdef LWS_HAVE_GETENV
332                 p = getenv("http_proxy");
333                 if (p)
334                         lws_set_proxy(vh, p);
335 #endif
336         }
337
338         vh->ka_time = info->ka_time;
339         vh->ka_interval = info->ka_interval;
340         vh->ka_probes = info->ka_probes;
341
342         if (lws_context_init_server_ssl(info, vh))
343                 goto bail;
344
345         if (lws_context_init_client_ssl(info, vh))
346                 goto bail;
347
348         if (lws_context_init_server(info, vh))
349                 goto bail;
350
351         while (1) {
352                 if (!(*vh1)) {
353                         *vh1 = vh;
354                         break;
355                 }
356                 vh1 = &(*vh1)->vhost_next;
357         };
358
359         return vh;
360
361 bail:
362         lws_free(vh);
363
364         return NULL;
365 }
366
367 /**
368  * lws_create_context() - Create the websocket handler
369  * @info:       pointer to struct with parameters
370  *
371  *      This function creates the listening socket (if serving) and takes care
372  *      of all initialization in one step.
373  *
374  *      After initialization, it returns a struct lws_context * that
375  *      represents this server.  After calling, user code needs to take care
376  *      of calling lws_service() with the context pointer to get the
377  *      server's sockets serviced.  This must be done in the same process
378  *      context as the initialization call.
379  *
380  *      The protocol callback functions are called for a handful of events
381  *      including http requests coming in, websocket connections becoming
382  *      established, and data arriving; it's also called periodically to allow
383  *      async transmission.
384  *
385  *      HTTP requests are sent always to the FIRST protocol in @protocol, since
386  *      at that time websocket protocol has not been negotiated.  Other
387  *      protocols after the first one never see any HTTP callack activity.
388  *
389  *      The server created is a simple http server by default; part of the
390  *      websocket standard is upgrading this http connection to a websocket one.
391  *
392  *      This allows the same server to provide files like scripts and favicon /
393  *      images or whatever over http and dynamic data over websockets all in
394  *      one place; they're all handled in the user callback.
395  */
396 LWS_VISIBLE struct lws_context *
397 lws_create_context(struct lws_context_creation_info *info)
398 {
399         struct lws_context *context = NULL;
400         struct lws wsi;
401 #ifndef LWS_NO_DAEMONIZE
402         int pid_daemon = get_daemonize_pid();
403 #endif
404         int n, m;
405 #if defined(__ANDROID__)
406         struct rlimit rt;
407 #endif
408
409
410         lwsl_notice("Initial logging level %d\n", log_level);
411         lwsl_notice("Libwebsockets version: %s\n", library_version);
412 #if LWS_POSIX
413 #ifdef LWS_USE_IPV6
414         if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6))
415                 lwsl_notice("IPV6 compiled in and enabled\n");
416         else
417                 lwsl_notice("IPV6 compiled in but disabled\n");
418 #else
419         lwsl_notice("IPV6 not compiled in\n");
420 #endif
421         lws_feature_status_libev(info);
422         lws_feature_status_libuv(info);
423 #endif
424         lwsl_info(" LWS_DEF_HEADER_LEN    : %u\n", LWS_DEF_HEADER_LEN);
425         lwsl_info(" LWS_MAX_PROTOCOLS     : %u\n", LWS_MAX_PROTOCOLS);
426         lwsl_info(" LWS_MAX_SMP           : %u\n", LWS_MAX_SMP);
427         lwsl_info(" SPEC_LATEST_SUPPORTED : %u\n", SPEC_LATEST_SUPPORTED);
428         lwsl_info(" sizeof (*info)        : %u\n", sizeof(*info));
429 #if LWS_POSIX
430         lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
431 #endif
432         if (lws_plat_context_early_init())
433                 return NULL;
434
435         context = lws_zalloc(sizeof(struct lws_context));
436         if (!context) {
437                 lwsl_err("No memory for websocket context\n");
438                 return NULL;
439         }
440 #ifndef LWS_NO_DAEMONIZE
441         if (pid_daemon) {
442                 context->started_with_parent = pid_daemon;
443                 lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
444         }
445 #endif
446 #if defined(__ANDROID__)
447                 n = getrlimit ( RLIMIT_NOFILE,&rt);
448                 if (-1 == n) {
449                         lwsl_err("Get RLIMIT_NOFILE failed!\n");
450                         return NULL;
451                 }
452                 context->max_fds = rt.rlim_cur;
453 #else
454                 context->max_fds = getdtablesize();
455 #endif
456
457         if (info->count_threads)
458                 context->count_threads = info->count_threads;
459         else
460                 context->count_threads = 1;
461
462         if (context->count_threads > LWS_MAX_SMP)
463                 context->count_threads = LWS_MAX_SMP;
464
465         context->token_limits = info->token_limits;
466
467         context->options = info->options;
468
469         if (info->timeout_secs)
470                 context->timeout_secs = info->timeout_secs;
471         else
472                 context->timeout_secs = AWAITING_TIMEOUT;
473
474         lwsl_info(" default timeout (secs): %u\n", context->timeout_secs);
475
476         if (info->max_http_header_data)
477                 context->max_http_header_data = info->max_http_header_data;
478         else
479                 context->max_http_header_data = LWS_DEF_HEADER_LEN;
480         if (info->max_http_header_pool)
481                 context->max_http_header_pool = info->max_http_header_pool;
482         else
483                 context->max_http_header_pool = LWS_DEF_HEADER_POOL;
484
485         /*
486          * Allocate the per-thread storage for scratchpad buffers,
487          * and header data pool
488          */
489         for (n = 0; n < context->count_threads; n++) {
490                 context->pt[n].serv_buf = lws_zalloc(LWS_MAX_SOCKET_IO_BUF);
491                 if (!context->pt[n].serv_buf) {
492                         lwsl_err("OOM\n");
493                         return NULL;
494                 }
495
496                 context->pt[n].context = context;
497                 context->pt[n].tid = n;
498                 context->pt[n].http_header_data = lws_malloc(context->max_http_header_data *
499                                                        context->max_http_header_pool);
500                 if (!context->pt[n].http_header_data)
501                         goto bail;
502
503                 context->pt[n].ah_pool = lws_zalloc(sizeof(struct allocated_headers) *
504                                               context->max_http_header_pool);
505                 for (m = 0; m < context->max_http_header_pool; m++)
506                         context->pt[n].ah_pool[m].data =
507                                 (char *)context->pt[n].http_header_data +
508                                 (m * context->max_http_header_data);
509                 if (!context->pt[n].ah_pool)
510                         goto bail;
511
512                 lws_pt_mutex_init(&context->pt[n]);
513         }
514
515         if (info->fd_limit_per_thread)
516                 context->fd_limit_per_thread = info->fd_limit_per_thread;
517         else
518                 context->fd_limit_per_thread = context->max_fds /
519                                                context->count_threads;
520
521         lwsl_notice(" Threads: %d each %d fds\n", context->count_threads,
522                     context->fd_limit_per_thread);
523
524         memset(&wsi, 0, sizeof(wsi));
525         wsi.context = context;
526
527         if (!info->ka_interval && info->ka_time > 0) {
528                 lwsl_err("info->ka_interval can't be 0 if ka_time used\n");
529                 return NULL;
530         }
531
532 #ifdef LWS_USE_LIBEV
533         /* (Issue #264) In order to *avoid breaking backwards compatibility*, we
534          * enable libev mediated SIGINT handling with a default handler of
535          * lws_sigint_cb. The handler can be overridden or disabled
536          * by invoking lws_sigint_cfg after creating the context, but
537          * before invoking lws_initloop:
538          */
539         context->use_ev_sigint = 1;
540         context->lws_ev_sigint_cb = &lws_ev_sigint_cb;
541 #endif /* LWS_USE_LIBEV */
542 #ifdef LWS_USE_LIBUV
543         /* (Issue #264) In order to *avoid breaking backwards compatibility*, we
544          * enable libev mediated SIGINT handling with a default handler of
545          * lws_sigint_cb. The handler can be overridden or disabled
546          * by invoking lws_sigint_cfg after creating the context, but
547          * before invoking lws_initloop:
548          */
549         context->use_ev_sigint = 1;
550         context->lws_uv_sigint_cb = &lws_uv_sigint_cb;
551 #endif
552
553         lwsl_info(" mem: context:         %5u bytes (%d ctx + (%d thr x %d))\n",
554                   sizeof(struct lws_context) +
555                   (context->count_threads * LWS_MAX_SOCKET_IO_BUF),
556                   sizeof(struct lws_context),
557                   context->count_threads,
558                   LWS_MAX_SOCKET_IO_BUF);
559
560         lwsl_info(" mem: http hdr rsvd:   %5u bytes (%u thr x (%u + %u) x %u))\n",
561                     (context->max_http_header_data +
562                      sizeof(struct allocated_headers)) *
563                     context->max_http_header_pool * context->count_threads,
564                     context->count_threads,
565                     context->max_http_header_data,
566                     sizeof(struct allocated_headers),
567                     context->max_http_header_pool);
568         n = sizeof(struct lws_pollfd) * context->count_threads *
569             context->fd_limit_per_thread;
570         context->pt[0].fds = lws_zalloc(n);
571         if (context->pt[0].fds == NULL) {
572                 lwsl_err("OOM allocating %d fds\n", context->max_fds);
573                 goto bail;
574         }
575         lwsl_info(" mem: pollfd map:      %5u\n", n);
576
577 #if LWS_MAX_SMP > 1
578         /* each thread serves his own chunk of fds */
579         for (n = 1; n < (int)info->count_threads; n++)
580                 context->pt[n].fds = context->pt[n - 1].fds +
581                                      context->fd_limit_per_thread;
582 #endif
583
584         if (lws_plat_init(context, info))
585                 goto bail;
586
587         lws_context_init_ssl_library(info);
588
589         /*
590          * if he's not saying he'll make his own vhosts later then act
591          * compatibly and make a default vhost using the data in the info
592          */
593         if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
594                 if (!lws_create_vhost(context, info, NULL)) {
595                         lwsl_err("Failed to create default vhost\n");
596                         return NULL;
597                 }
598
599         lws_context_init_extensions(info, context);
600
601         context->user_space = info->user;
602
603         lwsl_notice(" mem: per-conn:        %5u bytes + protocol rx buf\n",
604                     sizeof(struct lws));
605
606         strcpy(context->canonical_hostname, "unknown");
607         lws_server_get_canonical_hostname(context, info);
608
609         context->uid = info->uid;
610         context->gid = info->gid;
611
612         /*
613          * drop any root privs for this process
614          * to listen on port < 1023 we would have needed root, but now we are
615          * listening, we don't want the power for anything else
616          */
617         if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
618                 lws_plat_drop_app_privileges(info);
619
620         /*
621          * give all extensions a chance to create any per-context
622          * allocations they need
623          */
624         if (info->port != CONTEXT_PORT_NO_LISTEN) {
625                 if (lws_ext_cb_all_exts(context, NULL,
626                         LWS_EXT_CB_SERVER_CONTEXT_CONSTRUCT, NULL, 0) < 0)
627                         goto bail;
628         } else
629                 if (lws_ext_cb_all_exts(context, NULL,
630                         LWS_EXT_CB_CLIENT_CONTEXT_CONSTRUCT, NULL, 0) < 0)
631                         goto bail;
632
633         return context;
634
635 bail:
636         lws_context_destroy(context);
637         return NULL;
638 }
639
640 /**
641  * lws_context_destroy() - Destroy the websocket context
642  * @context:    Websocket context
643  *
644  *      This function closes any active connections and then frees the
645  *      context.  After calling this, any further use of the context is
646  *      undefined.
647  */
648 LWS_VISIBLE void
649 lws_context_destroy(struct lws_context *context)
650 {
651         const struct lws_protocols *protocol = NULL;
652         struct lws_context_per_thread *pt;
653         struct lws_vhost *vh, *vh1;
654         struct lws wsi;
655         int n, m;
656
657         lwsl_notice("%s\n", __func__);
658
659         if (!context)
660                 return;
661
662         m = context->count_threads;
663         context->being_destroyed = 1;
664
665         memset(&wsi, 0, sizeof(wsi));
666         wsi.context = context;
667
668 #ifdef LWS_LATENCY
669         if (context->worst_latency_info[0])
670                 lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
671 #endif
672
673         while (m--) {
674                 pt = &context->pt[m];
675
676                 for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
677                         struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
678                         if (!wsi)
679                                 continue;
680
681                         lws_close_free_wsi(wsi,
682                                 LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
683                                 /* no protocol close */);
684                         n--;
685                 }
686         }
687         /*
688          * give all extensions a chance to clean up any per-context
689          * allocations they might have made
690          */
691
692         n = lws_ext_cb_all_exts(context, NULL,
693                                 LWS_EXT_CB_SERVER_CONTEXT_DESTRUCT, NULL, 0);
694
695         n = lws_ext_cb_all_exts(context, NULL,
696                                 LWS_EXT_CB_CLIENT_CONTEXT_DESTRUCT, NULL, 0);
697
698         /*
699          * inform all the protocols that they are done and will have no more
700          * callbacks.
701          *
702          * We can't free things until after the event loop shuts down.
703          */
704         vh = context->vhost_list;
705         while (vh) {
706                 wsi.vhost = vh;
707                 protocol = vh->protocols;
708                 if (protocol) {
709                         n = 0;
710                         while (n < vh->count_protocols) {
711                                 wsi.protocol = protocol;
712                                 protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
713                                                    NULL, NULL, 0);
714                                 protocol++;
715                                 n++;
716                         }
717                 }
718
719                 vh = vh->vhost_next;
720         }
721
722         for (n = 0; n < context->count_threads; n++) {
723                 pt = &context->pt[n];
724
725                 lws_libev_destroyloop(context, n);
726                 lws_libuv_destroyloop(context, n);
727
728                 lws_free_set_NULL(context->pt[n].serv_buf);
729                 if (pt->ah_pool)
730                         lws_free(pt->ah_pool);
731                 if (pt->http_header_data)
732                         lws_free(pt->http_header_data);
733         }
734         lws_plat_context_early_destroy(context);
735         lws_ssl_context_destroy(context);
736
737         if (context->pt[0].fds)
738                 lws_free_set_NULL(context->pt[0].fds);
739
740         /* free all the vhost allocations */
741
742         vh = context->vhost_list;
743         while (vh) {
744                 protocol = vh->protocols;
745                 if (protocol) {
746                         n = 0;
747                         while (n < vh->count_protocols) {
748                                 if (vh->protocol_vh_privs &&
749                                     vh->protocol_vh_privs[n]) {
750                                         lws_free(vh->protocol_vh_privs[n]);
751                                         vh->protocol_vh_privs[n] = NULL;
752                                 }
753                                 protocol++;
754                                 n++;
755                         }
756                 }
757                 if (vh->protocol_vh_privs)
758                         lws_free(vh->protocol_vh_privs);
759                 lws_ssl_SSL_CTX_destroy(vh);
760 #ifdef LWS_WITH_PLUGINS
761                 if (context->plugin_list)
762                         lws_free((void *)vh->protocols);
763 #ifndef LWS_NO_EXTENSIONS
764                 if (context->plugin_extension_count)
765                         lws_free((void *)vh->extensions);
766 #endif
767 #endif
768                 vh1 = vh->vhost_next;
769                 lws_free(vh);
770                 vh = vh1;
771         }
772
773         lws_plat_context_late_destroy(context);
774
775         lws_free(context);
776 }