Beispiel #1
0
/**
 * Determines if a subscription has been reduced and logs a message if it has.
 *
 * @param origSub   [in] Original subscription
 * @param currSub   [in] Current subscription
 * @param entity    [in] Entity that reduced the subscription. Replaces the
 *                  blank in the sentence "Subscription reduced by one or more
 *                  _____".
 * @retval 0        If and only if the original subscription equals the
 *                  current subscription (i.e., the subscription has not been
 *                  reduced)
 */
int logIfReduced(
        const prod_class_t* const   origSub,
        const prod_class_t* const   currSub,
        const char*                 entity)
{
    int wasReduced = !clss_eq(origSub, currSub);

    if (wasReduced) {
        /*
         * The downstream LDM is not allowed to receive what it requested.
         */
        char origStr[1984];

        (void) s_prod_class(origStr, sizeof(origStr), origSub);
        log_warning("Subscription reduced by one or more %s: %s -> %s", entity,
                origStr, s_prod_class(NULL, 0, currSub));
    }

    return wasReduced;
}
Beispiel #2
0
/**
 * Notifies the LDM of the class of data-products that will be sent via LDM-5
 * protocols.
 *
 * Arguments:
 *      proxy           Pointer to the LDM proxy data-structure.
 *      offer           Pointer to the data-product class structure which will
 *                      be offered to the LDM.
 *      want            Pointer to a pointer to a data-product class structure.
 *                      "*want" will be set the data-product class structure
 *                      that the LDM wants. The client should call
 *                      "free_prod_class(*want)" when the product-class is no
 *                      longer needed.
 * Returns:
 *      0               Success. "*clsspp" might be modified.
 *      LP_TIMEDOUT     The RPC call timed-out. "log_start()" called.
 *      LP_RPC_ERROR    RPC error. "log_start()" called.
 *      LP_LDM_ERROR    LDM error. "log_start()" called.
 */
static LdmProxyStatus
my_hiya_5(
    LdmProxy* const             proxy,
    prod_class_t* const         offer,
    prod_class_t** const        want)
{
    static ldm_replyt   reply;
    enum clnt_stat      rpc_stat;
    CLIENT* const       clnt = proxy->clnt;

    memset(&reply, 0, sizeof(ldm_replyt));

    rpc_stat = clnt_call(clnt, HIYA, xdr_prod_class, (caddr_t)offer,
            xdr_ldm_replyt, (caddr_t)&reply, proxy->rpcTimeout);

    if (rpc_stat != RPC_SUCCESS) {
        return getStatus(proxy, "HIYA_5", NULL);
    }

    switch (reply.code) {
        case OK:
            *want = (prod_class_t*)PQ_CLASS_ALL;
            break;
        case SHUTTING_DOWN:
            LOG_START1("%s is shutting down", proxy->host);
            return LP_LDM_ERROR;
        case DONT_SEND:
        case RESTART:
        case REDIRECT: /* TODO */
        default:
            LOG_START2("%s: Unexpected reply from LDM: %s", proxy->host,
                    s_ldm_errt(reply.code));
            return LP_LDM_ERROR;
        case RECLASS:
            *want = reply.ldm_replyt_u.newclssp;
            clss_regcomp(*want);
            /* N.B. we use the downstream patterns */
            /* Use of "buf" added to prevent SIGSEGV on 64-bit RHEL 6 */
            (void)s_prod_class(buf, sizeof(buf)-1, *want);
            unotice("%s: reclass: %s", proxy->host, buf);
            break;
    }

    return 0;
}
Beispiel #3
0
static int
my_hiya_5(CLIENT *clnt, prod_class_t **clsspp)
{
        static ldm_replyt reply;
        enum clnt_stat rpc_stat;

        memset(&reply, 0, sizeof(ldm_replyt));

        rpc_stat = clnt_call(clnt, HIYA,
                xdr_prod_class, (caddr_t)*clsspp,
                xdr_ldm_replyt, (caddr_t)&reply,
                timeo);

        if(rpc_stat != RPC_SUCCESS)
        {
                uerror("hiya %s:  %s", remote, clnt_sperrno(rpc_stat));
                return ECONNABORTED; /* Perhaps could be more descriptive */
        }
        switch (reply.code) {
                case OK:
                        break;
                case SHUTTING_DOWN:
                        uerror("%s is shutting down", remote);
                        return ECONNABORTED;
                case DONT_SEND:
                case RESTART:
                case REDIRECT: /* TODO */
                default:
                        uerror("%s: unexpected reply type %s",
                                remote, s_ldm_errt(reply.code));
                        return ECONNABORTED;
                case RECLASS:
                        *clsspp = reply.ldm_replyt_u.newclssp;
                        clss_regcomp(*clsspp);
                        /* N.B. we use the downstream patterns */
                        unotice("%s: reclass: %s",
                                remote, s_prod_class(NULL, 0, *clsspp));
                        break;
        }
        return 0;
}
Beispiel #4
0
int main(int ac, char *av[])
{
        char *logfname = 0;
        unsigned timeo = DEFAULT_TIMEO; 
        unsigned interval = DEFAULT_TIMEO; 
        unsigned TotalTimeo = DEFAULT_TOTALTIMEO;
        prod_spec spec;
        int status;
        prod_class_t *clssp;
        unsigned remotePort = LDM_PORT;

        if(set_timestamp(&clss.from) != 0)
        {
                fprintf(stderr, "Couldn't set timestamp\n");
                exit(1);
        }
        clss.to = TS_ENDT;
        clss.psa.psa_len = 1;
        clss.psa.psa_val = &spec;
        spec.feedtype = DEFAULT_FEEDTYPE;
        spec.pattern = DEFAULT_PATTERN;

        { /* Begin getopt block */
        extern int optind;
        extern int opterr;
        extern char *optarg;
        int ch;
        int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) |
            LOG_MASK(LOG_NOTICE));
        int fterr;

        opterr = 1;

        while ((ch = getopt(ac, av, "vxl:f:o:t:h:P:p:T:")) != EOF)
                switch (ch) {
                case 'v':
                        logmask |= LOG_MASK(LOG_INFO);
                        break;
                case 'x':
                        logmask |= LOG_MASK(LOG_DEBUG);
                        break;
                case 'l':
                        logfname = optarg;
                        break;
                case 'h':
                        remote = optarg;
                        break;
                case 'P': {
                    char*       suffix = "";
                    long        port;

                    errno = 0;
                    port = strtol(optarg, &suffix, 0);

                    if (0 != errno || 0 != *suffix ||
                        0 >= port || 0xffff < port) {

                        (void)fprintf(stderr, "%s: invalid port %s\n",
                             av[0], optarg);
                        usage(av[0]);   
                    }

                    remotePort = (unsigned)port;

                    break;
                }
                case 'p':
                        spec.pattern = optarg;
                        /* compiled below */
                        break;
                case 'f':
                        fterr = strfeedtypet(optarg, &spec.feedtype);
                        if(fterr != FEEDTYPE_OK)
                        {
                                fprintf(stderr, "Bad feedtype \"%s\", %s\n",
                                        optarg, strfeederr(fterr));
                                usage(av[0]);   
                        }
                        break;
                case 'o':
                        clss.from.tv_sec -= atoi(optarg);
                        break;
                case 'T':
                        TotalTimeo = atoi(optarg);
                        if(TotalTimeo == 0)
                        {
                                fprintf(stderr, "%s: invalid TotalTimeo %s", av[0], optarg);
                                usage(av[0]);   
                        }
                        break;
                case 't':
                        timeo = (unsigned)atoi(optarg);
                        if(timeo == 0 || timeo > 32767)
                        {
                                fprintf(stderr, "%s: invalid timeout %s", av[0], optarg);
                                usage(av[0]);   
                        }
                        break;
                case '?':
                        usage(av[0]);
                        break;
                }

        if(ac - optind > 0)
                usage(av[0]);

        if (re_isPathological(spec.pattern))
        {
                fprintf(stderr, "Adjusting pathological regular-expression: "
                    "\"%s\"\n", spec.pattern);
                re_vetSpec(spec.pattern);
        }
        status = regcomp(&spec.rgx,
                spec.pattern,
                REG_EXTENDED|REG_NOSUB);
        if(status != 0)
        {
                fprintf(stderr, "Bad regular expression \"%s\"\n",
                        spec.pattern);
                usage(av[0]);
        }

        (void) setulogmask(logmask);

        if(TotalTimeo < timeo)
        {
                fprintf(stderr, "TotalTimeo %u < timeo %u\n",
                         TotalTimeo, timeo);
                usage(av[0]);
        }

        } /* End getopt block */

        /*
         * initialize logger
         */
        (void) openulog(ubasename(av[0]),
                (LOG_CONS|LOG_PID), LOG_LDM, logfname);
        unotice("Starting Up: %s: %s",
                        remote,
                        s_prod_class(NULL, 0, &clss));

        /*
         * register exit handler
         */
        if(atexit(cleanup) != 0)
        {
                serror("atexit");
                exit(1);
        }

        /*
         * set up signal handlers
         */
        set_sigactions();


        /*
         * Try forever.
         */
        while (exitIfDone(0))
        {
                clssp = &clss;
                status = forn5(NOTIFYME, remote, &clssp,
                                timeo, TotalTimeo, notifymeprog_5);

                (void)exitIfDone(0);

                switch(status) {
                        /* problems with remote, retry */       
                case ECONNABORTED:
                case ECONNRESET:
                case ETIMEDOUT:
                case ECONNREFUSED:
                        sleep(interval);
                        break;
                case 0:
                        /* assert(done); */
                        break;
                default:
                        /* some wierd error */
                        done = 1;
                        exit(1);
                }
        }

        exit(0);
        /*NOTREACHED*/
}
Beispiel #5
0
hiya_reply_t*
hiya_6_svc(
        prod_class_t *offered,
        struct svc_req *rqstp)
{
    const char* const pqfname = getQueuePath();
    static hiya_reply_t reply;
    SVCXPRT * const xprt = rqstp->rq_xprt;
    struct sockaddr_in *upAddr = (struct sockaddr_in*) svc_getcaller(xprt);
    const char *upName = hostbyaddr(upAddr);
    int error;
    int isPrimary;
    unsigned int maxHereis;
    static prod_class_t *accept;

    /*
     * Open the product-queue for writing.  It will be closed by cleanup()
     * during process termination.
     */
    if (pq) {
        (void) pq_close(pq);
        pq = NULL;
    }
    error = pq_open(pqfname, PQ_DEFAULT, &pq);
    if (error) {
        err_log_and_free(ERR_NEW2(error, NULL,
                "Couldn't open product-queue \"%s\" for writing: %s",
                pqfname,
                PQ_CORRUPT == error
                ? "The product-queue is inconsistent"
                : strerror(error)), ERR_FAILURE);
        svcerr_systemerr(xprt);
        svc_destroy(xprt);
        exit(error);
    }

    /* else */

    error = down6_init(upName, upAddr, pqfname, pq);
    if (error) {
        uerror("Couldn't initialize downstream LDM");
        svcerr_systemerr(xprt);
        svc_destroy(xprt);
        exit(error);
    }
    else {
        uinfo("Downstream LDM initialized");
    }

    /*
     * The previous "accept" is freed here -- rather than freeing the
     * soon-to-be-allocated "accept" at the end of its block -- because it can
     * be used in the reply.
     */
    if (accept) {
        free_prod_class(accept); /* NULL safe */
        accept = NULL;
    }

    error = lcf_reduceToAcceptable(upName, inet_ntoa(upAddr->sin_addr), offered,
            &accept, &isPrimary);

    maxHereis = isPrimary ? UINT_MAX : 0;

    if (error) {
        serror("Couldn't validate HIYA");
        svcerr_systemerr(xprt);
        svc_destroy(xprt);
        exit(error);
    }
    else {
        if (ulogIsDebug())
            udebug("intersection: %s", s_prod_class(NULL, 0, accept));

        if (accept->psa.psa_len == 0) {
            uwarn("Empty intersection of HIYA offer from %s (%s) and ACCEPT "
                    "entries", upName, s_prod_class(NULL, 0, offered));
            svcerr_weakauth(xprt);
            svc_destroy(xprt);
            exit(0);
        }
        else {
            error = down6_set_prod_class(accept);

            if (error) {
                if (DOWN6_SYSTEM_ERROR == error) {
                    serror("Couldn't set product class: %s",
                            s_prod_class(NULL, 0, accept));
                }
                else {
                    uerror("Couldn't set product class: %s",
                            s_prod_class(NULL, 0, accept));
                }

                svcerr_systemerr(xprt);
                svc_destroy(xprt);
                exit(EXIT_FAILURE);
            }

            /* else */

            if (clss_eq(offered, accept)) {
                unotice("hiya6: %s", s_prod_class(NULL, 0, offered));

                reply.code = OK;
                reply.hiya_reply_t_u.max_hereis = maxHereis;
            }
            else {
                if (ulogIsVerbose()) {
                    char off[512];
                    char acc[512];

                    (void) s_prod_class(off, sizeof(off), offered), (void) s_prod_class(
                            acc, sizeof(acc), accept);

                    uinfo("hiya6: RECLASS: %s -> %s", off, acc);
                }

                reply.code = RECLASS;
                reply.hiya_reply_t_u.feedPar.prod_class = accept;
                reply.hiya_reply_t_u.feedPar.max_hereis = maxHereis;
            }
        } /* product-intersection != empty set */
    } /* successful acl_check_hiya() */

    return &reply;
}
Beispiel #6
0
/**
 * 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;
}
Beispiel #7
0
int main(int ac, char *av[])
{
        const char* pqfname = getQueuePath();
        const char *opqfname = getSurfQueuePath();
        const char *progname = ubasename(av[0]);
        char *logfname;
        prod_class_t clss;
        prod_spec spec;
        int status = 0;
        unsigned interval = DEFAULT_INTERVAL;
        int logoptions = (LOG_CONS|LOG_PID);
        double age = DEFAULT_AGE;
        /* these are containers for the pqact args */
        char *argv[16];
        int argc = 0;
        int toffset = TOFFSET_NONE;

        logfname = "";

        if(set_timestamp(&clss.from) != ENOERR) /* corrected by toffset below */
        {
                int errnum = errno;
                fprintf(stderr, "Couldn't set timestamp: %s", 
                        strerror(errnum));
                exit(1);
        }
        clss.to = TS_ENDT;
        clss.psa.psa_len = 1;
        clss.psa.psa_val = &spec;
        
        spec.feedtype = DEFAULT_FEEDTYPE;
        spec.pattern = DEFAULT_PATTERN;

        memset(argv, 0, sizeof(argv));
        argv[0] = "pqact";
        argc++;

        {
        extern int optind;
        extern int opterr;
        extern char *optarg;
        int ch;
        int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) |
            LOG_MASK(LOG_NOTICE));
        int fterr;
        const char *conffilename = getPqsurfConfigPath();
        const char *datadir = getPqsurfDataDirPath();

        usePil = 1;
        opterr = 1;

        while ((ch = getopt(ac, av, "vxl:d:f:p:q:Q:o:i:a:t:")) != EOF)
                switch (ch) {
                case 'v':
                        argv[argc++] = "-v";
                        logmask |= LOG_MASK(LOG_INFO);
                        break;
                case 'x':
                        argv[argc++] = "-x";
                        logmask |= LOG_MASK(LOG_DEBUG);
                        break;
                case 'l':
                        argv[argc++] = "-l";
                        argv[argc++] = optarg;
                        logfname = optarg;
                        break;
                case 'd':
                        datadir = optarg;
                        break;
                case 'f':
                        fterr = strfeedtypet(optarg, &spec.feedtype);
                        if(fterr != FEEDTYPE_OK)
                        {
                                fprintf(stderr, "%s: %s: \"%s\"\n",
                                        av[0], strfeederr(fterr), optarg);
                                usage(progname);        
                        }
                        argv[argc++] = "-f";
                        argv[argc++] = optarg;
                        break;
                case 'p':
                        spec.pattern = optarg;
                        /* compiled below */
                        break;
                case 'q':
                        pqfname = optarg;
                        break;
                case 'Q':
                        opqfname = optarg;
                        break;
                case 'o':
                        toffset = atoi(optarg);
                        if(toffset == 0 && *optarg != '0')
                        {
                                fprintf(stderr, "%s: invalid offset %s\n",
                                         av[0], optarg);
                                usage(av[0]);   
                        }
                        argv[argc++] = "-o";
                        argv[argc++] = optarg;
                        break;
                case 'i':
                        interval = atoi(optarg);
                        if(interval == 0 && *optarg != '0')
                        {
                                fprintf(stderr, "%s: invalid interval \"%s\"\n",
                                        av[0], optarg);
                                usage(av[0]);
                        }
                        /* N.B. -i just used for input queue. */
                        break;
                case 'a':
                        age = atof(optarg);
                        if(age < 0.)
                        {
                            (void) fprintf(stderr,
                                        "age (%s) must be non negative\n",
                                        optarg);
                                usage(av[0]);   
                        }
                        break;
                case 't':
                        /* pipe_timeo */
                        argv[argc++] = "-t";
                        argv[argc++] = optarg;
                        break;
                case '?':
                        usage(progname);
                        break;
                }

        (void) setulogmask(logmask);

        if (re_isPathological(spec.pattern))
        {
                fprintf(stderr, "Adjusting pathological regular-expression: "
                    "\"%s\"\n", spec.pattern);
                re_vetSpec(spec.pattern);
        }
        status = regcomp(&spec.rgx,
                spec.pattern,
                REG_EXTENDED|REG_NOSUB);
        if(status != 0)
        {
                fprintf(stderr, "Bad regular expression \"%s\"\n",
                        spec.pattern);
                usage(av[0]);
        }

        if(ac - optind == 1)
                conffilename = av[optind];

        argv[argc++] = "-d";
        argv[argc++] = (char*)datadir;
        argv[argc++] = "-q";
        argv[argc++] = (char*)opqfname;
        argv[argc++] = (char*)conffilename;

        age *= 3600.;

        }

        if(toffset != TOFFSET_NONE)
        {
                clss.from.tv_sec -= toffset;
        }
        else
        {
                clss.from.tv_sec -= (age - interval);
        }


        /*
         * Set up error logging.
         * N.B. log ident is the remote
         */
        (void) openulog(progname,
                logoptions, LOG_LDM, logfname);
        unotice("Starting Up (%d)", getpgrp());

        /*
         * register exit handler
         */
        if(atexit(cleanup) != 0)
        {
                serror("atexit");
                exit(1);
        }

        /*
         * set up signal handlers
         */
        set_sigactions();


        /*
         * Open the output product queue
         */
        status = pq_open(opqfname, PQ_DEFAULT, &opq);
        if(status)
        {
                if (PQ_CORRUPT == status) {
                    uerror("The output product-queue \"%s\" is inconsistent\n",
                            opqfname);
                }
                else {
                    uerror("pq_open failed: %s: %s\n",
                            opqfname, strerror(status));
                }
                exit(1);
        }


        act_pid = run_child(argc, argv);
        if(act_pid == (pid_t)-1)
                exit(1);

        /*
         * Open the input product queue
         */
        status = pq_open(pqfname, PQ_READONLY, &pq);
        if(status)
        {
                if (PQ_CORRUPT == status) {
                    uerror("The product-queue \"%s\" is inconsistent\n",
                            pqfname);
                }
                else {
                    uerror("pq_open failed: %s: %s\n",
                            pqfname, strerror(status));
                }
                exit(1);
        }
        if(toffset == TOFFSET_NONE)
        {
                /* Jump to the end of the queue */
                timestampt sav;
                sav = clss.from;
                clss.from = TS_ZERO;
                (void) pq_last(pq, &clss, NULL);
                clss.from = sav;
        }
        else
        {
                pq_cset(pq, &clss.from);
        }

        if(ulogIsVerbose())
        {
                char buf[1984];
                uinfo("%s",
                         s_prod_class(buf, sizeof(buf), &clss));
        }

        while(exitIfDone(0))
        {
                if(stats_req)
                {
                        dump_stats();
                        stats_req = 0;
                }

                status = pq_sequence(pq, TV_GT, &clss, split_prod, NULL);

                switch(status) {
                case 0: /* no error */
                        continue; /* N.B., other cases sleep */
                case PQUEUE_END:
                        udebug("surf: End of Queue");
                        break;
                case EAGAIN:
                case EACCES:
                        udebug("Hit a lock");
                        break;
                default:
                        uerror("pq_sequence failed: %s (errno = %d)",
                                strerror(status), status);
                        exit(1);
                        break;
                }

                if(interval == 0)
                {
                        break;
                }


                (void) expire(opq, interval, age);

                pq_suspend(interval);

                (void) reap_act(WNOHANG);
        }

        /*
         * TODO: how can we determine that pqact has finished
         *       the work in opq?
         */
        sleep(5);

        exit(0);
}
Beispiel #8
0
int main(int ac, char *av[])
{
        unsigned      timeo = DEFAULT_TIMEO;
        unsigned      interval = DEFAULT_TIMEO;
        unsigned      TotalTimeo = DEFAULT_TOTALTIMEO;
        prod_spec     spec;
        int           status;
        prod_class_t* clssp;

        /*
         * initialize logger
         */
        if (log_init(av[0])) {
            log_syserr("Couldn't initialize logging module");
            exit(1);
        }

        if(set_timestamp(&clss.from) != 0)
        {
                fprintf(stderr, "Couldn't set timestamp\n");
                exit(1);
        }
        clss.to = TS_ENDT;
        clss.psa.psa_len = 1;
        clss.psa.psa_val = &spec;
        spec.feedtype = DEFAULT_FEEDTYPE;
        spec.pattern = DEFAULT_PATTERN;

        { /* Begin getopt block */
        extern int optind;
        extern int opterr;
        extern char *optarg;
        int ch;
        int fterr;

        opterr = 1;

        while ((ch = getopt(ac, av, "vxl:f:o:t:h:P:p:T:")) != EOF)
                switch (ch) {
                case 'v':
                        if (!log_is_enabled_info)
                            log_set_level(LOG_LEVEL_INFO);
                        break;
                case 'x':
                        log_set_level(LOG_LEVEL_DEBUG);
                        break;
                case 'l':
                        if (log_set_destination(optarg)) {
                            log_syserr("Couldn't set logging destination to \"%s\"",
                                    optarg);
                            usage(av[0]);
                        }
                        break;
                case 'h':
                        remote = optarg;
                        break;
                case 'P': {
                    log_warning("Port specification is ignored");
                    break;
                }
                case 'p':
                        spec.pattern = optarg;
                        /* compiled below */
                        break;
                case 'f':
                        fterr = strfeedtypet(optarg, &spec.feedtype);
                        if(fterr != FEEDTYPE_OK)
                        {
                                fprintf(stderr, "Bad feedtype \"%s\", %s\n",
                                        optarg, strfeederr(fterr));
                                usage(av[0]);   
                        }
                        break;
                case 'o':
                        clss.from.tv_sec -= atoi(optarg);
                        break;
                case 'T':
                        TotalTimeo = atoi(optarg);
                        if(TotalTimeo == 0)
                        {
                                fprintf(stderr, "%s: invalid TotalTimeo %s", av[0], optarg);
                                usage(av[0]);   
                        }
                        break;
                case 't':
                        timeo = (unsigned)atoi(optarg);
                        if(timeo == 0 || timeo > 32767)
                        {
                                fprintf(stderr, "%s: invalid timeout %s", av[0], optarg);
                                usage(av[0]);   
                        }
                        break;
                case '?':
                        usage(av[0]);
                        break;
                }

        if(ac - optind > 0)
                usage(av[0]);

        if (re_isPathological(spec.pattern))
        {
                fprintf(stderr, "Adjusting pathological regular-expression: "
                    "\"%s\"\n", spec.pattern);
                re_vetSpec(spec.pattern);
        }
        status = regcomp(&spec.rgx,
                spec.pattern,
                REG_EXTENDED|REG_NOSUB);
        if(status != 0)
        {
                fprintf(stderr, "Bad regular expression \"%s\"\n",
                        spec.pattern);
                usage(av[0]);
        }

        if(TotalTimeo < timeo)
        {
                fprintf(stderr, "TotalTimeo %u < timeo %u\n",
                         TotalTimeo, timeo);
                usage(av[0]);
        }

        } /* End getopt block */

        log_notice_q("Starting Up: %s: %s",
                        remote,
                        s_prod_class(NULL, 0, &clss));

        /*
         * register exit handler
         */
        if(atexit(cleanup) != 0)
        {
                log_syserr("atexit");
                exit(1);
        }

        /*
         * set up signal handlers
         */
        set_sigactions();


        /*
         * Try forever.
         */
        while (exitIfDone(0))
        {
                clssp = &clss;
                status = forn5(NOTIFYME, remote, &clssp,
                                timeo, TotalTimeo, notifymeprog_5);

                (void)exitIfDone(0);

                switch(status) {
                        /* problems with remote, retry */       
                case ECONNABORTED:
                case ECONNRESET:
                case ETIMEDOUT:
                case ECONNREFUSED:
                        sleep(interval);
                        break;
                case 0:
                        /* assert(done); */
                        break;
                default:
                        /* some wierd error */
                        done = 1;
                        exit(1);
                }
        }

        exit(0);
        /*NOTREACHED*/
}
Beispiel #9
0
/**
 * Notifies the LDM of the class of data-products that will be sent via LDM-6
 * protocols.
 *
 * Arguments:
 *      proxy           Pointer to the LDM proxy data-structure.
 *      offer           Pointer to the data-product class structure which will
 *                      be offered to the LDM.
 *      want            Pointer to a pointer to a data-product class structure.
 *                      "*want" will be set the data-product class structure
 *                      that the LDM wants. The client should call
 *                      "free_prod_class(*want)" when the product-class is no
 *                      longer needed.
 * Returns:
 *      0               Success. "*clsspp" might be modified.
 *      LP_RPC_ERROR    RPC error. "log_start()" called.
 *      LP_LDM_ERROR    LDM error. "log_start()" called.
 */
static LdmProxyStatus
my_hiya_6(
    LdmProxy* const             proxy,
    prod_class_t* const         offer,
    prod_class_t** const        want)
{
    CLIENT* const       clnt = proxy->clnt;
    hiya_reply_t*       reply;
    LdmProxyStatus      status;
    
    reply = hiya_6(offer, clnt);

    if (NULL == reply) {
        status = getStatus(proxy, "HIYA_6", NULL);
    }
    else {
        switch (reply->code) {
            case OK:
                *want = (prod_class_t*)PQ_CLASS_ALL;
                proxy->max_hereis = reply->hiya_reply_t_u.max_hereis;
                status = 0;
                break;

            case SHUTTING_DOWN:
                LOG_START1("%s: LDM shutting down", proxy->host);
                status = LP_LDM_ERROR;
                break;

            case BADPATTERN:
                LOG_START1("%s: Bad product-class pattern", proxy->host);
                status = LP_LDM_ERROR;
                break;

            case DONT_SEND:
                LOG_START1("%s: LDM says don't send", proxy->host);
                status = LP_LDM_ERROR;
                break;

            case RESEND:
                LOG_START1("%s: LDM says resend (ain't gonna happen)",
                        proxy->host);
                status = LP_LDM_ERROR;
                break;

            case RESTART:
                LOG_START1("%s: LDM says restart (ain't gonna happen)",
                        proxy->host);
                status = LP_LDM_ERROR;
                break;

            case REDIRECT:
                LOG_START1("%s: LDM says redirect (ain't gonna happen)",
                        proxy->host);
                status = LP_LDM_ERROR;
                break;

            case RECLASS:
                *want = reply->hiya_reply_t_u.feedPar.prod_class;
                proxy->max_hereis = reply->hiya_reply_t_u.feedPar.max_hereis;
                clss_regcomp(*want);
                /* N.B. we use the downstream patterns */
                /* Use of "buf" added to prevent SIGSEGV on 64-bit RHEL 6 */
                (void)s_prod_class(buf, sizeof(buf)-1, *want);
                unotice("%s: reclass: %s", proxy->host, buf);
                status = 0;
                break;
        }

        if (LP_OK != status)
            udebug("max_hereis = %u", proxy->max_hereis);
    }

    return status;
}
Beispiel #10
0
static int
my_hiya_6(CLIENT *clnt, prod_class_t **clsspp)
{
    static hiya_reply_t* reply;
    int                  error;
    
    reply = hiya_6(*clsspp, clnt);

    if (NULL == reply) {
        uerror("%s: HIYA_6 failure: %s", remote, clnt_errmsg(clnt));

        error = ECONNABORTED;
    }
    else {
        switch (reply->code) {
            case OK:
                max_hereis = reply->hiya_reply_t_u.max_hereis;
                error = 0;
                break;

            case SHUTTING_DOWN:
                uerror("%s: LDM shutting down", remote);
                error = ECONNABORTED;
                break;

            case BADPATTERN:
                uerror("%s: Bad product-class pattern", remote);
                error = ECONNABORTED;
                break;

            case DONT_SEND:
                uerror("%s: LDM says don't send", remote);
                error = ECONNABORTED;
                break;

            case RESEND:
                uerror("%s: LDM says resend (ain't gonna happen)", remote);
                error = ECONNABORTED;
                break;

            case RESTART:
                uerror("%s: LDM says restart (ain't gonna happen)", remote);
                error = ECONNABORTED;
                break;

            case REDIRECT:
                uerror("%s: LDM says redirect (ain't gonna happen)", remote);
                error = ECONNABORTED;
                break;

            case RECLASS:
                *clsspp = reply->hiya_reply_t_u.feedPar.prod_class;
                max_hereis = reply->hiya_reply_t_u.feedPar.max_hereis;
                clss_regcomp(*clsspp);
                /* N.B. we use the downstream patterns */
                unotice("%s: reclass: %s",
                        remote, s_prod_class(NULL, 0, *clsspp));
                error = 0;
                break;
        }

        if (!error)
            udebug("max_hereis = %u", max_hereis);
    }

    return error;
}