/* Set up standard signal-handling. */ static void InitSignals() { MakeSignalPipe(); signal(SIGINT, HandleSignalsForDaemon); signal(SIGTERM, HandleSignalsForDaemon); signal(SIGHUP, HandleSignalsForDaemon); signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, HandleSignalsForDaemon); signal(SIGUSR2, HandleSignalsForDaemon); }
int main(int argc, char *argv[]) { signal(SIGINT, HandleSignal); signal(SIGTERM, HandleSignal); Log(LOG_LEVEL_VERBOSE, "Starting cf-testd"); cfnet_init(NULL, NULL); MakeSignalPipe(); long n_threads = 1; CFTestD_Config *config = CFTestD_CheckOpts(argc, argv, &n_threads); if (config->address == NULL) { /* default to localhost */ config->address = xstrdup("127.0.0.1"); } CFTestD_Config **thread_configs = (CFTestD_Config**) xcalloc(n_threads, sizeof(CFTestD_Config*)); for (int i = 0; i < n_threads; i++) { thread_configs[i] = (CFTestD_Config*) xmalloc(sizeof(CFTestD_Config)); if (config->report_file != NULL && strstr(config->report_file, "%d") != NULL) { /* replace the '%d' with the thread number */ asprintf(&(thread_configs[i]->report_file), config->report_file, i); } else { thread_configs[i]->report_file = SafeStringDuplicate(config->report_file); } if (config->key_file != NULL && strstr(config->key_file, "%d") != NULL) { /* replace the '%d' with the thread number */ asprintf(&(thread_configs[i]->key_file), config->key_file, i); } else { thread_configs[i]->key_file = SafeStringDuplicate(config->key_file); } if (i == 0) { thread_configs[i]->address = xstrdup(config->address); } else { thread_configs[i]->address = IncrementIPaddress(thread_configs[i-1]->address); } } CFTestD_ConfigDestroy(config); bool failure = false; for (int i = 0; !failure && (i < n_threads); i++) { int ret = pthread_create(&(thread_configs[i]->t_id), NULL, CFTestD_ServeReport, thread_configs[i]); if (ret != 0) { Log(LOG_LEVEL_ERR, "Failed to create a new thread nr. %d: %s\n", i, strerror(ret)); failure = true; } } if (failure) { return EXIT_FAILURE; } for (int i = 0; i < n_threads; i++) { int ret = pthread_join(thread_configs[i]->t_id, NULL); if (ret != 0) { Log(LOG_LEVEL_ERR, "Failed to join the thread nr. %d: %s\n", i, strerror(ret)); } else { failure = failure && (thread_configs[i]->ret != 0); } CFTestD_ConfigDestroy(thread_configs[i]); } return failure ? EXIT_FAILURE : EXIT_SUCCESS; }
void StartServer(EvalContext *ctx, Policy **policy, GenericAgentConfig *config) { int sd = -1; fd_set rset; int ret_val; CfLock thislock; time_t last_policy_reload = 0; extern int COLLECT_WINDOW; struct sockaddr_storage cin; socklen_t addrlen = sizeof(cin); MakeSignalPipe(); signal(SIGINT, HandleSignalsForDaemon); signal(SIGTERM, HandleSignalsForDaemon); signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, HandleSignalsForDaemon); signal(SIGUSR2, HandleSignalsForDaemon); ServerTLSInitialize(); sd = SetServerListenState(ctx, QUEUESIZE, SERVER_LISTEN, &InitServer); TransactionContext tc = { .ifelapsed = 0, .expireafter = 1, }; Policy *server_cfengine_policy = PolicyNew(); Promise *pp = NULL; { Bundle *bp = PolicyAppendBundle(server_cfengine_policy, NamespaceDefault(), "server_cfengine_bundle", "agent", NULL, NULL); PromiseType *tp = BundleAppendPromiseType(bp, "server_cfengine"); pp = PromiseTypeAppendPromise(tp, config->input_file, (Rval) { NULL, RVAL_TYPE_NOPROMISEE }, NULL); } assert(pp); thislock = AcquireLock(ctx, pp->promiser, VUQNAME, CFSTARTTIME, tc, pp, false); if (thislock.lock == NULL) { PolicyDestroy(server_cfengine_policy); return; } if (sd != -1) { Log(LOG_LEVEL_VERBOSE, "Listening for connections ..."); } #ifdef __MINGW32__ if (!NO_FORK) { Log(LOG_LEVEL_VERBOSE, "Windows does not support starting processes in the background - starting in foreground"); } #else /* !__MINGW32__ */ if ((!NO_FORK) && (fork() != 0)) { _exit(EXIT_SUCCESS); } if (!NO_FORK) { ActAsDaemon(); } #endif /* !__MINGW32__ */ WritePID("cf-serverd.pid"); /* Andrew Stribblehill <*****@*****.**> -- close sd on exec */ #ifndef __MINGW32__ fcntl(sd, F_SETFD, FD_CLOEXEC); #endif CollectCallStart(COLLECT_INTERVAL); while (!IsPendingTermination()) { /* Note that this loop logic is single threaded, but ACTIVE_THREADS might still change in threads pertaining to service handling */ if (ThreadLock(cft_server_children)) { if (ACTIVE_THREADS == 0) { CheckFileChanges(ctx, policy, config, &last_policy_reload); } ThreadUnlock(cft_server_children); } // Check whether we have established peering with a hub if (CollectCallHasPending()) { int waiting_queue = 0; int new_client = CollectCallGetPending(&waiting_queue); if (waiting_queue > COLLECT_WINDOW) { Log(LOG_LEVEL_INFO, "Closing collect call because it would take" "longer than the allocated window [%d]", COLLECT_WINDOW); } ConnectionInfo *info = ConnectionInfoNew(); if (info) { ConnectionInfoSetSocket(info, new_client); ServerEntryPoint(ctx, POLICY_SERVER, info); CollectCallMarkProcessed(); } } else { /* check if listening is working */ if (sd != -1) { // Look for normal incoming service requests int signal_pipe = GetSignalPipe(); FD_ZERO(&rset); FD_SET(sd, &rset); FD_SET(signal_pipe, &rset); Log(LOG_LEVEL_DEBUG, "Waiting at incoming select..."); struct timeval timeout = { .tv_sec = 60, .tv_usec = 0 }; int max_fd = (sd > signal_pipe) ? (sd + 1) : (signal_pipe + 1); ret_val = select(max_fd, &rset, NULL, NULL, &timeout); // Empty the signal pipe. We don't need the values. unsigned char buf; while (recv(signal_pipe, &buf, 1, 0) > 0) {} if (ret_val == -1) /* Error received from call to select */ { if (errno == EINTR) { continue; } else { Log(LOG_LEVEL_ERR, "select failed. (select: %s)", GetErrorStr()); exit(1); } } else if (!ret_val) /* No data waiting, we must have timed out! */ { continue; } if (FD_ISSET(sd, &rset)) { int new_client = accept(sd, (struct sockaddr *)&cin, &addrlen); if (new_client == -1) { continue; } /* Just convert IP address to string, no DNS lookup. */ char ipaddr[CF_MAX_IP_LEN] = ""; getnameinfo((struct sockaddr *) &cin, addrlen, ipaddr, sizeof(ipaddr), NULL, 0, NI_NUMERICHOST); ConnectionInfo *info = ConnectionInfoNew(); if (info) { ConnectionInfoSetSocket(info, new_client); ServerEntryPoint(ctx, ipaddr, info); } } } } } CollectCallStop(); PolicyDestroy(server_cfengine_policy); } /*********************************************************************/ /* Level 2 */ /*********************************************************************/ int InitServer(size_t queue_size) { int sd = -1; if ((sd = OpenReceiverChannel()) == -1) { Log(LOG_LEVEL_ERR, "Unable to start server"); exit(EXIT_FAILURE); } if (listen(sd, queue_size) == -1) { Log(LOG_LEVEL_ERR, "listen failed. (listen: %s)", GetErrorStr()); exit(EXIT_FAILURE); } return sd; }