コード例 #1
0
static ErrorObj*
ldm_clnt_nullproc(CLIENT* const clnt)
{
    struct timeval timeout;
    ErrorObj*       error;

    log_assert(NULL != clnt);

    timeout.tv_sec = 25;        /* RPC default */
    timeout.tv_usec = 0;

    if (clnt_call(clnt, NULLPROC, xdr_void, NULL, xdr_void,
            NULL, timeout) == 0) {
        error = NULL;
    }
    else {
        struct rpc_err rpcErr;

        clnt_geterr(clnt, &rpcErr);

        error = ERR_NEW(rpcErr.re_status, NULL, clnt_errmsg(clnt));
    }

    return error;
}
コード例 #2
0
ファイル: UpFilter.c プロジェクト: Unidata/LDM
/*
 * Returns a new upstream filter.
 *
 * Arguments:
 *      upFilter        Pointer to pointer to returned upstream filter.  Must
 *                      not be NULL.  Set on and only on success.
 * Returns:
 *      NULL            Success.
 *      else            Failure error object.
 */
ErrorObj*
upFilter_new(
    UpFilter** const    upFilter)
{
    ErrorObj*            errObj;
    size_t              nbytes = sizeof(UpFilter);
    UpFilter* const     filt = (UpFilter*)malloc(nbytes);

    if (NULL == filt) {
        errObj = ERR_NEW2(0, NULL, "Couldn't allocate %lu-bytes: %s",
            (unsigned long)nbytes, strerror(errno));
    }
    else {
        StringBuf* const strBuf = strBuf_new(132);

        if (NULL == strBuf) {
            errObj = ERR_NEW(0, NULL, strBuf_strerror(strBuf));

            free(filt);
        }
        else {
            filt->strBuf = strBuf;
            filt->head = NULL;
            filt->stringOutOfDate = 1;
            filt->count = 0;
            *upFilter = filt;
            errObj = NULL;              /* success */
        }
    }                                   /* "filt" allocated */

    return errObj;
}
コード例 #3
0
/**
 * Creates a TCP connection for an LDM client.
 *
 * @param addr      [in/out] Internet socket address of the LDM server. The
 *                  port number is ignored.
 * @param version   [in] Version of the LDM server to use.
 * @param port      [in] The port number of the LDM server.
 * @param client    [out] The client-side transport. Set upon success. The
 *                  client should free when it is no longer needed.
 * @param sock      [in] The socket to use for the connection.
 * @retval NULL     Success. "*client" is set.
 * @return          The error object. "*client" is not set.
 */
static ErrorObj*
ldm_clnt_tcp_create(
    struct sockaddr_in* const addr,             /* modified <=> success */
    unsigned                  version,
    unsigned                  port,             /* 0 => consult portmapper */
    CLIENT** const            client,           /* modified <=> success */
    int* const                sock)             /* modified <=> success */
{
    struct sockaddr_in        ad;
    CLIENT*                   clnt;
    int                       sck;
    ErrorObj*                 error;

    log_assert(NULL != addr);
    log_assert(NULL != client);
    log_assert(NULL != sock);

    ad = *addr;
    sck = RPC_ANYSOCK;
    ad.sin_port = (short)htons((short)port);
    clnt = clnttcp_create(&ad, LDMPROG, version, &sck, 0, 0);

    if (clnt) {
        *client = clnt;
        *addr = ad;
        *sock = sck;
        error = NULL;
    }
    else {
        int     code;

        if (rpc_createerr.cf_stat == RPC_TIMEDOUT) {
            code = LDM_CLNT_TIMED_OUT;
        }
        else if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) {
            code = LDM_CLNT_UNKNOWN_HOST;
        }
        else if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) {
            code = LDM_CLNT_BAD_VERSION;
        }
        else {
            code = LDM_CLNT_NO_CONNECT;
        }

        error = ERR_NEW(code, NULL, clnt_spcreateerror(""));
    }

    return error;
}
コード例 #4
0
/*
 * Potentially lengthy operation.
 */
ErrorObj*
ldm_clnt_addr(const char* const name, struct sockaddr_in* addr)
{
    struct sockaddr_in  ad;
    ErrorObj*            error;

    log_assert(NULL != name);
    log_assert(NULL != addr);

    if (addrbyhost(name, &ad)) {
        const char* msg;

        if (HOST_NOT_FOUND == h_errno) {
            msg = "no such host is known";
        }
        else if (NO_DATA == h_errno) {
            msg = "no address for name";
        }
        else if (NO_RECOVERY == h_errno) {
            msg = "unexpected server failure";
        }
        else if (TRY_AGAIN == h_errno) {
            msg = "try again later";
        }
        else {
            msg = "unknown error";
        }

        error = ERR_NEW(h_errno, NULL, msg);
    }
    else {
        *addr = ad;
        error = NULL;
    }

    return error;
}
コード例 #5
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;
}
コード例 #6
0
ファイル: UpFilter.c プロジェクト: Unidata/LDM
/*
 * Adds a filter-component to an upstream-filter.
 *
 * Arguments:
 *      upFilter        Pointer to the upstream-filter to which to add the 
 *                      component.
 *      feedtype        The feedtype of the filter-component.
 *      okPattern       Pointer to the "OK pattern" of the filter-component to 
 *                      be added.  Caller may free upon return.
 *      notPattern      Pointer to the "not pattern" of the filter-component to
 *                      be added.  May be NULL to indicate that such matching
 *                      should be disabled.  Caller may free upon return.
 * Returns:
 *      NULL            Success.
 *      else            Error object.
 */
ErrorObj*
upFilter_addComponent(
    UpFilter* const             upFilter,
    const feedtypet             feedtype,
    const Pattern* const        okPattern,
    const Pattern* const        notPattern)
{
    ErrorObj*   errObj = NULL;          /* success */
    Element*    elt;

    /*
     * Ensure that the given feedtype is disjoint from all feedtypes already
     * in the filter.
     */
    for (elt = upFilter->head; NULL != elt; elt = elt->next) {
        if (feedtype & elt->ft) {
            char        ftSpec[512];

            (void)sprint_feedtypet(ftSpec, sizeof(ftSpec), feedtype);

            errObj = ERR_NEW2(0, NULL,
                "Feedtype %s overlaps with feedtype %s",
                ftSpec, s_feedtypet(elt->ft));

            break;
        }
    }

    if (NULL == errObj) {
        size_t          nbytes = sizeof(Element);

        elt = (Element*)malloc(nbytes);

        if (NULL == elt) {
            errObj = ERR_NEW2(0, NULL, "Couldn't allocate %lu-bytes: %s",
                (unsigned long)nbytes, strerror(errno));
        }
        else {
            if ((errObj = pat_clone(&elt->okPattern, okPattern))) {
                errObj = ERR_NEW(0, errObj, "Couldn't clone \"OK\" pattern");
                free(elt);
            }
            else {
                if (NULL == notPattern) {
                    elt->notPattern = NULL;
                }
                else {
                    if ((errObj = pat_clone(&elt->notPattern, notPattern))) {
                        errObj = ERR_NEW(0, errObj,
                            "Couldn't clone \"not\" pattern");
                        pat_free(elt->okPattern);
                        free(elt);
                        elt = NULL;
                    }
                }

                if (elt) {
                    elt->ft = feedtype;
                    elt->next = upFilter->head;
                    upFilter->head = elt;
                    upFilter->stringOutOfDate = 1;
                    upFilter->count++;
                }
            }                           /* "elt->okPattern" allocated */
        }                               /* "elt" allocated */
    } // given feedtype is disjoint from those already in filter

    return errObj;
}