예제 #1
0
파일: wmo_message.c 프로젝트: Unidata/LDM
void
wmo_stats(void)
{
	log_notice_q("  WMO Messages seen:  %8lu", completed);
	log_notice_q("  SOH/ETX missing  :  %8lu", sohetx_missed);
	log_notice_q("  parity/chksum err:  %8lu", bad_cksum);
	log_notice_q("  WMO format errors:  %8lu", not_wmo);
}
예제 #2
0
/*
 * Sends a single, open file to an LDM as a data-product. The number of bytes
 * to be sent is specified by the data-product's metadata. The bytes start at
 * the beginning of the file.
 *
 * Arguments:
 *      proxy           The LDM proxy data-structure.
 *      fd              The file-descriptor open on the file to be sent.
 *      info            The data-product's metadata. Must be completely set.
 *
 * Returns:
 *      0                       Success.
 *      SYSTEM_ERROR            O/S failure. "log_add()" called.
 *      CONNECTION_ABORTED      The connection was aborted. "log_add()"
 *                              called.
 */
static int
send_product(
    LdmProxy*           proxy,
    int                 fd,
    prod_info* const    info)
{
    int                 status;
    product             product;

    product.info = *info;
    product.data = mmap(NULL, info->sz, PROT_READ, MAP_PRIVATE, fd, 0);

    if (MAP_FAILED == product.data) {
        log_syserr_q("Couldn't memory-map file");
        status = SYSTEM_ERROR;
    }
    else {
        status = lp_send(proxy, &product);
        if (LP_UNWANTED == status) {
            log_notice_q("Unwanted product: %s", s_prod_info(NULL, 0, info,
                        log_is_enabled_debug));
            status = 0;
        }
        (void)munmap(product.data, info->sz);
    }                                           /* file is memory-mapped */

    return status;
}
예제 #3
0
파일: wmo_message.c 프로젝트: Unidata/LDM
static const char *
grib_ident(size_t remaining, const char *const wmo_msg, const char *const ident)
{
	static const char nada[] = "";
	const char *cp;
	size_t len;

	cp = scanFor("GRIB", remaining, wmo_msg);
	if(!cp)
	{
		log_notice_q("%s: Can't find `GRIB'", ident);
		return nada;
	}
	remaining -= cp - wmo_msg;
	if(remaining < (8 + 28 +4))
	{
		log_notice_q("%s: way too short", ident);
		return NULL;
	}

	len = ids_len(cp);
	if(remaining < len)
	{
		log_notice_q("%s: %d bytes too short", ident, len - remaining);
		return NULL;
	}

         /* this assumes 7777\r\r\n ETX, however, some products
            may have extra \r\n's so this test is too rigid-
            The test for 7777 at expected len should suffice (Chiz)
	if(remaining > len + 8)
	{
		LOG_NOTICE("%s: garbled product", ident);
		LOG_NOTICE("remaining %d, ids_len %d", remaining, len);
		return NULL;
	} */

	if(scanFor("7777", 8, cp + len - 8) == NULL)
	{
		log_notice_q("%s: no end of product", ident);
		return NULL;
	}

	return pds_ident(cp + 8);
}
예제 #4
0
파일: notifyme.c 프로젝트: Unidata/LDM
/*
 * Called at exit.
 * This callback routine registered by atexit().
 */
static void
cleanup(void)
{
        log_notice_q("exiting");

        /* TODO: sign off */

        log_fini();
}
예제 #5
0
/*
 * called at exit
 */
static void
cleanup(void)
{
    log_notice_q("Exiting");

    if (done) {
        /*
         * We are not in the interrupt context, so these can be performed
         * safely.
         */
        fl_closeAll();

        if (pq)
            (void)pq_close(pq);

        if (!tvEqual(palt_last_insertion, TS_ZERO)) {
            timestampt  now;

            (void)set_timestamp(&now);
            log_notice_q("Behind by %g s",
                    d_diff_timestamp(&now, &palt_last_insertion));

            if (stateWrite(&palt_last_insertion) < 0) {
                log_error_q("Couldn't save insertion-time of last processed "
                    "data-product");
            }
        }

        while (reap(-1, WNOHANG) > 0)
            /*EMPTY*/;
    }

    if(shmid != -1) {
        log_notice_q("Deleting shared segment.");
        shmctl(shmid, IPC_RMID, NULL);
    }
    if(semid != -1) {
        semctl(semid, 0, IPC_RMID);
    }

    log_fini();
}
예제 #6
0
파일: ldm5_svc.c 프로젝트: Unidata/LDM
/*
 * Handles incoming LDM-5 RPC requests.  This method is directly and repeatedly
 * invoked by the RPC layer after svc_run(3NSL) is invoked.
 *
 * rqstp        The RPC request.
 * transp       The server-side RPC transport.
 */
void
ldmprog_5(struct svc_req *rqstp, register SVCXPRT *transp)
{
        union {
                product hereis_5_arg;
                prod_class feedme_5_arg;
                prod_class hiya_5_arg;
                prod_info notification_5_arg;
                prod_class_t notifyme_5_arg;
                comingsoon_args comingsoon_5_arg;
                datapkt blkdata_5_arg;
        } argument;
        char *result;
        xdrproc_t xdr_argument, xdr_result;
        char *(*local)(char *, struct svc_req *);
        const char* procName;

        switch (rqstp->rq_proc) {
        case NULLPROC:
                log_debug("NULLPROC");
                (void)svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL);
                return;

        case HEREIS:
                xdr_argument = (xdrproc_t) xdr_product;
                xdr_result = (xdrproc_t) xdr_ldm_replyt;
                local = (char *(*)(char *, struct svc_req *)) hereis_5_svc;
                procName = "HEREIS";
                break;

        case FEEDME:
                xdr_argument = (xdrproc_t) xdr_prod_class;
                xdr_result = (xdrproc_t) xdr_ldm_replyt;
                local = (char *(*)(char *, struct svc_req *)) feedme_5_svc;
                procName = "FEEDME";
                break;

        case HIYA:
                xdr_argument = (xdrproc_t) xdr_prod_class;
                xdr_result = (xdrproc_t) xdr_ldm_replyt;
                local = (char *(*)(char *, struct svc_req *)) hiya_5_svc;
                procName = "HIYA";
                break;

        case NOTIFICATION:
                xdr_argument = (xdrproc_t) xdr_prod_info;
                xdr_result = (xdrproc_t) xdr_ldm_replyt;
                local = (char*(*)(char*, struct svc_req *)) notification_5_svc;
                procName = "NOTIFICATION";
                break;

        case NOTIFYME:
                xdr_argument = (xdrproc_t) xdr_prod_class;
                xdr_result = (xdrproc_t) xdr_ldm_replyt;
                local = (char *(*)(char *, struct svc_req *)) notifyme_5_svc;
                procName = "NOTIFYME";
                break;

        case COMINGSOON:
                xdr_argument = (xdrproc_t) xdr_comingsoon_args;
                xdr_result = (xdrproc_t) xdr_ldm_replyt;
                local = (char *(*)(char *, struct svc_req *)) comingsoon_5_svc;
                procName = "COMINGSOON";
                break;

        case BLKDATA:
                xdr_argument = (xdrproc_t) xdr_datapkt;
                xdr_result = (xdrproc_t) xdr_ldm_replyt;
                local = (char *(*)(char *, struct svc_req *)) blkdata_5_svc;
                procName = "BLKDATA";
                break;

        default:
                svcerr_noproc(transp);
                return;
         }

        log_debug("%s", procName);
        (void) memset((void *)&argument, 0, sizeof (argument));
        if (!svc_getargs(transp, xdr_argument, (void*) &argument)) {
                log_notice_q("%s: Couldn't decode RPC-request arguments",
                        procName);
                svcerr_decode(transp);
                return;
        }
        result = (*local)((char *)&argument, rqstp);
        if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
                log_notice_q("%s: Couldn't reply to RPC-request", procName);
                svcerr_systemerr(transp);
        }
        if (!svc_freeargs(transp, xdr_argument, (void*) &argument)) {
                log_error_q("unable to free arguments");
                exit(1);
        }
        return;
}
예제 #7
0
hiya_reply_t*
hiya_6_svc(
        prod_class_t *offered,
        struct svc_req *rqstp)
{
    const char* const pqfname = getQueuePath();
    static hiya_reply_t reply;
    SVCXPRT * const xprt = rqstp->rq_xprt;
    struct sockaddr_in *upAddr = (struct sockaddr_in*) svc_getcaller(xprt);
    const char *upName = hostbyaddr(upAddr);
    int error;
    int isPrimary;
    unsigned int maxHereis;
    static prod_class_t *accept;

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

    /* else */

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

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

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

    maxHereis = isPrimary ? UINT_MAX : 0;

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

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

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

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

            /* else */

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

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

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

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

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

    return &reply;
}
예제 #8
0
파일: notifyme.c 프로젝트: Unidata/LDM
int main(int ac, char *av[])
{
        unsigned      timeo = DEFAULT_TIMEO;
        unsigned      interval = DEFAULT_TIMEO;
        unsigned      TotalTimeo = DEFAULT_TOTALTIMEO;
        prod_spec     spec;
        int           status;
        prod_class_t* clssp;

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

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

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

        opterr = 1;

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

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

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

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

        } /* End getopt block */

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

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

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


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

                (void)exitIfDone(0);

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

        exit(0);
        /*NOTREACHED*/
}
예제 #9
0
파일: retrans.c 프로젝트: Unidata/LDM
/* init_retrans - Routine to initialize retransmission table */
int init_retrans(PROD_RETRANS_TABLE **pp_prod_retrans_table)
{

	static char FNAME[] = "init_retrans";
	long int	entry_base;		/* base of entry */
	long int	ii,iii;			/* loop counter */
	int	 flags, rtn_val;
	static const char *utc_time = "UTC";

	/* Pointer to prod_retrans table */
	PROD_RETRANS_ENTRY *p_retrans_entry;
	PROD_RETRANS_ENTRY_INFO *p_retrans_entry_info;

	/* pointer to prod_retrans_table */
	PROD_RETRANS_TABLE	*pl_prod_retrans_table;

	pl_prod_retrans_table = *pp_prod_retrans_table;

	log_debug("%s Begin init retrans_table   base=0x%x\n", FNAME, pl_prod_retrans_table);

	global_time_zone = (char *) utc_time;

	if (pl_prod_retrans_table != NULL){
		/* IMPORTANT, special init for local prod_retrans_table */

		/* Assume entries directly follow the entry info for all links */
		/*  and each is variable size */
		/* IMPORTANT, these must be initialized in order of their index value */
		/*   ie, GOES_EAST(0), NMC2(1), NMC(2), NOAAPORT_OPT(3), NMC3(4), NMC1(5) */
		/*    note NMC2 was GOES_WEST */
		/*   as per RETRANS_TBL_TYP_xxxxxxx */
		entry_base = (long)pl_prod_retrans_table + sizeof(PROD_RETRANS_TABLE);

		ii = 0; /* For now set to 0; Later can setup retrans table depending on the channel type */
		pl_prod_retrans_table->entry_info[GET_RETRANS_TABLE_TYP(sbn_type)].
			numb_entries = GET_RETRANS_CHANNEL_ENTRIES(sbn_type);
		log_debug("%s Total retrans numb_entries for channel %s of sbn_type (%d) = %d \n",
                               FNAME, sbn_channel_name,sbn_type,pl_prod_retrans_table->entry_info[ii].numb_entries);

		pl_prod_retrans_table->entry_info[GET_RETRANS_TABLE_TYP(sbn_type)].
			retrans_entry_base_offset = (long)entry_base -
				(long)(&pl_prod_retrans_table->entry_info[GET_RETRANS_TABLE_TYP(sbn_type)].
					retrans_entry_base_offset);

		entry_base += 
			(long) (pl_prod_retrans_table->entry_info[GET_RETRANS_TABLE_TYP(sbn_type)].
				numb_entries * (sizeof(PROD_RETRANS_ENTRY)));

		/*ii = GET_RETRANS_TABLE_TYP(sbn_type);*/
			p_prod_retrans_table->entry_info[ii].entry_bytes = 
				sizeof(PROD_RETRANS_ENTRY);
			pl_prod_retrans_table->entry_info[ii].index_last = 0;
			pl_prod_retrans_table->entry_info[ii].run_id_last = 0;
			pl_prod_retrans_table->entry_info[ii].tot_prods_rcvd = 0;
			pl_prod_retrans_table->entry_info[ii].tot_prods_lost = 0;
			pl_prod_retrans_table->entry_info[ii].tot_prods_lost_seqno = 0;
			pl_prod_retrans_table->entry_info[ii].tot_prods_lost_abort = 0;
			pl_prod_retrans_table->entry_info[ii].tot_prods_lost_other = 0;
			pl_prod_retrans_table->entry_info[ii].tot_prods_retrans_rcvd = 0;
			pl_prod_retrans_table->entry_info[ii].tot_prods_retrans_rcvd_lost = 0;
			pl_prod_retrans_table->entry_info[ii].tot_prods_retrans_rcvd_notlost=0;
			pl_prod_retrans_table->entry_info[ii].tot_prods_retrans_rqstd = 0;
			pl_prod_retrans_table->entry_info[ii].len_wmo_hdr_max = 
				MAX_WMO_ENTRY_LEN;
			pl_prod_retrans_table->entry_info[ii].len_wmo_hdr_abbrev_max = 
				MAX_RETRANS_LEN_WMO_HDR_ABBREV;
			pl_prod_retrans_table->entry_info[ii].last_wmo_hdr[0] = '\0'; 
			pl_prod_retrans_table->entry_info[ii].last_wmo_loghdr_info[0] = '\0'; 

			p_retrans_entry_info =
				&pl_prod_retrans_table->entry_info[ii];

			p_retrans_entry =
				(PROD_RETRANS_ENTRY *)(((long)&p_retrans_entry_info->
					retrans_entry_base_offset) +
					(long)p_retrans_entry_info->retrans_entry_base_offset);
	
			/* Now clear each entry */
			for(iii=0;
				iii < pl_prod_retrans_table->entry_info[ii].numb_entries; iii++) {
				p_retrans_entry[iii].prod_arrive_time = (long) 0;
				p_retrans_entry[iii].prod_seqno = (long) 0;
				p_retrans_entry[iii].prod_run_id = 0;
				p_retrans_entry[iii].prod_type = 0;
				p_retrans_entry[iii].prod_cat = 0;
				p_retrans_entry[iii].prod_code = 0;
				p_retrans_entry[iii].prod_sub_code = 0;
				p_retrans_entry[iii].prod_status = 0;
				p_retrans_entry[iii].prod_err_cause = 0;
				p_retrans_entry[iii].prod_link_id = 0;
				p_retrans_entry[iii].entry_flag = 0;
				p_retrans_entry[iii].WMO_hdr_abbrev[0] = '\0';
			} /* end for each numb entries */
		log_debug("%s  OK init retrans_table for channel [%s] numb_entries = %d\n",FNAME,
				sbn_channel_name,pl_prod_retrans_table->entry_info[ii].numb_entries);

	} /* end if pl_prod_retrans_table != NULL */


	/*Open retransmit pipe */
	if((global_retransmitpipe_fd = open(DEFAULT_RETRANSMIT_PIPENAME, O_RDWR,0)) <= 0){
		log_error_q("Fail to open %s pipe errno=%d \n",DEFAULT_RETRANSMIT_PIPENAME,errno);
		perror("pipe open err");
		return (-1);
	}

	if((flags = fcntl(global_retransmitpipe_fd, F_GETFL)) < 0){
		log_error_q("Fail fcntl(F_GETFL) %s pipe\n",DEFAULT_RETRANSMIT_PIPENAME);
		/* Continue for now */
	}else{

		flags |= DONT_BLOCK;
		if((rtn_val = fcntl(global_retransmitpipe_fd, F_SETFL, flags)) < 0){
			log_error_q("Fail fcntl(F_SETFL) %s pipe \n",DEFAULT_RETRANSMIT_PIPENAME);
		}

		log_notice_q(" OK open pipe[%d] for %s\n", global_retransmitpipe_fd,DEFAULT_RETRANSMIT_PIPENAME);
	}

	log_debug("%s Exiting  init retrans_table   base=0x%lx\n", FNAME,(unsigned long) pl_prod_retrans_table);
	return(0);

} /* end init_retrans */
예제 #10
0
파일: retrans.c 프로젝트: Unidata/LDM
int prod_retrans_ck(ACQ_TABLE *p_acqtable, BUFF_HDR *p_buffhdr, time_t *orig_arrive_time)
{

	char FNAME[] = "prod_retrans_ck";

	int index_value;
	int match_value;
	int retrans_table_type;
	PROD_RETRANS_ENTRY *p_retrans_entry;
	PROD_RETRANS_ENTRY_INFO *p_retrans_entry_info;
	long orig_prod_seqno;
	long now_prod_seqno;
	long	delta_prod_seqno;	/* delta for prod seqno */
	int		valid_retrans_flag;	/* valid retrans flag for table */


	match_value = PROD_NODUPLICATE;
	*orig_arrive_time = 0;
	
	if(prod_retrans_get_addr(p_acqtable->proc_base_channel_type_last,
		p_prod_retrans_table, &p_retrans_entry_info, &p_retrans_entry, 
		&retrans_table_type) < 0) {
		log_notice_q("%s ignore retrans_ck\n",	FNAME);
		return(match_value);
	}

	if(p_acqtable->proc_orig_prod_seqno_last != 0) {

		log_debug("%s ok retrans channel_typ=%d tbl[%d] so ck more\n",
			FNAME, p_acqtable->proc_base_channel_type_last, retrans_table_type);

		/* Assume have retransmitted product do following */
		p_acqtable->proc_tot_prods_retrans_rcvd++,
		p_retrans_entry_info->tot_prods_retrans_rcvd++;

		/* If is retransmission, need to see if original product was OK */
		/*  and ignore the product, else process the product */
		index_value = p_acqtable->proc_orig_prod_seqno_last % 
			p_retrans_entry_info->numb_entries;
		if(index_value < 0) {
			index_value = -index_value;
		}
		if(index_value >= p_retrans_entry_info->numb_entries) {
			index_value = 0;
		}

		/* Check if already have product in table */
		if((p_retrans_entry[index_value].prod_seqno ==
			p_acqtable->proc_orig_prod_seqno_last) &&
			(p_retrans_entry[index_value].prod_run_id ==
				p_acqtable->proc_orig_prod_run_id) &&
			(p_retrans_entry[index_value].entry_flag != 
				RETRANS_ENTRY_FLAG_AVAIL)) {
			/* Assume product matched */	
			match_value = PROD_DUPLICATE_MATCH;
			p_acqtable->proc_tot_prods_retrans_rcvd_notlost++;
			p_retrans_entry_info->tot_prods_retrans_rcvd_notlost++;
			*orig_arrive_time = p_retrans_entry[index_value].prod_arrive_time;
		} else {
			match_value = PROD_DUPLICATE_NOMATCH;
			p_acqtable->proc_tot_prods_retrans_rcvd_lost++;
			p_retrans_entry_info->tot_prods_retrans_rcvd_lost++;
			
		}

		log_debug("%s %s duplicate run(%d) prod|orig(%ld|%ld) tbl[%d]=%ld\n",
			FNAME,
			(match_value==PROD_DUPLICATE_MATCH)?"OK MATCH":"NO MATCH",
			p_acqtable->proc_orig_prod_run_id,
			p_buffhdr->proc_prod_seqno,
			p_acqtable->proc_orig_prod_seqno_last,
			index_value,
			p_retrans_entry[index_value].prod_seqno);
	
		/* Check if retransmit prod is within range of table entries */
		orig_prod_seqno = (long)p_acqtable->proc_orig_prod_seqno_last;
		now_prod_seqno = (long)p_buffhdr->proc_prod_seqno;

		valid_retrans_flag = 0;
		delta_prod_seqno = now_prod_seqno - orig_prod_seqno;

		if((match_value == PROD_DUPLICATE_MATCH) ||
			(match_value == PROD_DUPLICATE_NOMATCH)) {
			if((delta_prod_seqno > 0) && 
				(delta_prod_seqno < p_retrans_entry_info->numb_entries)) {
				valid_retrans_flag = 1;
			}
		}
		if((match_value == PROD_DUPLICATE_MATCH) ||
			(match_value == PROD_DUPLICATE_NOMATCH)) {
			if((delta_prod_seqno < 0) && 
				(now_prod_seqno < p_retrans_entry_info->numb_entries)) {
					valid_retrans_flag = 1;
			}
		}


		/* Now if the original is within the number of active entries */
		/*  go ahead and update the match table entry */
		/* Note, that p_acqtable->proc_base_prod_seqno is not yet set */
		if((match_value == PROD_DUPLICATE_NOMATCH) &&
			(valid_retrans_flag == 1)){
			/* Now update the prod_retrans_entry */
			prod_retrans_update_entry(p_acqtable, p_buffhdr,
				p_retrans_entry_info,
				&p_retrans_entry[index_value], 
				index_value,
				p_acqtable->proc_orig_prod_seqno_last, 
				p_acqtable->proc_orig_prod_run_id, 
				RETRANS_ENTRY_FLAG_RETRANS_VALID, 0);
			p_retrans_entry_info->index_last = index_value;
			p_retrans_entry_info->run_id_last = 
				p_acqtable->proc_prod_run_id; 
		} else {
			/* Check if retransmit prod is within range of table entries */
			if((match_value == PROD_DUPLICATE_MATCH) &&
				(valid_retrans_flag == 1)){
				/* Now update the prod_retrans_entry */
				/*  to tell other product is ok but duplicate */
				prod_retrans_update_entry(p_acqtable, p_buffhdr,
					p_retrans_entry_info,
					&p_retrans_entry[index_value], 
					index_value,
					p_acqtable->proc_orig_prod_seqno_last, 
					p_acqtable->proc_orig_prod_run_id, 
					RETRANS_ENTRY_FLAG_RETRANS_DUP, 0);

			} else {
				if(p_retrans_entry[index_value].prod_run_id ==
					p_acqtable->proc_orig_prod_run_id) {
					/* Possibly orig prod_seqno greater than current prod_seqno */
					/*  so discard */
				}
			}

			/* Note, prod is possibly too old to fit in table */
			/* Always, set product for discard */
			match_value = PROD_DUPLICATE_DISCARD;

		}

	} else {
		/* If this a new (not retransmitted) product do following */
		match_value = PROD_NODUPLICATE;

	} /* end if-else retransmitted product */


	/* In either case need to update entry for new product */
	index_value = p_buffhdr->proc_prod_seqno % 
			p_retrans_entry_info->numb_entries;
	if(index_value < 0) {
		index_value = -index_value;
	}
	if(index_value >= p_retrans_entry_info->numb_entries) {
		index_value = 0;
	}

	/* IMPORTANT, this value will be removed later if product in error */
	/* Now update the prod_retrans_entry */
	/*  and also indicate if was a retransmission product */
	prod_retrans_update_entry(p_acqtable, p_buffhdr,
		p_retrans_entry_info,
		&p_retrans_entry[index_value], 
		index_value,
		p_buffhdr->proc_prod_seqno,
		p_acqtable->proc_prod_run_id, 
		RETRANS_ENTRY_FLAG_NEW_VALID|
		((p_acqtable->proc_orig_prod_seqno_last != 0)?
			RETRANS_ENTRY_FLAG_NEW_W_DUP:0), 0);

	p_retrans_entry_info->index_last = index_value;
	p_retrans_entry_info->run_id_last = p_acqtable->proc_prod_run_id;

/* Debug only */

	if(match_value & PROD_NODUPLICATE) {
		log_debug(" %s %s entry(%d) prod(%ld) code=%d %s[%d]\n",
			FNAME,
			GET_PROD_TYPE_NAME(p_buffhdr->proc_prod_type),
			index_value,
			p_buffhdr->proc_prod_seqno,
			p_buffhdr->proc_prod_code,
			(match_value & PROD_NODUPLICATE)?"NO_DUPL":
			(match_value & PROD_DUPLICATE_MATCH)?"DUPL_MATCH":
			(match_value & PROD_DUPLICATE_NOMATCH)?"DUPL_NOMATCH":
				"UNKNOWN",
			match_value);
	} else {
		log_debug("%s %s entry(%d) prod|orig(%ld|%ld) code=%d %s[%d]\n",
			FNAME,
			GET_PROD_TYPE_NAME(p_buffhdr->proc_prod_type),
			index_value,
			p_buffhdr->proc_prod_seqno,
			p_acqtable->proc_orig_prod_seqno_last,
			p_buffhdr->proc_prod_code,
			(match_value & PROD_NODUPLICATE)?"NO_DUPL":
			(match_value & PROD_DUPLICATE_MATCH)?"DUPL_MATCH":
			(match_value & PROD_DUPLICATE_NOMATCH)?"DUPL_NOMATCH":
				"UNKNOWN",
			match_value);
	}
/* Debug only */

	return(match_value);

}
예제 #11
0
int
main(int ac, char *av[])
{
        int          status = 0;
        char*        logfname = 0;
        /// Data directory, conffile paths may be relative
        const char*  datadir;
        int          interval = DEFAULT_INTERVAL;
        prod_spec    spec;
        prod_class_t clss;
        int          toffset = TOFFSET_NONE;
        int          loggingToStdErr = 0;
        unsigned     queue_size = 5000;
        const char*  progname = basename(av[0]);
        unsigned     logopts = LOG_CONS|LOG_PID;

        /*
         * Setup default logging before anything else.
         */
        (void)log_init(progname);

        const char*  pqfname = getQueuePath();

        spec.feedtype = DEFAULT_FEEDTYPE;
        spec.pattern = DEFAULT_PATTERN;

        if(set_timestamp(&clss.from)) /* corrected by toffset below */
        {
                int errnum = errno;
                log_error_q("Couldn't set timestamp: %s", strerror(errnum));
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }
        clss.to = TS_ENDT;
        clss.psa.psa_len = 1;
        clss.psa.psa_val = &spec;

        /*
         * deal with the command line, set options
         */
        {
            extern int optind;
            extern int opterr;
            extern char *optarg;

            int ch;
            int fterr;

            opterr = 1;

            while ((ch = getopt(ac, av, "vxel:d:f:q:o:p:i:t:")) != EOF) {
                switch (ch) {
                case 'v':
                        if (!log_is_enabled_info)
                            (void)log_set_level(LOG_LEVEL_INFO);
                        break;
                case 'x':
                        (void)log_set_level(LOG_LEVEL_DEBUG);
                        break;
                case 'e':
                        key = ftok("/etc/rc.d/rc.local",'R');
                        semkey = ftok("/etc/rc.d/rc.local",'e');
                        shmid = shmget(key, sizeof(edex_message) * queue_size,
                                0666 | IPC_CREAT);
                        semid = semget(semkey, 2, 0666 | IPC_CREAT);
                        break;
                case 'l':
                        logfname = optarg;
                        (void)log_set_destination(logfname);
                        break;
                case 'd':
                        setPqactDataDirPath(optarg);
                        break;
                case 'f':
                        fterr = strfeedtypet(optarg, &spec.feedtype);
                        if(fterr != FEEDTYPE_OK)
                        {
                                log_error_q("Bad feedtype \"%s\", %s\n",
                                        optarg, strfeederr(fterr));
                                usage(progname);
                        }
                        break;
                case 'q':
                        pqfname = optarg;
                        break;
                case 'o':
                        toffset = atoi(optarg);
                        if(toffset == 0 && *optarg != '0')
                        {
                                log_error_q("invalid offset %s\n", optarg);
                                usage(progname);   
                        }
                        break;
                case 'i':
                        interval = atoi(optarg);
                        if(interval == 0 && *optarg != '0')
                        {
                                log_error_q("invalid interval %s\n", optarg);
                                usage(progname);   
                        }
                        break;
                case 't':
                        pipe_timeo = atoi(optarg);
                        if(pipe_timeo == 0 && *optarg != 0)
                        {
                                log_error_q("invalid pipe_timeo %s", optarg);
                                usage(progname);   
                        }
                        break;
                case 'p':
                        spec.pattern = optarg;
                        break;
                default:
                        usage(progname);
                        break;
                }
            }

            conffilename = getPqactConfigPath();
            datadir = getPqactDataDirPath();

            {
                int numOperands = ac - optind;

                if (1 < numOperands) {
                    log_error_q("Too many operands");
                    usage(progname);
                }
                else if (1 == numOperands) {
                    conffilename = av[optind];
                }
            }
        }

        setQueuePath(pqfname);
        log_notice_q("Starting Up");

        if ('/' != conffilename[0]) {
            /*
             * The pathname of the configuration-file is relative. Convert it
             * to absolute so that it can be (re)read even if the current
             * working directory changes.
             */
#ifdef PATH_MAX
            char    buf[PATH_MAX];          /* includes NUL */
#else
            char    buf[_POSIX_PATH_MAX];   /* includes NUL */
#endif
            if (getcwd(buf, sizeof(buf)) == NULL) {
                log_syserr_q("Couldn't get current working directory");
                exit(EXIT_FAILURE);
            }
            (void)strncat(buf, "/", sizeof(buf)-strlen(buf)-1);
            (void)strncat(buf, conffilename, sizeof(buf)-strlen(buf)-1);
            conffilename = strdup(buf);
            if (conffilename == NULL) {
                log_syserr_q("Couldn't duplicate string \"%s\"", buf);
                exit(EXIT_FAILURE);
            }
        }

        /*
         * Initialize the previous-state module for this process.
         */
        if (stateInit(conffilename) < 0) {
            log_error_q("Couldn't initialize previous-state module");
            exit(EXIT_FAILURE);
            /*NOTREACHED*/
        }

        /*
         * Configure the standard I/O streams for execution of child processes.
         */
        if (configure_stdio_file_descriptors()) {
            log_error_q("Couldn't configure standard I/O streams for execution "
                    "of child processes");
            exit(EXIT_FAILURE);
        }

        /*
         * Inform the "filel" module about the number of available file
         * descriptors.  File descriptors are reserved for stdin, stdout,
         * stderr, the product-queue, the configuration-file, and (possibly) 
         * logging.
         */
        if (0 != set_avail_fd_count(openMax() - 6))
        {
            log_error_q("Couldn't set number of available file-descriptors");
            log_notice_q("Exiting");
            exit(EXIT_FAILURE);
            /*NOTREACHED*/
        }

        /*
         * Inform the "filel" module of the shared memory segment
         */
        if (shmid != -1 && semid != -1)
        {
            set_shared_space(shmid, semid, queue_size);
        }

        /*
         * Compile the pattern.
         */
        if (re_isPathological(spec.pattern))
        {
                log_error_q("Adjusting pathological regular-expression: \"%s\"",
                    spec.pattern);
                re_vetSpec(spec.pattern);
        }
        status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB);
        if(status != 0)
        {
                log_error_q("Can't compile regular expression \"%s\"",
                        spec.pattern);
                log_notice_q("Exiting");
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }

        /*
         * register exit handler
         */
        if(atexit(cleanup) != 0)
        {
                log_syserr_q("atexit");
                log_notice_q("Exiting");
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }

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

        /*
         * Read in (compile) the configuration file.  We do this first so
         * its syntax may be checked without opening a product queue.
         */
        if ((status = readPatFile(conffilename)) < 0) {
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }
        else if (status == 0) {
            log_notice_q("Configuration-file \"%s\" has no entries. "
                "You should probably not start this program instead.",
                conffilename);
        }

        /*
         * Open the product queue
         */
        status = pq_open(pqfname, PQ_READONLY, &pq);
        if(status)
        {
                if (PQ_CORRUPT == status) {
                    log_error_q("The product-queue \"%s\" is inconsistent\n",
                            pqfname);
                }
                else {
                    log_error_q("pq_open failed: %s: %s\n",
                            pqfname, strerror(status));
                }
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }

        if(toffset != TOFFSET_NONE) {
            /*
             * Filter and queue position set by "toffset".
             */
            clss.from.tv_sec -= toffset;
            pq_cset(pq, &clss.from);
        }
        else {
            bool       startAtTailEnd = true;
            timestampt insertTime;

            clss.from = TS_ZERO;

            /*
             * Try getting the insertion-time of the last,
             * successfully-processed data-product from the previous session.
             */
            status = stateRead(&insertTime);

            if (status) {
                log_warning_q("Couldn't get insertion-time of last-processed "
                        "data-product from previous session");
            }
            else {
                timestampt now;
                (void)set_timestamp(&now);

                if (tvCmp(now, insertTime, <)) {
                    log_warning_q("Time of last-processed data-product from previous "
                            "session is in the future");
                }
                else {
                    char buf[80];
                    (void)strftime(buf, sizeof(buf), "%Y-%m-%d %T",
                        gmtime(&insertTime.tv_sec));
                    log_notice_q("Starting from insertion-time %s.%06lu UTC", buf,
                        (unsigned long)insertTime.tv_usec);

                    pq_cset(pq, &insertTime);
                    startAtTailEnd = false;
                }
            }

            if (startAtTailEnd) {
                log_notice_q("Starting at tail-end of product-queue");
                (void)pq_last(pq, &clss, NULL);
            }
        }
예제 #12
0
파일: gribinsert.c 프로젝트: Unidata/LDM
int
main (int ac, char *av[])
{
  char *progname = av[0];
  int status;
  int seq_start = 0;
  stat_info *sinfo, *shead = NULL, *slast = NULL;
  int statusoff=0;

  /*
   * Set up error logging
   */
    if (log_init(progname)) {
        log_syserr("Couldn't initialize logging module");
        exit(1);
    }

  const char* pqfname = getQueuePath();

  /*
   * Check the environment for some options.
   * May be overridden by command line switches below.
   */
  {
    const char *ldmpqfname = getenv ("LDMPQFNAME");
    if (ldmpqfname != NULL)
      pqfname = ldmpqfname;
  }

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

    opterr = 1;

    while ((ch = getopt (ac, av, "vxl:q:f:s:S")) != EOF)
      switch (ch)
	{
	case 'v':
          if (!log_is_enabled_info)
            (void)log_set_level(LOG_LEVEL_INFO);
	  break;
	case 'x':
          (void)log_set_level(LOG_LEVEL_DEBUG);
	  break;
	case 'l':
          if (log_set_destination(optarg)) {
              log_syserr("Couldn't set logging destination to \"%s\"",
                      optarg);
              exit(1);
          }
	  break;
	case 'q':
	  pqfname = 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 'S':
	     statusoff=1;
	     break;
	case '?':
	  usage (progname);
	  break;
	}

    setQueuePath(pqfname);

    ac -= optind;
    av += optind;

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

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

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

  /*
   * who am i, anyway
   */
  (void) strcpy (myname, ghostname ());

  /*
   * open the product queue
   */
  if ((status = pq_open (pqfname, PQ_DEFAULT, &pq)))
    {
      if (status > 0) {
          log_add_syserr("\"%s\" failed", pqfname);
          log_flush_error();
      }
      else {
          log_error_q("\"%s\" failed: %s", pqfname, "Internal error");
      }
      exit (2);
    }


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

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

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

    prod.info.seqno = seq_start;

    /*
     * Open the file to be inserted and process
     */
    while (ac > 0)
      {
        long insert_sum = 0;
	long sinfo_cnt = 0;
        long stat_size = 0;

	filename = *av;
	av++;
	ac--;

	log_notice_q ("open and memorymap %s\0", filename);

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

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

	if ((prodmmap = (unsigned char *) mmap (0, statb.st_size,
				       PROT_READ, MAP_PRIVATE, fd,
				       0)) == MAP_FAILED)
	  {
	    log_syserr ("allocation failed");
	  }
	else
	  {
	    int GRIBDONE = 0;
	    off_t griboff = 0;
	    size_t griblen = 0;
	    log_notice_q ("%ld bytes memory mapped\0", (long) statb.st_size);

	    while (!GRIBDONE)
	      {
		log_debug("griboff %d\0", (int) griboff);
		/* get offset of next grib product */
		status =
		  get_grib_info (prodmmap, statb.st_size, &griboff, &griblen,
				 &gversion);

		switch (status)
		  {
		  case 0:
		    prod.data = prodmmap + griboff;
		    prod.info.sz = griblen;

		    /*
		     * revised MD5 calculation...using filename
		     * to allow duplicate products in different files.
		     */
		    MD5Init (md5ctxp);
  		    MD5Update (md5ctxp, (void *)filename, strlen(filename));
  		    /*MD5Update (md5ctxp, (void *)prod.data, prod.info.sz);*/
		    if ( prod.info.sz > 10000 )
  		       MD5Update (md5ctxp, (void *)prod.data, 10000);
		    else
  		       MD5Update (md5ctxp, (void *)prod.data, prod.info.sz);
  		    MD5Final (prod.info.signature, md5ctxp);

		    /*if (mm_md5 (md5ctxp, prod.data, prod.info.sz,
				prod.info.signature) != 0)
		      {
			log_error_q ("could not compute MD5\0");
		      }
		    else
		      { */
			prod.info.ident = (char *) malloc (KEYSIZE + 1);
			get_gribname (gversion, prod.data, prod.info.sz,
				      filename, prod.info.seqno,
				      prod.info.ident);
			/*
			 * Do the deed
			 */
			status = set_timestamp (&prod.info.arrival);
			if (status != ENOERR)
			  {
			    log_add_syserr("could not set timestamp");
                            log_flush_error();
			  }
			/*
			 * Insert the product
			 */
			status = pq_insert (pq, &prod);
			log_info_q ("%d %s\0", status, prod.info.ident);
                
			if ( status == ENOERR )
			   insert_sum += prod.info.sz;

			if (! statusoff )
			  {
			  /*
			   * Log this status
			   */
			    sinfo_cnt++;
			    sinfo = (stat_info *)malloc(sizeof(stat_info));
                   	    sinfo->insertstatus = status;
			    sinfo->prodname = (char *)malloc(strlen(prod.info.ident)+1);
                   	    strcpy(sinfo->prodname, prod.info.ident);
                   	    sinfo->seqno = prod.info.seqno;
                   	    sinfo->prodsz = prod.info.sz;
                   	    sinfo->next = NULL;
                   	    stat_size += strlen(sinfo->prodname);
                   	    if(shead == NULL)
			      {
                      	        shead = sinfo;
                      	        slast = sinfo;
                   	      }
                   	    else 
			      {
                      	        slast->next = sinfo;
                      	        slast = sinfo;
                   	      }
			  }
		      /*}*/
		    griboff += griblen;
		    prod.info.seqno++;
		    break;
		  case -1:
		    GRIBDONE = 1;
		    break;
		  case -2:
		    log_error_q ("truncated grib file at: %d", prod.info.seqno);
		    GRIBDONE = 1;
		    break;
		  case -7:
		    log_error_q ("End sequence 7777 not found where expected: %d",
			    prod.info.seqno);
		    griboff += griblen;
		    log_error_q("resume looking at %d\0",griboff);
		    break;
		  default:
		    log_error_q ("unknown error %d\0", status);
		    griboff += griblen;
		    if (griboff >= statb.st_size)
		      GRIBDONE = 1;
		    break;
		  }

		if (griboff >= statb.st_size)
		  GRIBDONE = 1;
	      }


	    log_notice_q ("munmap\0");
	    (void) munmap ((void *)prodmmap, statb.st_size);

	    if ( stat_size != 0 )
	    /*
	     * Add a status message to product queue
	     */
	      {
		char *statusmess;
		log_notice_q("stats_size %ld %ld\0",stat_size,sinfo_cnt);

		statusmess = calloc((30 * sinfo_cnt) + stat_size +
                        strlen(filename) + 128, sizeof(char));
                if(statusmess == NULL) 
		  {
              	    log_syserr("could not malloc status message %ld\0",
              	            stat_size);
           	  }
           	else
		  {
		    char tmpprod[512];
                    sinfo = shead; slast = NULL;

                    status = set_timestamp(&prod.info.arrival);
                    /* ctime ends with \n\0" */
                    sprintf(statusmess,"%s complete (%ld bytes) at %sInserted %ld of %ld\n",
                       filename,(long)statb.st_size, ctime(&prod.info.arrival.tv_sec),
                       insert_sum,(long)statb.st_size);

                    while(sinfo != NULL) 
		      {
                        sprintf(tmpprod,"%3d %5d %8d %s\n",sinfo->insertstatus,
                            sinfo->seqno,sinfo->prodsz,sinfo->prodname);
                        strcat(statusmess,tmpprod);

                        slast = sinfo;
                 	sinfo = sinfo->next;

                        free(slast->prodname);
                    	free(slast);

                      }

		    shead = NULL;

                    sprintf(tmpprod,".status.%s %06d",filename, prod.info.seqno);
                    prod.info.ident = tmpprod;
                    prod.data = statusmess;
                    prod.info.sz = strlen(statusmess);
                    status = mm_md5(md5ctxp, prod.data, prod.info.sz, prod.info.signature);
                    status = set_timestamp(&prod.info.arrival);
                    status = pq_insert(pq, &prod);
                    if(log_is_enabled_info)
                        log_info_q("%s", s_prod_info(NULL, 0, &prod.info,
                                log_is_enabled_debug)) ;
                    free(statusmess);
		    prod.info.seqno++;
		  }
	      }
	  }

	(void) close (fd);
      }
  }

exit(0);
}