Example #1
0
/**
 * Reads NOAAPORT data from a shared-memory FIFO or a file, creates LDM
 * data-products, and inserts the data-products into an LDM product-queue.
 *
 * Usage:
 *
 *     readnoaaport [-nvx] [-q <em>queue</em>] [-u <em>n</em>] [-m mcastAddr] [path]\n
 *
 * Where:
 * <dl>
 *      <dt>-l <em>log</em></dt>
 *      <dd>Log to \e log. if \e log is "-", then logging occurs to the 
 *      standard error stream; otherwise, \e log is the pathname of a file to
 *      which logging will occur. If not specified, then log messages will go
 *      to the system logging daemon. </dd>
 *
 *      <dt>-m <em>mcastAddr</em></dt>
 *      <dd>Use the shared-memory FIFO associated with the UDP
 *      multicast address \e mcastAddr.</dd>
 *
 *      <dt>-n</dt>
 *      <dd>Log messages of level NOTICE and higher priority.</dd>
 *
 *      <dt>-q <em>queue</em></dt>
 *      <dd>Use \e queue as the pathname of the LDM product-queue. The default
 *      is to use the default LDM pathname of the product-queue.</dd>
 *
 *      <dt>-u <em>n</em></dt>
 *      <dd>If logging is to the system logging daemon, then use facility 
 *      <b>local</b><em>n</em>. The default is to use the LDM facility.
 *
 *      <dt>-v</dt>
 *      <dd>Log messages of level INFO and higher priority. Each data-product
 *      will generate a log message.</dd>
 *
 *      <dt>-x</dt>
 *      <dd>Log messages of level DEBUG and higher priority.</dd>
 *
 *      <dt><em>path</em></dt>
 *      <dd>Pathname of the file from which to read data. The default is to use
 *      a shared-memory FIFO.</dd>
 * </dl>
 *
 * @retval 0 if successful.
 * @retval 1 if an error occurred. At least one error-message is logged.
 */
int main(
     const int          argc,
     char* const        argv[])
{
#ifdef HAVE_GET_QUEUE_PATH
    const char*         pqfname = getQueuePath();
#else
    const char*         pqfname = DEFAULT_QUEUE;
#endif
    int                 fd;
    char*               prodmmap;
    char*               memheap = NULL;
    size_t              heapsize;
    size_t              heapcount;
    unsigned char       b1;
    int                 cnt, dataoff, datalen, deflen;
    int                 nscan;
    long                IOFF;
    int                 NWSTG, GOES, PNGINIT = 0, PROD_COMPRESSED;
    long                last_sbn_seqno = (-1);
    char                PROD_NAME[1024];
    int                 status;
    prodstore           prod;
    sbn_struct*         sbn;
    pdh_struct*         pdh;
    psh_struct*         psh;
    ccb_struct*         ccb;
    pdb_struct*         pdb;
    datastore*          pfrag;
    extern int          optind;
    extern int          opterr;
    extern char*        optarg;
    int                 ch;
    int                 logmask = LOG_MASK(LOG_ERR);
    const char*         logfname = NULL;        /* use system logging daemon */
    unsigned            logOptions = LOG_CONS | LOG_PID;
    unsigned            logFacility = LOG_LDM;  /* use default LDM facility */
    const char* const   progName = ubasename(argv[0]);
    MD5_CTX*            md5ctxp = NULL;
    /*unsigned char *compr;
    long                comprLen = 10000 * sizeof (int);*/
    int                 pid_channel = -1;

    /*compr = (unsigned char *) calloc (comprLen, 1);*/

    /* Initialize the logger. */
    (void)setulogmask(logmask);
    (void)openulog(progName, logOptions, logFacility, logfname);

    opterr = 1;
    while ((ch = getopt(argc, argv, "nvxl:q:u:m:")) != 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 'n':
            logmask |= LOG_MASK(LOG_NOTICE);
            (void)setulogmask(logmask);
            break;
        case 'l':
            if (optarg[0] == '-' && optarg[1] != 0) {
                nplError("logfile \"%s\" ??\n", optarg);
                usage(argv[0]);
            }
            /* else */
            logfname = optarg;
            (void)openulog(progName, logOptions, logFacility, logfname);
            break;
        case 'q':
            pqfname = optarg;
            break;
        case 'u': {
            int         i = atoi(optarg);

            if (0 <= i && 7 >= i) {
                static int  logFacilities[] = {LOG_LOCAL0, LOG_LOCAL1,
                    LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6,
                    LOG_LOCAL7};

                logFacility = logFacilities[i];

                (void)openulog(progName, logOptions, logFacility, logfname);
            }

            break;
        }
        case 'm':
            sscanf(optarg, "%*d.%*d.%*d.%d", &pid_channel);	
            if ((pid_channel < 1) || (pid_channel > MAX_DVBS_PID)) {
                pid_channel = -1;
            }
            else {  
                shm = shmfifo_new();
                cnt = 0;

                while (((status = shmfifo_shm_from_key(shm, 
                          s_port[pid_channel - 1])) == -3) && (cnt < 30)) {
                    nplInfo("Trying to get shared-memory FIFO");
                    cnt++;
                    sleep(1);
                }

                if (0 != status) {
                    nplError("Couldn't get shared-memory FIFO. "
                            "Check associated dvbs_multicast(1) process.");
                    shmfifo_free(shm);
                    shm = NULL;
                }
                else {
                    nplInfo("Got shared-memory FIFO");
                }
            }
            break;
        case '?':
            usage(argv[0]);
            break;
        }
    }

    if (argc - optind < 0)
        usage(argv[0]);

    nplNotice("Starting Up %s", PACKAGE_VERSION);

    fd = ((argc - optind) == 0)
        ? fileno(stdin)
        : open(argv[optind], O_RDONLY, 0);

    if ((!shm) && (fd == -1)) {
        nplError("could not open input file");
        exit(0);
    }

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

    /*
     * Register atexit routine
     */
    if (atexit(cleanup) != 0) {
        nplSerror("atexit");
        exit(-1);
    }

    sbn = (sbn_struct*)malloc(sizeof(sbn_struct));
    pdh = (pdh_struct*)malloc(sizeof(pdh_struct));
    psh = (psh_struct*)malloc(sizeof(psh_struct));
    ccb = (ccb_struct*)malloc(sizeof(ccb_struct));
    pdb = (pdb_struct*)malloc(sizeof(pdb_struct));
    prodmmap = (char*)malloc(10000);

    if (prodmmap == NULL) {
        nplError("could not allocate read buffer");
        exit(-1);
    }

    md5ctxp = new_MD5_CTX();
    prod.head = NULL;
    prod.tail = NULL;

    if (lpqGet(pqfname, &ldmProdQueue) != 0) {
        NPL_ADD1("Couldn't open LDM product-queue \"%s\"", pqfname);
        exit(1);
    }

    while (DONE == 0) {
        /* See if any stats need to be logged */
        if (logstats) {
            logstats = 0;
            dump_stats();
        }

        /* Look for first byte == 255  and a valid SBN checksum */
        if ((status = bufread(fd, prodmmap, 1)) != 0) {
            if (-3 == status)
                break;
            abort();
        }
        if ((b1 = (unsigned char)prodmmap[0]) != 255) {
            if (ulogIsVerbose())
                nplInfo("trying to resync %u", b1);
            if (ulogIsDebug())
                nplDebug("bufread loop");
            continue;
        }

        if (bufread(fd, prodmmap + 1, 15) != 0) {
            if (ulogIsDebug())
                nplDebug("couldn't read 16 bytes for sbn");
            continue;
        }

        while ((status = readsbn(prodmmap, sbn)) != 0) {
            if (ulogIsDebug())
                nplDebug("Not SBN start");

            IOFF = 1;

            while ((IOFF < 16) && ((b1 = (unsigned char) prodmmap[IOFF]) !=
                        255))
                IOFF++;

            if (IOFF > 15) {
                break;
            }
            else {
                for (ch = IOFF; ch < 16; ch++)
                    prodmmap[ch - IOFF] = prodmmap[ch];

                if (bufread(fd, prodmmap + 16 - IOFF, IOFF) != 0) {
                    if (ulogIsDebug())
                        nplDebug("Couldn't read bytes for SBN, resync");
                    break;
                }
            }
        }

        if (status != 0) {
            if (ulogIsDebug())
                nplDebug("SBN status continue");
            continue;
        }

        IOFF = 0;

        if (bufread(fd, prodmmap + 16, 16) != 0) {
            if (ulogIsDebug())
                nplDebug("error reading Product Definition Header");
            continue;
        }

        if (ulogIsDebug())
            nplDebug("***********************************************");
        if (last_sbn_seqno != -1) {
            if (sbn->seqno != last_sbn_seqno + 1) {
                nplNotice("Gap in SBN sequence number %ld to %ld [skipped %ld]",
                         last_sbn_seqno, sbn->seqno,
                         sbn->seqno - last_sbn_seqno - 1);
                if ( sbn->seqno > last_sbn_seqno )
                    nmissed = nmissed + 
                        (unsigned long)(sbn->seqno - last_sbn_seqno - 1);
            }
        }

        last_sbn_seqno = sbn->seqno;

        if (ulogIsVerbose())
            nplInfo("SBN seqnumber %ld", sbn->seqno);
        if (ulogIsVerbose())
            nplInfo("SBN datastream %d command %d", sbn->datastream,
                sbn->command);
        if (ulogIsDebug())
            nplDebug("SBN version %d length offset %d", sbn->version, sbn->len);
        if (((sbn->command != 3) && (sbn->command != 5)) || 
                (sbn->version != 1)) {
            nplError("Unknown sbn command/version %d PUNT", sbn->command);
            continue;
        }

        switch (sbn->datastream) {
        case 7:	      /* test */
        case 6:       /* was reserved...now nwstg2 */
        case 5:
            NWSTG = 1;
            GOES = 0;
            break;
        case 1:
        case 2:
        case 4:
            NWSTG = 0;
            GOES = 1;
            break;
        default:
            nplError("Unknown NOAAport channel %d PUNT", sbn->datastream);
            continue;
        }

        /* End of SBN version low 4 bits */

        if (readpdh(prodmmap + IOFF + sbn->len, pdh) == -1) {
            nplError("problem with pdh, PUNT");
            continue;
        }
        if (pdh->len > 16) {
            bufread(fd, prodmmap + sbn->len + 16, pdh->len - 16);
        }

        if (ulogIsDebug())
            nplDebug("Product definition header version %d pdhlen %d",
                pdh->version, pdh->len);

        if (pdh->version != 1) {
            nplError("Error: PDH transfer type %u, PUNT", pdh->transtype);
            continue;
        }
        else if (ulogIsDebug()) {
            nplDebug("PDH transfer type %u", pdh->transtype);
        }

        if ((pdh->transtype & 8) > 0)
            nplError("Product transfer flag error %u", pdh->transtype);
        if ((pdh->transtype & 32) > 0)
            nplError("Product transfer flag error %u", pdh->transtype);

        if ((pdh->transtype & 16) > 0) {
            PROD_COMPRESSED = 1;

            if (ulogIsDebug())
                nplDebug("Product transfer flag compressed %u", pdh->transtype);
        }
        else {
            PROD_COMPRESSED = 0;
        }

        if (ulogIsDebug())
            nplDebug("header length %ld [pshlen = %d]", pdh->len + pdh->pshlen,
                pdh->pshlen);
        if (ulogIsDebug())
            nplDebug("blocks per record %ld records per block %ld\n",
                pdh->blocks_per_record, pdh->records_per_block);
        if (ulogIsDebug())
            nplDebug("product seqnumber %ld block number %ld data block size "
                "%ld", pdh->seqno, pdh->dbno, pdh->dbsize);

        /* Stop here if no psh */
        if ((pdh->pshlen == 0) && (pdh->transtype == 0)) {
            IOFF = IOFF + sbn->len + pdh->len;
            continue;
        }

        if (pdh->pshlen != 0) {
            if (bufread(fd, prodmmap + sbn->len + pdh->len, pdh->pshlen) != 0) {
                nplError("problem reading psh");
                continue;
            }
            else {
                if (ulogIsDebug())
                    nplDebug("read psh %d", pdh->pshlen);
            }

            /* Timing block */
            if (sbn->command == 5) {
                if (ulogIsDebug())
                    nplDebug("Timing block recieved %ld %ld\0", psh->olen,
                        pdh->len);
                /*
                 * Don't step on our psh of a product struct of prod in
                 * progress.
                 */
                continue;
            }

            if (readpsh(prodmmap + IOFF + sbn->len + pdh->len, psh) == -1) {
                nplError("problem with readpsh");
                continue;
            }
            if (psh->olen != pdh->pshlen) {
                nplError("ERROR in calculation of psh len %ld %ld", psh->olen,
                    pdh->len);
                continue;
            }
            if (ulogIsDebug())
                nplDebug("len %ld", psh->olen);
            if (ulogIsDebug())
                nplDebug("product header flag %d, version %d", psh->hflag,
                    psh->version);
            if (ulogIsDebug())
                nplDebug("prodspecific data length %ld", psh->psdl);
            if (ulogIsDebug())
                nplDebug("bytes per record %ld", psh->bytes_per_record);
            if (ulogIsDebug())
                nplDebug("Fragments = %ld category %d ptype %d code %d",
                    psh->frags, psh->pcat, psh->ptype, psh->pcode);
            if (psh->frags < 0)
                nplError("check psh->frags %d", psh->frags);
            if (psh->origrunid != 0)
                nplError("original runid %d", psh->origrunid);
            if (ulogIsDebug())
                nplDebug("next header offset %ld", psh->nhoff);
            if (ulogIsDebug())
                nplDebug("original seq number %ld", psh->seqno);
            if (ulogIsDebug())
                nplDebug("receive time %ld", psh->rectime);
            if (ulogIsDebug())
                nplDebug("transmit time %ld", psh->transtime);
            if (ulogIsDebug())
                nplDebug("run ID %ld", psh->runid);
            if (ulogIsDebug())
                nplDebug("original run id %ld", psh->origrunid);
            if (prod.head != NULL) {
                nplError("OOPS, start of new product [%ld ] with unfinished "
                    "product %ld", pdh->seqno, prod.seqno);

                ds_free();

                prod.head = NULL;
                prod.tail = NULL;

                if (PNGINIT != 0) {
                    pngout_end();
                    PNGINIT = 0;
                }

                nplError("Product definition header version %d pdhlen %d",
                        pdh->version, pdh->len);
                nplError("PDH transfer type %u", pdh->transtype);

                if ((pdh->transtype & 8) > 0)
                    nplError("Product transfer flag error %u", pdh->transtype);
                if ((pdh->transtype & 32) > 0)
                    nplError("Product transfer flag error %u", pdh->transtype);

                nplError("header length %ld [pshlen = %d]",
                    pdh->len + pdh->pshlen, pdh->pshlen);
                nplError("blocks per record %ld records per block %ld",
                    pdh->blocks_per_record, pdh->records_per_block);
                nplError("product seqnumber %ld block number %ld data block "
                    "size %ld", pdh->seqno, pdh->dbno, pdh->dbsize);
                nplError("product header flag %d", psh->hflag);
                nplError("prodspecific data length %ld", psh->psdl);
                nplError("bytes per record %ld", psh->bytes_per_record);
                nplError("Fragments = %ld category %d", psh->frags, psh->pcat);

                if (psh->frags < 0)
                    nplError("check psh->frags %d", psh->frags);
                if (psh->origrunid != 0)
                    nplError("original runid %d", psh->origrunid);

                nplError("next header offset %ld", psh->nhoff);
                nplError("original seq number %ld", psh->seqno);
                nplError("receive time %ld", psh->rectime);
                nplError("transmit time %ld", psh->transtime);
                nplError("run ID %ld", psh->runid);
                nplError("original run id %ld", psh->origrunid);
            }

            prod.seqno = pdh->seqno;
            prod.nfrag = psh->frags;

            ds_init(prod.nfrag);

            /* NWSTG CCB = dataoff, WMO = dataoff + 24 */

            if (bufread(fd, prodmmap + sbn->len + pdh->len + pdh->pshlen,
                    pdh->dbsize) != 0) {
                nplError("problem reading datablock");
                continue;
            }
            if (sbn->datastream == 4) {
                if (psh->pcat != 3) {
                    GOES = 0;
                    NWSTG = 1;
                }
            }

            heapcount = 0;

            MD5Init(md5ctxp);

            if (GOES == 1) {
                if (readpdb(prodmmap + IOFF + sbn->len + pdh->len + pdh->pshlen,
                        psh, pdb, PROD_COMPRESSED, pdh->dbsize) == -1) {
                    nplError("Error reading pdb, punt");
                    continue;
                }

                memcpy(PROD_NAME, psh->pname, sizeof(PROD_NAME));

                if (ulogIsDebug())
                    nplDebug("Read GOES %d %d %d [%d] %d", sbn->len, pdh->len,
                        pdh->pshlen, sbn->len + pdh->len + pdh->pshlen,
                        pdb->len);

                /* Data starts at first block after pdb */
                ccb->len = 0;
                heapsize = prodalloc(psh->frags, 5152, &memheap);
            }
            if (NWSTG == 1) {
                memset(psh->pname, 0, sizeof(psh->pname));

                if (readccb(prodmmap + IOFF + sbn->len + pdh->len + pdh->pshlen,
                        ccb, psh, pdh->dbsize) == -1)
                    nplError("Error reading ccb, using default name");
                if (ulogIsDebug())
                    nplDebug("look at ccb start %d %d", ccb->b1, ccb->len);

                /*
                   cnt = 0;
                   memset(psh->pname,0,sizeof(psh->pname));
                   while ((b1 = (unsigned char)prodmmap[
                           IOFF + sbn->len + pdh->len + pdh->pshlen + ccb->len +
                           cnt]) >= 32) {
                       psh->pname[cnt] = prodmmap[
                           IOFF + sbn->len + pdh->len + pdh->pshlen + ccb->len +
                           cnt];
                       cnt++;
                   } 
                   if(cnt > 0)
                 */
                if (ulogIsVerbose())
                    nplInfo("%s", psh->pname);

                memcpy(PROD_NAME, psh->pname, sizeof(PROD_NAME));

                heapsize = prodalloc(psh->frags, 4000 + 15, &memheap);
                /*
                 * We will only compute md5 checksum on the data, 11 FOS
                 * characters at start
                 */
                /*
                 * sprintf(memheap,"\001\015\015\012%04d\015\015\012",
                 * ((int)pdh->seqno)%10000);
                 */
                sprintf(memheap, "\001\015\015\012%03d\040\015\015\012",
                    ((int) pdh->seqno) % 1000);

                heapcount += 11;

                if (psh->metaoff > 0)
                    psh->metaoff = psh->metaoff + 11;
            }
        }
        else {
            /* If a continuation record...don't let psh->pcat get missed */
            if ((sbn->datastream == 4) && (psh->pcat != 3)) {
                GOES = 0;
                NWSTG = 1;
            }

            ccb->len = 0;

            if (ulogIsDebug())
                nplDebug("continuation record");
            if ((pdh->transtype & 4) > 0) {
                psh->frags = 0;
            }
            if (bufread(fd, prodmmap + sbn->len + pdh->len + pdh->pshlen,
                    pdh->dbsize) != 0) {
                nplError("problem reading datablock (cont)");
                continue;
            }
            if (prod.head == NULL) {
                if (ulogIsVerbose())
                    nplInfo("found data block before header, "
                        "skipping sequence %d frag #%d", pdh->seqno, pdh->dbno);
                continue;
            }
        }

        /* Get the data */
        dataoff = IOFF + sbn->len + pdh->len + pdh->pshlen + ccb->len;
        datalen = pdh->dbsize - ccb->len;

        if (ulogIsDebug())
            nplDebug("look at datalen %d", datalen);

        pfrag = ds_alloc();
        pfrag->seqno = pdh->seqno;
        pfrag->fragnum = pdh->dbno;
        pfrag->recsiz = datalen;
        pfrag->offset = heapcount;
        pfrag->next = NULL;

        /*memcpy(memheap+heapcount,prodmmap+dataoff,datalen);
        MD5Update(md5ctxp, (unsigned char *)(memheap+heapcount), datalen);
        test_deflate(compr,comprLen,(unsigned char *)(memheap+heapcount),
        datalen);*/

        if (GOES == 1) {
            if (pfrag->fragnum > 0) {
                if ((pfrag->fragnum != prod.tail->fragnum + 1) || 
                        (pfrag->seqno != prod.seqno)) {
                    nplError("Missing GOES fragment in sequence, "
                        "last %d/%d this %d/%d\0", prod.tail->fragnum,
                        prod.seqno, pfrag->fragnum, pfrag->seqno);
                    ds_free();

                    prod.head = NULL;
                    prod.tail = NULL;

                    continue;
                }

                if ((PNGINIT != 1) && (!PROD_COMPRESSED)) {
                    nplError("failed pnginit %d %d %s", sbn->datastream,
                            psh->pcat, PROD_NAME);
                    continue;
                }
                if (pdh->records_per_block < 1) {
                    nplError("records_per_block %d blocks_per_record %d "
                        "nx %d ny %d", pdh->records_per_block,
                        pdh->blocks_per_record, pdb->nx, pdb->ny);
                    nplError("source %d sector %d channel %d", pdb->source,
                        pdb->sector, pdb->channel);
                    nplError("nrec %d recsize %d date %02d%02d%02d %02d%02d "
                        "%02d.%02d", pdb->nrec, pdb->recsize, pdb->year,
                        pdb->month, pdb->day, pdb->hour, pdb->minute,
                        pdb->second, pdb->sechunds);
                    nplError("pshname %s", psh->pname);
                }
                if (!PROD_COMPRESSED) {
                    for (nscan = 0; (nscan * pdb->nx) < pdh->dbsize; nscan++) {
                        if (ulogIsDebug())
                            nplDebug("png write nscan %d", nscan);
                        if (nscan >= pdh->records_per_block) {
                            nplError("nscan exceeding records per block %d [%d "
                                "%d %d]", pdh->records_per_block, nscan,
                                pdb->nx, pdh->dbsize);
                        }
                        else {
                          pngwrite(prodmmap + dataoff + (nscan * pdb->nx));
                        }
                    }
                }
                else {
                    memcpy(memheap + heapcount, prodmmap + dataoff, datalen);
                    MD5Update(md5ctxp, (unsigned char *) (memheap + heapcount),
                        datalen);
                    heapcount += datalen;
                }
            }
            else {
                if (!PROD_COMPRESSED) {
                    png_set_memheap(memheap, md5ctxp);
                    png_header(prodmmap + dataoff, datalen);
                    /*
                     * Add 1 to number of scanlines, image ends with 
                     * f0f0f0f0...
                     */
                    pngout_init(pdb->nx, pdb->ny + 1);

                    PNGINIT = 1;
                }
                else {
                    memcpy(memheap + heapcount, prodmmap + dataoff, datalen);
                    MD5Update(md5ctxp, (unsigned char*)(memheap + heapcount),
                        datalen);
                    heapcount += datalen;
                }
                nplNotice("records_per_block %d blocks_per_record %d nx %d ny %d",
                    pdh->records_per_block, pdh->blocks_per_record, pdb->nx,
                    pdb->ny);
                nplNotice("source %d sector %d channel %d", pdb->source,
                    pdb->sector, pdb->channel);
                nplNotice("nrec %d recsize %d date %02d%02d%02d %02d%02d "
                    "%02d.%02d", pdb->nrec, pdb->recsize, pdb->year, pdb->month,
                    pdb->day, pdb->hour, pdb->minute, pdb->second,
                    pdb->sechunds);
                nplNotice("pshname %s", psh->pname);
            }
            deflen = 0;
        }
        else {
            /*
             * test_deflate(memheap+heapcount,heapsize-heapcount,(unsigned char
             * *)(prodmmap+dataoff),datalen,&deflen);
             */
            /* If the product already has a FOS trailer, don't add
             * another....this will match what pqing(SDI) sees
             */
            if ((prod.nfrag != 0) && (prod.tail != NULL)) {
                if ((pfrag->fragnum != prod.tail->fragnum + 1) ||
                        (pfrag->seqno != prod.seqno)) {
                    nplError("Missing fragment in sequence, last %d/%d this "
                        "%d/%d\0", prod.tail->fragnum, prod.seqno,
                        pfrag->fragnum, pfrag->seqno);
                    ds_free();

                    prod.head = NULL;
                    prod.tail = NULL;

                    continue;
                }
            }
            if ((prod.nfrag == 0) || (prod.nfrag == (pfrag->fragnum + 1))) {
                char testme[4];

                while (datalen > 4) {
                    memcpy(testme, prodmmap + (dataoff + datalen - 4), 4);

                    if (memcmp(testme, FOS_TRAILER, 4) == 0) {
                        datalen -= 4;

                        if (ulogIsDebug())
                            nplDebug("removing FOS trailer from %s", PROD_NAME);
                    }
                    else {
                        break;
                    }
                }
            }
            if (heapcount + datalen > heapsize) {
                /*
                 * this above wasn't big enough heapsize =
                 * prodalloc(psh->frags,4000+15,&memheap);
                 */
                nplError("Error in heapsize %d product size %d [%d %d], Punt!\0",
                    heapsize, (heapcount + datalen), heapcount, datalen);
                continue;
            }

            memcpy(memheap + heapcount, prodmmap + dataoff, datalen);

            deflen = datalen;

            MD5Update(md5ctxp, (unsigned char *) (memheap + heapcount),
                deflen);
        }

        pfrag->recsiz = deflen;
        /*heapcount += datalen;*/
        heapcount += deflen;

        if (prod.head == NULL) {
            prod.head = pfrag;
            prod.tail = pfrag;
        }
        else {
            prod.tail->next = pfrag;
            prod.tail = pfrag;
        }

        if ((prod.nfrag == 0) || (prod.nfrag == (pfrag->fragnum + 1))) {
            if (GOES == 1) {
                if (PNGINIT == 1) {
                    pngout_end();
                    heapcount = png_get_prodlen();
                }
                else {
                    if (ulogIsDebug())
                        nplDebug("GOES product already compressed %d", heapcount);
                }
            }
            if (ulogIsVerbose())
              nplInfo("we should have a complete product %ld %ld/%ld %ld /heap "
                  "%ld", prod.seqno, pfrag->seqno, prod.nfrag, pfrag->fragnum,
                 (long) heapcount);
            if ((NWSTG == 1) && (heapcount > 4)) {
                cnt = 4;		/* number of bytes to add for TRAILER */

                /*
                 * Do a DDPLUS vs HDS check for NWSTG channel only
                 */
                if (sbn->datastream == 5) {
                    /* nwstg channel */
                    switch (psh->pcat) {
                    case 1:
                    case 7:
                      /* Do a quick check for non-ascii text products */
                      if (!prod_isascii(PROD_NAME, memheap, heapcount))
                        psh->pcat += 100;	/* call these HDS */
                      /* else {
                         ** call these DDPLUS **
                         if (memheap[heapcount-1] == FOS_TRAILER[3]) **
                             ETX check **
                             cnt = 0; ** no need to add extra ETX pqing doesn't
                             see it **
                         }
                       */
                      break;
                    }
                }

                if (cnt > 0) {
                    memcpy(memheap + heapcount, FOS_TRAILER + 4 - cnt, cnt);
                    MD5Update(md5ctxp, (unsigned char*)(memheap + heapcount),
                        cnt);
                    heapcount += cnt;
                }
            }

            process_prod(prod, PROD_NAME, memheap, heapcount,
                md5ctxp, ldmProdQueue, psh, sbn);
            ds_free();

            prod.head = NULL;
            prod.tail = NULL;
            PNGINIT = 0;
        }
        else {
            if (ulogIsDebug())
                nplDebug("processing record %ld [%ld %ld]", prod.seqno,
                    prod.nfrag, pfrag->fragnum);
            if ((pdh->transtype & 4) > 0) {
                nplError("Hmmm....should call completed product %ld [%ld %ld]",
                    prod.seqno, prod.nfrag, pfrag->fragnum);
            }
        }

        IOFF += (sbn->len + pdh->len + pdh->pshlen + pdh->dbsize);

        if (ulogIsDebug())
            nplDebug("look IOFF %ld datalen %ld (deflate %ld)", IOFF, datalen,
                deflen);
    }

    if (fd != -1)
       (void)close(fd);

    exit(0);
}
Example #2
0
/**
 * Reads a NOAAPORT data stream, creates LDM data-products from the stream, and
 * inserts the data-products into an LDM product-queue.  The NOAAPORT data
 * stream can take the form of multicast UDP packets from (for example) a
 * Novra S300 DVB-S2 receiver or the standard input stream.
 *
 * Usage:
 *     noaaportIngester [-l <em>log</em>] [-n|-v|-x] [-q <em>queue</em>] [-u <em>n</em>] [-m <em>mcastAddr</em>] [-I <em>iface</em>] [-b <em>npages</em>]\n
 *
 * Where:
 * <dl>
 *      <dt>-b <em>npages</em></dt>
 *      <dd>Allocate \e npages pages of memory for the internal buffer.</dd>
 *
 *      <dt>-I <em>iface</em></dt>
 *      <dd>Listen for multicast packets on interface \e iface.</dd>
 *
 *      <dt>-l <em>log</em></dt>
 *      <dd>Log to file \e log. The default is to use the system logging daemon
 *      if the current process is a daemon; otherwise, the standard error
 *      stream is used.</dd>
 *
 *      <dt>-m <em>mcastAddr</em></dt>
 *      <dd>Use the multicast address \e mcastAddr. The default is to
 *      read from the standard input stream.</dd>
 *
 *      <dt>-n</dt>
 *      <dd>Log messages of level NOTE and higher priority. Each data-product
 *      will generate a log message.</dd>
 *
 *      <dt>-q <em>queue</em></dt>
 *      <dd>Use \e queue as the pathname of the LDM product-queue. The default
 *      is to use the default LDM pathname of the product-queue.</dd>
 *
 *      <dt>-u <em>n</em></dt>
 *      <dd>If logging is to the system logging daemon, then use facility 
 *      <b>local</b><em>n</em>. The default is to use the LDM facility.</dd>
 *
 *      <dt>-v</dt>
 *      <dd>Log messages of level INFO and higher priority.</dd>
 *
 *      <dt>-x</dt>
 *      <dd>Log messages of level DEBUG and higher priority.</dd>
 * </dl>
 *
 * If neither -n, -v, nor -x is specified, then logging will be restricted to
 * levels ERROR and WARN only.
 *
 * @retval 0 if successful.
 * @retval 1 if an error occurred. At least one error-message will be logged.
 */
int main(
    const int           argc,           /**< [in] Number of arguments */
    char* const         argv[])         /**< [in] Arguments */
{
    int                 status = 0;     /* default success */
    extern int          optind;
    extern int          opterr;
    int                 ch;
    const char* const   progName = ubasename(argv[0]);
    const char*         interface = NULL;
    int                 logmask = LOG_UPTO(LOG_WARNING);
    const unsigned      logOptions = LOG_CONS | LOG_PID;
    const char*         mcastSpec = NULL;
    const char*         prodQueuePath = NULL;
    size_t              npages = DEFAULT_NPAGES;
    Fifo*               fifo;
    int                 ttyFd = open("/dev/tty", O_RDONLY);
    int                 processPriority = 0;
    const char*         logPath = (-1 == ttyFd)
        ? NULL                          /* log to system logging daemon */
        : "-";                          /* log to standard error stream */

    (void)close(ttyFd);
    (void)setulogmask(logmask);

    status = initLogging(progName, logOptions, logFacility, logPath);
    opterr = 0;                         /* no error messages from getopt(3) */

    while (0 == status && (ch = getopt(argc, argv, "b:I:l:m:np:q:u:vx")) != -1)
    {
        switch (ch) {
            extern char*    optarg;
            extern int      optopt;

            case 'b': {
                unsigned long   n;

                if (sscanf(optarg, "%lu", &n) != 1) {
                    NPL_SERROR1("Couldn't decode FIFO size in pages: \"%s\"",
                            optarg);
                    status = 1;
                }
                else {
                    npages = n;
                }
            }
            case 'I':
                interface = optarg;
                break;
            case 'l':
                logPath = optarg;
                status = initLogging(progName, logOptions, logFacility,
                        logPath);
                break;
            case 'm':
                mcastSpec = optarg;
                break;
            case 'n':
                logmask |= LOG_MASK(LOG_NOTICE);
                (void)setulogmask(logmask);
                break;
            case 'p': {
                char* cp;

                errno = 0;
                processPriority = (int)strtol(optarg, &cp, 0);

                if (0 != errno) {
                    NPL_SERROR1("Couldn't decode priority \"%s\"", optarg);
                    nplLog(LOG_ERR);
                }
                else {
                    if (processPriority < -20)
                        processPriority = -20;
                    else if (processPriority > 20)
                        processPriority = 20;
                }

                break;
            }
            case 'q':
                prodQueuePath = optarg;
                break;
            case 'u': {
                int         i = atoi(optarg);

                if (0 > i || 7 < i) {
                    NPL_START1("Invalid logging facility number: %d", i);
                    status = 1;
                }
                else {
                    static int  logFacilities[] = {LOG_LOCAL0, LOG_LOCAL1,
                        LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5,
                        LOG_LOCAL6, LOG_LOCAL7};

                    logFacility = logFacilities[i];

                    status = initLogging(progName, logOptions, logFacility,
                            logPath);
                }

                break;
            }
            case 'v':
                logmask |= LOG_MASK(LOG_INFO);
                (void)setulogmask(logmask);
                break;
            case 'x':
                logmask |= LOG_MASK(LOG_DEBUG);
                (void)setulogmask(logmask);
                break;
            default:
                optopt = ch;
                /*FALLTHROUGH*/
            case '?': {
                nplError("Unknown option: \"%c\"", optopt);
                status = 1;
            }
        }                               /* option character switch */
    }                                   /* getopt() loop */

    if (0 == status) {
        if (optind < argc) {
            nplError("Extraneous command-line argument: \"%s\"",
                    argv[optind]);
            status = 1;
        }
    }

    if (0 != status) {
        nplError("Error decoding command-line");
        usage(progName);
    }
    else {
        nplNotice("Starting Up %s", PACKAGE_VERSION);
        nplNotice("%s", COPYRIGHT_NOTICE);

        if ((status = fifoNew(npages, &fifo)) != 0) {
            NPL_ADD0("Couldn't create FIFO");
            nplLog(LOG_ERR);
        }
        else {
            LdmProductQueue*    prodQueue;

            if ((status = lpqGet(prodQueuePath, &prodQueue)) != 0) {
                NPL_ADD0("Couldn't open LDM product-queue");
                nplLog(LOG_ERR);
            }
            else {
                if (NULL == mcastSpec) {
                    if (0 == (status = spawnProductMaker(NULL, fifo, prodQueue,
                                    &productMaker, &productMakerThread))) {
                        status = spawnFileReader(NULL, NULL, fifo, &reader,
                                &readerThread);
                    }
                }                               /* reading file */
                else {
                    pthread_attr_t  attr;

                    if (0 != (status = pthread_attr_init(&attr))) {
                        NPL_ERRNUM0(status,
                                "Couldn't initialize thread attribute");
                    }
                    else {
#ifndef _POSIX_THREAD_PRIORITY_SCHEDULING
                        nplWarn("Can't adjust thread priorities due to lack of "
                                "necessary support from environment");
#else
                        /*
                         * In order to not miss any data, the reader thread
                         * should preempt the product-maker thread as soon as
                         * data is available and run as long as data is
                         * available.
                         */
                        const int           SCHED_POLICY = SCHED_FIFO;
                        struct sched_param  param;

                        param.sched_priority =
                            sched_get_priority_max(SCHED_POLICY) - 1;

                        (void)pthread_attr_setinheritsched(&attr,
                                PTHREAD_EXPLICIT_SCHED);
                        (void)pthread_attr_setschedpolicy(&attr, SCHED_POLICY);
                        (void)pthread_attr_setschedparam(&attr, &param);
                        (void)pthread_attr_setscope(&attr,
                                PTHREAD_SCOPE_SYSTEM);
#endif
                        if (0 == (status = spawnProductMaker(&attr, fifo,
                                        prodQueue, &productMaker,
                                        &productMakerThread))) {
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
                            param.sched_priority++;
                            (void)pthread_attr_setschedparam(&attr, &param);
#endif
                            status = spawnMulticastReader(&attr, mcastSpec,
                                    interface, fifo, &reader, &readerThread);
                        }                       /* product-maker spawned */
                    }                           /* "attr" initialized */
                }                               /* reading multicast packets */

                if (0 != status) {
                    nplLog(LOG_ERR);
                    status = 1;
                }
                else {
                    pthread_t   statThread;

                    (void)gettimeofday(&startTime, NULL);
                    reportTime = startTime;

                    (void)pthread_create(&statThread, NULL,
                            reportStatsWhenSignaled, NULL);

                    set_sigactions();

                    (void)pthread_join(readerThread, NULL);

                    status = readerStatus(reader);

                    (void)pthread_cancel(statThread);
                    (void)pthread_join(statThread, NULL);
                    (void)fifoCloseWhenEmpty(fifo);
                    (void)pthread_join(productMakerThread, NULL);

                    if (0 != status)
                        status = pmStatus(productMaker);

                    reportStats();
                    readerFree(reader);
                }               /* "reader" spawned */

                (void)lpqClose(prodQueue);
            }                       /* "prodQueue" open */
        }                           /* "fifo" created */
    }                               /* command line decoded */

    return status;
}
Example #3
0
/**
 * Reads a NOAAPORT data stream, creates LDM data-products from the stream, and
 * inserts the data-products into an LDM product-queue.  The NOAAPORT data
 * stream can take the form of multicast UDP packets from (for example) a
 * Novra S300 DVB-S2 receiver or the standard input stream.
 *
 * Usage:
 *     noaaportIngester [-l <em>log</em>] [-n|-v|-x] [-q <em>queue</em>] [-u <em>n</em>] [-m <em>mcastAddr</em>] [-I <em>iface</em>] [-b <em>npages</em>]\n
 *
 * Where:
 * <dl>
 *      <dt>-b <em>npages</em></dt>
 *      <dd>Allocate \e npages pages of memory for the internal buffer.</dd>
 *
 *      <dt>-I <em>iface</em></dt>
 *      <dd>Listen for multicast packets on interface \e iface.</dd>
 *
 *      <dt>-l <em>log</em></dt>
 *      <dd>Log to file \e log. The default is to use the system logging daemon
 *      if the current process is a daemon; otherwise, the standard error
 *      stream is used.</dd>
 *
 *      <dt>-m <em>mcastAddr</em></dt>
 *      <dd>Use the multicast address \e mcastAddr. The default is to
 *      read from the standard input stream.</dd>
 *
 *      <dt>-n</dt>
 *      <dd>Log messages of level NOTE and higher priority. Each data-product
 *      will generate a log message.</dd>
 *
 *      <dt>-q <em>queue</em></dt>
 *      <dd>Use \e queue as the pathname of the LDM product-queue. The default
 *      is to use the default LDM pathname of the product-queue.</dd>
 *
 *      <dt>-u <em>n</em></dt>
 *      <dd>If logging is to the system logging daemon, then use facility 
 *      <b>local</b><em>n</em>. The default is to use the LDM facility.</dd>
 *
 *      <dt>-v</dt>
 *      <dd>Log messages of level INFO and higher priority.</dd>
 *
 *      <dt>-x</dt>
 *      <dd>Log messages of level DEBUG and higher priority.</dd>
 * </dl>
 *
 * If neither -n, -v, nor -x is specified, then logging will be restricted to
 * levels ERROR and WARN only.
 *
 * @retval 0 if successful.
 * @retval 1 if an error occurred. At least one error-message will be logged.
 */
int main(
    const int           argc,           /**< [in] Number of arguments */
    char* const         argv[])         /**< [in] Arguments */
{
    int                 status = 0;     /* default success */
    extern int          optind;
    extern int          opterr;
    int                 ch;
    const char* const   progName = ubasename(argv[0]);
    const char*         interface = NULL;
    int                 logmask = LOG_UPTO(LOG_WARNING);
    const unsigned      logOptions = LOG_CONS | LOG_PID;
    const char*         mcastSpec = NULL;
    const char*         prodQueuePath = NULL;
    size_t              npages = DEFAULT_NPAGES;
    Fifo*               fifo;
    int                 ttyFd = open("/dev/tty", O_RDONLY);
    int                 processPriority = 0;
    int                 idx;
    const char*         logPath = (-1 == ttyFd)
        ? NULL                          /* log to system logging daemon */
        : "-";                          /* log to standard error stream */

    (void)close(ttyFd);
    (void)setulogmask(logmask);

    status = initLogging(progName, logOptions, logFacility, logPath);
    opterr = 0;                         /* no error messages from getopt(3) */

    while (0 == status && (ch = getopt(argc, argv, "b:I:l:m:np:q:r:s:t:u:vx")) != -1)
    {
        switch (ch) {
            extern char*    optarg;
            extern int      optopt;

            case 'b': {
                unsigned long   n;

                if (sscanf(optarg, "%lu", &n) != 1) {
                    LOG_SERROR1("Couldn't decode FIFO size in pages: \"%s\"",
                            optarg);
                    status = 1;
                }
                else {
                    npages = n;
                }
                break;
            }
            case 'I':
                interface = optarg;
                break;
            case 'l':
                logPath = optarg;
                status = initLogging(progName, logOptions, logFacility,
                        logPath);
                break;
            case 'm':
                mcastSpec = optarg;
                break;
            case 'n':
                logmask |= LOG_MASK(LOG_NOTICE);
                (void)setulogmask(logmask);
                break;
            case 'p': {
                char* cp;

                errno = 0;
                processPriority = (int)strtol(optarg, &cp, 0);

                if (0 != errno) {
                    LOG_SERROR1("Couldn't decode priority \"%s\"", optarg);
                    log_log(LOG_ERR);
                }
                else {
                    if (processPriority < -20)
                        processPriority = -20;
                    else if (processPriority > 20)
                        processPriority = 20;
                }

                break;
            }
            case 'q':
                prodQueuePath = optarg;
                break;
            case 'r':
#ifdef RETRANS_SUPPORT
                retrans_xmit_enable = atoi(optarg);
                if(retrans_xmit_enable == 1)
                  retrans_xmit_enable = OPTION_ENABLE;
                else
                  retrans_xmit_enable = OPTION_DISABLE;
#endif
                break;
           case 's': {
#ifdef RETRANS_SUPPORT
			strcpy(sbn_channel_name, optarg);
                        if(!strcmp(optarg,NAME_SBN_TYP_GOES)) {
                                sbn_type = SBN_TYP_GOES;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_NOAAPORT_OPT)) {
                                sbn_type = SBN_TYP_NOAAPORT_OPT;
                                break;
                        }
                        if(!strcmp(optarg,"NWSTG")) {
                                sbn_type = SBN_TYP_NMC;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_NMC)) {
                                sbn_type = SBN_TYP_NMC;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_NMC2)) {
                                sbn_type = SBN_TYP_NMC2;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_NMC3)) {
                                sbn_type = SBN_TYP_NMC3;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_NWWS)) {
                                sbn_type = SBN_TYP_NWWS;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_ADD)) {
                                sbn_type = SBN_TYP_ADD;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_ENC)) {
                                sbn_type = SBN_TYP_ENC;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_EXP)) {
                                sbn_type = SBN_TYP_EXP;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_GRW)) {
                                sbn_type = SBN_TYP_GRW;
                                break;
                        }
                        if(!strcmp(optarg,NAME_SBN_TYP_GRE)) {
                                sbn_type = SBN_TYP_GRE;
                                break;
                        }
                        printf("Operator input: UNKNOWN type must be\n");
                        printf(" %s, %s, %s, %s, %s, %s, %s, %s, %s, %s  or %s \n",
                                NAME_SBN_TYP_NMC,
                                NAME_SBN_TYP_GOES,
                                NAME_SBN_TYP_NOAAPORT_OPT,
                                NAME_SBN_TYP_NMC2,
                                NAME_SBN_TYP_NMC3,
                                NAME_SBN_TYP_NWWS,
                                NAME_SBN_TYP_ADD,
                                NAME_SBN_TYP_ENC,
                                NAME_SBN_TYP_EXP,
                                NAME_SBN_TYP_GRW,
                                NAME_SBN_TYP_GRE);
#endif
                break;
              }
            case 't':
#ifdef RETRANS_SUPPORT
                strcpy(transfer_type, optarg);
                if(!strcmp(transfer_type,"MHS") || !strcmp(transfer_type,"mhs")){
                     /** Using MHS for communication with NCF  **/
                }else{
                     uerror("No other mechanism other than MHS is currently supported\n");
                     status  = 1;
                 }
#endif
                break;
            case 'u': {
                int         i = atoi(optarg);

                if (0 > i || 7 < i) {
                    LOG_START1("Invalid logging facility number: %d", i);
                    status = 1;
                }
                else {
                    static int  logFacilities[] = {LOG_LOCAL0, LOG_LOCAL1,
                        LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5,
                        LOG_LOCAL6, LOG_LOCAL7};

                    logFacility = logFacilities[i];

                    status = initLogging(progName, logOptions, logFacility,
                            logPath);
                }

                break;
            }
            case 'v':
                logmask |= LOG_MASK(LOG_INFO);
                (void)setulogmask(logmask);
                break;
            case 'x':
                logmask |= LOG_MASK(LOG_DEBUG);
                (void)setulogmask(logmask);
                break;
            default:
                optopt = ch;
                /*FALLTHROUGH*/
                /* no break */
            case '?': {
                uerror("Unknown option: \"%c\"", optopt);
                status = 1;
                break;
            }
        }                               /* option character switch */
    }                                   /* getopt() loop */

    if (0 == status) {
        if (optind < argc) {
            uerror("Extraneous command-line argument: \"%s\"",
                    argv[optind]);
            status = 1;
        }
    }

    if (0 != status) {
        uerror("Error decoding command-line");
        usage(progName);
    }
    else {
        unotice("Starting Up %s", PACKAGE_VERSION);
        unotice("%s", COPYRIGHT_NOTICE);

        if ((status = fifoNew(npages, &fifo)) != 0) {
            LOG_ADD0("Couldn't create FIFO");
            log_log(LOG_ERR);
        }
        else {
            LdmProductQueue*    prodQueue;

            if ((status = lpqGet(prodQueuePath, &prodQueue)) != 0) {
                LOG_ADD0("Couldn't open LDM product-queue");
                log_log(LOG_ERR);
            }
            else {
                if (NULL == mcastSpec) {
                    if (0 == (status = spawnProductMaker(NULL, fifo, prodQueue,
                                    &productMaker, &productMakerThread))) {
                        status = spawnFileReader(NULL, NULL, fifo, &reader,
                                &readerThread);
                    }
                }                               /* reading file */
                else {
                    pthread_attr_t  attr;

                    if (0 != (status = pthread_attr_init(&attr))) {
                        LOG_ERRNUM0(status,
                                "Couldn't initialize thread attribute");
                    }
                    else {
#ifndef _POSIX_THREAD_PRIORITY_SCHEDULING
                        uwarn("Can't adjust thread priorities due to lack of "
                                "necessary support from environment");
#else
                        /*
                         * In order to not miss any data, the reader thread
                         * should preempt the product-maker thread as soon as
                         * data is available and run as long as data is
                         * available.
                         */
                        const int           SCHED_POLICY = SCHED_FIFO;
                        struct sched_param  param;

                        param.sched_priority =
                            sched_get_priority_max(SCHED_POLICY) - 1;

                        (void)pthread_attr_setinheritsched(&attr,
                                PTHREAD_EXPLICIT_SCHED);
                        (void)pthread_attr_setschedpolicy(&attr, SCHED_POLICY);
                        (void)pthread_attr_setschedparam(&attr, &param);
                        (void)pthread_attr_setscope(&attr,
                                PTHREAD_SCOPE_SYSTEM);
#endif
#ifdef RETRANS_SUPPORT
                        if (retrans_xmit_enable == OPTION_ENABLE){
                         /* Copy mcastAddress needed to obtain the cpio entries */
                         strcpy(mcastAddr, mcastSpec);
                        }
#endif
                        if (0 == (status = spawnProductMaker(&attr, fifo,
                                        prodQueue, &productMaker,
                                        &productMakerThread))) {
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
                            param.sched_priority++;
                            (void)pthread_attr_setschedparam(&attr, &param);
#endif
                            status = spawnMulticastReader(&attr, mcastSpec,
                                    interface, fifo, &reader, &readerThread);

                        }                       /* product-maker spawned */
                    }                           /* "attr" initialized */
                }                               /* reading multicast packets */

                if (0 != status) {
                    log_log(LOG_ERR);
                    status = 1;
                }
                else {
                    pthread_t   statThread;

                    (void)gettimeofday(&startTime, NULL);
                    reportTime = startTime;

                    (void)pthread_create(&statThread, NULL,
                            reportStatsWhenSignaled, NULL);

                    set_sigactions();

                    (void)pthread_join(readerThread, NULL);

                    status = readerStatus(reader);

                    (void)pthread_cancel(statThread);
                    (void)pthread_join(statThread, NULL);
                    (void)fifoCloseWhenEmpty(fifo);
                    (void)pthread_join(productMakerThread, NULL);

                    if (0 != status)
                        status = pmStatus(productMaker);

                    reportStats();
                    readerFree(reader);
#ifdef RETRANS_SUPPORT
					/** Release buffer allocated for retransmission **/
					if(retrans_xmit_enable == OPTION_ENABLE){
					  freeRetransMem();
					}
#endif
                }               /* "reader" spawned */

                (void)lpqClose(prodQueue);
            }                       /* "prodQueue" open */
        }                           /* "fifo" created */
    }                               /* command line decoded */

    return status;
}