static void CollectCallIfDue(EvalContext *ctx) { /* Check whether we have established peering with a hub */ if (CollectCallHasPending()) { extern int COLLECT_WINDOW; int waiting_queue = 0; int new_client = CollectCallGetPending(&waiting_queue); assert(new_client >= 0); if (waiting_queue > COLLECT_WINDOW) { Log(LOG_LEVEL_INFO, "Abandoning collect call attempt with queue longer than collect_window [%d > %d]", waiting_queue, COLLECT_WINDOW); cf_closesocket(new_client); CollectCallMarkProcessed(); } else { ConnectionInfo *info = ConnectionInfoNew(); assert(info); ConnectionInfoSetSocket(info, new_client); info->is_call_collect = true; /* Mark processed when done. */ ServerEntryPoint(ctx, PolicyServerGetIP(), info); } } }
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; }