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(); }
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; }
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; }