示例#1
0
文件: child_map.c 项目: bradh/LDM
/*
 * Adds an entry to a child-map.
 *
 * @retval 0    Success
 * @retval 1    Usage error. \c log_start() called.
 * @retval 2    O/S failure. \c log_start() called.
 */
int cm_add_string(
    ChildMap* const     map,            /**< [in/out] Pointer to the child-map
                                         */
    const pid_t         pid,            /**< [in] Process ID of the child.
                                         *   Must not already exist in map. */
    const char* const   command)        /**< [in] Command-line of the child.
                                         *   Defensively copied. */
{
    int    status;

    if (NULL == map) {
        LOG_START0("Null map argument");
        status = 1;
    }
    else if (NULL == command) {
        LOG_START0("Null command argument");
        status = 1;
    }
    else {
        status = cm_contains(map, pid);

        if (0 == status) {
            Entry* const    entry = (Entry*)malloc(sizeof(Entry));

            if (NULL == entry) {
                LOG_SERROR0("Couldn't allocate new entry");
                status = 2;
            }
            else {
                entry->command = strdup(command);

                if (NULL == entry->command) {
                    LOG_SERROR0("Couldn't duplicate command-line");
                    status = 2;
                }
                else {
                    entry->pid = pid;

                    if (NULL == tsearch(entry, &map->root, compare)) {
                        LOG_SERROR0("Couldn't add entry to map");
                        status = 2;
                    }
                    else {
                        map->count++;
                        status = 0;
                    }

                    if (0 != status)
                        free(entry->command);
                }                       /* "entry->command" allocated */

                if (0 != status)
                    free(entry);
            }                           /* "entry" allocated */
        }                               /* "pid" not in map */
    }                                   /* valid arguments */

    return status;
}
示例#2
0
/**
 * Returns a new product-maker.
 *
 * This function is thread-safe.
 *
 * @retval 0    Success.
 * @retval 1    Usage failure. \c log_start() called.
 * @retval 2    O/S failure. \c log_start() called.
 */
int pmNew(
    Fifo* const             fifo,           /**< [in] Pointer to FIFO from
                                              *  which to get data */
    LdmProductQueue* const  lpq,            /**< [in] LDM product-queue into
                                              *  which to put data-products */
    ProductMaker** const    productMaker)   /**< [out] Pointer to pointer to
                                              *  returned product-maker */
{
    int             status = 2;             /* default failure */
    ProductMaker*   w = (ProductMaker*)malloc(sizeof(ProductMaker));

    if (NULL == w) {
        LOG_SERROR0("Couldn't allocate new product-maker");
    }
    else {
        MD5_CTX*    md5ctxp = new_MD5_CTX();

        if (NULL == md5ctxp) {
            LOG_SERROR0("Couldn't allocate MD5 object");
        }
        else {
            if ((status = pthread_mutex_init(&w->mutex, NULL)) != 0) {
                LOG_ERRNUM0(status, "Couldn't initialize product-maker mutex");
                status = 2;
            }
            else {
                w->fifo = fifo;
                w->ldmProdQueue = lpq;
                w->npackets = 0;
                w->nmissed = 0;
                w->nprods = 0;
                w->md5ctxp = md5ctxp;
                w->status = 0;
                *productMaker = w;
            }
        }
    }

    return status;
}
示例#3
0
static void
waitUntilDone(void)
{
    struct sigaction newAction;

    (void)sigemptyset(&newAction.sa_mask);
    newAction.sa_flags = 0;
    newAction.sa_handler = termSigHandler;

    struct sigaction oldAction;
    if (setTermSigHandling(&newAction, &oldAction)) {
        LOG_SERROR0("Couldn't set termination signal handling");
        abortProcess();
    }

    waitForDoneCondition();

    if (setTermSigHandling(&oldAction, NULL)) {
        LOG_SERROR0("Couldn't reset termination signal handling");
        abortProcess();
    }
}
示例#4
0
文件: child_map.c 项目: bradh/LDM
/**
 * Returns a new instance of a child-map.
 *
 * @retval NULL         Failure. \c log_start() called.
 * @retval !NULL        Pointer to a new instance.
 */
ChildMap* cm_new(void)
{
    ChildMap*   map = (ChildMap*)malloc(sizeof(ChildMap));

    if (NULL == map) {
        LOG_SERROR0("Couldn't allocate new child-map");
    }
    else {
        map->root = NULL;
        map->count = 0;
        map->buf = strBuf_new(132);

        if (NULL == map->buf) {
            LOG_SERROR0("Couldn't allocate command-line buffer");
            free(map);

            map = NULL;
        }
    }

    return map;
}
示例#5
0
static int
mlsm_ensureCleanup(void)
{
    if (cleanupRegistered)
        return 0;

    int status = atexit(mlsm_killChild);
    if (status) {
        LOG_SERROR0("Couldn't register cleanup routine");
        status = LDM7_SYSTEM;
    }
    else {
        cleanupRegistered = true;
    }
    return status;
}
示例#6
0
/**
 * @param[in]       newAction
 * @param[out]      oldAction
 * @retval 0        Success
 * @retval ENOTSUP  The SA_SIGINFO bit flag is set in the `sa_flags` field of
 *                  `newAction` and the implementation does not support either
 *                  the Realtime Signals Extension option, or the XSI Extension
 *                  option.
 */
static int
setTermSigHandling(
    struct sigaction* newAction,
    struct sigaction* oldAction)
{
    int              status;

    if (sigaction(SIGINT, newAction, oldAction) ||
            sigaction(SIGTERM, newAction, oldAction)) {
        LOG_SERROR0("sigaction() failure");
        status = errno;
    }
    else {
        status = 0;
    }

    return status;
}
示例#7
0
/**
 * Obtains a read-write lock based on an existing semaphore set.
 *
 * @retval RWL_SUCCESS  Success.
 * @retval RWL_EXIST    The lock doesn't exist.
 * @retval RWL_SYSTEM   System error. See "errno". log_add() called.
 */
static srwl_Status getLock(
        const key_t key /**< [in] the key associated with the semaphore */,
        int* const semId /**< [out] pointer to the semaphore identifier */)
{
    srwl_Status status;
    int id = semget(key, SI_NUM_SEMS, read_write);

    if (-1 == id) {
        LOG_SERROR0("Couldn't get existing semaphore set");
        status = RWL_EXIST;
    }
    else {
        *semId = id;
        status = RWL_SUCCESS;
    }

    return status;
}
示例#8
0
/**
 * Unconditionally deletes a read/write lock by IPC key. The Semaphore on
 * which the lock is based is deleted.
 *
 * @param key           The IPC key
 * @retval RWL_SUCCESS  Success
 * @retval RWL_EXIST    The key has no associated read/write lock
 * @retval RWL_SYSTEM   System error. log_add() called.
 */
srwl_Status srwl_deleteByKey(
        const key_t key)
{
    int status = semget(key, 0, read_write);

    if (-1 == status) {
        LOG_SERROR0("Couldn't get semaphore set");
        status = (ENOENT == errno) ? RWL_EXIST : RWL_SYSTEM;
    }
    else if (semctl(status, 0, IPC_RMID)) {
        LOG_SERROR1("Couldn't delete existing semaphore set %d", status);
        status = RWL_SYSTEM;
    }
    else {
        status = RWL_SUCCESS;
    }

    return status;
}
示例#9
0
/**
 * Creates a read/write lock based on creating a new semaphore set. Any previous
 * semaphore set will be deleted.
 *
 * @retval RWL_SUCCESS  Success
 * @retval RWL_SYSTEM   System error. See "errno". log_add() called.
 */
static srwl_Status createLock(
        const key_t key /**< [in] the key associated with the semaphore */,
        int* const semId /**< [out] pointer to the semaphore identifier */)
{
    srwl_Status status;
    int id;

    (void) deleteSemSet(semget(key, 0, read_write));
    log_clear();

    id = semget(key, SI_NUM_SEMS, IPC_CREAT | IPC_EXCL | read_write);

    if (-1 == id) {
        LOG_SERROR0("Couldn't create semaphore set");
        status = RWL_SYSTEM;
    }
    else {
        unsigned short semVal[SI_NUM_SEMS];
        union semun {
            int val; /* Value for SETVAL */
            struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
            unsigned short *array; /* Array for GETALL, SETALL */
        } arg;

        semVal[SI_LOCK] = 1;
        semVal[SI_NUM_READERS] = 0;
        arg.array = semVal;

        if (semctl(id, 0, SETALL, arg) == -1) {
            LOG_SERROR1("Couldn't initialize semaphore set: semId=%d", id);
            (void) deleteSemSet(id);
            status = RWL_SYSTEM;
        }
        else {
            *semId = id;
            status = RWL_SUCCESS;
        }
    }

    return status;
}
示例#10
0
/**
 * Initializes logging.
 *
 * @retval 0    Success
 * @retval 1    Usage error.
 */
static int initLogging(
    const char* const   progName,       /**< [in] Name of the program */
    const unsigned      logOptions,     /**< [in] Logging options */
    const unsigned      logFacility,    /**< [in] Logging facility */
    const char* const   logPath)        /**< [in] Pathname of the log file,
                                          *  "-", or NULL */
{
    int status;

    if (openulog(progName, logOptions, logFacility, logPath) == -1) {
        LOG_SERROR0("Couldn't initialize logging");
        log_log(LOG_ERR);
        usage(progName);
        status = 1;
    }
    else {
        status = 0;
    }

    return status;
}
示例#11
0
文件: up7.c 项目: khallock/LDM
/**
 * Ensures the existence of a client-side transport on the TCP connection.
 *
 * @param[in] xprt      Server-side RPC transport.
 * @retval    true      Success.
 * @retval    false     System error. `log_start()` called.
 */
static bool
up7_ensureClientTransport(
        struct SVCXPRT* const xprt)
{
    bool success;

    if (clnt) {
        success = true;
    }
    else {
        /*
         * Create a client-side RPC transport on the TCP connection.
         */
        do {
            clnt = clnttcp_create(&xprt->xp_raddr, LDMPROG, SEVEN,
                    &xprt->xp_sock, MAX_RPC_BUF_NEEDED, 0);
            /* TODO: adjust sending buffer size in above */
        } while (clnt == NULL && rpc_createerr.cf_stat == RPC_TIMEDOUT);

        if (clnt == NULL ) {
            LOG_START2("Couldn't create client-side transport to downstream LDM-7 on "
                    "%s%s", hostbyaddr(&xprt->xp_raddr), clnt_spcreateerror(""));
            success = false;
        }
        else {
            if (atexit(up7_cleanup)) {
                LOG_SERROR0("Couldn't register upstream LDM-7 cleanup function");
                log_log(LOG_ERR);
                success = false;
            }
            else {
                success = true;
            }
        }
    }

    return success;
}
示例#12
0
文件: ldm_server.c 项目: khallock/LDM
/**
 * Feeds or notifies a downstream LDM. This function returns either NULL or a
 * reply to be sent to the downstream LDM (e.g., a RECLASS message) or
 * terminates this process (hopefully after sending some data).
 * 
 * @param xprt          [in/out] Pointer to server-side transport handle.
 * @param want          [in] Pointer to subscription by downstream LDM.
 *                      May contain a "signature" product-specification.
 * @param isNotifier    [in] Whether or not the upstream LDM is a feeder or a
 *                      notifier.
 * @param maxHereis     Maximum HEREIS size parameter. Ignored if "isNotifier"
 *                      is true.
 * @return              The reply for the downstream LDM or NULL if no reply
 *                      should be made.
 */
static fornme_reply_t*
feed_or_notify(
    SVCXPRT* const              xprt,
    const prod_class_t* const   want,
    const int                   isNotifier,
    const max_hereis_t          maxHereis)
{
    struct sockaddr_in      downAddr = *svc_getcaller(xprt);
    ErrorObj*               errObj;
    int                     status;
    char*                   downName = NULL;
    prod_class_t*           origSub = NULL;
    prod_class_t*           allowSub = NULL;
    const signaturet*       signature = NULL;
    UpFilter*               upFilter = NULL;
    fornme_reply_t*         reply = NULL;
    int                     isPrimary;
    static fornme_reply_t   theReply;
    static prod_class_t*    uldbSub = NULL;

    /*
     * Clean-up from a (possibly) previous invocation
     */
    (void)memset(&theReply, 0, sizeof(theReply));
    if (uldbSub != NULL) {
        free_prod_class(uldbSub);
        uldbSub = NULL;
    }

    downName = strdup(hostbyaddr(&downAddr));
    if (NULL == downName) {
        LOG_ADD1("Couldn't duplicate downstream host name: \"%s\"",
                hostbyaddr(&downAddr));
        log_log(LOG_ERR);
        svcerr_systemerr(xprt);
        goto return_or_exit;
    }

    set_abbr_ident(downName, isNotifier ? "(noti)" : "(feed)");

    /*
     * Remove any "signature" specification from the subscription.
     */
    if ((errObj = separateProductClass(want, &origSub, &signature)) != NULL) {
        err_log_and_free(errObj, ERR_FAILURE);
        svcerr_systemerr(xprt);
        goto free_down_name;
    }

    /*
     * Get the upstream filter
     */
    errObj = lcf_getUpstreamFilter(downName, &downAddr.sin_addr, origSub,
            &upFilter);
    if (errObj) {
        err_log_and_free(ERR_NEW(0, errObj,
                "Couldn't get \"upstream\" filter"), ERR_FAILURE);
        svcerr_systemerr(xprt);
        goto free_orig_sub;
    }
    if (NULL == upFilter) {
        err_log_and_free(ERR_NEW1(0, NULL,
                "Upstream filter prevents data-transfer: %s",
                s_prod_class(NULL, 0, origSub)), ERR_FAILURE);
        svcerr_weakauth(xprt);
        goto free_orig_sub;
    }

    /* TODO: adjust time? */

    /*
     * Reduce the subscription according to what the downstream host is allowed
     * to receive.
     */
    status = lcf_reduceToAllowed(downName, &downAddr.sin_addr, origSub,
            &allowSub);
    if (status == ENOMEM) {
        LOG_SERROR0("Couldn't compute wanted/allowed product intersection");
        log_log(LOG_ERR);
        svcerr_systemerr(xprt);
        goto free_up_filter;
    }
    if (status == EINVAL) {
        LOG_ADD1("Invalid pattern in product-class: %s",
                s_prod_class(NULL, 0, origSub));
        log_log(LOG_WARNING);
        theReply.code = BADPATTERN;
        reply = &theReply;
        goto free_up_filter;
    }
    assert(status == 0);
    (void) logIfReduced(origSub, allowSub, "ALLOW entries");

    /*
     * Reduce the subscription according to existing subscriptions from the
     * same downstream host and, if `isAntiDosEnabled()` returns `true`,
     * terminate every previously-existing upstream LDM process that's feeding
     * (not notifying) a subset of the subscription to the same IP address.
     *
     * The following relies on atexit()-registered cleanup for removal of the
     * entry from the upstream LDM database.
     */
    isPrimary = maxHereis > UINT_MAX / 2;
    status = uldb_addProcess(getpid(), 6, &downAddr, allowSub, &uldbSub,
            isNotifier, isPrimary);
    if (status) {
        LOG_ADD0("Couldn't add this process to the upstream LDM database");
        log_log(LOG_ERR);
        svcerr_systemerr(xprt);
        goto free_allow_sub;
    }
    (void) logIfReduced(allowSub, uldbSub, "existing subscriptions");

    /*
     * Send a RECLASS reply to the downstream LDM if appropriate.
     */
    if (!clss_eq(origSub, uldbSub)) {
        theReply.code = RECLASS;

        if (0 < uldbSub->psa.psa_len) {
            /*
             * The downstream LDM is allowed less than it requested and was
             * entered into the upstream LDM database.
             */
            (void)uldb_remove(getpid()); /* maybe next time */

            theReply.fornme_reply_t_u.prod_class = uldbSub;
        }
        else {
            /*
             * The downstream LDM isn't allowed anything and wasn't entered
             * into the upstream LDM database.
             */
            static prod_class noSub = { { 0, 0 }, /* TS_ZERO */
                { 0, 0 }, /* TS_ZERO */ { 0, (prod_spec *) NULL } };

            theReply.fornme_reply_t_u.prod_class = &noSub;
        }

        reply = &theReply;

        goto free_allow_sub;
    }

    /*
     * Reply to the downstream LDM that the subscription will be honored.
     */
    theReply.code = OK;
    theReply.fornme_reply_t_u.id = (unsigned) getpid();
    if (!svc_sendreply(xprt, (xdrproc_t)xdr_fornme_reply_t,
            (caddr_t)&theReply)) {
        LOG_ADD0("svc_sendreply(...) failure");
        log_log(LOG_ERR);
        svcerr_systemerr(xprt);
        goto free_allow_sub;
    }

    /*
     * Wait a second before sending anything to the downstream LDM.
     */
    (void) sleep(1);

    status = isNotifier
            ? up6_new_notifier(xprt->xp_sock, downName, &downAddr, uldbSub,
                    signature, getQueuePath(), interval, upFilter)
            : up6_new_feeder(xprt->xp_sock, downName, &downAddr, uldbSub,
                    signature, getQueuePath(), interval, upFilter,
                    isPrimary);

    svc_destroy(xprt); /* closes the socket */
    exit(status);

    /*
     * Reply and error handling:
     */
    free_allow_sub:
        free_prod_class(allowSub);

    free_up_filter:
        upFilter_free(upFilter);

    free_orig_sub:
        free_prod_class(origSub);

    free_down_name:
        free(downName);

    return_or_exit:
        return reply;
}
示例#13
0
/**
 * @retval LDM7_INVAL  No multicast sender child process exists.
 */
static int
sender_terminate(void)
{
    int retval = 0;
    int status;

#if CANCEL_SENDER
    udebug("Canceling sender thread");
    status = pthread_cancel(sender.thread);
    if (status) {
        LOG_ERRNUM0(status, "Couldn't cancel sender thread");
        retval = status;
    }
#else
    udebug("Writing to termination pipe");
    status = write(sender.fds[1], &status, sizeof(int));
    if (status == -1) {
        LOG_SERROR0("Couldn't write to termination pipe");
        retval = status;
    }
#endif

    void* statusPtr;

    udebug("Joining sender thread");
    status = pthread_join(sender.thread, &statusPtr);
    if (status) {
        LOG_ERRNUM0(status, "Couldn't join sender thread");
        retval = status;
    }

    if (statusPtr != PTHREAD_CANCELED) {
        status = *(int*)statusPtr;
        if (status) {
            LOG_START1("Sender task exit-status was %d", status);
            retval = status;
        }
    }

    (void)close(sender.sock);

    udebug("Terminating multicast sender");
    status = terminateMcastSender();
    if (status) {
        LOG_ADD0("Couldn't terminate multicast sender process");
        retval = status;
    }

    udebug("Clearing multicast LDM sender manager");
    status = mlsm_clear();
    if (status) {
        LOG_ADD0("mlsm_clear() failure");
        retval = status;
    }

    status = pq_close(pq);
    if (status) {
        LOG_ADD0("pq_close() failure");
        retval = status;
    }

    status = deleteProductQueue(UP7_PQ_PATHNAME);
    if (status) {
        LOG_ADD0("deleteProductQueue() failure");
        retval = status;
    }

    return retval;
}
示例#14
0
/*ARGSUSED*/
static int
exec_prodput(
     const product*     prod,
     int                argc,
     char**             argv,
     const void*        xprod,
     size_t             xlen)
{
    pid_t       pid = 0;

    if (NULL == execMap) {
        execMap = cm_new();

        if (NULL == execMap) {
            LOG_ADD0("Couldn't create child-process map for EXEC entries");
            log_log(LOG_ERR);
            pid = -1;
        }
    }                                   /* child-process map not allocated */

    if (0 == pid) {
        int     waitOnChild = 0;        /* default is not to wait */

        if (strcmp(argv[0], "-wait") == 0) {
            waitOnChild = 1;            /* => wait for child */
            argc--; argv++;
        }

        pid = ldmfork();
        if (-1 == pid) {
            LOG_SERROR0("Couldn't fork EXEC process");
            log_log(LOG_ERR);
        }
        else {
            if (0 == pid) {
                /*
                 * Child process.
                 *
                 * Detach the child process from the parents process group??
                 *
                 * (void) setpgid(0,0);
                 */
                const unsigned  ulogOptions = ulog_get_options();
                const char*     ulogIdent = getulogident();
                const unsigned  ulogFacility = getulogfacility();
                const char*     ulogPath = getulogpath();

                (void)signal(SIGTERM, SIG_DFL);
                (void)pq_close(pq);

                /*
                 * It is assumed that the standard input, output, and error
                 * streams are correctly established and should not be
                 * modified.
                 */

                /*
                 * Don't let the child process get any inappropriate privileges.
                 */
                endpriv();

                (void) execvp(argv[0], argv);
                openulog(ulogIdent, ulogOptions, ulogFacility, ulogPath);
                LOG_SERROR1("Couldn't execute command \"%s\"", argv[0]);
                log_log(LOG_ERR);
                exit(EXIT_FAILURE);
            }                           /* child process */
            else {
                /*
                 * Parent process.
                 */
                (void)cm_add_argv(execMap, pid, argv);

                if (!waitOnChild) {
                    udebug("    exec %s[%d]", argv[0], pid);
                }
                else {
                    udebug("    exec -wait %s[%d]", argv[0], pid);
                    (void)reap(pid, 0);
                }
            }
        }                               /* child-process forked */
    }                                   /* child-process map allocated */

    return -1 == pid ? -1 : 1;
}