Example #1
0
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;
}
Example #2
0
/* 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(&ltime);

    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;
}
Example #4
0
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;
}
Example #5
0
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;
}