Пример #1
0
static int
sender_start(
    const feedtypet feedtype)
{
    // The following ensures that the first product-index will be 0
    int status = pim_delete(NULL, feedtype);
    if (status) {
        LOG_ADD1("Couldn't delete product-index map for feedtype %#lx",
                 feedtype);
    }
    else {
        status = createEmptyProductQueue(UP7_PQ_PATHNAME);
        if (status) {
            LOG_ADD1("Couldn't create empty product queue \"%s\"",
                     UP7_PQ_PATHNAME);
        }
        else {
            // Thread-safe because 2 threads: upstream LDM-7 & product insertion.
            status = pq_open(getQueuePath(), PQ_READONLY | PQ_THREADSAFE, &pq);
            if (status) {
                LOG_ADD1("Couldn't open product-queue \"%s\"", getQueuePath());
            }
            else {
                McastInfo* mcastInfo;

                status = setMcastInfo(&mcastInfo, feedtype);
                if (status) {
                    LOG_ADD0("Couldn't set multicast information");
                }
                else {
                    status = mlsm_clear();
                    status = mlsm_addPotentialSender(mcastInfo, 2, LOCAL_HOST,
                                                     UP7_PQ_PATHNAME);
                    if (status) {
                        LOG_ADD0("mlsm_addPotentialSender() failure");
                    }
                    else {
                        // Starts the sender on a new thread
                        status = sender_spawn();
                        if (status) {
                            LOG_ADD0("Couldn't spawn sender");
                        }
                        else {
                            done = 0;
                        }
                    }
                    mi_free(mcastInfo);
                } // `mcastInfo` allocated

                if (status)
                    (void)pq_close(pq);
            } // Product-queue open

            if (status)
                (void)deleteProductQueue(UP7_PQ_PATHNAME);
        } // empty product-queue created
    } // product-index map deleted

    return status;
}
Пример #2
0
/**
 * Indicates whether or not the anti-denial-of-service attack feature is
 * enabled.
 *
 * @retval 0  The feature is disabled.
 * @retval 1  The feature is enabled.
 */
int
isAntiDosEnabled(void)
{
    static int isEnabled;
    static int isSet = 0;

    if (!isSet) {
        int status = reg_getBool(REG_ANTI_DOS, &isEnabled);

        if (status) {
            isEnabled = 1;
            LOG_ADD1("Using default value: %s", isEnabled ? "TRUE" : "FALSE");
            if (status == ENOENT) {
                log_log(LOG_INFO);
                isSet = 1;
            }
            else {
                log_log(LOG_ERR);
            }
        }
        else {
            isSet = 1;
        }
    }

    return isEnabled;
}
Пример #3
0
/**
 * Locks a read/write lock for writing. Waits until the lock is available.
 * Reentrant.
 *
 * @retval RWL_SUCCESS  Success
 * @retval RWL_INVALID  Lock structure is invalid. log_add() called.
 * @retval RWL_EXIST    Lock is locked for reading and the current process is
 *                      the one that created it. log_add() called.
 * @retval RWL_SYSTEM   System error. See "errno". log_add() called. Resulting
 *                      state of the lock is unspecified.
 */
srwl_Status srwl_writeLock(
        srwl_Lock* const lock /**< [in/out] the lock to be locked */)
{
    srwl_Status status = vet(lock);

    if (RWL_SUCCESS == status) {
        if (0 < lock->numReadLocks) {
            LOG_ADD1("Lock is locked for reading; semId=%d", lock->semId);
            status = RWL_EXIST;
        }
        else if (0 < lock->numWriteLocks) {
            lock->numWriteLocks++;
            status = RWL_SUCCESS;
        }
        else {
            if (semop(lock->semId, writeLockOps,
                    sizeof(writeLockOps) / sizeof(writeLockOps[0])) == -1) {
                LOG_SERROR1("Couldn't lock for writing: semId=%d", lock->semId);
                status = RWL_SYSTEM;
            }
            else {
                lock->numWriteLocks = 1;
                status = RWL_SUCCESS;
            }
        }
    }

    return status;
}
Пример #4
0
/**
 * Returns the backlog time-offset for making requests of an upstream LDM.
 *
 * @return  The backlog time-offset, in seconds, for making requests of an
 *          upstream LDM.
 */
unsigned
getTimeOffset(void)
{
    static unsigned timeOffset;
    static int      isSet = 0;

    if (!isSet) {
        int status = reg_getUint(REG_TIME_OFFSET, &timeOffset);

        if (status) {
            timeOffset = 3600;
            LOG_ADD1("Using default value: %u seconds", timeOffset);
            if (status == ENOENT) {
                log_log(LOG_INFO);
                isSet = 1;
            }
            else {
                log_log(LOG_ERR);
            }
        }
        else {
            isSet = 1;
        }
    }

    return timeOffset;
}
Пример #5
0
/*
 * Returns the LDM proxy status for a given client failure. Logs the failure.
 *
 * Arguments:
 *      proxy           The LDM proxy data-structure.
 *      name            The name of the failed message or NULL.
 *      info            Metadata on the data-product that couldn't be sent or
 *                      NULL.
 * Returns:
 *      0               Success.
 *      LP_TIMEDOUT     The failure was due to an RPC timeout. "log_start()"
 *                      called iff "name" isn't NULL.
 *      LP_RPC_ERROR    RPC error. "log_start()" called iff "name" isn't NULL.
 */
static LdmProxyStatus
getStatus(
    LdmProxy* const     proxy,
    const char* const   name,
    prod_info* const    info)
{
    LdmProxyStatus      status;
    struct rpc_err      rpcErr;

    clnt_geterr(proxy->clnt, &rpcErr);

    if (0 == rpcErr.re_status) {
        status = 0;
    }
    else {
        if (NULL != name) {
            LOG_START3("%s failure to host \"%s\": %s", name, proxy->host, 
                    clnt_errmsg(proxy->clnt));

            if (NULL != info) {
                LOG_ADD1("Couldn't send product: %s", s_prod_info(NULL, 0,
                            info, ulogIsDebug()));
            }
        }

        status = RPC_TIMEDOUT == rpcErr.re_status
            ? LP_TIMEDOUT
            : LP_RPC_ERROR;
    }

    return status;
}
Пример #6
0
static void
sender_insertProducts(void)
{
    pqueue* pq;
    int     status = pq_open(UP7_PQ_PATHNAME, 0, &pq);

    CU_ASSERT_EQUAL_FATAL(status, 0);

    product        prod;
    prod_info*     info = &prod.info;
    char           ident[80];
    void*          data = NULL;
    unsigned short xsubi[3] = {(unsigned short)1234567890,
                               (unsigned short)9876543210,
                               (unsigned short)1029384756
                              };
    info->feedtype = EXP;
    info->ident = ident;
    info->origin = "localhost";
    (void)memset(info->signature, 0, sizeof(info->signature));

    for (int i = 0; i < NUM_PRODS; i++) {
        const unsigned size = MAX_PROD_SIZE*erand48(xsubi) + 0.5;
        const ssize_t  nbytes = snprintf(ident, sizeof(ident), "%d", i);

        CU_ASSERT_TRUE_FATAL(nbytes >= 0 && nbytes < sizeof(ident));
        status = set_timestamp(&info->arrival);
        CU_ASSERT_EQUAL_FATAL(status, 0);
        info->seqno = i;
        uint32_t signet = htonl(i);
        (void)memcpy(info->signature+sizeof(signaturet)-sizeof(signet), &signet,
                     sizeof(signet));
        info->sz = size;

        data = realloc(data, size);
        CU_ASSERT_PTR_NOT_NULL(data);
        prod.data = data;

        status = pq_insert(pq, &prod);
        CU_ASSERT_EQUAL_FATAL(status, 0);
        char buf[LDM_INFO_MAX];
        LOG_ADD1("Inserted: prodInfo=\"%s\"",
                 s_prod_info(buf, sizeof(buf), info, 1));
        log_log(LOG_INFO);

        struct timespec duration;
        duration.tv_sec = 0;
        duration.tv_nsec = 5000000; // 5 ms
        status = nanosleep(&duration, NULL);
        CU_ASSERT_EQUAL_FATAL(status, 0);
    }

    free(data);
    status = pq_close(pq);
    CU_ASSERT_EQUAL_FATAL(status, 0);
}
Пример #7
0
static int
createEmptyProductQueue(
    const char* const pathname)
{
    pqueue* pq;
    int     status = pq_create(pathname, 0666, PQ_DEFAULT, 0, PQ_SIZE,
                               NUM_PQ_SLOTS, &pq); // PQ_DEFAULT => clobber existing

    if (status == 0) {
        status = pq_close(pq);
        if (status) {
            LOG_ADD1("Couldn't close product-queue \"%s\"", pathname);
        }
    }
    return status;
}
Пример #8
0
/**
 * Executes a multicast receiver. Blocks until the receiver is stopped.
 *
 * @param[in,out] receiver      The receiver.
 * @retval        0             Success. The receiver was stopped.
 * @retval        EINVAL        @code{receiver == NULL}. \c log_add() called.
 * @retval        -1            Other failure. \c log_add() called.
 */
int
mcastReceiver_execute(
    const McastReceiver* const receiver)
{
    if (0 == receiver) {
        LOG_ADD0("NULL receiver argument");
        return EINVAL;
    }

    try {
        receiver->receiver->RunReceivingThread();
        return 0;
    }
    catch (const std::exception& e) {
        LOG_ADD1("%s", e.what());
        return -1;
    }
}
Пример #9
0
/**
 * Executes a multicast receiver. Only returns when an error occurs.
 *
 * @param[in,out] receiver      The receiver.
 * @retval        EINVAL        @code{receiver == NULL}. \c log_add() called.
 * @retval        -1            Other failure. \c log_add() called.
 */
int
mcastReceiver_execute(
    const McastReceiver* const receiver)
{
    if (0 == receiver) {
        LOG_ADD0("NULL receiver argument");
        return EINVAL;
    }

    try {
        // VCMTP call
        receiver->receiver->Start();
    }
    catch (const std::exception& e) {
        LOG_ADD1("%s", e.what());
    }
    return -1;
}
Пример #10
0
/*
 * Returns the path name of a file.
 *
 * Arguments:
 *      name            The name of the registry parameter that contains the
 *                      desired pathname.
 *      buf             Buffer of length PATH_MAX into which to put the path.
 *      desc            Pointer to a description of the file.
 * Returns:
 *      NULL            Error.  "log_log()" called.
 *      else            Pointer to the pathname of the file.  Might be absolute
 *                      or relative to the current working directory.
 */
static const char* getPath(
    const char* const   name,
    char                buf[PATH_MAX],
    const char* const   desc)
{
    if (0 == buf[0]) {
        char*           var;

        if (reg_getString(name, &var)) {
            LOG_ADD1("Couldn't get pathname of %s", desc);
            return NULL;
        }
        else {
            setPath(var, buf);
            free(var);
        }
    }

    return buf;
}
Пример #11
0
/**
 * Locks a read/write lock for reading. Waits until the lock is available.
 * Reentrant.
 *
 * @retval RWL_SUCCESS  Success
 * @retval RWL_INVALID  Lock structure is invalid. log_add() called.
 * @retval RWL_EXIST    Lock is locked for writing and the current process is
 *                      the one that created it. log_add() called.
 * @retval RWL_SYSTEM   System error. See "errno". log_add() called. Resulting
 *                      state of the lock is unspecified.
 */
srwl_Status srwl_readLock(
        srwl_Lock* const lock /**< [in/out] the lock to be locked */)
{
    srwl_Status status = vet(lock);

    if (RWL_SUCCESS == status) {
        if (0 < lock->numWriteLocks) {
            LOG_ADD1("Lock is locked for writing; semId=%d", lock->semId);
            status = RWL_EXIST;
        }
        else if (0 < lock->numReadLocks) {
            lock->numReadLocks++;
            status = RWL_SUCCESS;
        }
        else {
            /*
             * A read-lock is obtained in two steps because the semop(2)
             * specification doesn't indicate that the operations array is
             * executed sequentially.
             */
            if (semop(lock->semId, readLockOps,
                    sizeof(readLockOps) / sizeof(readLockOps[0])) == -1) {
                LOG_SERROR1("Couldn't lock for reading: semId=%d", lock->semId);
                status = RWL_SYSTEM;
            }
            else if (semop(lock->semId, shareOps,
                    sizeof(shareOps) / sizeof(shareOps[0])) == -1) {
                LOG_SERROR1("Couldn't share read-lock: semId=%d", lock->semId);
                status = RWL_SYSTEM;
            }
            else {
                lock->numReadLocks = 1;
                status = RWL_SUCCESS;
            }
        }
    }

    return status;
}
Пример #12
0
/**
 * Returns a new server contact information object.
 *
 * @param[in] id    Name or formatted IP address of the host running the server.
 * @param[in] port  Port number of the server.
 * @retval NULL     Error. \c log_add() called.
 * @return          Pointer to a new server contact information object. The
 *                  client should call \c serverInfo_free() when it is no longer
 *                  needed.
 */
ServerInfo*
serverInfo_new(
    const char* const    id,
    const unsigned short port)
{
    ServerInfo* si = LOG_MALLOC(sizeof(ServerInfo),
            "server contact information");

    if (si) {
        si->id = strdup(id);

        if (!si->id) {
            LOG_ADD1("Couldn't duplicate server identifier \"%s\"", id);
            free(si);
            si = NULL;
        }
        else {
            si->port = port;
        }
    }

    return si;
}
Пример #13
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;
}
Пример #14
0
int main(
        int ac,
        char *av[]
)
{
        const char* const       pqfname = getQueuePath();
        const char* const progname = ubasename(av[0]);
        int useProductID = FALSE;
        int signatureFromId = FALSE;
        char *productID = NULL;
        int multipleFiles = FALSE;
        char identifier[KEYSIZE];
        int status;
        int seq_start = 0;
        enum ExitCode {
            exit_success = 0,   /* all files inserted successfully */
            exit_system = 1,    /* operating-system failure */
            exit_pq_open = 2,   /* couldn't open product-queue */
            exit_infile = 3,    /* couldn't process input file */
            exit_dup = 4,       /* input-file already in product-queue */
            exit_md5 = 6        /* couldn't initialize MD5 processing */
        } exitCode = exit_success;

#if !USE_MMAP
        pqeIndex = PQE_NONE;
#endif

        {
            extern int optind;
            extern int opterr;
            extern char *optarg;
            int ch;

            (void) openulog(progname, LOG_NOTIME, LOG_LDM, "-");
            (void) setulogmask(LOG_UPTO(LOG_NOTICE));

            opterr = 0; /* Suppress getopt(3) error messages */

            while ((ch = getopt(ac, av, ":ivxl:q:f:s:p:")) != EOF)
                    switch (ch) {
                    case 'i':
                            signatureFromId = 1;
                            break;
                    case 'v':
                            (void) setulogmask(getulogmask() | LOG_MASK(LOG_INFO));
                            break;
                    case 'x':
                            (void) setulogmask(getulogmask() | LOG_MASK(LOG_DEBUG));
                            break;
                    case 'l':
                            openulog(progname, ulog_get_options(), LOG_LDM, optarg);
                            break;
                    case 'q':
                            setQueuePath(optarg);
                            break;
                    case 's':
                            seq_start = atoi(optarg);
                            break;
                    case 'f':
                            feedtype = atofeedtypet(optarg);
                            if(feedtype == NONE)
                            {
                                fprintf(stderr, "Unknown feedtype \"%s\"\n", optarg);
                                    usage(progname);
                            }
                            break;
                    case 'p':
                            useProductID = TRUE;
                            productID = optarg;
                            break;
                    case ':': {
                        LOG_ADD1("Option \"-%c\" requires an operand", optopt);
                        usage(progname);
                    }
                    /* no break */
                    default:
                        LOG_ADD1("Unknown option: \"%c\"", optopt);
                        usage(progname);
                        /* no break */
                    }

            ac -= optind; av += optind ;

            if(ac < 1) usage(progname);
            }

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

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

        /*
         * who am i, anyway
         */
        (void) strncpy(myname, ghostname(), sizeof(myname));
        myname[sizeof(myname)-1] = 0;

        /*
         * open the product queue
         */
        if(status = pq_open(pqfname, PQ_DEFAULT, &pq))
        {
                if (PQ_CORRUPT == status) {
                    uerror("The product-queue \"%s\" is inconsistent\n",
                            pqfname);
                }
                else {
                    uerror("pq_open: \"%s\" failed: %s",
                            pqfname, status > 0 ? strerror(status) :
                                            "Internal error");
                }
                exit(exit_pq_open);
        }


        {
        char *filename;
        int fd;
        struct stat statb;
        product prod;
        MD5_CTX *md5ctxp = NULL;

        /*
         * Allocate an MD5 context
         */
        md5ctxp = new_MD5_CTX();
        if(md5ctxp == NULL)
        {
                serror("new_md5_CTX failed");
                exit(exit_md5);
        }


        /* These members are constant over the loop. */
        prod.info.origin = myname;
        prod.info.feedtype = feedtype;

        if (ac > 1) {
          multipleFiles = TRUE;
        }

        for(prod.info.seqno = seq_start ; ac > 0 ;
                         av++, ac--, prod.info.seqno++)
        {
                filename = *av;

                fd = open(filename, O_RDONLY, 0);
                if(fd == -1)
                {
                        serror("open: %s", filename);
                        exitCode = exit_infile;
                        continue;
                }

                if( fstat(fd, &statb) == -1) 
                {
                        serror("fstat: %s", filename);
                        (void) close(fd);
                        exitCode = exit_infile;
                        continue;
                }

                /* Determine what to use for product identifier */
                if (useProductID) 
                  {
                    if (multipleFiles) 
                      {
                        sprintf(identifier,"%s.%d", productID, prod.info.seqno);
                        prod.info.ident = identifier;
                      }
                    else
                      prod.info.ident = productID;
                   }
                else
                    prod.info.ident = filename;
                
                prod.info.sz = statb.st_size;
                prod.data = NULL;

                /* These members, and seqno, vary over the loop. */
                status = set_timestamp(&prod.info.arrival);
                if(status != ENOERR) {
                        serror("set_timestamp: %s, filename");
                        exitCode = exit_infile;
                        continue;
                }

#if USE_MMAP
                prod.data = mmap(0, prod.info.sz,
                        PROT_READ, MAP_PRIVATE, fd, 0);
                if(prod.data == NULL)
                {
                        serror("mmap: %s", filename);
                        (void) close(fd);
                        exitCode = exit_infile;
                        continue;
                }

                status = 
                    signatureFromId
                        ? mm_md5(md5ctxp, prod.info.ident,
                            strlen(prod.info.ident), prod.info.signature)
                        : mm_md5(md5ctxp, prod.data, prod.info.sz,
                            prod.info.signature);

                (void)exitIfDone(1);

                if (status != 0) {
                    serror("mm_md5: %s", filename);
                    (void) munmap(prod.data, prod.info.sz);
                    (void) close(fd);
                    exitCode = exit_infile;
                    continue;
                }

                /* These members, and seqno, vary over the loop. */
                status = set_timestamp(&prod.info.arrival);
                if(status != ENOERR) {
                        serror("set_timestamp: %s, filename");
                        exitCode = exit_infile;
                        continue;
                }

                /*
                 * Do the deed
                 */
                status = pq_insert(pq, &prod);

                switch (status) {
                case ENOERR:
                    /* no error */
                    if(ulogIsVerbose())
                        uinfo("%s", s_prod_info(NULL, 0, &prod.info,
                            ulogIsDebug())) ;
                    break;
                case PQUEUE_DUP:
                    uerror("Product already in queue: %s",
                        s_prod_info(NULL, 0, &prod.info, 1));
                    exitCode = exit_dup;
                    break;
                case PQUEUE_BIG:
                    uerror("Product too big for queue: %s",
                        s_prod_info(NULL, 0, &prod.info, 1));
                    exitCode = exit_infile;
                    break;
                case ENOMEM:
                    uerror("queue full?");
                    exitCode = exit_system;
                    break;  
                case EINTR:
#if defined(EDEADLOCK) && EDEADLOCK != EDEADLK
                case EDEADLOCK:
                    /*FALLTHROUGH*/
#endif
                case EDEADLK:
                    /* TODO: retry ? */
                    /*FALLTHROUGH*/
                default:
                    uerror("pq_insert: %s", status > 0
                        ? strerror(status) : "Internal error");
                    break;
                }

                (void) munmap(prod.data, prod.info.sz);
#else // USE_MMAP above; !USE_MMAP below
                status = 
                    signatureFromId
                        ? mm_md5(md5ctxp, prod.info.ident,
                            strlen(prod.info.ident), prod.info.signature)
                        : fd_md5(md5ctxp, fd, statb.st_size,
                            prod.info.signature);

                (void)exitIfDone(1);

                if (status != 0) {
                        serror("xx_md5: %s", filename);
                        (void) close(fd);
                        exitCode = exit_infile;
                        continue;
                }

                if(lseek(fd, 0, SEEK_SET) == (off_t)-1)
                {
                        serror("rewind: %s", filename);
                        (void) close(fd);
                        exitCode = exit_infile;
                        continue;
                }

                pqeIndex = PQE_NONE;
                status = pqe_new(pq, &prod.info, &prod.data, &pqeIndex);

                if(status != ENOERR) {
                    serror("pqe_new: %s", filename);
                    exitCode = exit_infile;
                }
                else {
                    ssize_t     nread = read(fd, prod.data, prod.info.sz);

                    (void)exitIfDone(1);

                    if (nread != prod.info.sz) {
                        serror("read %s %u", filename, prod.info.sz);
                        status = EIO;
                    }
                    else {
                        status = pqe_insert(pq, pqeIndex);
                        pqeIndex = PQE_NONE;

                        switch (status) {
                        case ENOERR:
                            /* no error */
                            if(ulogIsVerbose())
                                uinfo("%s", s_prod_info(NULL, 0, &prod.info,
                                    ulogIsDebug())) ;
                            break;
                        case PQUEUE_DUP:
                            uerror("Product already in queue: %s",
                                s_prod_info(NULL, 0, &prod.info, 1));
                            exitCode = exit_dup;
                            break;
                        case ENOMEM:
                            uerror("queue full?");
                            break;  
                        case EINTR:
#if defined(EDEADLOCK) && EDEADLOCK != EDEADLK
                        case EDEADLOCK:
                            /*FALLTHROUGH*/
#endif
                        case EDEADLK:
                            /* TODO: retry ? */
                            /*FALLTHROUGH*/
                        default:
                            uerror("pq_insert: %s", status > 0
                                ? strerror(status) : "Internal error");
                        }
                    }                   /* data read into `pqeIndex` region */

                    if (status != ENOERR) {
                        (void)pqe_discard(pq, pqeIndex);
                        pqeIndex = PQE_NONE;
                    }
                }                       /* `pqeIndex` region allocated */

#endif
                (void) close(fd);
        }                               /* input-file loop */

        free_MD5_CTX(md5ctxp);  
        }                               /* code block */

        exit(exitCode);
}
Пример #15
0
int
main(int ac, char *av[])
{
        int logfd;
        int width;
        int ready;
        unsigned long idle;
        fd_set readfds;
        fd_set exceptfds;
        struct timeval timeo;
        const char* const progname = ubasename(av[0]);
        unsigned logopts = LOG_CONS|LOG_PID;
        int logmask = LOG_UPTO(LOG_NOTICE);
        unsigned long maxProductSize = DEFAULT_MAX_PRODUCT_SIZE;

        /*
         * Setup default logging before anything else.
         */
        logfd = openulog(progname, logopts, LOG_LDM, logpath);
        (void) setulogmask(logmask);

        feedtype = whatami(av[0]);

        {
            extern int optind;
            extern int opterr;
            extern char *optarg;
            int ch;

            opterr = 0; /* stops getopt() from printing to stderr */
            usePil = 1;
            useNex = 1;
            pqpath = getQueuePath();

            while ((ch = getopt(ac, av, ":vxcni5Nl:b:p:P:T:q:r:f:s:")) != EOF)
                    switch (ch) {
                    case 'v':
                            logmask |= LOG_MASK(LOG_INFO);
                            (void) setulogmask(logmask);
                            break;
                    case 'x':
                            logmask |= LOG_MASK(LOG_DEBUG);
                            (void) setulogmask(logmask);
                            break;
                    case 'c':
                            chkflag = CHK_CHECK;
                            break;
                    case 'n':
                            chkflag = CHK_DONT;
                            break;
                    case 'i':
                            usePil = 0;
                            break;
                    case 'N':
                            useNex = 0;
                            break;
                    case '5':
                            skipLeadingCtlString = 0;
                            break;
                    case 'l': {
                            logpath = optarg;
                            if (strcmp(logpath, "-") == 0) {
                                logopts = LOG_NOTIME;
                            }
                            else {
                                logopts = LOG_CONS | LOG_PID;
                                (void) fclose(stderr);
                            }
                            logfd = openulog(progname, logopts, LOG_LDM, logpath);
                            break;
                    }
                    case 'b':
                            baud = optarg;
                            break;
                    case 'p':
                            parity = optarg;
                            break;
    #if NET
                    case 'P':
                            *((int *)&server_port) = atoi(optarg); /* cast away const */
                            if(server_port <= 0 || server_port > 65536)
                            {
                                    LOG_ADD1("Invalid server port: \"%s\"", optarg);
                                    log_log(LOG_ERR);
                                    usage(progname);
                            }
                            break;
                    case 'T':
                            reset_secs = atoi(optarg);
                            if(reset_secs < 0)
                            {
                                    LOG_ADD1("Invalid timeout: \"%s\"", optarg);
                                    usage(progname);
                            }
                            break;
    #endif /* NET */
                    case 's': {
                            unsigned long size;
                            int           nbytes;

                            if (sscanf(optarg, "%lu %n", &size, &nbytes) != 1 ||
                                    optarg[nbytes] != 0 || 1 > size) {
                                LOG_ADD1("Invalid maximum data-product size: \"%s\"",
                                        optarg);
                                log_log(LOG_ERR);
                                usage(progname);
                            }

                            maxProductSize = size;
                            break;
                    }
                    case 'q':
                            pqpath = optarg;
                            break;
                    case 'r':
                            rawfname = optarg;
                            break;
                    case 'f':
                            {
                                    feedtypet type;
                                    type = atofeedtypet(optarg);
                                    if(type != NONE)
                                    {
                                            feedtype = type;
                                            if(!parity && !baud)
                                                    setFeedDefaults(type);
                                    }
                            }
                            break;
                    case '?': {
                            LOG_ADD1("Unknown option: \"%c\"", optopt);
                            usage(progname);
                            break;
                    }
                    case ':':
                    /*FALLTHROUGH*/
                    default:
                            LOG_ADD1("Missing argument for option: \"%c\"", optopt);
                            usage(progname);
                            break;
                    }

            /* last arg, feedfname, is required */
            if(ac - optind != 1) {
                    LOG_ADD1("Wrong number of operands: %d", ac - optind);
                    usage(progname);
            }
            (void)strncat(feedfname, av[optind], sizeof(feedfname)-6);
        }

        unotice("Starting Up");
        udebug(PACKAGE_VERSION);

        if(logpath == NULL || !(*logpath == '-' && logpath[1] == 0))
        {
                if (logfd < 0) {
                    uerror("logfd < 0");
                    return 1;
                }
                setbuf(fdopen(logfd, "a"), NULL);
        }       

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

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

        /*
         * open the product queue, unless we were invoked as "feedtest"
         */
        if(strcmp(progname, "feedtest") != 0)
        {
                if((ready = pq_open(pqpath, PQ_DEFAULT, &pq)))
                {
                        if (PQ_CORRUPT == ready) {
                            uerror("The product-queue \"%s\" is inconsistent\n",
                                    pqpath);
                        }
                        else {
                            uerror("pq_open: \"%s\" failed: %s",
                                    pqpath, strerror(ready));
                        }
                        return 1;
                }
        }

        /*
         * who am i, anyway
         */
        (void) strncpy(myname, ghostname(), sizeof(myname));
        myname[sizeof(myname)-1] = 0;

        /*
         * open the feed
         */
        if(!(*feedfname == '-' && feedfname[1] == 0) && logfd != 0)
                (void) close(0);

        if(open_feed(feedfname, &ifd, maxProductSize) != ENOERR)
                return 1;

        if(usePil == 1)
           {
           if ((feedtype & DDS)||(feedtype & PPS)||(feedtype & IDS)||
                (feedtype & HRS))
              {
              usePil = 1;
              uinfo("Creating AFOS-like pil tags\0");
              }
           else
              {
              usePil = 0;
              }
           }

        if (feedtype & HDS)
        {
                if(chkflag == CHK_CHECK
                                || (isatty(ifd) && chkflag != CHK_DONT))
                        setTheScanner(scan_wmo_binary_crc);
                else
                        setTheScanner(scan_wmo_binary);
        }
        else if (feedtype == ( DDPLUS | IDS ) ) 
        { 
                /* this is the combined NOAAPORT fos-alike. We know these have the
                   4 byte start and end sequences. Using the binary scanner
                   ensures that we don't stop on an arbitray embedded CTRL-C */
                unotice("Note: Using the wmo_binary scanner for SDI ingest\0");
                setTheScanner (scan_wmo_binary); 
        }
        else if (feedtype & (NMC2 | NMC3))
        {
                setTheScanner(scan_wmo_binary);
        }
        else if (feedtype == AFOS)
        {
                prod_stats = afos_stats;
                setTheScanner(scan_afos);
        }
        else if (feedtype == FAA604)
        {
                prod_stats = faa604_stats;
                if(chkflag == CHK_CHECK
                        || (isatty(ifd)
                                 && chkflag != CHK_DONT
                                 && parity != NULL
                                 && *parity != 'n')
                        )
                {
                        setTheScanner(scan_faa604_parity);
                }
                else
                {
                        setTheScanner(scan_faa604);
                }
        }
        else
        {
                if(chkflag == CHK_CHECK
                        || (isatty(ifd)
                                 && chkflag != CHK_DONT
                                 && parity != NULL
                                 && *parity != 'n')
                        )
                {
                        setTheScanner(scan_wmo_parity);
                }
                else
                {
                        setTheScanner(scan_wmo);
                }
        }

        /*
         * Allocate an MD5 context
         */
        md5ctxp = new_MD5_CTX();
        if(md5ctxp == NULL)
        {
                serror("new_md5_CTX failed");
                return 1;
        }


        /*
         * Main Loop
         */
        idle = 0;
        while(exitIfDone(0))
        {
#if NET
if (INPUT_IS_SOCKET)
{
                if (port_error)
                {
                        /*
                         * lost connection => close
                         */
                        if (ifd >= 0)
                        {
                                if(feed_close)
                                        (*feed_close)(ifd);
                                ifd = -1;
                        }
                        port_error = 0;
                        sleep (2);      /* allow things to settle down */
                        continue;
                }
}
#endif
                if(stats_req)
                {
                        unotice("Statistics Request"); 
                        if(pq != NULL)
                        {
                                off_t highwater = 0;
                                size_t maxregions = 0;
                                (void) pq_highwater(pq, &highwater,
                                         &maxregions);
                                unotice("  Queue usage (bytes):%8ld",
                                                        (long)highwater);
                                unotice("           (nregions):%8ld",
                                                        (long)maxregions);
                        }
                        unotice("       Idle: %8lu seconds", idle);
#if NET
if (INPUT_IS_SOCKET)
{
                        unotice("    Timeout: %8d", reset_secs);
}
#endif
                        unotice("%21s: %s", "Status",
                                (ifd < 0) ?
                                "Not connected or input not open." :
                                "Connected.");
                        (*prod_stats)();
                        (*feed_stats)();
                        stats_req = 0;
                }
#if NET
if (INPUT_IS_SOCKET)
{
                if (ifd < 0)
                {
                        /* Attempt reconnect */
                        static int retries = 0;
                        if (retries > MAX_RETRIES)
                        {
                                uerror ("maximum retry attempts %d, aborting",
                                        MAX_RETRIES);
                                done = !0;
                                continue;
                        }
                        /* Try to reopen on tcp read errors */
                        unotice("Trying to re-open connection on port %d", 
                                server_port);
                        ++retries;
                        if(open_feed(feedfname, &ifd, maxProductSize) != ENOERR)
                        {
                                unotice ("sleeping %d seconds before retry %d",
                                         retries * RETRY_DELAY, retries+1);
                                sleep (retries * RETRY_DELAY);
                                continue;
                        }
                        retries = 0;
                }
}
#endif /* NET */
                timeo.tv_sec = 3;
                timeo.tv_usec = 0;
                FD_ZERO(&readfds);
                FD_ZERO(&exceptfds);
                FD_SET(ifd, &readfds);
                FD_SET(ifd, &exceptfds);
                width =  ifd + 1;
                ready = select(width, &readfds, 0, &exceptfds, &timeo);
                if(ready < 0 )
                {
                        /* handle EINTR as a special case */
                        if(errno == EINTR)
                        {
                                errno = 0;
                                continue;
                        }
                        serror("select");
                        return 1;
                }
                /* else */
#if 0
                if (FD_ISSET(ifd, &exceptfds))
                {
                        uerror("Exception on input fd %d, select returned %d",
                               ifd, ready);
                }
#endif
                if(ready > 0)
                {
                        /* do some work */
                        if(FD_ISSET(ifd, &readfds) || 
                           FD_ISSET(ifd, &exceptfds))
                        {
                                idle = 0;
                                if(feedTheXbuf(ifd) != ENOERR)
                                {
#if NET
if (INPUT_IS_SOCKET)
{
                                        port_error = !0;
                                        continue;
}                                       /* else */
#endif /* NET */
                                        done = !0;
                                }
                                FD_CLR(ifd, &readfds);
                                FD_CLR(ifd, &exceptfds);
                        }
                        else
                        {
                                uerror("select returned %d but ifd not set",
                                        ready);
                                idle += timeo.tv_sec;
                        }
                }
                else    /* ready == 0 */
                {
                        idle += timeo.tv_sec;
#if NET
if (INPUT_IS_SOCKET)
{
                        /* VOODOO
                         * This is necessary to stimulate
                         * 'Connection reset by peer'
                         * when the Portmaster goes down and comes
                         * back up.
                         */
                        static char zed[1] = {0};
                        if(write(ifd, zed, sizeof(zed)) < 0)
                        {
                                port_error = !0;
                                continue;
                        }

}
#endif
                }
#if NET
if (INPUT_IS_SOCKET)
{
                if ((reset_secs > 0) && (idle >= reset_secs))
                {
                        unotice("Idle for %ld seconds, reconnecting",
                                idle);
                        /* force reconnect */
                        port_error = !0;
                        idle = 0;
                        continue;
                }
}
#endif /* NET */
                (void) scanTheXbuf();
        }

        return 0;
}