bool_t XPlat_SocketUtils_CreateListening( XPlat_Socket* sock, XPlat_Port* port, bool_t nonblock ) { static int backlog = 128; int err, optval; bool_t soret, success; XPlat_Socket _sock; XPlat_Port _port = *port; const char* err_str = NULL; struct sockaddr_in local_addr; if( InvalidPort == _port ) _port = 0; _sock = socket( AF_INET, SOCK_STREAM, 0 ); if( -1 == _sock ) { err = XPlat_NetUtils_GetLastError(); err_str = XPlat_Error_GetErrorString(err); xplat_dbg( 1, xplat_printf(FLF, stderr, "socket() failed with '%s'\n", err_str) ); return false; } xplat_dbg( 3, xplat_printf(FLF, stderr, "sock:%d, port:%d\n", _sock, _port) ); // Close socket on exec if( ! SetCloseOnExec(_sock) ) { xplat_dbg( 1, xplat_printf(FLF, stderr, "failed to set close-on-exec\n") ); } // Set listening socket to non-blocking if requested if( nonblock ) { if( ! XPlat_SocketUtils_SetBlockingMode(_sock, false) ) xplat_dbg( 1, xplat_printf(FLF, stderr, "failed to set non-blocking\n") ); } #ifndef os_windows /* Set the socket so that it does not hold onto its port after * the process exits (needed because on at least some platforms we * use well-known ports when connecting sockets) */ optval = 1; soret = XPlat_SocketUtils_SetOption( _sock, SOL_SOCKET, SO_REUSEADDR, (void*) &optval, (socklen_t) sizeof(optval) ); if( ! soret ) { err = XPlat_NetUtils_GetLastError(); err_str = XPlat_Error_GetErrorString(err); xplat_dbg( 1, xplat_printf(FLF, stderr, "setsockopt() failed with '%s'\n", err_str) ); } #endif memset( &local_addr, 0, sizeof(local_addr) ); local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = htonl( INADDR_ANY ); if( 0 != _port ) { // try to bind and listen using the supplied port local_addr.sin_port = htons( _port ); if( -1 == bind(_sock, (struct sockaddr*)&local_addr, sizeof(local_addr)) ) { err = XPlat_NetUtils_GetLastError(); err_str = XPlat_Error_GetErrorString(err); xplat_dbg( 1, xplat_printf(FLF, stderr, "bind() to static port %d failed with '%s'\n", _port, err_str) ); XPlat_SocketUtils_Close( _sock ); return false; } } #ifndef os_windows // else, the system will assign a port for us in listen if( -1 == listen(_sock, backlog) ) { err = XPlat_NetUtils_GetLastError(); err_str = XPlat_Error_GetErrorString(err); xplat_dbg( 1, xplat_printf(FLF, stderr, "listen() failed with '%s'\n", err_str) ); XPlat_SocketUtils_Close( _sock ); return false; } // determine which port we were actually assigned to if( ! XPlat_SocketUtils_GetPort(_sock, &_port) ) { xplat_dbg( 1, xplat_printf(FLF, stderr, "failed to obtain port from socket\n" ) ); XPlat_SocketUtils_Close( _sock ); return false; } #else // try binding ports, starting from 1st dynamic port _port = 49152; success = false; do { local_addr.sin_port = htons( _port ); if( -1 == bind(_sock, (struct sockaddr*)&local_addr, sizeof(local_addr)) ) { err = XPlat_NetUtils_GetLastError(); if( XPlat_Error_EAddrInUse( err ) ) { ++_port; continue; } else { err_str = XPlat_Error_GetErrorString(err); xplat_dbg( 1, xplat_printf(FLF, stderr, "bind() to dynamic port %d failed with '%s'\n", _port, err_str) ); XPlat_SocketUtils_Close( _sock ); return false; } } else { if( -1 == listen(_sock, backlog) ) { err = XPlat_NetUtils_GetLastError(); if( XPlat_Error_EAddrInUse( err ) ) { ++_port; continue; } else { err_str = XPlat_Error_GetErrorString(err); xplat_dbg( 1, xplat_printf(FLF, stderr, "listen() failed with '%s'\n", err_str) ); XPlat_SocketUtils_Close( _sock ); return false; } } success = true; } } while( ! success ); #endif // Turn off Nagle algorithm if( ! SetTcpNoDelay(_sock) ) { xplat_dbg( 1, xplat_printf(FLF, stderr, "failed to set TCP_NODELAY\n") ); } *port = _port; *sock = _sock; xplat_dbg( 3, xplat_printf(FLF, stderr, "returning socket=%d, port=%hu\n", _sock, _port) ); return true; }
/* Prepare synthetic agent promise and lock it. */ static CfLock AcquireServerLock(EvalContext *ctx, GenericAgentConfig *config, Policy *server_policy) { Promise *pp = NULL; { Bundle *bp = PolicyAppendBundle(server_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, NULL); } assert(pp); TransactionContext tc = { .ifelapsed = 0, .expireafter = 1, }; return AcquireLock(ctx, pp->promiser, VUQNAME, CFSTARTTIME, tc, pp, false); } /* Final preparations for running as server */ static void PrepareServer(int sd) { if (sd != -1) { Log(LOG_LEVEL_VERBOSE, "Listening for connections ..."); } if (!NO_FORK) #ifdef __MINGW32__ { Log(LOG_LEVEL_VERBOSE, "Windows does not support starting processes in the background - running in foreground"); } #else { if (fork() != 0) { _exit(EXIT_SUCCESS); } ActAsDaemon(); } #endif /* Close sd on exec, needed for not passing the socket to cf-runagent * spawned commands. */ SetCloseOnExec(sd, true); Log(LOG_LEVEL_NOTICE, "Server is starting..."); WritePID("cf-serverd.pid"); /* Arranges for atexit() to tidy it away */ } /* Wait for connection-handler threads to finish their work. * * @return Number of live threads remaining after waiting. */ static int WaitOnThreads() { int result = 1; for (int i = 2; i > 0; i--) { if (ThreadLock(cft_server_children)) { result = ACTIVE_THREADS; ThreadUnlock(cft_server_children); } if (result == 0) { break; } Log(LOG_LEVEL_VERBOSE, "Waiting %ds for %d connection threads to finish", i, result); sleep(1); } if (result > 0) { Log(LOG_LEVEL_VERBOSE, "There are %d connection threads left, exiting anyway", result); } else { assert(result == 0); Log(LOG_LEVEL_VERBOSE, "All threads are done, cleaning up allocations"); ClearAuthAndACLs(); ServerTLSDeInitialize(); } return result; }
/** * Makes the needed initializations * * @param const string& p_loggerName - the logger object name * @param const string& p_logConfFile - the full path of the logger configuration file * @param const string& p_pidFile - the full path of the pid file * @param const string& p_lockFile - the full path of the lock files */ int Application::init(const string& p_logConfFile, const string& p_pidFile, const string& p_lockFile) { if (m_state > APP_RESET) { return 1; } signal( SIGABRT, HandlerFATAL );/// do NOT use delayed processing with HandlerFATAL. Stack trace must be dumped on event signal( SIGSEGV, HandlerFATAL );/// do NOT use delayed processing with HandlerFATAL. Stack trace must be dumped on event signal( SIGFPE , HandlerFATAL );/// do NOT use delayed processing with HandlerFATAL. Stack trace must be dumped on event SignalsManager::Ignore(SIGTTOU); SignalsManager::Ignore(SIGTTIN); SignalsManager::Ignore(SIGTSTP); SignalsManager::Ignore(SIGPIPE); SignalsManager::Ignore(SIGCHLD); SignalsManager::Ignore(SIGALRM);//ignore alarm signal SignalsManager::Ignore(SIGUSR1); SignalsManager::Install(SIGTERM, HandlerSIGTERM); SignalsManager::Install(SIGINT, HandlerSIGTERM); SignalsManager::Install(SIGUSR2, HandlerSIG_USR2); // used to create SystemManager commands(sm_commands.ini). SignalsManager::Install(SIGHUP, HandlerSIG_HUP); // used to reload provisioning records(system_manager.ini) AND reload configuration files(config.ini, subnet.ini, subnet_xx.ini). Isa100::Common::SmSettingsLogic::instance().logConfFileName = p_logConfFile; NE::Common::SettingsLogic::managerVersion = SYSTEM_MANAGER_VERSION; LOG_INIT(p_logConfFile); time_t ltime; ltime = time(NULL); struct tm *Tm; Tm = localtime(<ime); LOG_INFO("Starting System Manager version " << SYSTEM_MANAGER_VERSION << ". Started on " << std::setw(2) << std::setfill('0') << Tm->tm_mday << ":" << std::setw(2) << std::setfill('0') << Tm->tm_mon + 1 << ":" << std::setw(2) << std::setfill('0') << Tm->tm_year + 1900 << "," << std::setw(2) << std::setfill('0') << Tm->tm_hour << ":" << std::setw(2) << std::setfill('0') << Tm->tm_min << ":" << std::setw(2) << std::setfill('0') << Tm->tm_sec); LOG_INFO("signal handlers initialized"); Isa100::Common::SmSettingsLogic::instance().load(); m_pidFile = Isa100::Common::SmSettingsLogic::instance().lockFilesFolder; m_pidFile += p_pidFile; m_lockFile = Isa100::Common::SmSettingsLogic::instance().lockFilesFolder; m_lockFile += p_lockFile; m_syncFd = open(m_lockFile.c_str(), O_RDWR | O_CREAT, 0666); if (flock(m_syncFd, LOCK_EX | LOCK_NB)) { LOG_FATAL("another instance of this application is already running - exiting"); std::cout << "another instance of this application is already running - exiting"; exit(4); } if (!SetCloseOnExec(m_syncFd)) { exit(5); } m_state = APP_INITIALIZED; return 1; }
static NTSTATUS InitEventThread( PKQUEUE_POOL pPool, PLW_THREAD_POOL_ATTRIBUTES pAttrs, PKQUEUE_THREAD pThread, ULONG ulCpu ) { NTSTATUS status = STATUS_SUCCESS; struct kevent event; pthread_attr_t threadAttr; BOOLEAN bThreadAttrInit = FALSE; status = LwErrnoToNtStatus(pthread_attr_init(&threadAttr)); GOTO_ERROR_ON_STATUS(status); bThreadAttrInit = TRUE; pThread->pPool = pPool; status = LwErrnoToNtStatus(pthread_mutex_init(&pThread->Lock, NULL)); GOTO_ERROR_ON_STATUS(status); status = LwErrnoToNtStatus(pthread_cond_init(&pThread->Event, NULL)); GOTO_ERROR_ON_STATUS(status); if (pipe(pThread->SignalFds) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } SetCloseOnExec(pThread->SignalFds[0]); SetCloseOnExec(pThread->SignalFds[1]); if ((pThread->KqueueFd = kqueue()) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } SetCloseOnExec(pThread->KqueueFd); /* Add signal fd to kqueue set */ EV_SET(&event, pThread->SignalFds[0], EVFILT_READ, EV_ADD, 0, 0, NULL); if (kevent(pThread->KqueueFd, &event, 1, NULL, 0, NULL) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } RingInit(&pThread->Tasks); status = LwRtlSetAffinityThreadAttribute(&threadAttr, ulCpu); GOTO_ERROR_ON_STATUS(status); if (pAttrs && pAttrs->ulTaskThreadStackSize) { status = LwErrnoToNtStatus( pthread_attr_setstacksize(&threadAttr, pAttrs->ulTaskThreadStackSize)); GOTO_ERROR_ON_STATUS(status); } status = LwErrnoToNtStatus( pthread_create( &pThread->Thread, &threadAttr, EventThread, pThread)); GOTO_ERROR_ON_STATUS(status); error: if (bThreadAttrInit) { pthread_attr_destroy(&threadAttr); } return status; }
static bool IsReadReady(int fd, int timeout_sec) { fd_set rset; FD_ZERO(&rset); FD_SET(fd, &rset); struct timeval tv = { .tv_sec = timeout_sec, .tv_usec = 0, }; int ret = select(fd + 1, &rset, NULL, NULL, &tv); if(ret < 0) { Log(LOG_LEVEL_ERR, "IsReadReady: Failed checking for data. (select: %s)", GetErrorStr()); return false; } if(FD_ISSET(fd, &rset)) { return true; } if(ret == 0) // timeout { return false; } // can we get here? Log(LOG_LEVEL_ERR, "IsReadReady: Unknown outcome (ret > 0 but our only fd is not set). (select: %s)", GetErrorStr()); return false; } #if defined(__hpux) && defined(__GNUC__) #pragma GCC diagnostic warning "-Wstrict-aliasing" #endif #endif /* __MINGW32__ */ void LocalExec(const ExecConfig *config) { time_t starttime = time(NULL); void *thread_name = ThreadUniqueName(); { char starttime_str[64]; cf_strtimestamp_local(starttime, starttime_str); Log(LOG_LEVEL_VERBOSE, "----------------------------------------------------------------"); Log(LOG_LEVEL_VERBOSE, " LocalExec(%sscheduled) at %s", config->scheduled_run ? "" : "not ", starttime_str); Log(LOG_LEVEL_VERBOSE, "----------------------------------------------------------------"); } /* Need to make sure we have LD_LIBRARY_PATH here or children will die */ char cmd[CF_BUFSIZE]; if (strlen(config->exec_command) > 0) { strlcpy(cmd, config->exec_command, CF_BUFSIZE); if (!strstr(cmd, "-Dfrom_cfexecd")) { strcat(cmd, " -Dfrom_cfexecd"); } } else { ConstructFailsafeCommand(config->scheduled_run, cmd); } char esc_command[CF_BUFSIZE]; strlcpy(esc_command, MapName(cmd), CF_BUFSIZE); char filename[CF_BUFSIZE]; { char line[CF_BUFSIZE]; snprintf(line, CF_BUFSIZE, "_%jd_%s", (intmax_t) starttime, CanonifyName(ctime(&starttime))); { char canonified_fq_name[CF_BUFSIZE]; strlcpy(canonified_fq_name, config->fq_name, CF_BUFSIZE); CanonifyNameInPlace(canonified_fq_name); snprintf(filename, CF_BUFSIZE, "%s/outputs/cf_%s_%s_%p", GetWorkDir(), canonified_fq_name, line, thread_name); MapName(filename); } } /* What if no more processes? Could sacrifice and exec() - but we need a sentinel */ FILE *fp = fopen(filename, "w"); if (!fp) { Log(LOG_LEVEL_ERR, "Couldn't open '%s' - aborting exec. (fopen: %s)", filename, GetErrorStr()); return; } /* * Don't inherit this file descriptor on fork/exec */ if (fileno(fp) != -1) { SetCloseOnExec(fileno(fp), true); } Log(LOG_LEVEL_VERBOSE, "Command => %s", cmd); FILE *pp = cf_popen_sh(esc_command, "r"); if (!pp) { Log(LOG_LEVEL_ERR, "Couldn't open pipe to command '%s'. (cf_popen: %s)", cmd, GetErrorStr()); fclose(fp); return; } Log(LOG_LEVEL_VERBOSE, "Command is executing...%s", esc_command); int count = 0; int complete = false; size_t line_size = CF_BUFSIZE; char *line = xmalloc(line_size); while (!IsPendingTermination()) { if (!IsReadReady(fileno(pp), config->agent_expireafter * SECONDS_PER_MINUTE)) { char errmsg[] = "cf-execd: timeout waiting for output from agent" " (agent_expireafter=%d) - terminating it\n"; fprintf(fp, errmsg, config->agent_expireafter); /* Trim '\n' before Log()ing. */ errmsg[strlen(errmsg) - 1] = '\0'; Log(LOG_LEVEL_NOTICE, errmsg, config->agent_expireafter); count++; pid_t pid_agent; if (PipeToPid(&pid_agent, pp)) { ProcessSignalTerminate(pid_agent); } else { Log(LOG_LEVEL_ERR, "Could not get PID of agent"); } break; } ssize_t res = CfReadLine(&line, &line_size, pp); if (res == -1) { if (feof(pp)) { complete = true; } else { Log(LOG_LEVEL_ERR, "Unable to read output from command '%s'. (cfread: %s)", cmd, GetErrorStr()); } break; } const char *sp = line; while (*sp != '\0' && isspace(*sp)) { sp++; } if (*sp != '\0') /* line isn't entirely blank */ { char *line_escaped = xmalloc(2 * line_size); ReplaceStr(line, line_escaped, 2 * line_size, "%", "%%"); fprintf(fp, "%s\n", line_escaped); count++; /* If we can't send mail, log to syslog */ if (strlen(config->mail_to_address) == 0) { strncat(line_escaped, "\n", sizeof(line_escaped) - 1 - strlen(line_escaped)); if ((strchr(line_escaped, '\n')) == NULL) { line_escaped[sizeof(line_escaped) - 2] = '\n'; } Log(LOG_LEVEL_INFO, "%s", line_escaped); } line[0] = '\0'; free(line_escaped); } } free(line); cf_pclose(pp); Log(LOG_LEVEL_DEBUG, "Closing fp"); fclose(fp); Log(LOG_LEVEL_VERBOSE, complete ? "Command is complete" : "Terminated command"); if (count) { Log(LOG_LEVEL_VERBOSE, "Mailing result"); MailResult(config, filename); } else { Log(LOG_LEVEL_VERBOSE, "No output"); unlink(filename); } }
/** make any necessary initialisation */ int CApp::Init( const char *p_lpszLogFile, int p_nMaxLogSize /*= 524288*/ ) { //Modified by Claudiu Hobeanu on 2004/10/25 14:34 // Changes : move signals handle in CSignalsMgr CSignalsMgr::Ignore(SIGHUP); CSignalsMgr::Ignore(SIGTTOU); CSignalsMgr::Ignore(SIGTTIN); CSignalsMgr::Ignore(SIGTSTP); CSignalsMgr::Ignore(SIGPIPE); CSignalsMgr::Install( SIGTERM, HandlerSIGTERM ); CSignalsMgr::Install( SIGINT, HandlerSIGTERM ); ///NEVER USE CSignalsMgr TO HANDLE SIGABRT/SIGSEGV signal( SIGABRT, HandlerFATAL );/// do NOT use delayed processing with HandlerFATAL. Stack trace must be dumped on event signal( SIGSEGV, HandlerFATAL );/// do NOT use delayed processing with HandlerFATAL. Stack trace must be dumped on event signal( SIGFPE, HandlerFATAL );/// do NOT use delayed processing with HandlerFATAL. Stack trace must be dumped on event //close stdin, stdout and stderr then open them as /dev/null (fix problems with fd's after forking) #if !defined( DONT_CLOSE_STD ) close(0); close(1); close(2); open("/dev/null", O_RDWR); open("/dev/null", O_RDWR); open("/dev/null", O_RDWR); #endif strcpy(m_szAppPidFile, p_lpszLogFile); int nLen = strlen(m_szAppPidFile); if ( m_szAppPidFile[nLen-1] == 'g' && m_szAppPidFile[nLen-2] == 'o' && m_szAppPidFile[nLen-3] == 'l' && m_szAppPidFile[nLen-4] == '.' ) { m_szAppPidFile[nLen-4] = 0; } char szLockFile[256]; strcpy(szLockFile, m_szAppPidFile); strcat(szLockFile, ".flock"); strcat(m_szAppPidFile, ".pid" ); //open ilog file with default parameters... to have something... if( !g_stLog.Open(p_lpszLogFile, "Start session", p_nMaxLogSize)) return 0; LOG( "CApp(%s)::Init - version: %s", m_szModule, version() ); m_nSyncFd = open( szLockFile, O_RDWR | O_CREAT, 0666 ); if( flock( m_nSyncFd, LOCK_EX | LOCK_NB ) ) { LOG( "Process %d try to start but another instance of program is running ",getpid()); return 0; } SetCloseOnExec(m_nSyncFd); LOG("System MEMORY Available: %dkB", GetSysFreeMemK() ); if (!m_oModulesActivity.Open()) { return 0; } return 1; }