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); }
/* * 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; }
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); }
/* * Called at exit. * This callback routine registered by atexit(). */ static void cleanup(void) { log_notice_q("exiting"); /* TODO: sign off */ log_fini(); }
/* * 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(); }
/* * 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; }
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; }
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*/ }
/* 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 */
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); }
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); } }
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); }