Exemplo n.º 1
0
void uplink_thread(void *asdf)
{
	sigset_t sigs_to_block;
	int rc;
	int next_uplink = -1; /* the index to the next regular uplink candidate */
	int uplink_error_set = -1;
	
	pthreads_profiling_reset("uplink");
	
	sigemptyset(&sigs_to_block);
	sigaddset(&sigs_to_block, SIGALRM);
	sigaddset(&sigs_to_block, SIGINT);
	sigaddset(&sigs_to_block, SIGTERM);
	sigaddset(&sigs_to_block, SIGQUIT);
	sigaddset(&sigs_to_block, SIGHUP);
	sigaddset(&sigs_to_block, SIGURG);
	sigaddset(&sigs_to_block, SIGPIPE);
	sigaddset(&sigs_to_block, SIGUSR1);
	sigaddset(&sigs_to_block, SIGUSR2);
	pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
	
	//hlog(LOG_INFO, "Uplink thread starting...");
	
	uplink_reconfiguring = 1;
	while (!uplink_shutting_down) {
		if (uplink_reconfiguring || uplink_config_updated) {
			hlog(LOG_INFO, "Uplink thread applying new configuration...");
			__sync_synchronize();
			uplink_reconfiguring = 0;
			close_uplinkers();
			
			free_uplink_config(&uplink_config);
			uplink_config = uplink_config_install;
			uplink_config_install = NULL;
			if (uplink_config)
				uplink_config->prevp = &uplink_config;
			
			uplink_config_updated = 0;
			
			hlog(LOG_INFO, "Uplink thread configured.");
		}
		
		/* speed up shutdown */
		if (uplink_shutting_down || uplink_reconfiguring)
			continue;
		
		if (uplink_config_updated) {
			uplink_reconfiguring = 1;
			continue;
		}
		
		if ((rc = pthread_mutex_lock(&uplink_client_mutex))) {
			hlog(LOG_ERR, "uplink_thread(): could not lock uplink_client_mutex: %s", strerror(rc));
			continue;
		}
		
		/* Check if all we have a single regular uplink connection up, out of all
		 * the configured ones. Also, check that all the UPLINKMULTI links are
		 * connected.
		 */
		
		int has_uplink = 0; /* do we have a single regular uplink? */
		int avail_uplink = 0; /* how many regular uplinks are configured? */
		
		struct uplink_config_t *l = uplink_config;
		for (; l; l = l->next) {
			if (l->client_flags & CLFLAGS_UPLINKMULTI) {
				/* MULTI uplink, needs to be up */
				if (l->state < UPLINK_ST_CONNECTING)
					make_uplink(l);
			} else {
				/* regular uplink, need to have one connected */
				if (l->state >= UPLINK_ST_CONNECTING)
					has_uplink++;
				avail_uplink++;
			}
		}
		
		if (avail_uplink && !has_uplink) {
			hlog(LOG_INFO, "Uplink: %d uplinks configured, %d are connected, need to pick new", avail_uplink, has_uplink);
			/* we have regular uplinks but none are connected,
			 * pick the next one and connect */
			next_uplink++;
			if (next_uplink >= avail_uplink)
				next_uplink = 0;
			//hlog(LOG_DEBUG, "Uplink: picked uplink %d as the new candidate", next_uplink);
			l = uplink_config;
			int i = 0;
			while ((l) && i < next_uplink) {
				if (!(l->client_flags & CLFLAGS_UPLINKMULTI))
					i++;
				l = l->next;
			}
			if (l) {
				hlog(LOG_DEBUG, "Uplink: trying %s (%s:%s)", l->name, l->host, l->port);
				make_uplink(l);
			}
		}
		
		if ((rc = pthread_mutex_unlock(&uplink_client_mutex))) {
			hlog(LOG_CRIT, "close_uplinkers(): could not unlock uplink_client_mutex: %s", strerror(rc));
			continue;
		}
		
		if (avail_uplink && !has_uplink) {
			status_error(3600, "no_uplink");
			uplink_error_set = 1;
		} else {
			if (uplink_error_set == 1) {
				status_error(-1, "no_uplink");
				uplink_error_set = 0;
			}
		}
		
		/* sleep for 4 seconds between successful rounds */
		for (rc = 0; (!uplink_shutting_down) && rc < 4000/200; rc++)
			if (poll(NULL, 0, 200) == -1 && errno != EINTR)
				hlog(LOG_WARNING, "uplink: poll sleep failed: %s", strerror(errno));
	}
	
	hlog(LOG_DEBUG, "Uplink thread shutting down uplinking sockets...");
	close_uplinkers();
}
Exemplo n.º 2
0
Arquivo: http.c Projeto: snip/aprsc
void http_thread(void *asdf)
{
	sigset_t sigs_to_block;
	struct http_config_t *lc;
	struct timeval http_timer_tv;
	
	http_timer_tv.tv_sec = 0;
	http_timer_tv.tv_usec = 200000;
	
	pthreads_profiling_reset("http");
	
	sigemptyset(&sigs_to_block);
	sigaddset(&sigs_to_block, SIGALRM);
	sigaddset(&sigs_to_block, SIGINT);
	sigaddset(&sigs_to_block, SIGTERM);
	sigaddset(&sigs_to_block, SIGQUIT);
	sigaddset(&sigs_to_block, SIGHUP);
	sigaddset(&sigs_to_block, SIGURG);
	sigaddset(&sigs_to_block, SIGPIPE);
	sigaddset(&sigs_to_block, SIGUSR1);
	sigaddset(&sigs_to_block, SIGUSR2);
	pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
	
	/* start the http thread, which will start server threads */
	hlog(LOG_INFO, "HTTP thread starting...");
	
	/* we allocate a worker structure to be used within the http thread
	 * for parsing incoming packets and passing them on to the dupecheck
	 * thread.
	 */
	http_worker = worker_alloc();
	http_worker->id = 80;
	
	/* we also need a client structure to be used with incoming
	 * HTTP position uploads
	 */
	http_pseudoclient = pseudoclient_setup(80);
	
	http_reconfiguring = 1;
	while (!http_shutting_down) {
		if (http_reconfiguring) {
			http_reconfiguring = 0;
			
			// shut down existing instance
			http_server_free();
			
			// do init
#if 1
			libbase = event_base_new(); // libevent 2.x
#else
                        libbase = event_init(); // libevent 1.x
#endif
			
			// timer for the whole libevent, to catch shutdown signal
			ev_timer = event_new(libbase, -1, EV_TIMEOUT, http_timer, NULL);
			event_add(ev_timer, &http_timer_tv);
			
			for (lc = http_config; (lc); lc = lc->next) {
				hlog(LOG_INFO, "Binding HTTP %s socket %s:%d", lc->upload_port ? "upload" : "status", lc->host, lc->port);
				
				struct evhttp *srvr;
				struct evhttp_bound_socket *handle;
				
				if (lc->upload_port) {
					if (!srvr_upload) {
						srvr_upload = evhttp_new(libbase);
						http_srvr_defaults(srvr_upload);
						evhttp_set_allowed_methods(srvr_upload, EVHTTP_REQ_POST); /* uploads are POSTs, after all */
						evhttp_set_gencb(srvr_upload, http_router, (void *)2);
					}
					srvr = srvr_upload;
				} else {
					if (!srvr_status) {
						srvr_status = evhttp_new(libbase);
						http_srvr_defaults(srvr_status);
						evhttp_set_gencb(srvr_status, http_router, (void *)1);
					}
					srvr = srvr_status;
				}
				
				handle = evhttp_bind_socket_with_handle(srvr, lc->host, lc->port);
				if (!handle) {
					hlog(LOG_ERR, "Failed to bind HTTP socket %s:%d: %s", lc->host, lc->port, strerror(errno));
					// TODO: should exit?
				}
			}
			
			hlog(LOG_INFO, "HTTP thread ready.");
		}
		
		event_base_dispatch(libbase);
	}
	
	hlog(LOG_DEBUG, "HTTP thread shutting down...");
	
	http_server_free();
	
	/* free up the pseudo-client */
	client_free(http_pseudoclient);
	http_pseudoclient = NULL;
	
	/* free up the pseudo-worker structure */
	worker_free_buffers(http_worker);
	hfree(http_worker);
	http_worker = NULL;
}
Exemplo n.º 3
0
void accept_thread(void *asdf)
{
	sigset_t sigs_to_block;
	int e, n;
	struct pollfd *acceptpfd = NULL;
	struct listen_t **acceptpl = NULL;
	int listen_n = 0;
	int poll_n = 0;
	struct listen_t *l;

	pthreads_profiling_reset("accept");
	
	sigemptyset(&sigs_to_block);
	sigaddset(&sigs_to_block, SIGALRM);
	sigaddset(&sigs_to_block, SIGINT);
	sigaddset(&sigs_to_block, SIGTERM);
	sigaddset(&sigs_to_block, SIGQUIT);
	sigaddset(&sigs_to_block, SIGHUP);
	sigaddset(&sigs_to_block, SIGURG);
	sigaddset(&sigs_to_block, SIGPIPE);
	sigaddset(&sigs_to_block, SIGUSR1);
	sigaddset(&sigs_to_block, SIGUSR2);
	pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
	
	/* start the accept thread, which will start server threads */
	hlog(LOG_INFO, "Accept thread starting...");
	
	/* we allocate a worker structure to be used within the accept thread
	 * for parsing incoming UDP packets and passing them on to the dupecheck
	 * thread.
	 */
	udp_worker = worker_alloc();
	udp_worker->id = 81;
	
	/* we also need a client structure to be used with incoming
	 * HTTP position uploads
	 */
	udp_pseudoclient = pseudoclient_setup(81);
	udp_pseudoclient->flags |= CLFLAGS_UDPSUBMIT;
	
	accept_reconfiguring = 1;
	while (!accept_shutting_down) {
		if (accept_reconfiguring) {
			accept_reconfiguring = 0;
			listen_n -= close_removed_listeners();
			
			/* start listening on the sockets */
			listen_n += open_missing_listeners();
			
			if (listen_n < 1) {
				hlog(LOG_CRIT, "Failed to listen on any ports.");
				exit(2);
			}
			
			/* reconfiguration must scan old clients against ACL */
			rescan_client_acls();
			
			/* how many are we polling */
			poll_n = 0;
			for (l = listen_list; (l); l = l->next)
				if (!l->corepeer)
					poll_n++;
			
			hlog(LOG_DEBUG, "Generating polling list for %d/%d listeners...", poll_n, listen_n);
			
			/* array of FDs for poll() */
			if (acceptpfd)
				hfree(acceptpfd);
			acceptpfd = hmalloc(poll_n * sizeof(*acceptpfd));
			
			/* array of listeners */
			if (acceptpl)
				hfree(acceptpl);
			acceptpl = hmalloc(poll_n * sizeof(*acceptpl));
			
			n = 0;
			for (l = listen_list; (l); l = l->next) {
				/* The accept thread does not poll() UDP sockets for core peers.
				 * Worker 0 takes care of that, and processes the incoming packets.
				 */
				if (l->corepeer) {
					hlog(LOG_DEBUG, "... %d: fd %d (%s) - not polled, is corepeer", n, (l->udp) ? l->udp->fd : l->fd, l->addr_s);
					continue;
				}
				
				int fd;
				if (l->udp) {
					l->udp->polled = 1;
					fd = l->udp->fd;
				} else {
					fd = l->fd;
				}
				
				hlog(LOG_DEBUG, "... %d: fd %d (%s)", n, fd, l->addr_s);
				acceptpfd[n].fd = fd;
				acceptpfd[n].events = POLLIN|POLLPRI|POLLERR|POLLHUP;
				acceptpl[n] = l;
				n++;
			}
			hlog(LOG_INFO, "Accept thread ready.");
			
			/* stop the dupechecking and uplink threads while adjusting
			 * the amount of workers... they walk the worker list, and
			 * might get confused when workers are stopped or started.
			 */
			if (workers_running != workers_configured) {
				uplink_stop();
				dupecheck_stop();
				workers_start();
				dupecheck_start();
				uplink_start();
			}
			
			/*
			 * generate UDP peer clients
			 */
			peerip_clients_close();
			if (peerip_config)
				peerip_clients_config();
			
			/* accept liveupgrade clients */
			if (liveupgrade_status)
				accept_liveupgrade_accept();
		}
		
		/* check for new connections */
		e = poll(acceptpfd, poll_n, 200);
		if (e == 0)
			continue;
		if (e < 0) {
			if (errno == EINTR)
				continue;
			hlog(LOG_ERR, "poll() on accept failed: %s (continuing)", strerror(errno));
			continue;
		}
		
		/* now, which socket was that on? */
		for (n = 0; n < poll_n; n++) {
			l = acceptpl[n];
			if (!(l) || (l->udp ? l->udp->fd : l->fd) != acceptpfd[n].fd) {
				hlog(LOG_CRIT, "accept_thread: polling list and listener list do mot match!");
				exit(1);
			}
			if (acceptpfd[n].revents) {
				if (l->udp)
					accept_udp_recv(l); /* receive UDP packets */
				else
					do_accept(l); /* accept a single connection */
			}
		}
	}
	
	if (accept_shutting_down == 2)
		worker_shutdown_clients = cJSON_CreateArray();
	
	hlog(LOG_DEBUG, "Accept thread shutting down listening sockets and worker threads...");
	uplink_stop();
	close_listeners();
	dupecheck_stop();
	http_shutting_down = 1;
	workers_stop(accept_shutting_down);
	hfree(acceptpfd);
	hfree(acceptpl);
	acceptpfd = NULL;
	acceptpl = NULL;
	
	/* free up the pseudo-client */
	client_free(udp_pseudoclient);
	udp_pseudoclient = NULL;
	
	/* free up the pseudo-worker structure, after dupecheck is long dead */
	worker_free_buffers(udp_worker);
	hfree(udp_worker);
	udp_worker = NULL;
}