// destroy the cache and free all the memory it uses
void web_client_cache_destroy(void) {
#ifdef NETDATA_INTERNAL_CHECKS
    if(unlikely(web_clients_cache.pid != 0 && web_clients_cache.pid != gettid()))
        error("Oops! wrong thread accessing the cache. Expected %d, found %d", (int)web_clients_cache.pid, (int)gettid());

    web_client_cache_verify(1);
#endif

    netdata_thread_disable_cancelability();

    struct web_client *w, *t;

    w = web_clients_cache.used;
    while(w) {
        t = w;
        w = w->next;
        web_client_free(t);
    }
    web_clients_cache.used = NULL;
    web_clients_cache.used_count = 0;

    w = web_clients_cache.avail;
    while(w) {
        t = w;
        w = w->next;
        web_client_free(t);
    }
    web_clients_cache.avail = NULL;
    web_clients_cache.avail_count = 0;

    netdata_thread_enable_cancelability();
}
示例#2
0
static inline void cleanup_web_clients(void) {
	struct web_client *w;

	for (w = web_clients; w;) {
		if (w->obsolete) {
			debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
			// pthread_cancel(w->thread);
			// pthread_join(w->thread, NULL);
			w = web_client_free(w);
#ifdef NETDATA_INTERNAL_CHECKS
			log_allocations();
#endif
		}
		else w = w->next;
	}
}
void web_client_release(struct web_client *w) {
#ifdef NETDATA_INTERNAL_CHECKS
    if(unlikely(web_clients_cache.pid != 0 && web_clients_cache.pid != gettid()))
        error("Oops! wrong thread accessing the cache. Expected %d, found %d", (int)web_clients_cache.pid, (int)gettid());

    if(unlikely(w->running))
        error("%llu: releasing web client from %s port %s, but it still running.", w->id, w->client_ip, w->client_port);
#endif

    debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port);

    web_server_log_connection(w, "DISCONNECTED");
    web_client_request_done(w);
    web_client_disconnected();

    netdata_thread_disable_cancelability();

    if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) {
        if (w->ifd != -1) close(w->ifd);
        if (w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
        w->ifd = w->ofd = -1;
    }

    // unlink it from the used
    if (w == web_clients_cache.used) web_clients_cache.used = w->next;
    if(w->prev) w->prev->next = w->next;
    if(w->next) w->next->prev = w->prev;
    web_clients_cache.used_count--;

    if(web_clients_cache.avail_count >= 2 * web_clients_cache.used_count) {
        // we have too many of them - free it
        web_client_free(w);
    }
    else {
        // link it to the avail
        if (web_clients_cache.avail) web_clients_cache.avail->prev = w;
        w->next = web_clients_cache.avail;
        w->prev = NULL;
        web_clients_cache.avail = w;
        web_clients_cache.avail_count++;
    }

    netdata_thread_enable_cancelability();
}
示例#4
0
void *socket_listen_main_single_threaded(void *ptr) {
	(void)ptr;

	web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED;

	info("Single threaded WEB SERVER thread created with task id %d", gettid());

	struct web_client *w;
	int retval, failures = 0;

	if(ptr) { ; }

	if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
		error("Cannot set pthread cancel type to DEFERRED.");

	if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
		error("Cannot set pthread cancel state to ENABLE.");

	if(listen_fd < 0 || listen_fd >= FD_SETSIZE)
		fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fd);

	int i;
	for(i = 0; i < FD_SETSIZE ; i++)
		single_threaded_clients[i] = NULL;

	fd_set ifds, ofds, efds, rifds, rofds, refds;
	FD_ZERO (&ifds);
	FD_ZERO (&ofds);
	FD_ZERO (&efds);
	FD_SET(listen_fd, &ifds);
	FD_SET(listen_fd, &efds);
	int fdmax = listen_fd;

	for(;;) {
		debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (listen fd = %d, fdmax = %d)...", listen_fd, fdmax);

		struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
		rifds = ifds;
		rofds = ofds;
		refds = efds;
		retval = select(fdmax+1, &rifds, &rofds, &refds, &tv);

		if(unlikely(retval == -1)) {
			debug(D_WEB_CLIENT, "LISTENER: select() failed.");
			failures++;
			if(failures > 10) {
				if(global_statistics.connected_clients) {
					error("REMOVING ALL %lu WEB CLIENTS !", global_statistics.connected_clients);
					while (web_clients) {
						single_threaded_unlink_client(web_clients, &ifds, &ofds, &efds);
						web_client_free(web_clients);
					}
				}

				error("LISTENER: our listen port %d seems dead. Re-opening it.", listen_fd);

				close(listen_fd);
				listen_fd = -1;
				sleep(5);

				create_listen_socket();
				if(listen_fd < 0 || listen_fd >= FD_SETSIZE)
					fatal("Cannot listen for web clients (connected clients %llu).", global_statistics.connected_clients);

				FD_ZERO (&ifds);
				FD_ZERO (&ofds);
				FD_ZERO (&efds);
				FD_SET(listen_fd, &ifds);
				FD_SET(listen_fd, &efds);
				failures = 0;
			}
		}
		else if(likely(retval)) {
			failures = 0;
			debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something.");

			if(FD_ISSET(listen_fd, &rifds)) {
				debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
				w = web_client_create(listen_fd);
				if(single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
					web_client_free(w);
				}
			}

			for(i = 0 ; i <= fdmax ; i++) {
				if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds)))
					continue;

				w = single_threaded_clients[i];
				if(unlikely(!w))
					continue;

				if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) {
					web_client_free(w);
					continue;
				}

				if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) {
					web_client_free(w);
					continue;
				}

				if (unlikely(w->wait_receive && FD_ISSET(w->ifd, &rifds))) {
					if (unlikely(web_client_receive(w) < 0)) {
						web_client_free(w);
						continue;
					}

					if (w->mode != WEB_CLIENT_MODE_FILECOPY) {
						debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id);
						web_client_process(w);
					}
				}

				if (unlikely(w->wait_send && FD_ISSET(w->ofd, &rofds))) {
					if (unlikely(web_client_send(w) < 0)) {
						debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
						web_client_free(w);
						continue;
					}
				}

				if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) {
					web_client_free(w);
				}
			}
		}
		else {
			debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout.");
#ifdef NETDATA_INTERNAL_CHECKS
			log_allocations();
#endif
		}
	}

	debug(D_WEB_CLIENT, "LISTENER: exit!");
	close(listen_fd);
	listen_fd = -1;
	return NULL;
}
示例#5
0
void *socket_listen_main_multi_threaded(void *ptr) {
	(void)ptr;

	web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
	info("Multi-threaded WEB SERVER thread created with task id %d", gettid());

	struct web_client *w;
	int retval, failures = 0, counter = 0;

	if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
		error("Cannot set pthread cancel type to DEFERRED.");

	if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
		error("Cannot set pthread cancel state to ENABLE.");

	if(listen_fd < 0)
		fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fd);

	for(;;) {
		struct pollfd fd = { .fd = listen_fd, .events = POLLIN, .revents = 0 };
		int timeout = 10 * 1000;

		// debug(D_WEB_CLIENT, "LISTENER: Waiting...");
		retval = poll(&fd, 1, timeout);

		if(unlikely(retval == -1)) {
			debug(D_WEB_CLIENT, "LISTENER: poll() failed.");
			failures++;

			if(failures > 10) {
				error("LISTENER: our listen port %d seems dead. Re-opening it.", listen_fd);
				close(listen_fd);
				listen_fd = -1;
				sleep(5);
				create_listen_socket();
				if(listen_fd < 0)
					fatal("Cannot listen for web clients (connected clients %llu).", global_statistics.connected_clients);

				failures = 0;
			}

			continue;
		}
		else if(likely(retval)) {
			// check for new incoming connections
			if(fd.revents & POLLIN || fd.revents & POLLPRI) {
				w = web_client_create(listen_fd);
				if(unlikely(!w)) {
					// no need for error log - web_client_create already logged the error
					continue;
				}

				if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) {
					error("%llu: failed to create new thread for web client.");
					w->obsolete = 1;
				}
				else if(pthread_detach(w->thread) != 0) {
					error("%llu: Cannot request detach of newly created web client thread.", w->id);
					w->obsolete = 1;
				}
			}
			else {
				failures++;
				debug(D_WEB_CLIENT, "LISTENER: select() didn't do anything.");
				continue;
			}
		}
		else {
			debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
			counter = CLEANUP_EVERY_EVENTS;
		}

		// cleanup unused clients
		counter++;
		if(counter > CLEANUP_EVERY_EVENTS) {
			counter = 0;
			for (w = web_clients; w;) {
				if (w->obsolete) {
					debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
					// pthread_cancel(w->thread);
					// pthread_join(w->thread, NULL);
					w = web_client_free(w);
#ifdef NETDATA_INTERNAL_CHECKS
					log_allocations();
#endif
				}
				else w = w->next;
			}
		}

		failures = 0;
	}

	debug(D_WEB_CLIENT, "LISTENER: exit!");
	close(listen_fd);
	listen_fd = -1;
	return NULL;
}

struct web_client *single_threaded_clients[FD_SETSIZE];

static inline int single_threaded_link_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds, int *max) {
	if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
		return 1;

	if(unlikely(w->ifd < 0 || w->ifd >= FD_SETSIZE || w->ofd < 0 || w->ofd >= FD_SETSIZE)) {
		error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, FD_SETSIZE);
		return 1;
	}

	FD_SET(w->ifd, efds);
	if(unlikely(*max < w->ifd)) *max = w->ifd;

	if(unlikely(w->ifd != w->ofd)) {
		if(*max < w->ofd) *max = w->ofd;
		FD_SET(w->ofd, efds);
	}

	if(w->wait_receive) FD_SET(w->ifd, ifds);
	if(w->wait_send)    FD_SET(w->ofd, ofds);

	single_threaded_clients[w->ifd] = w;
	single_threaded_clients[w->ofd] = w;

	return 0;
}

static inline int single_threaded_unlink_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds) {
	FD_CLR(w->ifd, efds);
	if(unlikely(w->ifd != w->ofd)) FD_CLR(w->ofd, efds);

	if(w->wait_receive) FD_CLR(w->ifd, ifds);
	if(w->wait_send)    FD_CLR(w->ofd, ofds);

	single_threaded_clients[w->ifd] = NULL;
	single_threaded_clients[w->ofd] = NULL;

	if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
		return 1;

	return 0;
}
示例#6
0
void *socket_listen_main_single_threaded(void *ptr) {
	(void)ptr;

	web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED;

	info("Single-threaded WEB SERVER thread created with task id %d", gettid());

	struct web_client *w;
	int retval;

	if(ptr) { ; }

	if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
		error("Cannot set pthread cancel type to DEFERRED.");

	if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
		error("Cannot set pthread cancel state to ENABLE.");

	int i;

	if(!listen_fds_count)
		fatal("LISTENER: no listen sockets available.");

	for(i = 0; i < FD_SETSIZE ; i++)
		single_threaded_clients[i] = NULL;

	fd_set ifds, ofds, efds, rifds, rofds, refds;
	FD_ZERO (&ifds);
	FD_ZERO (&ofds);
	FD_ZERO (&efds);
	int fdmax = 0;

	for(i = 0; i < listen_fds_count ; i++) {
		if (listen_fds[i] < 0 || listen_fds[i] >= FD_SETSIZE)
			fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fds[i]);

        info("Listening on '%s'", (listen_fds_names[i])?listen_fds_names[i]:"UNKNOWN");

		FD_SET(listen_fds[i], &ifds);
		FD_SET(listen_fds[i], &efds);
		if(fdmax < listen_fds[i])
            fdmax = listen_fds[i];
	}

	for(;;) {
		debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax);

		struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
		rifds = ifds;
		rofds = ofds;
		refds = efds;
		retval = select(fdmax+1, &rifds, &rofds, &refds, &tv);

		if(unlikely(retval == -1)) {
			error("LISTENER: select() failed.");
			continue;
		}
		else if(likely(retval)) {
			debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something.");

			for(i = 0; i < listen_fds_count ; i++) {
				if (FD_ISSET(listen_fds[i], &rifds)) {
					debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
					w = web_client_create(listen_fds[i]);
					if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
						web_client_free(w);
					}
				}
			}

			for(i = 0 ; i <= fdmax ; i++) {
				if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds)))
					continue;

				w = single_threaded_clients[i];
				if(unlikely(!w))
					continue;

				if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) {
					web_client_free(w);
					continue;
				}

				if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) {
					web_client_free(w);
					continue;
				}

				if (unlikely(w->wait_receive && FD_ISSET(w->ifd, &rifds))) {
					if (unlikely(web_client_receive(w) < 0)) {
						web_client_free(w);
						continue;
					}

					if (w->mode != WEB_CLIENT_MODE_FILECOPY) {
						debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id);
						web_client_process(w);
					}
				}

				if (unlikely(w->wait_send && FD_ISSET(w->ofd, &rofds))) {
					if (unlikely(web_client_send(w) < 0)) {
						debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
						web_client_free(w);
						continue;
					}
				}

				if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) {
					web_client_free(w);
				}
			}
		}
		else {
			debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout.");
#ifdef NETDATA_INTERNAL_CHECKS
			log_allocations();
#endif
		}
	}

	debug(D_WEB_CLIENT, "LISTENER: exit!");
    close_listen_sockets();
	return NULL;
}
示例#7
0
文件: web_server.c 项目: 2-B/netdata
void *socket_listen_main(void *ptr)
{
	if(ptr) { ; }

	info("WEB SERVER thread created with task id %d", gettid());

	struct web_client *w;
	struct timeval tv;
	int retval;

	if(ptr) { ; }

	if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
		error("Cannot set pthread cancel type to DEFERRED.");

	if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
		error("Cannot set pthread cancel state to ENABLE.");

	web_client_timeout = (int) config_get_number("global", "disconnect idle web clients after seconds", DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS);
	web_enable_gzip = config_get_boolean("global", "enable web responses gzip compression", web_enable_gzip);

	if(listen_fd < 0) fatal("LISTENER: Listen socket is not ready.");

	fd_set ifds, ofds, efds;
	int fdmax = listen_fd;

	FD_ZERO (&ifds);
	FD_ZERO (&ofds);
	FD_ZERO (&efds);

	for(;;) {
		tv.tv_sec = 0;
		tv.tv_usec = 200000;

		if(listen_fd >= 0) {
			FD_SET(listen_fd, &ifds);
			FD_SET(listen_fd, &efds);
		}

		// debug(D_WEB_CLIENT, "LISTENER: Waiting...");
		retval = select(fdmax+1, &ifds, &ofds, &efds, &tv);

		if(retval == -1) {
			error("LISTENER: select() failed.");
			continue;
		}
		else if(retval) {
			// check for new incoming connections
			if(FD_ISSET(listen_fd, &ifds)) {
				w = web_client_create(listen_fd);
				if(unlikely(!w)) {
					// no need for error log - web_client_create already logged the error
					continue;
				}

				if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) {
					error("%llu: failed to create new thread for web client.");
					w->obsolete = 1;
				}
				else if(pthread_detach(w->thread) != 0) {
					error("%llu: Cannot request detach of newly created web client thread.", w->id);
					w->obsolete = 1;
				}
			}
			else debug(D_WEB_CLIENT, "LISTENER: select() didn't do anything.");

		}
		//else {
		//	debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
		//}

		// cleanup unused clients
		for(w = web_clients; w ; w = w?w->next:NULL) {
			if(w->obsolete) {
				debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
				// pthread_join(w->thread,  NULL);
				w = web_client_free(w);
				log_allocations();
			}
		}
	}

	error("LISTENER: exit!");

	if(listen_fd >= 0) close(listen_fd);
	exit(2);

	return NULL;
}