Skip to content
Snippets Groups Projects
context.c 31.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • Andy Green's avatar
    Andy Green committed
    #endif
    
    
    	/*
    	 * drop any root privs for this process
    	 * to listen on port < 1023 we would have needed root, but now we are
    	 * listening, we don't want the power for anything else
    	 */
    
    Andy Green's avatar
    Andy Green committed
    	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
    		lws_plat_drop_app_privileges(info);
    
    
    	/*
    	 * give all extensions a chance to create any per-context
    	 * allocations they need
    	 */
    	if (info->port != CONTEXT_PORT_NO_LISTEN) {
    
    Andy Green's avatar
    Andy Green committed
    		if (lws_ext_cb_all_exts(context, NULL,
    
    			LWS_EXT_CB_SERVER_CONTEXT_CONSTRUCT, NULL, 0) < 0)
    
    Andy Green's avatar
    Andy Green committed
    		if (lws_ext_cb_all_exts(context, NULL,
    
    			LWS_EXT_CB_CLIENT_CONTEXT_CONSTRUCT, NULL, 0) < 0)
    
    	lws_context_destroy(context);
    
    Andy Green's avatar
    Andy Green committed
    LWS_VISIBLE LWS_EXTERN void
    lws_context_deprecate(struct lws_context *context, lws_reload_func cb)
    {
    	struct lws_vhost *vh = context->vhost_list, *vh1;
    	struct lws *wsi;
    
    	/*
    	 * "deprecation" means disable the context from accepting any new
    	 * connections and free up listen sockets to be used by a replacement
    	 * context.
    	 *
    	 * Otherwise the deprecated context remains operational, until its
    	 * number of connected sockets falls to zero, when it is deleted.
    	 */
    
    	/* for each vhost, close his listen socket */
    
    	while (vh) {
    		wsi = vh->lserv_wsi;
    		if (wsi) {
    			wsi->socket_is_permanently_unusable = 1;
    			lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
    			wsi->context->deprecation_pending_listen_close_count++;
    			/*
    			 * other vhosts can share the listen port, they
    			 * point to the same wsi.  So zap those too.
    			 */
    			vh1 = context->vhost_list;
    			while (vh1) {
    				if (vh1->lserv_wsi == wsi)
    					vh1->lserv_wsi = NULL;
    				vh1 = vh1->vhost_next;
    			}
    		}
    		vh = vh->vhost_next;
    	}
    
    	context->deprecated = 1;
    	context->deprecation_cb = cb;
    }
    
    LWS_VISIBLE LWS_EXTERN int
    lws_context_is_deprecated(struct lws_context *context)
    {
    	return context->deprecated;
    }
    
    LWS_VISIBLE void
    lws_context_destroy2(struct lws_context *context);
    
    
    lws_context_destroy(struct lws_context *context)
    
    	const struct lws_protocols *protocol = NULL;
    
    Andy Green's avatar
    Andy Green committed
    	struct lws_context_per_thread *pt;
    
    Andy Green's avatar
    Andy Green committed
    	struct lws_vhost *vh = NULL;
    
    Andy Green's avatar
    Andy Green committed
    	if (!context) {
    		lwsl_notice("%s: ctx %p\n", __func__, context);
    		return;
    	}
    	if (context->being_destroyed1) {
    		lwsl_notice("%s: ctx %p: already being destroyed\n", __func__, context);
    
    Andy Green's avatar
    Andy Green committed
    	}
    
    	lwsl_notice("%s: ctx %p\n", __func__, context);
    
    	context->being_destroyed = 1;
    
    Andy Green's avatar
    Andy Green committed
    	context->being_destroyed1 = 1;
    
    	memset(&wsi, 0, sizeof(wsi));
    	wsi.context = context;
    
    
    #ifdef LWS_LATENCY
    	if (context->worst_latency_info[0])
    		lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
    #endif
    
    
    Andy Green's avatar
    Andy Green committed
    	while (m--) {
    		pt = &context->pt[m];
    
    
    Andy Green's avatar
    Andy Green committed
    		for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
    
    Andy Green's avatar
    Andy Green committed
    			struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
    
    Andy Green's avatar
    Andy Green committed
    			if (!wsi)
    				continue;
    
    Andy Green's avatar
    Andy Green committed
    
    			lws_close_free_wsi(wsi,
    				LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
    
    				/* no protocol close */);
    
    Andy Green's avatar
    Andy Green committed
    			n--;
    		}
    
    		lws_pt_mutex_destroy(pt);
    
    Andy Green's avatar
    Andy Green committed
    	}
    
    Andy Green's avatar
    Andy Green committed
    
    
    	/*
    	 * give all extensions a chance to clean up any per-context
    	 * allocations they might have made
    	 */
    
    Andy Green's avatar
    Andy Green committed
    	n = lws_ext_cb_all_exts(context, NULL,
    
    Andy Green's avatar
    Andy Green committed
    				LWS_EXT_CB_SERVER_CONTEXT_DESTRUCT, NULL, 0);
    
    Andy Green's avatar
    Andy Green committed
    	n = lws_ext_cb_all_exts(context, NULL,
    
    Andy Green's avatar
    Andy Green committed
    				LWS_EXT_CB_CLIENT_CONTEXT_DESTRUCT, NULL, 0);
    
    
    	/*
    	 * inform all the protocols that they are done and will have no more
    
    Andy Green's avatar
    Andy Green committed
    	 * callbacks.
    	 *
    	 * We can't free things until after the event loop shuts down.
    
    	if (context->protocol_init_done)
    		vh = context->vhost_list;
    
    Andy Green's avatar
    Andy Green committed
    	while (vh) {
    
    Andy Green's avatar
    Andy Green committed
    		wsi.vhost = vh;
    
    Andy Green's avatar
    Andy Green committed
    		protocol = vh->protocols;
    
    Andy Green's avatar
    Andy Green committed
    		if (protocol) {
    			n = 0;
    			while (n < vh->count_protocols) {
    				wsi.protocol = protocol;
    
    Andy Green's avatar
    Andy Green committed
    				protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
    						   NULL, NULL, 0);
    				protocol++;
    
    Andy Green's avatar
    Andy Green committed
    				n++;
    
    Andy Green's avatar
    Andy Green committed
    			}
    
    Andy Green's avatar
    Andy Green committed
    		}
    
    
    Andy Green's avatar
    Andy Green committed
    		vh = vh->vhost_next;
    	}
    
    Andy Green's avatar
    Andy Green committed
    	for (n = 0; n < context->count_threads; n++) {
    
    Andy Green's avatar
    Andy Green committed
    		pt = &context->pt[n];
    
    		lws_libev_destroyloop(context, n);
    		lws_libuv_destroyloop(context, n);
    
    		lws_libevent_destroyloop(context, n);
    
    Andy Green's avatar
    Andy Green committed
    
    
    Andy Green's avatar
    Andy Green committed
    		lws_free_set_NULL(context->pt[n].serv_buf);
    
    Andy Green's avatar
    Andy Green committed
    		if (pt->ah_pool)
    			lws_free(pt->ah_pool);
    		if (pt->http_header_data)
    			lws_free(pt->http_header_data);
    
    Andy Green's avatar
    Andy Green committed
    	}
    
    	lws_plat_context_early_destroy(context);
    
    Andy Green's avatar
    Andy Green committed
    
    
    Andy Green's avatar
    Andy Green committed
    	if (context->pt[0].fds)
    
    Andy Green's avatar
    Andy Green committed
    		lws_free_set_NULL(context->pt[0].fds);
    
    Andy Green's avatar
    Andy Green committed
    	if (!LWS_LIBUV_ENABLED(context))
    		lws_context_destroy2(context);
    }
    
    /*
     * call the second one after the event loop has been shut down cleanly
     */
    
    LWS_VISIBLE void
    lws_context_destroy2(struct lws_context *context)
    {
    	const struct lws_protocols *protocol = NULL;
    	struct lws_vhost *vh = NULL, *vh1;
    	int n;
    
    	lwsl_notice("%s: ctx %p\n", __func__, context);
    
    	/*
    	 * free all the per-vhost allocations
    	 */
    
    Andy Green's avatar
    Andy Green committed
    
    	vh = context->vhost_list;
    	while (vh) {
    		protocol = vh->protocols;
    		if (protocol) {
    			n = 0;
    			while (n < vh->count_protocols) {
    				if (vh->protocol_vh_privs &&
    				    vh->protocol_vh_privs[n]) {
    
    Andy Green's avatar
    Andy Green committed
    					// lwsl_notice("   %s: freeing per-vhost protocol data %p\n", __func__, vh->protocol_vh_privs[n]);
    
    Andy Green's avatar
    Andy Green committed
    					lws_free(vh->protocol_vh_privs[n]);
    					vh->protocol_vh_privs[n] = NULL;
    				}
    				protocol++;
    				n++;
    			}
    		}
    		if (vh->protocol_vh_privs)
    			lws_free(vh->protocol_vh_privs);
    		lws_ssl_SSL_CTX_destroy(vh);
    
    		lws_free(vh->same_vh_protocol_list);
    
    Andy Green's avatar
    Andy Green committed
    #ifdef LWS_WITH_PLUGINS
    		if (context->plugin_list)
    			lws_free((void *)vh->protocols);
    
    #else
    		if (vh->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
    			lws_free((void *)vh->protocols);
    #endif
    #ifdef LWS_WITH_PLUGINS
    
    Andy Green's avatar
    Andy Green committed
    #ifndef LWS_NO_EXTENSIONS
    		if (context->plugin_extension_count)
    			lws_free((void *)vh->extensions);
    #endif
    #endif
    
    #ifdef LWS_WITH_ACCESS_LOG
    
    		if (vh->log_fd != (int)LWS_INVALID_FILE)
    
    			close(vh->log_fd);
    #endif
    
    
    Andy Green's avatar
    Andy Green committed
    		vh1 = vh->vhost_next;
    		lws_free(vh);
    		vh = vh1;
    	}
    
    
    Andy Green's avatar
    Andy Green committed
    	lws_stats_log_dump(context);
    
    
    Andy Green's avatar
    Andy Green committed
    	lws_ssl_context_destroy(context);
    
    	lws_plat_context_late_destroy(context);
    
    	if (context->external_baggage_free_on_destroy)
    		free(context->external_baggage_free_on_destroy);
    
    
    	lws_free(context);