static pid_t reap_act(int options) { pid_t wpid = 0; if (act_pid != 0) { int status = 0; #ifdef HAVE_WAITPID wpid = waitpid(act_pid, &status, options); #else if(options == 0) wpid = wait(&status); /* customize here for older systems, use wait3 or whatever */ #endif if(wpid == -1) { if(!(errno == ECHILD && act_pid == -1)) { /* Only complain if relevant */ serror("waitpid"); } return -1; } /* else */ if(wpid != 0) { /* tag_pid_entry(wpid); */ #ifdef HAVE_WAITPID if(WIFSTOPPED(status)) { unotice("child %d stopped by signal %d", wpid, WSTOPSIG(status)); } else if(WIFSIGNALED(status)) { unotice("child %d terminated by signal %d", wpid, WTERMSIG(status)); /* DEBUG */ switch(WTERMSIG(status)) { /* * If a child dumped core, * shut everything down. */ case SIGQUIT: case SIGILL: case SIGTRAP: /* ??? */ case SIGABRT: #if defined(SIGEMT) case SIGEMT: /* ??? */ #endif case SIGFPE: /* ??? */ case SIGBUS: case SIGSEGV: #if defined(SIGSYS) case SIGSYS: /* ??? */ #endif #ifdef SIGXCPU case SIGXCPU: #endif #ifdef SIGXFSZ case SIGXFSZ: #endif act_pid = -1; exit(1); break; } } else if(WIFEXITED(status)) { if(WEXITSTATUS(status) != 0) unotice("child %d exited with status %d", wpid, WEXITSTATUS(status)); else udebug("child %d exited with status %d", wpid, WEXITSTATUS(status)); act_pid = -1; exit(WEXITSTATUS(status)); } #endif } } return wpid; }
static void alarm_handler() { unotice("SIGALRM: no data, returning EOF"); timeout_flag++; }
/** * Executes a product-maker. * * This function is thread-compatible but not thread-safe. * * @retval (void*)0 The FIFO was closed. * @retval (void*)1 Usage failure. \c log_start() called. * @retval (void*)2 O/S failure. \c log_start() called. * @retval (void*)-1 Retransmission failure. \c log_start() called. */ void* pmStart( void* const arg) /**< [in/out] Pointer to the * product-maker to be executed */ { ProductMaker* const productMaker = (ProductMaker*)arg; int status; Fifo* const fifo = productMaker->fifo; unsigned char* buf = productMaker->buf; sbn_struct* sbn = &productMaker->sbn; pdh_struct* pdh = &productMaker->pdh; psh_struct* psh = &productMaker->psh; pdb_struct* pdb = &productMaker->pdb; ccb_struct* ccb = &productMaker->ccb; unsigned long last_sbn_seqno; unsigned long last_sbn_runno = ULONG_MAX; int PNGINIT = 0; char* memheap = NULL; MD5_CTX* md5ctxp = productMaker->md5ctxp; int logResync = 1; prodstore prod; #ifdef RETRANS_SUPPORT long cpio_addr_tmp; int cpio_fd_tmp; /* char transfer_type[10]={0};*/ int retrans_val,idx; long retrans_tbl_size; time_t orig_arrive_time; int new_key; /* shm key */ ACQ_TABLE *acq_tbl = NULL; long num_prod_discards=0; int save_prod = 1; int discard_prod = 0; long proc_orig_prod_seqno_last_save=0; #endif prod.head = NULL; prod.tail = NULL; /*** For Retranmission Purpose ***/ #ifdef RETRANS_SUPPORT if (ulogIsDebug()) udebug(" retrans_xmit_enable = %d transfer_type = %s sbn_channel_name=%s \n",retrans_xmit_enable,transfer_type,sbn_channel_name); if((retrans_xmit_enable == OPTION_ENABLE) && (!strcmp(transfer_type,"MHS") || !strcmp(transfer_type,"mhs"))){ idx = get_cpio_addr(mcastAddr); if( idx >= 0 && idx < NUM_CPIO_ENTRIES){ global_cpio_fd = cpio_tbl[idx].cpio_fd; global_cpio_addr = cpio_tbl[idx].cpio_addr; if (ulogIsDebug()) udebug("Global cpio_addr = 0x%x Global cpio_fd = %d \n",global_cpio_addr,global_cpio_fd); }else{ uerror("Invalid multicast address provided"); return (void*)-1; } retrans_tbl_size = sizeof(PROD_RETRANS_TABLE); /** Modified to setup retrans table on per channel basis - Sathya - 14-Mar'2013 **/ retrans_tbl_size += (sizeof(PROD_RETRANS_ENTRY) * GET_RETRANS_CHANNEL_ENTRIES(sbn_type)); /**** retrans_tbl_size += (sizeof(PROD_RETRANS_ENTRY) * DEFAULT_RETRANS_ENTRIES_NMC); retrans_tbl_size += (sizeof(PROD_RETRANS_ENTRY) * DEFAULT_RETRANS_ENTRIES_NMC1); retrans_tbl_size += (sizeof(PROD_RETRANS_ENTRY) * DEFAULT_RETRANS_ENTRIES_NMC2); retrans_tbl_size += (sizeof(PROD_RETRANS_ENTRY) * DEFAULT_RETRANS_ENTRIES_NMC3); retrans_tbl_size += (sizeof(PROD_RETRANS_ENTRY) * DEFAULT_RETRANS_ENTRIES_GOES_EAST); retrans_tbl_size += (sizeof(PROD_RETRANS_ENTRY) * DEFAULT_RETRANS_ENTRIES_NOAAPORT_OPT); ****/ p_prod_retrans_table = (PROD_RETRANS_TABLE *) malloc (retrans_tbl_size); if(p_prod_retrans_table == NULL){ uerror("Unable to allocate memory for retrans table..Quitting.\n"); return (void*)-1; } if( init_retrans(&p_prod_retrans_table) < 0 ){ uerror("Error in initializing retrans table \n"); if(p_prod_retrans_table) free(p_prod_retrans_table); return (void*)-1; } GET_SHMPTR(global_acq_tbl,ACQ_TABLE,ACQ_TABLE_SHMKEY,DEBUGGETSHM); if (ulogIsDebug()) udebug("Global acquisition table = 0x%x cpio_fd = %d \n",global_acq_tbl,global_cpio_fd); acq_tbl = &global_acq_tbl[global_cpio_fd]; if (ulogIsDebug()) udebug("Obtained acquisition table = 0x%x \n",acq_tbl); /* ACQ_TABLE already initialized in acq_ldm_getshm */ /* if(init_acq_table(acq_tbl) < 0){ uerror("Unable to initialize acq table\n"); exit(-1); } */ buff_hdr = (BUFF_HDR *) malloc(sizeof(BUFF_HDR)); if(init_buff_hdr(buff_hdr) < 0){ uerror("Unalbe to initialize buffer header \n"); if(acq_tbl) free(acq_tbl); if(p_prod_retrans_table) free(p_prod_retrans_table); return (void*)-1; } acq_tbl->pid = getpid(); acq_tbl->link_id = global_cpio_fd; acq_tbl->link_addr = global_cpio_addr; if(ulogIsVerbose()){ uinfo("Initialized acq_tbl = 0x%x & buff_hdr = 0x%x pid = %d \n",acq_tbl,buff_hdr,acq_tbl->pid); uinfo("Global link id = %d Global link addr = %ld \n",acq_tbl->link_id,acq_tbl->link_addr); uinfo("acq_tbl->read_distrib_enable = 0x%x \n",acq_tbl->read_distrib_enable); } } /*** For Retranmission Purpose ***/ #endif for (;;) { unsigned char b1; long IOFF; int NWSTG; int GOES; int PROD_COMPRESSED; size_t heapcount; size_t heapsize; char PROD_NAME[1024]; int dataoff; int datalen; datastore* pfrag; int nscan; int deflen; static const char* FOS_TRAILER = "\015\015\012\003"; int cnt; /* Look for first byte == 255 and a valid SBN checksum */ if ((status = fifoRead(fifo, buf, 1)) != 0) { if (3 == status) status = 0; break; } if ((b1 = (unsigned char)buf[0]) != 255) { if (logResync) { uinfo("Trying to resync %u", b1); logResync = 0; } continue; } logResync = 1; if (fifoRead(fifo, buf + 1, 15) != 0) { if (ulogIsDebug()) udebug("couldn't read 16 bytes for sbn"); continue; } while ((status = readsbn(buf, sbn)) != 0) { if (ulogIsDebug()) udebug("Not SBN start"); IOFF = 1; while ((IOFF < 16) && ((b1 = (unsigned char) buf[IOFF]) != 255)) IOFF++; if (IOFF > 15) { break; } else { int ch; for (ch = IOFF; ch < 16; ch++) buf[ch - IOFF] = buf[ch]; if (fifoRead(fifo, buf + 16 - IOFF, IOFF) != 0) { if (ulogIsDebug()) udebug("Couldn't read bytes for SBN, resync"); break; } } } if (status != 0) { if (ulogIsDebug()) udebug("SBN status continue"); continue; } IOFF = 0; if (fifoRead(fifo, buf + 16, 16) != 0) { if (ulogIsDebug()) udebug("error reading Product Definition Header"); continue; } #ifdef RETRANS_SUPPORT /* Update acq table stats - Begin */ if(retrans_xmit_enable == OPTION_ENABLE){ buff_hdr->read_channel_type = sbn->datastream; } /* Update acq table stats - End */ #endif if (ulogIsDebug()) udebug("***********************************************"); if (last_sbn_runno != sbn->runno) { last_sbn_runno = sbn->runno; } else { unsigned long delta = sbn->seqno - last_sbn_seqno; # define MAX_SEQNO 0xFFFFFFFFu if (0 == delta || MAX_SEQNO/2 < delta) { uwarn("Retrograde packet number: previous=%lu, latest=%lu, " "difference=%lu", last_sbn_seqno, sbn->seqno, 0 == delta ? 0ul : MAX_SEQNO - delta + 1); } else { if (1 != delta) { unsigned long gap = delta - 1; uwarn("Gap in packet sequence: %lu to %lu [skipped %lu]", last_sbn_seqno, sbn->seqno, gap); (void)pthread_mutex_lock(&productMaker->mutex); productMaker->nmissed += gap; (void)pthread_mutex_unlock(&productMaker->mutex); } (void)pthread_mutex_lock(&productMaker->mutex); productMaker->npackets++; (void)pthread_mutex_unlock(&productMaker->mutex); } /* non-retrograde packet number */ } /* "last_sbn_seqno" initialized */ last_sbn_seqno = sbn->seqno; if (ulogIsVerbose()) uinfo("SBN seqnumber %ld", sbn->seqno); if (ulogIsVerbose()) uinfo("SBN datastream %d command %d", sbn->datastream, sbn->command); if (ulogIsDebug()) udebug("SBN version %d length offset %d", sbn->version, sbn->len); if (((sbn->command != 3) && (sbn->command != 5)) || (sbn->version != 1)) { uerror("Unknown sbn command/version %d PUNT", sbn->command); continue; } switch (sbn->datastream) { case 5: /* nwstg */ case 6: /* nwtg2 */ case 7: /* polarsat */ case 8: /* NOAA Weather Wire Service (NWWS) */ case 9: case 10: case 11: case 12: /* GOES-R */ case 13: /* GOES-R */ NWSTG = 1; GOES = 0; break; case 1: /* GINI GOES */ case 2: /* GINI GOES */ case 4: /* OCONUS */ NWSTG = 0; GOES = 1; break; default: uerror("Unknown NOAAport channel %d PUNT", sbn->datastream); continue; } /* End of SBN version low 4 bits */ if (readpdh(buf + IOFF + sbn->len, pdh) == -1) { uerror("problem with pdh, PUNT"); continue; } if (pdh->len > 16) { if (fifoRead(fifo, buf + sbn->len + 16, pdh->len - 16) != 0) continue; } if (ulogIsDebug()) udebug("Product definition header version %d pdhlen %d", pdh->version, pdh->len); if (pdh->version != 1) { uerror("Error: PDH transfer type %u, PUNT", pdh->transtype); continue; } else if (ulogIsDebug()) { udebug("PDH transfer type %u", pdh->transtype); } if ((pdh->transtype & 8) > 0) uerror("Product transfer flag error %u", pdh->transtype); if ((pdh->transtype & 32) > 0) uerror("Product transfer flag error %u", pdh->transtype); if ((pdh->transtype & 16) > 0) { PROD_COMPRESSED = 1; if (ulogIsDebug()) udebug("Product transfer flag compressed %u", pdh->transtype); } else { PROD_COMPRESSED = 0; } if (ulogIsDebug()) udebug("header length %ld [pshlen = %d]", pdh->len + pdh->pshlen, pdh->pshlen); if (ulogIsDebug()) udebug("blocks per record %ld records per block %ld\n", pdh->blocks_per_record, pdh->records_per_block); if (ulogIsDebug()) udebug("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; } #ifdef RETRANS_SUPPORT /** Update acquisition table statistics **/ if(retrans_xmit_enable == OPTION_ENABLE){ acq_tbl->read_tot_buff_read++; } #endif if (pdh->pshlen != 0) { if (fifoRead(fifo, buf + sbn->len + pdh->len, pdh->pshlen) != 0) { uerror("problem reading psh"); continue; } else { if (ulogIsDebug()) udebug("read psh %d", pdh->pshlen); } /* Timing block */ if (sbn->command == 5) { if (ulogIsDebug()) udebug("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(buf + IOFF + sbn->len + pdh->len, psh) == -1) { uerror("problem with readpsh"); continue; } if (psh->olen != pdh->pshlen) { uerror("ERROR in calculation of psh len %ld %ld", psh->olen, pdh->len); continue; } if (ulogIsDebug()) udebug("len %ld", psh->olen); if (ulogIsDebug()) udebug("product header flag %d, version %d", psh->hflag, psh->version); if (ulogIsDebug()) udebug("prodspecific data length %ld", psh->psdl); if (ulogIsDebug()) udebug("bytes per record %ld", psh->bytes_per_record); if (ulogIsDebug()) udebug("Fragments = %ld category %d ptype %d code %d", psh->frags, psh->pcat, psh->ptype, psh->pcode); if (psh->frags < 0) uerror("check psh->frags %d", psh->frags); if (psh->origrunid != 0) uerror("original runid %d", psh->origrunid); if (ulogIsDebug()) udebug("next header offset %ld", psh->nhoff); if (ulogIsDebug()) udebug("original seq number %ld", psh->seqno); if (ulogIsDebug()) udebug("receive time %ld", psh->rectime); if (ulogIsDebug()) udebug("transmit time %ld", psh->transtime); if (ulogIsDebug()) udebug("run ID %ld", psh->runid); if (ulogIsDebug()) udebug("original run id %ld", psh->origrunid); #ifdef RETRANS_SUPPORT /* Update acq table stats - Begin */ if(retrans_xmit_enable == OPTION_ENABLE){ buff_hdr->buff_data_length = pdh->dbsize; if(pdh->dbno == 0) { /* Assume first block */ acq_tbl->proc_base_prod_type_last = psh->ptype; acq_tbl->proc_base_prod_cat_last = psh->pcat; acq_tbl->proc_base_prod_code_last = psh->pcode; acq_tbl->proc_prod_NCF_rcv_time = (time_t)psh->rectime; acq_tbl->proc_prod_NCF_xmit_time = (time_t)psh->transtime; if(psh->hflag & XFR_PROD_RETRANSMIT){ acq_tbl->proc_orig_prod_seqno_last = psh->seqno; acq_tbl->proc_orig_prod_run_id = psh->origrunid; if(ulogIsDebug()) udebug("ORIG SEQ# = %ld CURR SEQ#: %ld \n",acq_tbl->proc_orig_prod_seqno_last,pdh->seqno); }else{ acq_tbl->proc_orig_prod_seqno_last = 0; acq_tbl->proc_orig_prod_run_id = 0; } acq_tbl->proc_prod_run_id = psh->runid; buff_hdr->buff_datahdr_length = psh->psdl; time(&acq_tbl->proc_prod_start_time); acq_tbl->proc_tot_prods_handled++; }else{ buff_hdr->buff_datahdr_length = 0; } buff_hdr->proc_prod_seqno= pdh->seqno; buff_hdr->proc_blkno = pdh->dbno; buff_hdr->proc_sub_code = 0; buff_hdr->proc_prod_flag = pdh->transtype; acq_tbl->proc_base_channel_type_last = buff_hdr->read_channel_type; buff_hdr->proc_prod_type = acq_tbl->proc_base_prod_type_last; buff_hdr->proc_prod_code = acq_tbl->proc_base_prod_code_last; buff_hdr->proc_prod_cat = acq_tbl->proc_base_prod_cat_last; acq_tbl->proc_prod_bytes_read = buff_hdr->buff_data_length; /* Check prod_seqno for lost products */ if((buff_hdr->proc_prod_seqno - acq_tbl->proc_base_prod_seqno_last) != 1){ do_prod_lost(buff_hdr,acq_tbl); } retrans_val = prod_retrans_ck(acq_tbl, buff_hdr, &orig_arrive_time); log_buff[0] = '\0'; if((retrans_val == PROD_DUPLICATE_DISCARD) || ((retrans_val == PROD_DUPLICATE_MATCH) && (acq_tbl->proc_retransmit_ctl_flag & ENABLE_RETRANS_DUP_MATCH_DISCARD)) || ((retrans_val == PROD_DUPLICATE_NOMATCH) && (acq_tbl->proc_retransmit_ctl_flag & ENABLE_RETRANS_DUP_NOMATCH_DISCARD))){ /* Log product details and discard the product */ strcpy(log_buff,"DISCARD"); if(acq_tbl->proc_orig_prod_seqno_last != 0){ strcat(log_buff, "/RETRANS"); } log_prod_end(log_buff, acq_tbl->proc_orig_prod_seqno_last, buff_hdr->proc_prod_seqno,buff_hdr->proc_blkno, buff_hdr->proc_prod_code, acq_tbl->proc_prod_bytes_read,orig_arrive_time); save_prod = 0; acq_tbl->proc_base_prod_seqno_last = buff_hdr->proc_prod_seqno; /* Current prod discarded and continue with next */ /*continue; */ }else{ if(retrans_val == PROD_DUPLICATE_NOMATCH){ strcpy(log_buff,"SAVE RETRANS"); log_prod_end(log_buff, acq_tbl->proc_orig_prod_seqno_last, buff_hdr->proc_prod_seqno,buff_hdr->proc_blkno, buff_hdr->proc_prod_code, acq_tbl->proc_prod_bytes_read,acq_tbl->proc_prod_start_time); } } } #endif if (prod.head != NULL) { uerror("OOPS, start of new product [%ld ] with unfinished " "product %ld", pdh->seqno, prod.seqno); #ifdef RETRANS_SUPPORT /* Request retrans when prod is partially received but before completion */ /* if there is frame error and continue with different prod then, we need */ /* to abort the old prod and clear retrans table. */ if((retrans_xmit_enable == OPTION_ENABLE) /*&& (pdh->dbno != 0)*/){ acq_tbl->proc_acqtab_prodseq_errs++; if(proc_orig_prod_seqno_last_save != acq_tbl->proc_orig_prod_seqno_last){ /* Clear retrans table for the orig prod if the previous prod is retrans */ /* of original prod */ prod_retrans_abort_entry(acq_tbl, proc_orig_prod_seqno_last_save, RETRANS_RQST_CAUSE_RCV_ERR); } prod_retrans_abort_entry(acq_tbl, prod.seqno, RETRANS_RQST_CAUSE_RCV_ERR); /* Update Statistics */ acq_tbl->proc_tot_prods_lost_errs++; /* For now, generate retrans request only for non-imagery products */ if(!((buff_hdr->proc_prod_cat == PROD_CAT_IMAGE) && (PROD_TYPE_NESDIS_HDR_TRUE(buff_hdr->proc_prod_type)))){ generate_retrans_rqst(acq_tbl,prod.seqno , prod.seqno, RETRANS_RQST_CAUSE_RCV_ERR); } acq_tbl->proc_base_prod_seqno_last = buff_hdr->proc_prod_seqno; } #endif ds_free(); prod.head = NULL; prod.tail = NULL; if (PNGINIT != 0) { pngout_end(); PNGINIT = 0; } uerror("Product definition header version %d pdhlen %d", pdh->version, pdh->len); uerror("PDH transfer type %u", pdh->transtype); if ((pdh->transtype & 8) > 0) uerror("Product transfer flag error %u", pdh->transtype); if ((pdh->transtype & 32) > 0) uerror("Product transfer flag error %u", pdh->transtype); uerror("header length %ld [pshlen = %d]", pdh->len + pdh->pshlen, pdh->pshlen); uerror("blocks per record %ld records per block %ld", pdh->blocks_per_record, pdh->records_per_block); uerror("product seqnumber %ld block number %ld data block " "size %ld", pdh->seqno, pdh->dbno, pdh->dbsize); uerror("product header flag %d", psh->hflag); uerror("prodspecific data length %ld", psh->psdl); uerror("bytes per record %ld", psh->bytes_per_record); uerror("Fragments = %ld category %d", psh->frags, psh->pcat); if (psh->frags < 0) uerror("check psh->frags %d", psh->frags); if (psh->origrunid != 0) uerror("original runid %d", psh->origrunid); uerror("next header offset %ld", psh->nhoff); uerror("original seq number %ld", psh->seqno); uerror("receive time %ld", psh->rectime); uerror("transmit time %ld", psh->transtime); uerror("run ID %ld", psh->runid); uerror("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 (fifoRead(fifo, buf + sbn->len + pdh->len + pdh->pshlen, pdh->dbsize) != 0) { uerror("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(buf + IOFF + sbn->len + pdh->len + pdh->pshlen, psh, pdb, PROD_COMPRESSED, pdh->dbsize) == -1) { uerror("Error reading pdb, punt"); continue; } (void)memcpy(PROD_NAME, psh->pname, sizeof(PROD_NAME)); if (ulogIsDebug()) udebug("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(buf + IOFF + sbn->len + pdh->len + pdh->pshlen, ccb, psh, pdh->dbsize) == -1) uerror("Error reading ccb, using default name"); if (ulogIsDebug()) udebug("look at ccb start %d %d", ccb->b1, ccb->len); if (ulogIsVerbose()) uinfo("%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%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()) udebug("continuation record"); #ifdef RETRANS_SUPPORT if(retrans_xmit_enable == OPTION_ENABLE){ buff_hdr->buff_data_length = pdh->dbsize; buff_hdr->buff_datahdr_length = 0; buff_hdr->proc_prod_seqno= pdh->seqno; buff_hdr->proc_blkno = pdh->dbno; buff_hdr->proc_sub_code = 0; buff_hdr->proc_prod_flag = pdh->transtype; acq_tbl->proc_base_channel_type_last = buff_hdr->read_channel_type; buff_hdr->proc_prod_type = acq_tbl->proc_base_prod_type_last; buff_hdr->proc_prod_code = acq_tbl->proc_base_prod_code_last; buff_hdr->proc_prod_cat = acq_tbl->proc_base_prod_cat_last; acq_tbl->proc_prod_bytes_read += buff_hdr->buff_data_length; } #endif if ((pdh->transtype & 4) > 0) { psh->frags = 0; } if (fifoRead(fifo, buf + sbn->len + pdh->len + pdh->pshlen, pdh->dbsize) != 0) { uerror("problem reading datablock (cont)"); continue; } if (prod.head == NULL) { if (ulogIsVerbose()) uinfo("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()) udebug("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; if (GOES == 1) { if (pfrag->fragnum > 0) { if ((pfrag->fragnum != prod.tail->fragnum + 1) || (pfrag->seqno != prod.seqno)) { uerror("Missing GOES fragment in sequence, " "last %d/%d this %d/%d\0", prod.tail->fragnum, prod.seqno, pfrag->fragnum, pfrag->seqno); #ifdef RETRANS_SUPPORT if(retrans_xmit_enable == OPTION_ENABLE){ acq_tbl->proc_acqtab_prodseq_errs++; do_prod_mismatch(acq_tbl,buff_hdr); acq_tbl->proc_base_prod_seqno_last = buff_hdr->proc_prod_seqno; } #endif ds_free(); prod.head = NULL; prod.tail = NULL; continue; } if ((PNGINIT != 1) && (!PROD_COMPRESSED)) { uerror("failed pnginit %d %d %s", sbn->datastream, psh->pcat, PROD_NAME); continue; } if (pdh->records_per_block < 1) { uerror("records_per_block %d blocks_per_record %d " "nx %d ny %d", pdh->records_per_block, pdh->blocks_per_record, pdb->nx, pdb->ny); uerror("source %d sector %d channel %d", pdb->source, pdb->sector, pdb->channel); uerror("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); uerror("pshname %s", psh->pname); } if (!PROD_COMPRESSED) { for (nscan = 0; (nscan * pdb->nx) < pdh->dbsize; nscan++) { if (ulogIsDebug()) udebug("png write nscan %d", nscan); if (nscan >= pdh->records_per_block) { uerror("nscan exceeding records per block %d [%d " "%d %d]", pdh->records_per_block, nscan, pdb->nx, pdh->dbsize); } else { pngwrite(buf + dataoff + (nscan * pdb->nx)); } } } else { memcpy(memheap + heapcount, buf + dataoff, datalen); MD5Update(md5ctxp, (unsigned char *) (memheap + heapcount), datalen); heapcount += datalen; } } else { if (!PROD_COMPRESSED) { png_set_memheap(memheap, md5ctxp); png_header(buf + 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, buf + dataoff, datalen); MD5Update(md5ctxp, (unsigned char*)(memheap + heapcount), datalen); heapcount += datalen; } unotice("records_per_block %d blocks_per_record %d nx %d ny %d", pdh->records_per_block, pdh->blocks_per_record, pdb->nx, pdb->ny); unotice("source %d sector %d channel %d", pdb->source, pdb->sector, pdb->channel); unotice("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); unotice("pshname %s", psh->pname); } deflen = 0; #ifdef RETRANS_SUPPORT if(retrans_xmit_enable == OPTION_ENABLE){ if(buff_hdr->proc_blkno != 0){ /*acq_tbl->proc_prod_bytes_read += buff_hdr->buff_data_length;*/ acq_tbl->proc_prod_bytes_read += datalen; } } #endif } else { /* 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)) { uerror("Missing fragment in sequence, last %d/%d this " "%d/%d\0", prod.tail->fragnum, prod.seqno, pfrag->fragnum, pfrag->seqno); #ifdef RETRANS_SUPPORT if(retrans_xmit_enable == OPTION_ENABLE){ acq_tbl->proc_acqtab_prodseq_errs++; if(ulogIsDebug()) udebug("do_prod_mismatch() proc_base_prod_seqno_last = %d \n", acq_tbl->proc_base_prod_seqno_last); do_prod_mismatch(acq_tbl,buff_hdr); acq_tbl->proc_base_prod_seqno_last = buff_hdr->proc_prod_seqno; } #endif 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, buf + (dataoff + datalen - 4), 4); if (memcmp(testme, FOS_TRAILER, 4) == 0) { datalen -= 4; if (ulogIsDebug()) udebug("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); */ uerror("Error in heapsize %d product size %d [%d %d], Punt!\0", heapsize, (heapcount + datalen), heapcount, datalen); #ifdef RETRANS_SUPPORT if(retrans_xmit_enable == OPTION_ENABLE){ /* Update Statistics */ acq_tbl->proc_tot_prods_lost_errs++; /* Abort entry and request retransmission */ prod_retrans_abort_entry(acq_tbl, prod.seqno, RETRANS_RQST_CAUSE_RCV_ERR); generate_retrans_rqst(acq_tbl, prod.seqno, prod.seqno, RETRANS_RQST_CAUSE_RCV_ERR); if(acq_tbl->proc_orig_prod_seqno_last != 0){ strcpy(log_buff, "RETRANS"); } log_prod_end(log_buff, acq_tbl->proc_orig_prod_seqno_last, buff_hdr->proc_prod_seqno,buff_hdr->proc_blkno, buff_hdr->proc_prod_code, acq_tbl->proc_prod_bytes_read, acq_tbl->proc_prod_start_time); acq_tbl->proc_base_prod_seqno_last = buff_hdr->proc_prod_seqno; } #endif continue; } memcpy(memheap + heapcount, buf + dataoff, datalen); deflen = datalen; MD5Update(md5ctxp, (unsigned char *) (memheap + heapcount), deflen); #ifdef RETRANS_SUPPORT if(retrans_xmit_enable == OPTION_ENABLE){ if(buff_hdr->proc_blkno != 0){ /*acq_tbl->proc_prod_bytes_read += buff_hdr->buff_data_length;*/ acq_tbl->proc_prod_bytes_read += datalen; } } #endif } pfrag->recsiz = deflen; heapcount += deflen; if (prod.head == NULL) { prod.head = pfrag; prod.tail = pfrag; } else { prod.tail->next = pfrag; prod.tail = pfrag; } #ifdef RETRANS_SUPPORT if(((prod.nfrag == 0) || (prod.nfrag >= (pfrag->fragnum +1))) && (save_prod == 0)){ if(ulogIsVerbose()) uinfo("Do not save prod [seqno=%ld] as its retrans dup fragnum/total fragments =[%d of %d] save_prod=[%d] \n", prod.seqno,pfrag->fragnum,prod.nfrag,save_prod); ds_free (); prod.head = NULL; prod.tail = NULL; PNGINIT = 0; }else{ #endif if ((prod.nfrag == 0) || (prod.nfrag == (pfrag->fragnum + 1))) { if (GOES == 1) { if (PNGINIT == 1) { pngout_end(); heapcount = png_get_prodlen(); } else { if (ulogIsDebug()) udebug("GOES product already compressed %d", heapcount); } } if (ulogIsVerbose()) uinfo("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 */ break; } } if (cnt > 0) { memcpy(memheap + heapcount, FOS_TRAILER + 4 - cnt, cnt); MD5Update(md5ctxp, (unsigned char*)(memheap + heapcount), cnt); heapcount += cnt; } } #ifdef RETRANS_SUPPORT if((retrans_xmit_enable == OPTION_ENABLE) && (acq_tbl->read_distrib_enable & READ_CTL_DISCARD)){ num_prod_discards++; /* Set discard_prod to 1; Otherwise already stored prod may be requested for retransmit */ discard_prod=1; if(ulogIsVerbose()) uinfo("No of products discarded = %ld prod.seqno=%ld \n ",num_prod_discards,prod.seqno); prod_retrans_abort_entry(acq_tbl, prod.seqno, RETRANS_RQST_CAUSE_RCV_ERR); acq_tbl->proc_base_prod_seqno_last = buff_hdr->proc_prod_seqno -1 ; ds_free (); prod.head = NULL; prod.tail = NULL; PNGINIT = 0; }else{ /* Do not insert prod into queue if its a duplicate product */ if(save_prod != 0) #endif process_prod(prod, PROD_NAME, memheap, heapcount, md5ctxp, productMaker->ldmProdQueue, psh, sbn); #ifdef RETRANS_SUPPORT /* Update acq table with last processed seqno -Begin */ if(retrans_xmit_enable == OPTION_ENABLE){ acq_tbl->proc_base_prod_seqno_last = buff_hdr->proc_prod_seqno; uinfo(" prod with seqno processed = %ld\n",acq_tbl->proc_base_prod_seqno_last); } /* Update acq table with last processed seqno -End */ #endif ds_free(); prod.head = NULL; prod.tail = NULL; PNGINIT = 0; (void)pthread_mutex_lock(&productMaker->mutex); productMaker->nprods++; (void)pthread_mutex_unlock(&productMaker->mutex); #ifdef RETRANS_SUPPORT } #endif } else { if (ulogIsDebug()) udebug("processing record %ld [%ld %ld]", prod.seqno, prod.nfrag, pfrag->fragnum); if ((pdh->transtype & 4) > 0) { uerror("Hmmm....should call completed product %ld [%ld %ld]", prod.seqno, prod.nfrag, pfrag->fragnum); } } #ifdef RETRANS_SUPPORT if(retrans_xmit_enable == OPTION_ENABLE){ if(!(acq_tbl->read_distrib_enable & READ_CTL_DISCARD)) if(!discard_prod){ acq_tbl->proc_base_prod_seqno_last = buff_hdr->proc_prod_seqno; discard_prod = 0; } } #endif #ifdef RETRANS_SUPPORT } save_prod = 1; #endif IOFF += (sbn->len + pdh->len + pdh->pshlen + pdh->dbsize); if (ulogIsDebug()) udebug("look IOFF %ld datalen %ld (deflate %ld)", IOFF, datalen, deflen); #ifdef RETRANS_SUPPORT if(retrans_xmit_enable == OPTION_ENABLE){ total_prods_retrans_rcvd = acq_tbl->proc_tot_prods_retrans_rcvd; /* prods retrans rcvd by proc */ total_prods_retrans_rcvd_lost = acq_tbl->proc_tot_prods_retrans_rcvd_lost; /* prods retrans rcvd lost */ total_prods_retrans_rcvd_notlost = acq_tbl->proc_tot_prods_retrans_rcvd_notlost; /* prods rcvd not lost */ total_prods_retrans_rqstd = acq_tbl->proc_tot_prods_retrans_rqstd; /* prods retrans requested */ total_prods_handled = acq_tbl->proc_tot_prods_handled; /* prods retrans requested */ total_prods_lost_err = acq_tbl->proc_tot_prods_lost_errs; /* prods retrans requested */ total_frame_cnt = acq_tbl->read_tot_buff_read; total_frame_err = acq_tbl->read_frame_tot_lost_errs; proc_orig_prod_seqno_last_save = acq_tbl->proc_orig_prod_seqno_last; } #endif } if (NULL != memheap) free(memheap); productMaker->status = status; return NULL; }
/* * Create a TCP socket, bind it to a port, call 'listen' (we are a * server), and inform the portmap (rpcbind) service. Does _not_ create * an RPC SVCXPRT or do the xprt_register() or svc_fds() stuff. * * Arguments: * sockp Pointer to socket (file) descriptor. Set on and only on * success. * localIpAddr The IP address, in network byte order, of the * local interface to use. May be htonl(INADDR_ANY). * localPort The number of the local port on which the LDM server * should listen. * Returns: * 0 Success. * EACCES The process doesn't have appropriate privileges. * EADDRINUSE The local address is already in use. * EADDRNOTAVAIL The specified address is not available from the local * machine. * EAFNOSUPPORT The system doesn't support IP. * EMFILE No more file descriptors are available for this process. * ENFILE No more file descriptors are available for the system. * ENOBUFS Insufficient resources were available in the system. * ENOMEM Insufficient memory was available. * ENOSR There were insufficient STREAMS resources available. * EOPNOTSUPP The socket protocol does not support listen(). * EPROTONOSUPPORT The system doesn't support TCP. */ static int create_ldm_tcp_svc( int* sockp, in_addr_t localIpAddr, unsigned localPort) { int error = 0; /* success */ int sock; /* * Get a TCP socket. */ udebug("create_ldm_tcp_svc(): Getting TCP socket"); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { error = errno; serror("Couldn't get socket for server"); } else { unsigned short port = (unsigned short) localPort; struct sockaddr_in addr; socklen_t len = sizeof(addr); /* * Eliminate problem with EADDRINUSE for reserved socket. * We get this if an upstream data source hasn't tried to * write on the other end and we are in FIN_WAIT_2 */ udebug("create_ldm_tcp_svc(): Eliminating EADDRINUSE problem."); { int on = 1; (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); } (void) memset(&addr, 0, len); addr.sin_family = AF_INET; addr.sin_addr.s_addr = localIpAddr; addr.sin_port = (short) htons((short) port); /* * If privilege available, set it so we can bind to the port for LDM * services. Also needed for the pmap_set() call. */ udebug("create_ldm_tcp_svc(): Getting root privs"); rootpriv(); udebug("create_ldm_tcp_svc(): Binding socket"); if (bind(sock, (struct sockaddr *) &addr, len) < 0) { error = errno; serror("Couldn't obtain local address %s:%u for server", inet_ntoa(addr.sin_addr), (unsigned) port); if (error == EACCES) { error = 0; addr.sin_port = 0; /* let system assign port */ if (bind(sock, (struct sockaddr *) &addr, len) < 0) { error = errno; serror("Couldn't obtain local address %s:* for server", inet_ntoa(addr.sin_addr)); } } /* requested port is reserved */ } /* couldn't bind to requested port */ if (!error) { /* * Get the local address associated with the bound socket. */ udebug("create_ldm_tcp_svc(): Calling getsockname()"); if (getsockname(sock, (struct sockaddr *) &addr, &len) < 0) { error = errno; serror("Couldn't get local address of server's socket"); } else { port = (short) ntohs((short) addr.sin_port); unotice("Using local address %s:%u", inet_ntoa(addr.sin_addr), (unsigned) port); udebug("create_ldm_tcp_svc(): Calling listen()"); if (listen(sock, 32) != 0) { error = errno; serror("Couldn't listen() on server's socket"); } else { /* * Register with the portmapper if it's running. The * check to see if it's running is made because on a * FreeBSD 4.7-STABLE system, a pmap_set() call takes * one minute even if the portmapper isn't running. */ udebug("create_ldm_tcp_svc(): Checking portmapper"); if (local_portmapper_running()) { udebug("create_ldm_tcp_svc(): Registering"); if (pmap_set(LDMPROG, 6, IPPROTO_TCP, port) == 0) { uwarn("Can't register TCP service %lu on " "port %u", LDMPROG, (unsigned) port); uwarn("Downstream LDMs won't be able to " "connect via the RPC portmapper daemon " "(rpcbind(8), portmap(8), etc.)"); } else { portIsMapped = 1; (void) pmap_set(LDMPROG, 5, IPPROTO_TCP, port); } } /* a local portmapper is running */ /* * Done with the need for privilege. */ udebug("create_ldm_tcp_svc(): Releasing root privs"); unpriv(); *sockp = sock; } /* listen() success */ } /* getsockname() success */ } /* "sock" is bound to local address */ if (error) (void) close(sock); } /* "sock" is open */ return error; }
int main(int ac, char *av[]) { int logfd; int width; int ready; unsigned long idle; fd_set readfds; fd_set exceptfds; struct timeval timeo; const char* const progname = ubasename(av[0]); unsigned logopts = LOG_CONS|LOG_PID; int logmask = LOG_UPTO(LOG_NOTICE); unsigned long maxProductSize = DEFAULT_MAX_PRODUCT_SIZE; /* * Setup default logging before anything else. */ logfd = openulog(progname, logopts, LOG_LDM, logpath); (void) setulogmask(logmask); feedtype = whatami(av[0]); { extern int optind; extern int opterr; extern char *optarg; int ch; opterr = 0; /* stops getopt() from printing to stderr */ usePil = 1; useNex = 1; pqpath = getQueuePath(); while ((ch = getopt(ac, av, ":vxcni5Nl:b:p:P:T:q:r:f:s:")) != EOF) switch (ch) { case 'v': logmask |= LOG_MASK(LOG_INFO); (void) setulogmask(logmask); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); (void) setulogmask(logmask); break; case 'c': chkflag = CHK_CHECK; break; case 'n': chkflag = CHK_DONT; break; case 'i': usePil = 0; break; case 'N': useNex = 0; break; case '5': skipLeadingCtlString = 0; break; case 'l': { logpath = optarg; if (strcmp(logpath, "-") == 0) { logopts = LOG_NOTIME; } else { logopts = LOG_CONS | LOG_PID; (void) fclose(stderr); } logfd = openulog(progname, logopts, LOG_LDM, logpath); break; } case 'b': baud = optarg; break; case 'p': parity = optarg; break; #if NET case 'P': *((int *)&server_port) = atoi(optarg); /* cast away const */ if(server_port <= 0 || server_port > 65536) { LOG_ADD1("Invalid server port: \"%s\"", optarg); log_log(LOG_ERR); usage(progname); } break; case 'T': reset_secs = atoi(optarg); if(reset_secs < 0) { LOG_ADD1("Invalid timeout: \"%s\"", optarg); usage(progname); } break; #endif /* NET */ case 's': { unsigned long size; int nbytes; if (sscanf(optarg, "%lu %n", &size, &nbytes) != 1 || optarg[nbytes] != 0 || 1 > size) { LOG_ADD1("Invalid maximum data-product size: \"%s\"", optarg); log_log(LOG_ERR); usage(progname); } maxProductSize = size; break; } case 'q': pqpath = optarg; break; case 'r': rawfname = optarg; break; case 'f': { feedtypet type; type = atofeedtypet(optarg); if(type != NONE) { feedtype = type; if(!parity && !baud) setFeedDefaults(type); } } break; case '?': { LOG_ADD1("Unknown option: \"%c\"", optopt); usage(progname); break; } case ':': /*FALLTHROUGH*/ default: LOG_ADD1("Missing argument for option: \"%c\"", optopt); usage(progname); break; } /* last arg, feedfname, is required */ if(ac - optind != 1) { LOG_ADD1("Wrong number of operands: %d", ac - optind); usage(progname); } (void)strncat(feedfname, av[optind], sizeof(feedfname)-6); } unotice("Starting Up"); udebug(PACKAGE_VERSION); if(logpath == NULL || !(*logpath == '-' && logpath[1] == 0)) { if (logfd < 0) { uerror("logfd < 0"); return 1; } setbuf(fdopen(logfd, "a"), NULL); } /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); return 1; } /* * set up signal handlers */ set_sigactions(); /* * open the product queue, unless we were invoked as "feedtest" */ if(strcmp(progname, "feedtest") != 0) { if((ready = pq_open(pqpath, PQ_DEFAULT, &pq))) { if (PQ_CORRUPT == ready) { uerror("The product-queue \"%s\" is inconsistent\n", pqpath); } else { uerror("pq_open: \"%s\" failed: %s", pqpath, strerror(ready)); } return 1; } } /* * who am i, anyway */ (void) strncpy(myname, ghostname(), sizeof(myname)); myname[sizeof(myname)-1] = 0; /* * open the feed */ if(!(*feedfname == '-' && feedfname[1] == 0) && logfd != 0) (void) close(0); if(open_feed(feedfname, &ifd, maxProductSize) != ENOERR) return 1; if(usePil == 1) { if ((feedtype & DDS)||(feedtype & PPS)||(feedtype & IDS)|| (feedtype & HRS)) { usePil = 1; uinfo("Creating AFOS-like pil tags\0"); } else { usePil = 0; } } if (feedtype & HDS) { if(chkflag == CHK_CHECK || (isatty(ifd) && chkflag != CHK_DONT)) setTheScanner(scan_wmo_binary_crc); else setTheScanner(scan_wmo_binary); } else if (feedtype == ( DDPLUS | IDS ) ) { /* this is the combined NOAAPORT fos-alike. We know these have the 4 byte start and end sequences. Using the binary scanner ensures that we don't stop on an arbitray embedded CTRL-C */ unotice("Note: Using the wmo_binary scanner for SDI ingest\0"); setTheScanner (scan_wmo_binary); } else if (feedtype & (NMC2 | NMC3)) { setTheScanner(scan_wmo_binary); } else if (feedtype == AFOS) { prod_stats = afos_stats; setTheScanner(scan_afos); } else if (feedtype == FAA604) { prod_stats = faa604_stats; if(chkflag == CHK_CHECK || (isatty(ifd) && chkflag != CHK_DONT && parity != NULL && *parity != 'n') ) { setTheScanner(scan_faa604_parity); } else { setTheScanner(scan_faa604); } } else { if(chkflag == CHK_CHECK || (isatty(ifd) && chkflag != CHK_DONT && parity != NULL && *parity != 'n') ) { setTheScanner(scan_wmo_parity); } else { setTheScanner(scan_wmo); } } /* * Allocate an MD5 context */ md5ctxp = new_MD5_CTX(); if(md5ctxp == NULL) { serror("new_md5_CTX failed"); return 1; } /* * Main Loop */ idle = 0; while(exitIfDone(0)) { #if NET if (INPUT_IS_SOCKET) { if (port_error) { /* * lost connection => close */ if (ifd >= 0) { if(feed_close) (*feed_close)(ifd); ifd = -1; } port_error = 0; sleep (2); /* allow things to settle down */ continue; } } #endif if(stats_req) { unotice("Statistics Request"); if(pq != NULL) { off_t highwater = 0; size_t maxregions = 0; (void) pq_highwater(pq, &highwater, &maxregions); unotice(" Queue usage (bytes):%8ld", (long)highwater); unotice(" (nregions):%8ld", (long)maxregions); } unotice(" Idle: %8lu seconds", idle); #if NET if (INPUT_IS_SOCKET) { unotice(" Timeout: %8d", reset_secs); } #endif unotice("%21s: %s", "Status", (ifd < 0) ? "Not connected or input not open." : "Connected."); (*prod_stats)(); (*feed_stats)(); stats_req = 0; } #if NET if (INPUT_IS_SOCKET) { if (ifd < 0) { /* Attempt reconnect */ static int retries = 0; if (retries > MAX_RETRIES) { uerror ("maximum retry attempts %d, aborting", MAX_RETRIES); done = !0; continue; } /* Try to reopen on tcp read errors */ unotice("Trying to re-open connection on port %d", server_port); ++retries; if(open_feed(feedfname, &ifd, maxProductSize) != ENOERR) { unotice ("sleeping %d seconds before retry %d", retries * RETRY_DELAY, retries+1); sleep (retries * RETRY_DELAY); continue; } retries = 0; } } #endif /* NET */ timeo.tv_sec = 3; timeo.tv_usec = 0; FD_ZERO(&readfds); FD_ZERO(&exceptfds); FD_SET(ifd, &readfds); FD_SET(ifd, &exceptfds); width = ifd + 1; ready = select(width, &readfds, 0, &exceptfds, &timeo); if(ready < 0 ) { /* handle EINTR as a special case */ if(errno == EINTR) { errno = 0; continue; } serror("select"); return 1; } /* else */ #if 0 if (FD_ISSET(ifd, &exceptfds)) { uerror("Exception on input fd %d, select returned %d", ifd, ready); } #endif if(ready > 0) { /* do some work */ if(FD_ISSET(ifd, &readfds) || FD_ISSET(ifd, &exceptfds)) { idle = 0; if(feedTheXbuf(ifd) != ENOERR) { #if NET if (INPUT_IS_SOCKET) { port_error = !0; continue; } /* else */ #endif /* NET */ done = !0; } FD_CLR(ifd, &readfds); FD_CLR(ifd, &exceptfds); } else { uerror("select returned %d but ifd not set", ready); idle += timeo.tv_sec; } } else /* ready == 0 */ { idle += timeo.tv_sec; #if NET if (INPUT_IS_SOCKET) { /* VOODOO * This is necessary to stimulate * 'Connection reset by peer' * when the Portmaster goes down and comes * back up. */ static char zed[1] = {0}; if(write(ifd, zed, sizeof(zed)) < 0) { port_error = !0; continue; } } #endif } #if NET if (INPUT_IS_SOCKET) { if ((reset_secs > 0) && (idle >= reset_secs)) { unotice("Idle for %ld seconds, reconnecting", idle); /* force reconnect */ port_error = !0; idle = 0; continue; } } #endif /* NET */ (void) scanTheXbuf(); } return 0; }
static pid_t reap( pid_t pid, int options) { pid_t wpid = 0; int status = 0; #ifdef HAVE_WAITPID wpid = waitpid(pid, &status, options); #else if(options == 0) { wpid = wait(&status); } /* customize here for older systems, use wait3 or whatever */ #endif if (wpid == -1) { if (!(errno == ECHILD && pid == -1)) /* Only complain when relevant */ serror("waitpid"); return -1; } /* else */ if (wpid != 0) { char command[512]; #if !defined(WIFSIGNALED) && !defined(WIFEXITED) #error "Can't decode wait status" #endif #if defined(WIFSTOPPED) if (WIFSTOPPED(status)) { int n = exec_getCommandLine(wpid, command, sizeof(command)); if (n == -1) { log_add("Couldn't get command-line of EXEC process " "%ld", wpid); log_log(LOG_ERR); } unotice( n <= 0 ? "child %d stopped by signal %d" : "child %d stopped by signal %d: %*s", wpid, WSTOPSIG(status), n, command); } else #endif /*WIFSTOPPED*/ #if defined(WIFSIGNALED) if (WIFSIGNALED(status)) { int n = exec_getCommandLine(wpid, command, sizeof(command)); cps_remove(wpid); /* upstream LDM processes */ exec_free(wpid); /* EXEC processes */ if (n == -1) { log_add("Couldn't get command-line of EXEC process " "%ld", wpid); log_log(LOG_ERR); } unotice( n <= 0 ? "child %d terminated by signal %d" : "child %d terminated by signal %d: %*s", wpid, WTERMSIG(status), n, command); /* DEBUG */ switch (WTERMSIG(status)) { /* * If a child dumped core, * shut everything down. */ case SIGQUIT: case SIGILL: case SIGTRAP: /* ??? */ case SIGABRT: #if defined(SIGEMT) case SIGEMT: /* ??? */ #endif case SIGFPE: /* ??? */ case SIGBUS: case SIGSEGV: #if defined(SIGSYS) case SIGSYS: /* ??? */ #endif #ifdef SIGXCPU case SIGXCPU: #endif #ifdef SIGXFSZ case SIGXFSZ: #endif unotice("Killing (SIGTERM) process group"); (void) kill(0, SIGTERM); break; } } else #endif /*WIFSIGNALED*/ #if defined(WIFEXITED) if (WIFEXITED(status)) { int exitStatus = WEXITSTATUS(status); int n = exec_getCommandLine(wpid, command, sizeof(command)); cps_remove(wpid); /* upstream LDM processes */ exec_free(wpid); /* EXEC processes */ if (n == -1) { log_add("Couldn't get command-line of EXEC process " "%ld", wpid); log_log(LOG_ERR); } log_start( n <= 0 ? "child %d exited with status %d" : "child %d exited with status %d: %*s", wpid, exitStatus, n, command); log_log(exitStatus ? LOG_NOTICE : LOG_INFO); } #endif /*WIFEXITED*/ } return wpid; }
hiya_reply_t* hiya_6_svc( prod_class_t *offered, struct svc_req *rqstp) { const char* const pqfname = getQueuePath(); static hiya_reply_t reply; SVCXPRT * const xprt = rqstp->rq_xprt; struct sockaddr_in *upAddr = (struct sockaddr_in*) svc_getcaller(xprt); const char *upName = hostbyaddr(upAddr); int error; int isPrimary; unsigned int maxHereis; static prod_class_t *accept; /* * Open the product-queue for writing. It will be closed by cleanup() * during process termination. */ if (pq) { (void) pq_close(pq); pq = NULL; } error = pq_open(pqfname, PQ_DEFAULT, &pq); if (error) { err_log_and_free(ERR_NEW2(error, NULL, "Couldn't open product-queue \"%s\" for writing: %s", pqfname, PQ_CORRUPT == error ? "The product-queue is inconsistent" : strerror(error)), ERR_FAILURE); svcerr_systemerr(xprt); svc_destroy(xprt); exit(error); } /* else */ error = down6_init(upName, upAddr, pqfname, pq); if (error) { uerror("Couldn't initialize downstream LDM"); svcerr_systemerr(xprt); svc_destroy(xprt); exit(error); } else { uinfo("Downstream LDM initialized"); } /* * The previous "accept" is freed here -- rather than freeing the * soon-to-be-allocated "accept" at the end of its block -- because it can * be used in the reply. */ if (accept) { free_prod_class(accept); /* NULL safe */ accept = NULL; } error = lcf_reduceToAcceptable(upName, inet_ntoa(upAddr->sin_addr), offered, &accept, &isPrimary); maxHereis = isPrimary ? UINT_MAX : 0; if (error) { serror("Couldn't validate HIYA"); svcerr_systemerr(xprt); svc_destroy(xprt); exit(error); } else { if (ulogIsDebug()) udebug("intersection: %s", s_prod_class(NULL, 0, accept)); if (accept->psa.psa_len == 0) { uwarn("Empty intersection of HIYA offer from %s (%s) and ACCEPT " "entries", upName, s_prod_class(NULL, 0, offered)); svcerr_weakauth(xprt); svc_destroy(xprt); exit(0); } else { error = down6_set_prod_class(accept); if (error) { if (DOWN6_SYSTEM_ERROR == error) { serror("Couldn't set product class: %s", s_prod_class(NULL, 0, accept)); } else { uerror("Couldn't set product class: %s", s_prod_class(NULL, 0, accept)); } svcerr_systemerr(xprt); svc_destroy(xprt); exit(EXIT_FAILURE); } /* else */ if (clss_eq(offered, accept)) { unotice("hiya6: %s", s_prod_class(NULL, 0, offered)); reply.code = OK; reply.hiya_reply_t_u.max_hereis = maxHereis; } else { if (ulogIsVerbose()) { char off[512]; char acc[512]; (void) s_prod_class(off, sizeof(off), offered), (void) s_prod_class( acc, sizeof(acc), accept); uinfo("hiya6: RECLASS: %s -> %s", off, acc); } reply.code = RECLASS; reply.hiya_reply_t_u.feedPar.prod_class = accept; reply.hiya_reply_t_u.feedPar.max_hereis = maxHereis; } } /* product-intersection != empty set */ } /* successful acl_check_hiya() */ return &reply; }
/* 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; if(ulogIsDebug()) udebug("%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); if(ulogIsDebug()){ udebug("%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 */ if(ulogIsDebug()){ udebug("%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){ uerror("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){ uerror("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){ uerror("Fail fcntl(F_SETFL) %s pipe \n",DEFAULT_RETRANSMIT_PIPENAME); } unotice(" OK open pipe[%d] for %s\n", global_retransmitpipe_fd,DEFAULT_RETRANSMIT_PIPENAME); } if(ulogIsDebug()) udebug("%s Exiting init retrans_table base=0x%lx\n", FNAME,(unsigned long) pl_prod_retrans_table); return(0); } /* end init_retrans */
int log_prod_end(char *end_msg, long in_orig_prod_seqno, long in_prod_seqno, int in_prod_blkno, int in_prod_code, int in_prod_bytes, long in_prod_start_time) { static const char FNAME[40+1]="log_prod_end"; #define MAX_WMO_HDR_NAME_LEN 64 /* max wmo hdr name len */ char prod_log_buff[256]; /* prod log buffer */ time_t now_time; /* current time */ struct tm *tmtime; /* time */ int ii; /* loop counter */ long log_ratio; /* log ratio of compr to total */ static long log_eop_count; /* counter to track number of log EOP entries */ #define LOG_DH_PROC_STATUS_CNT_INTERVAL 50 /* log status every 50 entries */ log_eop_count++; prod_log_buff[0] = '\0'; time(&now_time); tmtime = (struct tm *)gmtime(&now_time); /* time */ sprintf(prod_log_buff, "%s %s", "END", get_date_time(tmtime, global_time_zone)); if(in_orig_prod_seqno != 0) { /* Assume have an original SBN prod seqno */ sprintf(prod_log_buff, "%s #%ld/%d orig(#%ld)", prod_log_buff, in_prod_seqno, in_prod_blkno, in_orig_prod_seqno); } else { sprintf(prod_log_buff, "%s #%ld/%d", prod_log_buff, in_prod_seqno, in_prod_blkno); } sprintf(prod_log_buff, "%s bytes(%d)", prod_log_buff, in_prod_bytes); sprintf(prod_log_buff, "%s c(%d)", prod_log_buff, in_prod_code); if((now_time - in_prod_start_time) > 0){ sprintf(prod_log_buff, "%s +%lds", prod_log_buff, (now_time - in_prod_start_time)); } if(end_msg[0] != '\0') { sprintf(prod_log_buff, "%s %s", prod_log_buff, end_msg); } /* Finally do the brief product logging */ unotice("%s \n", prod_log_buff); return(0); } /* end acqpro_log_prod_end */
static int my_hiya_6(CLIENT *clnt, prod_class_t **clsspp) { static hiya_reply_t* reply; int error; reply = hiya_6(*clsspp, clnt); if (NULL == reply) { uerror("%s: HIYA_6 failure: %s", remote, clnt_errmsg(clnt)); error = ECONNABORTED; } else { switch (reply->code) { case OK: max_hereis = reply->hiya_reply_t_u.max_hereis; error = 0; break; case SHUTTING_DOWN: uerror("%s: LDM shutting down", remote); error = ECONNABORTED; break; case BADPATTERN: uerror("%s: Bad product-class pattern", remote); error = ECONNABORTED; break; case DONT_SEND: uerror("%s: LDM says don't send", remote); error = ECONNABORTED; break; case RESEND: uerror("%s: LDM says resend (ain't gonna happen)", remote); error = ECONNABORTED; break; case RESTART: uerror("%s: LDM says restart (ain't gonna happen)", remote); error = ECONNABORTED; break; case REDIRECT: uerror("%s: LDM says redirect (ain't gonna happen)", remote); error = ECONNABORTED; break; case RECLASS: *clsspp = reply->hiya_reply_t_u.feedPar.prod_class; max_hereis = reply->hiya_reply_t_u.feedPar.max_hereis; clss_regcomp(*clsspp); /* N.B. we use the downstream patterns */ unotice("%s: reclass: %s", remote, s_prod_class(NULL, 0, *clsspp)); error = 0; break; } if (!error) udebug("max_hereis = %u", max_hereis); } return error; }
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) { unotice("%s ignore retrans_ck\n", FNAME); return(match_value); } if(p_acqtable->proc_orig_prod_seqno_last != 0) { if (ulogIsDebug ())/* Debug only */ { udebug("%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++; } if (ulogIsDebug ()){ udebug("%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(ulogIsDebug()) { if(match_value & PROD_NODUPLICATE) { udebug(" %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 { udebug("%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 readccb(char *buf,ccb_struct *ccb, psh_struct *psh, int blen) { int iret=0; unsigned char b1,b2; char wmohead[256]; int wmolen, metaoff=-1; char redbook_title[45]; char wmometa[256]; redbook_title[0] = '\0'; wmometa[0] = '\0'; b1 = (unsigned char)buf[0]; b2 = (unsigned char)buf[1]; ccb->b1 = b1; ccb->len = 2 * (int)(((b1 & 63) << 8) + b2); if ( ccb->len > blen ) /* A rouge product missing its CCB, reported to NWS DM 3/10/05 by Chiz */ { uerror ("invalid ccb length = %d %d %d, blen %d\n",ccb->len,b1,b2,blen); /* try a failsafe header, otherwise use our own! */ wmolen = 0; while ( ( (int)buf[wmolen] >= 32) && ( wmolen < 256 ) ) wmolen++; if ( wmolen > 0 ) strncat(psh->pname,buf,wmolen); else sprintf(psh->pname,"Unidentifiable product\0"); ccb->len = 0; return(-1); } b1 = (unsigned char)buf[10]; b2 = (unsigned char)buf[11]; psh->ccbmode = b1; psh->ccbsubmode = b2; udebug("ccb mode %d ccb submode %d\0",psh->ccbmode,psh->ccbsubmode); psh->hasccb = 1; b1 = (unsigned char)buf[12]; b2 = (unsigned char)buf[13]; ccb->user1 = b1; ccb->user2 = b1; udebug("ccb user1 %d ccb user2 %d\0",ccb->user1,ccb->user2); psh->ccbdtype[0] = '\0'; /* Initialize ccbdtype...eventually used to identify data type */ /* see if this looks like a WMO header, if so canonicalize */ if(wmo_header(buf+ccb->len,blen - ccb->len,wmohead,wmometa,&metaoff)==0) { if(strlen(wmohead) > 0) { strcat(psh->pname,wmohead); if (metaoff > 0) psh->metaoff = metaoff; } else { wmolen = 0; while ( ( (int)buf[wmolen + ccb->len] >= 32) && ( wmolen < 256 ) ) wmolen++; strncat(psh->pname,buf+ccb->len,wmolen); } } else { wmolen = 0; while ( ( (int)buf[wmolen + ccb->len] >= 32) && ( wmolen < 256 ) ) wmolen++; if ( wmolen > 0 ) strncat(psh->pname,buf+ccb->len,wmolen); else sprintf(psh->pname,"Unidentifiable product\0"); unotice("Non-wmo product type %s ccbmode %d ccbsubmode %d\0", psh->pname, psh->ccbmode, psh->ccbsubmode); } /* for now, since NEXRAD is not identified as a separate PTYPE, use WMO header check */ if((psh->ccbmode == 2)&&(psh->ccbsubmode == 0)) { if((memcmp(buf+ccb->len,"SDUS5",5) == 0)|| (memcmp(buf+ccb->len,"SDUS2",5) == 0)|| (memcmp(buf+ccb->len,"SDUS3",5) == 0)|| (memcmp(buf+ccb->len,"SDUS7",5) == 0)|| (memcmp(buf+ccb->len,"SDUS8",5) == 0) ) { /* uncompressed nids check */ if(ccb->user1 != 'F') sprintf(psh->ccbdtype,"nids/\0"); psh->pcat = 99; } } /* unfortunately, NWS isn't using CCB mode for all product types else if((psh->pcat == 4)&&(psh->ccbmode == 2)&&(psh->ccbsubmode == 1)) sprintf(psh->ccbdtype,"grib/\0"); else if(psh->pcat == 5) sprintf(psh->ccbdtype,"bufr/\0"); */ else if (psh->pcat == 2) { /* see if this is recognizeable as a redbook graphic */ redbook_header(buf+ccb->len,blen - ccb->len, redbook_title); if(strlen(redbook_title) > 0) sprintf(psh->ccbdtype,"redbook %d_%d/\0", ccb->user1, ccb->user2); else sprintf(psh->ccbdtype,"graph %d_%d/\0", ccb->user1, ccb->user2); } /* create metadata */ sprintf(psh->metadata," !\0"); if ( psh->ccbdtype[0] != '\0') strcat ( psh->metadata, psh->ccbdtype); if ( redbook_title[0] != '\0' ) strcat( psh->metadata, redbook_title); if ( wmometa[0] != '\0' ) strcat( psh->metadata, wmometa); if ( psh->metadata[2] == '\0' ) psh->metadata[0] = '\0'; /* restore meta data to PROD NAME strcat(psh->pname,psh->metadata); */ return(iret); }
static void cleanup(void) { unotice("Exiting"); (void) closeulog(); }
/* * Returns: * 0 Success. Write-count of product-queue is zero. * 1 System failure. See error-message. * 2 Product-queue doesn't support a writer-counter. Not possible * if "-F" option used. * 3 Write-count of product-queue is greater than zero. Not possible * if "-F" option used. * 4 The product-queue is internally inconsistent. */ int main(int ac, char *av[]) { const char *progname = ubasename(av[0]); char *logfname; int status = 0; int logoptions = (LOG_CONS|LOG_PID) ; unsigned write_count; int force = 0; logfname = ""; if(isatty(fileno(stderr))) { /* set interactive defaults */ logfname = "-" ; logoptions = 0 ; } { extern int opterr; extern char *optarg; int ch; int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) | LOG_MASK(LOG_NOTICE)); opterr = 1; pqfname = getQueuePath(); while ((ch = getopt(ac, av, "Fvxl:q:")) != EOF) switch (ch) { case 'F': force = 1; break; case 'v': logmask |= LOG_MASK(LOG_INFO); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': logfname = optarg; break; case 'q': pqfname = optarg; break; case '?': usage(progname); break; } (void) setulogmask(logmask); } /* * Set up error logging. */ (void) openulog(progname, logoptions, LOG_LDM, logfname); unotice("Starting Up (%d)", getpgrp()); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); return 1; } /* * set up signal handlers */ set_sigactions(); if (force) { /* * Add writer-counter capability to the file, if necessary, and set * the writer-counter to zero. */ status = pq_clear_write_count(pqfname); if (status) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent", pqfname); return 4; } else { uerror("pq_clear_write_count() failure: %s: %s", pqfname, strerror(status)); return 1; } } write_count = 0; } else { /* * Get the writer-counter of the product-queue. */ status = pq_get_write_count(pqfname, &write_count); if (status) { if (ENOSYS == status) { uerror("Product-queue \"%s\" doesn't have a writer-counter", pqfname); return 2; } else if (PQ_CORRUPT == status) { uerror("Product-queue \"%s\" is inconsistent", pqfname); return 4; } else { uerror("pq_get_write_count() failure: %s: %s", pqfname, strerror(status)); return 1; } } } uinfo("The writer-counter of the product-queue is %u", write_count); return write_count == 0 ? 0 : 3; }
int main(int ac, char *av[]) { const char* pqfname = getQueuePath(); const char *opqfname = getSurfQueuePath(); const char *progname = ubasename(av[0]); char *logfname; prod_class_t clss; prod_spec spec; int status = 0; unsigned interval = DEFAULT_INTERVAL; int logoptions = (LOG_CONS|LOG_PID); double age = DEFAULT_AGE; /* these are containers for the pqact args */ char *argv[16]; int argc = 0; int toffset = TOFFSET_NONE; logfname = ""; if(set_timestamp(&clss.from) != ENOERR) /* corrected by toffset below */ { int errnum = errno; fprintf(stderr, "Couldn't set timestamp: %s", strerror(errnum)); exit(1); } clss.to = TS_ENDT; clss.psa.psa_len = 1; clss.psa.psa_val = &spec; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = DEFAULT_PATTERN; memset(argv, 0, sizeof(argv)); argv[0] = "pqact"; argc++; { extern int optind; extern int opterr; extern char *optarg; int ch; int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) | LOG_MASK(LOG_NOTICE)); int fterr; const char *conffilename = getPqsurfConfigPath(); const char *datadir = getPqsurfDataDirPath(); usePil = 1; opterr = 1; while ((ch = getopt(ac, av, "vxl:d:f:p:q:Q:o:i:a:t:")) != EOF) switch (ch) { case 'v': argv[argc++] = "-v"; logmask |= LOG_MASK(LOG_INFO); break; case 'x': argv[argc++] = "-x"; logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': argv[argc++] = "-l"; argv[argc++] = optarg; logfname = optarg; break; case 'd': datadir = optarg; break; case 'f': fterr = strfeedtypet(optarg, &spec.feedtype); if(fterr != FEEDTYPE_OK) { fprintf(stderr, "%s: %s: \"%s\"\n", av[0], strfeederr(fterr), optarg); usage(progname); } argv[argc++] = "-f"; argv[argc++] = optarg; break; case 'p': spec.pattern = optarg; /* compiled below */ break; case 'q': pqfname = optarg; break; case 'Q': opqfname = optarg; break; case 'o': toffset = atoi(optarg); if(toffset == 0 && *optarg != '0') { fprintf(stderr, "%s: invalid offset %s\n", av[0], optarg); usage(av[0]); } argv[argc++] = "-o"; argv[argc++] = optarg; break; case 'i': interval = atoi(optarg); if(interval == 0 && *optarg != '0') { fprintf(stderr, "%s: invalid interval \"%s\"\n", av[0], optarg); usage(av[0]); } /* N.B. -i just used for input queue. */ break; case 'a': age = atof(optarg); if(age < 0.) { (void) fprintf(stderr, "age (%s) must be non negative\n", optarg); usage(av[0]); } break; case 't': /* pipe_timeo */ argv[argc++] = "-t"; argv[argc++] = optarg; break; case '?': usage(progname); break; } (void) setulogmask(logmask); if (re_isPathological(spec.pattern)) { fprintf(stderr, "Adjusting pathological regular-expression: " "\"%s\"\n", spec.pattern); re_vetSpec(spec.pattern); } status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB); if(status != 0) { fprintf(stderr, "Bad regular expression \"%s\"\n", spec.pattern); usage(av[0]); } if(ac - optind == 1) conffilename = av[optind]; argv[argc++] = "-d"; argv[argc++] = (char*)datadir; argv[argc++] = "-q"; argv[argc++] = (char*)opqfname; argv[argc++] = (char*)conffilename; age *= 3600.; } if(toffset != TOFFSET_NONE) { clss.from.tv_sec -= toffset; } else { clss.from.tv_sec -= (age - interval); } /* * Set up error logging. * N.B. log ident is the remote */ (void) openulog(progname, logoptions, LOG_LDM, logfname); unotice("Starting Up (%d)", getpgrp()); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Open the output product queue */ status = pq_open(opqfname, PQ_DEFAULT, &opq); if(status) { if (PQ_CORRUPT == status) { uerror("The output product-queue \"%s\" is inconsistent\n", opqfname); } else { uerror("pq_open failed: %s: %s\n", opqfname, strerror(status)); } exit(1); } act_pid = run_child(argc, argv); if(act_pid == (pid_t)-1) exit(1); /* * Open the input product queue */ status = pq_open(pqfname, PQ_READONLY, &pq); if(status) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent\n", pqfname); } else { uerror("pq_open failed: %s: %s\n", pqfname, strerror(status)); } exit(1); } if(toffset == TOFFSET_NONE) { /* Jump to the end of the queue */ timestampt sav; sav = clss.from; clss.from = TS_ZERO; (void) pq_last(pq, &clss, NULL); clss.from = sav; } else { pq_cset(pq, &clss.from); } if(ulogIsVerbose()) { char buf[1984]; uinfo("%s", s_prod_class(buf, sizeof(buf), &clss)); } while(exitIfDone(0)) { if(stats_req) { dump_stats(); stats_req = 0; } status = pq_sequence(pq, TV_GT, &clss, split_prod, NULL); switch(status) { case 0: /* no error */ continue; /* N.B., other cases sleep */ case PQUEUE_END: udebug("surf: End of Queue"); break; case EAGAIN: case EACCES: udebug("Hit a lock"); break; default: uerror("pq_sequence failed: %s (errno = %d)", strerror(status), status); exit(1); break; } if(interval == 0) { break; } (void) expire(opq, interval, age); pq_suspend(interval); (void) reap_act(WNOHANG); } /* * TODO: how can we determine that pqact has finished * the work in opq? */ sleep(5); exit(0); }
void gb2_param ( char *wmovartbl, char *lclvartbl, Gribmsg *cmsg, char *param, int *scal, float *msng, int *iret ) /************************************************************************ * gb2_param * * * * This routine gets the parameter values * * from the GRIB2 PDS, and obtains the GEMPAK parameter information * * from the appropriate GRIB2 parameter table. * * * * If either wmovartbl or lclvartbl are NULL, the default tables are * * read. * * * * gb2_param ( wmovartbl, lclvartbl, cmsg, param, scal, msng, iret ) * * * * Input parameters: * * *wmovartbl char WMO parameter table * * *lclvartbl char Local parameter table * * *cmsg struct Gribmsg GRIB2 message structure * * * * Output parameters: * * *param char 12 character parameter name. * * *scal int scale factor associated with * * current parameter * * *msng float missing value associated with * * current parameter * * *iret int return code * * 1 = No gempak param name * * defined for this grid * ** * * Log: * * S. Gilbert/NCEP 12/04 * * S. Gilbert/NCEP 10/05 Fix null character location * * S. Gilbert/NCEP 10/05 Use new routines to read tables * ***********************************************************************/ { int ier, disc, cat, id, pdtn, iver, lclver, len; const char* filename; G2Vinfo g2var; G2vars_t *g2vartbl; /*---------------------------------------------------------------------*/ *iret = 0; strncpy( param, "UNKNOWN", 12); /* * Get Parameter information from Parameter table(s). */ iver=cmsg->gfld->idsect[2]; lclver=cmsg->gfld->idsect[3]; disc=cmsg->gfld->discipline; cat=cmsg->gfld->ipdtmpl[0]; id=cmsg->gfld->ipdtmpl[1]; pdtn=cmsg->gfld->ipdtnum; #if 0 /* * Some GRIB2 messages from NCEP *don't* have the Master Table Version * number set to 255 (which is wrong). Consequently, the following hack sets * things right. */ if (iver != 255 && strcmp(cmsg->origcntr, "wmo")) { unotice("Setting Master Table Version to 255 for non-WMO originating center: " "iver=%d, disc=%d, cat=%d, id=%d, pdtn=%d, " "center=%.*s, lclver=%d", iver, disc, cat, id, pdtn, (int)sizeof(cmsg->origcntr), cmsg->origcntr, lclver); cmsg->gfld->idsect[2] = iver = 255; } #endif if ((iver != 255) && ((disc < 192 || disc == 255 ) && (cat < 192 || cat == 255 ) && (id < 192 || id == 255 ) && (pdtn < 32768 || pdtn == 65535))) { /* * Get WMO Parameter table. */ gb2_gtvartbl(wmovartbl, "wmo", iver, &g2vartbl, &filename, &ier); } else { /* * Get Local Parameter table. */ gb2_gtvartbl(lclvartbl, cmsg->origcntr, lclver, &g2vartbl, &filename, &ier); } if (ier != 0) { unotice("Couldn't get parameter table: iver=%d, disc=%d, cat=%d, " "id=%d, pdtn=%d, center=%.*s, lclver=%d", iver, disc, cat, id, pdtn, (int)sizeof(cmsg->origcntr), cmsg->origcntr, lclver); *iret = 1; return; } /* * Get parameter information from table. */ gb2_skvar(disc, cat, id, pdtn, g2vartbl, &g2var, &ier); if (ier != 0) { unotice("Couldn't get parameter info: iver=%d, disc=%d, cat=%d, id=%d, " "pdtn=%d, center=%.*s, lclver=%d, file=%s", iver, disc, cat, id, pdtn, (int)sizeof(cmsg->origcntr), cmsg->origcntr, lclver, filename); *iret = 1; return; } /* * Insert time range period in parameter abbreviation, * if necessary. */ gb2_ctim ( cmsg->tmrange, g2var.gemname ); /* * Adjust ensemble information in parameter abbreviation, * if necessary. * NOT DESIRED AT THIS TIME gb2_ens ( cmsg->gfld, g2var.gemname ); */ /* * Adjust probability information in parameter abbreviation, * if necessary. */ gb2_prob ( cmsg->gfld, g2var.gemname ); /* * Add generating process information in parameter abbreviation * if necessary. */ gb2_proc ( cmsg->gfld, g2var.gemname ); len = strlen(g2var.gemname); strncpy( param, g2var.gemname, 12); if ( len > 12 ) param[12]='\0'; if ( len < 12 ) { /* pad gempak parameter name with blanks */ char blanks[13]=" "; strncat( param, blanks, 12-len ); } *scal = g2var.scale; *msng = g2var.missing; }
int main(int ac, char *av[]) { char *logfname = 0; unsigned timeo = DEFAULT_TIMEO; unsigned interval = DEFAULT_TIMEO; unsigned TotalTimeo = DEFAULT_TOTALTIMEO; prod_spec spec; int status; prod_class_t *clssp; unsigned port = 0; if(set_timestamp(&clss.from) != 0) { fprintf(stderr, "Couldn't set timestamp\n"); exit(1); } clss.to = TS_ENDT; clss.psa.psa_len = 1; clss.psa.psa_val = &spec; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = DEFAULT_PATTERN; { /* Begin getopt block */ extern int optind; extern int opterr; extern char *optarg; int ch; int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) | LOG_MASK(LOG_NOTICE)); int fterr; opterr = 1; while ((ch = getopt(ac, av, "vxl:f:o:t:h:P:p:T:")) != EOF) switch (ch) { case 'v': logmask |= LOG_MASK(LOG_INFO); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': logfname = optarg; break; case 'h': remote = optarg; break; case 'P': { char* suffix = ""; long p; errno = 0; p = strtol(optarg, &suffix, 0); if (0 != errno || 0 != *suffix || 0 >= p || 0xffff < p) { (void)fprintf(stderr, "%s: invalid port %s\n", av[0], optarg); usage(av[0]); } else { port = p; } break; } case 'p': spec.pattern = optarg; /* compiled below */ break; case 'f': fterr = strfeedtypet(optarg, &spec.feedtype); if(fterr != FEEDTYPE_OK) { fprintf(stderr, "Bad feedtype \"%s\", %s\n", optarg, strfeederr(fterr)); usage(av[0]); } break; case 'o': clss.from.tv_sec -= atoi(optarg); break; case 'T': TotalTimeo = atoi(optarg); if(TotalTimeo == 0) { fprintf(stderr, "%s: invalid TotalTimeo %s", av[0], optarg); usage(av[0]); } break; case 't': timeo = (unsigned)atoi(optarg); if(timeo == 0 || timeo > 32767) { fprintf(stderr, "%s: invalid timeout %s", av[0], optarg); usage(av[0]); } break; case '?': usage(av[0]); break; } if(ac - optind > 0) usage(av[0]); if (re_isPathological(spec.pattern)) { fprintf(stderr, "Adjusting pathological regular-expression: " "\"%s\"\n", spec.pattern); re_vetSpec(spec.pattern); } status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB); if(status != 0) { fprintf(stderr, "Bad regular expression \"%s\"\n", spec.pattern); usage(av[0]); } (void) setulogmask(logmask); if(TotalTimeo < timeo) { fprintf(stderr, "TotalTimeo %u < timeo %u\n", TotalTimeo, timeo); usage(av[0]); } } /* End getopt block */ /* * initialize logger */ (void) openulog(ubasename(av[0]), (LOG_CONS|LOG_PID), LOG_LDM, logfname); unotice("Starting Up: %s: %s", remote, s_prod_class(NULL, 0, &clss)); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Try forever. */ while (exitIfDone(0)) { clssp = &clss; status = forn5(NOTIFYME, remote, &clssp, timeo, TotalTimeo, notifymeprog_5); (void)exitIfDone(0); switch(status) { /* problems with remote, retry */ case ECONNABORTED: case ECONNRESET: case ETIMEDOUT: case ECONNREFUSED: sleep(interval); break; case 0: /* assert(done); */ break; default: /* some wierd error */ done = 1; exit(1); } } exit(0); /*NOTREACHED*/ }
/** * Notifies the LDM of the class of data-products that will be sent via LDM-6 * protocols. * * Arguments: * proxy Pointer to the LDM proxy data-structure. * offer Pointer to the data-product class structure which will * be offered to the LDM. * want Pointer to a pointer to a data-product class structure. * "*want" will be set the data-product class structure * that the LDM wants. The client should call * "free_prod_class(*want)" when the product-class is no * longer needed. * Returns: * 0 Success. "*clsspp" might be modified. * LP_RPC_ERROR RPC error. "log_start()" called. * LP_LDM_ERROR LDM error. "log_start()" called. */ static LdmProxyStatus my_hiya_6( LdmProxy* const proxy, prod_class_t* const offer, prod_class_t** const want) { CLIENT* const clnt = proxy->clnt; hiya_reply_t* reply; LdmProxyStatus status; reply = hiya_6(offer, clnt); if (NULL == reply) { status = getStatus(proxy, "HIYA_6", NULL); } else { switch (reply->code) { case OK: *want = (prod_class_t*)PQ_CLASS_ALL; proxy->max_hereis = reply->hiya_reply_t_u.max_hereis; status = 0; break; case SHUTTING_DOWN: LOG_START1("%s: LDM shutting down", proxy->host); status = LP_LDM_ERROR; break; case BADPATTERN: LOG_START1("%s: Bad product-class pattern", proxy->host); status = LP_LDM_ERROR; break; case DONT_SEND: LOG_START1("%s: LDM says don't send", proxy->host); status = LP_LDM_ERROR; break; case RESEND: LOG_START1("%s: LDM says resend (ain't gonna happen)", proxy->host); status = LP_LDM_ERROR; break; case RESTART: LOG_START1("%s: LDM says restart (ain't gonna happen)", proxy->host); status = LP_LDM_ERROR; break; case REDIRECT: LOG_START1("%s: LDM says redirect (ain't gonna happen)", proxy->host); status = LP_LDM_ERROR; break; case RECLASS: *want = reply->hiya_reply_t_u.feedPar.prod_class; proxy->max_hereis = reply->hiya_reply_t_u.feedPar.max_hereis; clss_regcomp(*want); /* N.B. we use the downstream patterns */ /* Use of "buf" added to prevent SIGSEGV on 64-bit RHEL 6 */ (void)s_prod_class(buf, sizeof(buf)-1, *want); unotice("%s: reclass: %s", proxy->host, buf); status = 0; break; } if (LP_OK != status) udebug("max_hereis = %u", proxy->max_hereis); } return status; }
int main( int ac, char* av[]) { const char* pqfname = getQueuePath(); int sock = -1; int status; int doSomething = 1; in_addr_t locIpAddr = (in_addr_t) htonl(INADDR_ANY ); unsigned ldmPort = LDM_PORT; ensureDumpable(); /* * deal with the command line, set options */ { extern int optind; extern int opterr; extern char *optarg; int ch; int logmask = LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) | LOG_MASK(LOG_NOTICE); opterr = 1; while ((ch = getopt(ac, av, "I:vxl:nq:o:P:M:m:t:")) != EOF) { switch (ch) { case 'I': { in_addr_t ipAddr = inet_addr(optarg); if ((in_addr_t) -1 == ipAddr) { (void) fprintf(stderr, "Interface specification \"%s\" " "isn't an IP address\n", optarg); exit(1); } locIpAddr = ipAddr; break; } case 'v': logmask |= LOG_MASK(LOG_INFO); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': logfname = optarg; break; case 'q': pqfname = optarg; setQueuePath(optarg); break; case 'o': toffset = atoi(optarg); if (toffset == 0 && *optarg != '0') { (void) fprintf(stderr, "%s: invalid offset %s\n", av[0], optarg); usage(av[0]); } break; case 'P': { char* suffix = ""; long port; errno = 0; port = strtol(optarg, &suffix, 0); if (0 != errno || 0 != *suffix || 0 >= port || 0xffff < port) { (void) fprintf(stderr, "%s: invalid port %s\n", av[0], optarg); usage(av[0]); } ldmPort = (unsigned) port; break; } case 'M': { int max = atoi(optarg); if (max < 0) { (void) fprintf(stderr, "%s: invalid maximum number of clients %s\n", av[0], optarg); usage(av[0]); } maxClients = max; break; } case 'm': max_latency = atoi(optarg); if (max_latency <= 0) { (void) fprintf(stderr, "%s: invalid max_latency %s\n", av[0], optarg); usage(av[0]); } break; case 'n': doSomething = 0; break; case 't': rpctimeo = (unsigned) atoi(optarg); if (rpctimeo == 0 || rpctimeo > 32767) { (void) fprintf(stderr, "%s: invalid timeout %s", av[0], optarg); usage(av[0]); } break; case '?': usage(av[0]); break; } /* "switch" statement */ } /* argument loop */ if (ac - optind == 1) setLdmdConfigPath(av[optind]); (void) setulogmask(logmask); if (toffset != TOFFSET_NONE && toffset > max_latency) { (void) fprintf(stderr, "%s: invalid toffset (%d) > max_latency (%d)\n", av[0], toffset, max_latency); usage(av[0]); } } /* command-line argument decoding */ #ifndef DONTFORK /* * daemon behavior * * Background the process unless we are logging to stderr, in which * case we assume interactive. */ if (logfname == NULL || *logfname != '-') { /* detach */ pid_t pid; pid = ldmfork(); if (pid == -1) { log_add("Couldn't fork LDM daemon"); log_log(LOG_ERR); exit(2); } if (pid > 0) { /* parent */ (void) printf("%ld\n", (long) pid); exit(0); } /* detach the child from parents process group ?? */ (void) setsid(); } #endif /* * Initialize logger. * (Close fd 2 to remap stderr to the logfile, when * appropriate. I know, this is anal.) */ if (logfname == NULL ) (void) fclose(stderr); else if (!(logfname[0] == '-' && logfname[1] == 0)) (void) close(2); (void) openulog(ubasename(av[0]), (LOG_CONS | LOG_PID), LOG_LDM, logfname); unotice("Starting Up (version: %s; built: %s %s)", PACKAGE_VERSION, __DATE__, __TIME__); /* * register exit handler */ if (atexit(cleanup) != 0) { serror("atexit"); unotice("Exiting"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Close the standard input and standard output streams because they won't * be used (more anality :-) */ (void) fclose(stdout); (void) fclose(stdin); if (!doSomething) { /* * Vet the configuration file. */ udebug("main(): Vetting configuration-file"); if (read_conf(getLdmdConfigPath(), doSomething, ldmPort) != 0) { log_log(LOG_ERR); exit(1); } } else { /* * Create a service portal. This should be done before anything is * created because this is the function that relinquishes superuser * privileges. */ udebug("main(): Creating service portal"); if (create_ldm_tcp_svc(&sock, locIpAddr, ldmPort) != ENOERR) { /* error reports are emitted from create_ldm_tcp_svc() */ exit(1); } udebug("tcp sock: %d", sock); /* * Verify that the product-queue can be open for writing. */ udebug("main(): Opening product-queue"); if (status = pq_open(pqfname, PQ_DEFAULT, &pq)) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent", pqfname); } else { uerror("pq_open failed: %s: %s", pqfname, strerror(status)); } exit(1); } (void) pq_close(pq); pq = NULL; /* * Create the sharable database of upstream LDM metadata. */ udebug("main(): Creating shared upstream LDM database"); if (status = uldb_delete(NULL)) { if (ULDB_EXIST == status) { log_clear(); } else { LOG_ADD0( "Couldn't delete existing shared upstream LDM database"); log_log(LOG_ERR); exit(1); } } if (uldb_create(NULL, maxClients * 1024)) { LOG_ADD0("Couldn't create shared upstream LDM database"); log_log(LOG_ERR); exit(1); } /* * Read the configuration file (downstream LDM-s are started). */ udebug("main(): Reading configuration-file"); if (read_conf(getLdmdConfigPath(), doSomething, ldmPort) != 0) { log_log(LOG_ERR); exit(1); } /* * Serve */ udebug("main(): Serving socket"); sock_svc(sock); } /* "doSomething" is true */ return (0); }
int main(int ac, char *av[]) { const char* const pqfname = getQueuePath(); const char* const progname = ubasename(av[0]); char *logfname = NULL; /* log to syslogd(8) */ int logoptions = LOG_CONS | LOG_PID; int logmask = LOG_UPTO(LOG_NOTICE); prod_class_t clss; prod_spec spec; int status = 0; int interval = DEFAULT_INTERVAL; int toffset = TOFFSET_NONE; extern const char *remote; char* hostname = ghostname(); /* * Setup default logging before anything else. */ (void) openulog(progname, logoptions, LOG_LDM, logfname); (void) setulogmask(logmask); remote = "localhost"; if(set_timestamp(&clss.from) != ENOERR) /* corrected by toffset below */ { int errnum = errno; fprintf(stderr, "Couldn't set timestamp: %s", strerror(errnum)); exit(1); } clss.to = TS_ENDT; clss.psa.psa_len = 1; clss.psa.psa_val = &spec; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = ".*"; /* * Sigh, in order to read back from existing stats files, * we call mktime(3). Since the stats are in UTC, * and mktime uses "local" time, the local time for * this program must be UTC. */ if(setenv("TZ", "UTC0",1)) { int errnum = errno; uerror("setenv: Couldn't set TZ: %s", strerror(errnum)); exit(1); } { int ch; opterr = 0; /* stops getopt() from printing to stderr */ while ((ch = getopt(ac, av, ":vxl:p:f:q:o:i:H:h:P:")) != 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 'l': logfname = optarg; if (strcmp(logfname, "") == 0) logfname = NULL; logoptions = (logfname == NULL) ? (LOG_CONS|LOG_PID) : LOG_NOTIME; openulog(progname, logoptions, LOG_LDM, logfname); break; case 'H': hostname = optarg; break; case 'h': remote = optarg; break; case 'p': spec.pattern = optarg; if (re_isPathological(spec.pattern)) { unotice("Adjusting pathological regular-expression \"%s\"", spec.pattern); re_vetSpec(spec.pattern); } break; case 'f': { int fterr = strfeedtypet(optarg, &spec.feedtype) ; if (fterr != FEEDTYPE_OK) { uerror("Bad feedtype \"%s\", %s", optarg, strfeederr(fterr)) ; usage(progname); } break; } case 'q': setQueuePath(optarg); break; case 'o': toffset = atoi(optarg); if(toffset == 0 && *optarg != '0') { uerror("Invalid offset %s", optarg); usage(progname); } break; case 'P': { char* suffix = ""; long port; errno = 0; port = strtol(optarg, &suffix, 0); if (0 != errno || 0 != *suffix || 0 >= port || 0xffff < port) { uerror("Invalid port %s", optarg); usage(progname); } remotePort = (unsigned)port; break; } case 'i': interval = atoi(optarg); if (interval == 0 && *optarg != '0') { uerror("Invalid interval %s", optarg); usage(progname); } break; case '?': uerror("Invalid option \"%c\"", optopt); usage(progname); break; case ':': uerror("No argument for option \"%c\"", optopt); usage(progname); break; } } /* getopt() loop */ if (optind != ac) { uerror("Invalid operand: \"%s\"", av[optind]); usage(progname); } } /* command-line decoding block */ if (regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB)) { uerror("Bad regular expression \"%s\"\n", spec.pattern); usage(progname); } unotice("Starting Up (%d)", getpgrp()); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Open the product queue */ status = pq_open(pqfname, PQ_READONLY, &pq); if(status) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent\n", pqfname); } else { uerror("pq_open failed: %s: %s\n", pqfname, strerror(status)); } exit(1); } if(toffset == TOFFSET_NONE) { /* * Be permissive with the time filter, * jump now to the end of the queue. */ clss.from = TS_ZERO; (void) pq_last(pq, &clss, NULL); } else { /* * Filter and queue position set by * toffset. */ clss.from.tv_sec -= toffset; pq_cset(pq, &clss.from); } while(exitIfDone(0)) { if(stats_req) { dump_statsbins(); stats_req = 0; } status = pq_sequence(pq, TV_GT, &clss, addtostats, 0); switch(status) { case 0: /* no error */ continue; /* N.B., other cases sleep */ case PQUEUE_END: udebug("End of Queue"); break; case EAGAIN: case EACCES: udebug("Hit a lock"); break; default: uerror("pq_sequence failed: %s (errno = %d)", strerror(status), status); exit(1); break; } syncbinstats(hostname); if(interval == 0) { done = 1; break; } pq_suspend(interval); } return 0; }
/* * Called at exit. * This callback routine registered by atexit(). */ static void cleanup( void) { const char* const pqfname = getQueuePath(); unotice("Exiting"); lcf_savePreviousProdInfo(); free_remote_clss(); /* * Ensure release of COMINGSOON-reserved space in product-queue. */ clr_pip_5(); down6_destroy(); /* * Close product-queue. */ if (pq) { (void) pq_close(pq); pq = NULL; } /* * Ensure that this process has no entry in the upstream LDM database and * that the database is closed. */ (void) uldb_remove(getpid()); (void) uldb_close(); log_clear(); if (getpid() == getpgrp()) { /* * This process is the process group leader (i.e., the top-level * LDM server). */ if (portIsMapped) { int vers; /* * Superuser privileges might be required to unmap the * port on which the LDM is listening. */ rootpriv(); for (vers = MIN_LDM_VERSION; vers <= MAX_LDM_VERSION; vers++) { if (!pmap_unset(LDMPROG, vers)) uerror("pmap_unset(LDMPROG %lu, LDMVERS %lu) " "failed", LDMPROG, vers); else portIsMapped = 0; } unpriv(); } /* * Terminate all child processes. */ { /* * Ignore the signal I'm about to send my process group. */ struct sigaction sigact; (void) sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigact.sa_handler = SIG_IGN; (void) sigaction(SIGTERM, &sigact, NULL ); } /* * Signal my process group. */ unotice("Terminating process group"); (void) kill(0, SIGTERM); while (reap(-1, 0) > 0) ; /*empty*/ /* * Delete the upstream LDM database. */ (void) uldb_delete(NULL); #if WANT_MULTICAST /* * Destroy the multicast LDM sender map. */ msm_destroy(); #endif } /* * Free access-control-list resources. */ lcf_free(); /* * Close registry. */ if (reg_close()) log_log(LOG_ERR); /* * Terminate logging. */ (void) closeulog(); }
static void null_stats(void) { unotice(" No feed statistics: never opened feed"); }
/* * Handles an incoming RPC connection on a socket. This method will fork(2) * a copy of this program, if appropriate, for handling incoming RPC messages. * * sock The socket with the incoming RPC connection. */ static void handle_connection( int sock) { struct sockaddr_in raddr; socklen_t len; int xp_sock; pid_t pid; SVCXPRT *xprt; int status = 1; /* EXIT_FAILURE assumed unless one_svc_run() success */ peer_info* remote = get_remote(); again: len = sizeof(raddr); (void) memset(&raddr, 0, len); xp_sock = accept(sock, (struct sockaddr *) &raddr, &len); (void) exitIfDone(0); if (xp_sock < 0) { if (errno == EINTR) { errno = 0; goto again; } /* else */ serror("accept"); return; } /* * Don't bother continuing if no more clients are allowed. */ if (cps_count() >= maxClients) { setremote(&raddr, xp_sock); unotice("Denying connection from [%s] because too many clients", remote->astr); (void) close(xp_sock); return; } pid = ldmfork(); if (pid == -1) { log_add("Couldn't fork process to handle incoming connection"); log_log(LOG_ERR); /* TODO: try again?*/ (void) close(xp_sock); return; } if (pid > 0) { /* parent */ /* unotice("child %d", pid); */ (void) close(xp_sock); if (cps_add(pid)) serror("Couldn't add child PID to set"); return; } /* else child */ setremote(&raddr, xp_sock); /* Access control */ if (!lcf_isHostOk(remote)) { ensureRemoteName(&raddr); if (!lcf_isHostOk(remote)) { if (remote->printname == remote->astr) { unotice("Denying connection from [%s] because not " "allowed", remote->astr); } else { unotice("Denying connection from \"%s\" because not " "allowed", remote_name()); } /* * Try to tell the other guy. * TODO: Why doesn't this work? */ xprt = svcfd_create(xp_sock, remote->sendsz, remote->recvsz); if (xprt != NULL ) { xprt->xp_raddr = raddr; xprt->xp_addrlen = (int) len; svcerr_weakauth(xprt); svc_destroy(xprt); } goto unwind_sock; } } /* else */ endpriv(); portIsMapped = 0; /* don't call pmap_unset() from child */ (void) close(sock); /* Set the ulog identifier, optional. */ set_abbr_ident(remote_name(), NULL ); uinfo("Connection from %s", remote_name()); xprt = svcfd_create(xp_sock, remote->sendsz, remote->recvsz); if (xprt == NULL ) { uerror("Can't create fd service."); goto unwind_sock; } /* hook up the remote address to the xprt. */ /* xprt->xp_raddr = raddr; */ xprt->xp_raddr = raddr; xprt->xp_addrlen = (int) len; if (!svc_register(xprt, LDMPROG, 4, ldmprog_4, 0)) { uerror("unable to register LDM-4 service."); svc_destroy(xprt); goto unwind_sock; } if (!svc_register(xprt, LDMPROG, FIVE, ldmprog_5, 0)) { uerror("unable to register LDM-5 service."); svc_destroy(xprt); goto unwind_sock; } if (!svc_register(xprt, LDMPROG, SIX, ldmprog_6, 0)) { uerror("unable to register LDM-6 service."); svc_destroy(xprt); goto unwind_sock; } #if WANT_MULTICAST if (!svc_register(xprt, LDMPROG, SEVEN, ldmprog_7, 0)) { uerror("unable to register LDM-7 service."); svc_destroy(xprt); goto unwind_sock; } #endif /* * handle rpc requests */ { const unsigned TIMEOUT = 2*interval; status = one_svc_run(xp_sock, TIMEOUT); (void) exitIfDone(0); if (status == 0) { log_add("Done"); log_log(LOG_INFO); } else if (status == ETIMEDOUT) { log_add("Connection from client LDM silent for %u seconds", TIMEOUT); log_log(LOG_NOTICE); } else { /* connection to client lost */ log_add("Connection with client LDM closed"); log_log(LOG_INFO); status = 0; /* EXIT_SUCCESS */ } } /* svc_destroy(xprt); done by svc_getreqset() */ unwind_sock: (void) close(xp_sock); exit(status); }
/** * 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, ¶m); (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, ¶m); #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; }