/** * Returns a new multicast sender. Starts the sender's TCP server. This method * doesn't block. * * @param[out] sender Pointer to returned sender. Caller should call * `mcastSender_free(*sender)` when it's no longer * needed. * @param[in] serverAddr Dotted-decimal IPv4 address of the interface on which * the TCP server will listen for connections from * receivers for retrieving missed data-blocks. * @param[in] serverPort Port number of the TCP server. * @param[in] groupAddr Dotted-decimal IPv4 address address of the multicast * group. * @param[in] groupPort Port number of the multicast group. * @param[out] ttl Time-to-live of outgoing packets. * 0 Restricted to same host. Won't be output by * any interface. * 1 Restricted to the same subnet. Won't be * forwarded by a router (default). * <32 Restricted to the same site, organization or * department. * <64 Restricted to the same region. * <128 Restricted to the same continent. * <255 Unrestricted in scope. Global. * @retval 0 Success. `*sender` is set. * @retval EINVAL One of the address couldn't be converted into a * binary IP address. `log_start()` called. * @retval ENOMEM Out of memory. \c log_start() called. * @retval -1 Other failure. \c log_start() called. */ int mcastSender_new( void** const sender, const char* const serverAddr, const unsigned short serverPort, const char* const groupAddr, const unsigned short groupPort, const unsigned ttl) { try { VCMTPSender* sndr = new VCMTPSender(std::string(serverAddr), serverPort); try { sndr->JoinGroup(std::string(groupAddr), groupPort); *sender = sndr; return 0; } catch (const std::exception& e) { delete sndr; throw; } // `sndr->sender` allocated } // `sndr` allocated catch (const std::invalid_argument& e) { LOG_START1("%s", e.what()); return EINVAL; } catch (const std::exception& e) { LOG_START1("%s", e.what()); return -1; } }
/* * Send a product to an LDM using the LDM-5 message HEREIS. * * Arguments: * proxy Pointer to the LDM proxy data-structure. * info Pointer to the data-product's metadata. * datap Pointer to the data-product's data. * Returns: * 0 Success. * LP_UNWANTED Data-product was unwanted. * LP_TIMEDOUT The RPC call timed-out. "log_start()" called. * LP_RPC_ERROR RPC error. "log_start()" called. * LP_LDM_ERROR LDM error. "log_start()" called. */ static LdmProxyStatus my_hereis_5( LdmProxy* const proxy, product* const product) { CLIENT* const clnt = proxy->clnt; LdmProxyStatus status = 0; /* success */ ldm_replyt reply; enum clnt_stat rpc_stat; memset(&reply, 0, sizeof(ldm_replyt)); rpc_stat = clnt_call(clnt, HEREIS, xdr_product, (caddr_t)product, xdr_ldm_replyt, (caddr_t)&reply, proxy->rpcTimeout); if (rpc_stat != RPC_SUCCESS) { status = getStatus(proxy, "HEREIS_5", &product->info); } else if (reply.code != OK) { if (reply.code == DONT_SEND) { status = LP_UNWANTED; } else { LOG_START1("Unexpected reply from LDM: %s", s_ldm_errt(reply.code)); status = LP_LDM_ERROR; } } return status; }
/* * Sends a data-product to an LDM using the LDM-5 messages COMINGSOON and * BLOCKDATA. * * Arguments: * proxy Pointer to the LDM proxy data-structure. * info Pointer to the data-product's metadata. * datap Pointer to the data-product's data. * Returns: * 0 Success. * LP_UNWANTED Data-product was unwanted. * LP_TIMEDOUT The RPC call timed-out. "log_start()" called. * LP_RPC_ERROR RPC error. "log_start()" called. * LP_LDM_ERROR LDM error. "log_start()" called. */ static LdmProxyStatus my_csbd_5( LdmProxy* const proxy, product* const product) { CLIENT* const clnt = proxy->clnt; LdmProxyStatus status = 0; /* success */ ldm_replyt reply; prod_info* const info = &product->info; memset(&reply, 0, sizeof(ldm_replyt)); status = my_comingsoon_5(proxy, info, DBUFMAX, &reply); if (0 == status) { if (reply.code != OK) { if (reply.code == DONT_SEND) { status = LP_UNWANTED; } else { LOG_START2("send_5: %s: %s", info->ident, s_ldm_errt(reply.code)); status = LP_LDM_ERROR; } } else { size_t unsent = info->sz; char* data = product->data; datapkt pkt; pkt.signaturep = &info->signature; pkt.pktnum = 0; while (unsent > 0) { size_t nsend = DBUFMAX < unsent ? DBUFMAX : unsent; pkt.data.dbuf_len = (u_int)nsend; pkt.data.dbuf_val = data; status = my_blkdata_5(proxy, &pkt, &reply); if (0 != status) { getStatus(proxy, "BLOCKDATA_5", info); break; } else if (reply.code != OK) { LOG_START1("Unexpected reply from LDM: %s", s_ldm_errt(reply.code)); status = LP_LDM_ERROR; break; } pkt.pktnum++; data += nsend; unsent -= nsend; } } /* reply.code == OK */ } /* OK COMINGSOON */ return status; }
/** * Returns a new multicast sender. Starts the sender's TCP server. This method * doesn't block. * * @param[out] sender Pointer to returned sender. Caller should call * `mcastSender_free(*sender)` when it's no longer * needed. * @param[in] serverAddr Dotted-decimal IPv4 address of the interface on which * the TCP server will listen for connections from * receivers for retrieving missed data-blocks. * @param[in] serverPort Port number of the TCP server. * @param[in] groupAddr Dotted-decimal IPv4 address address of the multicast * group. * @param[in] groupPort Port number of the multicast group. * @param[in] ttl Time-to-live of outgoing packets. * 0 Restricted to same host. Won't be output by * any interface. * 1 Restricted to the same subnet. Won't be * forwarded by a router (default). * <32 Restricted to the same site, organization or * department. * <64 Restricted to the same region. * <128 Restricted to the same continent. * <255 Unrestricted in scope. Global. * @param[in] iProd Initial product-index. The first multicast data- * product will have this as its index. * @retval 0 Success. `*sender` is set. * @retval EINVAL One of the address couldn't be converted into a * binary IP address. `log_start()` called. * @retval ENOMEM Out of memory. \c log_start() called. * @retval -1 Other failure. \c log_start() called. */ int mcastSender_new( void** const sender, const char* const serverAddr, const unsigned short serverPort, const char* const groupAddr, const unsigned short groupPort, const unsigned ttl, const McastProdIndex iProd) { try { vcmtpSendv3* sndr = new vcmtpSendv3(serverAddr, serverPort, groupAddr, groupPort, iProd); } catch (const std::invalid_argument& e) { LOG_START1("%s", e.what()); return EINVAL; } catch (const std::exception& e) { LOG_START1("%s", e.what()); return -1; } }
/** * Multicasts memory data. * * @param[in] sender VCMTP sender. * @param[in] data Data to send. * @param[in] nbytes Amount of data in bytes. * @retval 0 Success. * @retval EIO Failure. `log_start()` called. */ int mcastSender_send( void* const sender, void* const data, const size_t nbytes) { try { ((VCMTPSender*)sender)->SendMemoryData(data, nbytes); return 0; } catch (const std::exception& e) { LOG_START1("%s", e.what()); return EIO; } }
/* * Sends a data-product to an LDM using the LDM-6 COMINGSOON and BLOCKDATA * messages. * * Arguments: * proxy Pointer to the LDM proxy data-structure. * product Pointer to the data-product to be sent. * Return: * 0 Success. * LP_UNWANTED Data-product was unwanted. * LP_TIMEDOUT The RPC call timed-out. "log_start()" called. * LP_RPC_ERROR RPC error. "log_start()" called. * LP_LDM_ERROR LDM error. "log_start()" called. */ static LdmProxyStatus my_csbd_6( LdmProxy* const proxy, product* const product) { LdmProxyStatus status = 0; /* success */ CLIENT* const clnt = proxy->clnt; prod_info* const info = &product->info; const unsigned size = info->sz; comingsoon_reply_t* reply; comingsoon_args soonArg; udebug("Sending file via COMINGSOON_6/BLKDATA_6"); soonArg.infop = info; soonArg.pktsz = size; reply = comingsoon_6(&soonArg, clnt); if (NULL == reply) { status = getStatus(proxy, "COMINGSOON_6", &product->info); } else { if (DONT_SEND == *reply) { status = LP_UNWANTED; } else if (0 != *reply) { LOG_START1("Unexpected reply from LDM: %s", s_ldm_errt(*reply)); status = LP_LDM_ERROR; } else { datapkt packet; packet.signaturep = (signaturet*)&info->signature; packet.pktnum = 0; packet.data.dbuf_len = size; packet.data.dbuf_val = product->data; if (NULL == blkdata_6(&packet, clnt)) status = getStatus(proxy, "BLKDATA_6", &product->info); } } return status; }
/** * Notifies the LDM of the class of data-products that will be sent via LDM-5 * 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_TIMEDOUT The RPC call timed-out. "log_start()" called. * LP_RPC_ERROR RPC error. "log_start()" called. * LP_LDM_ERROR LDM error. "log_start()" called. */ static LdmProxyStatus my_hiya_5( LdmProxy* const proxy, prod_class_t* const offer, prod_class_t** const want) { static ldm_replyt reply; enum clnt_stat rpc_stat; CLIENT* const clnt = proxy->clnt; memset(&reply, 0, sizeof(ldm_replyt)); rpc_stat = clnt_call(clnt, HIYA, xdr_prod_class, (caddr_t)offer, xdr_ldm_replyt, (caddr_t)&reply, proxy->rpcTimeout); if (rpc_stat != RPC_SUCCESS) { return getStatus(proxy, "HIYA_5", NULL); } switch (reply.code) { case OK: *want = (prod_class_t*)PQ_CLASS_ALL; break; case SHUTTING_DOWN: LOG_START1("%s is shutting down", proxy->host); return LP_LDM_ERROR; case DONT_SEND: case RESTART: case REDIRECT: /* TODO */ default: LOG_START2("%s: Unexpected reply from LDM: %s", proxy->host, s_ldm_errt(reply.code)); return LP_LDM_ERROR; case RECLASS: *want = reply.ldm_replyt_u.newclssp; 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); break; } return 0; }
/** * Sends a product. * * @param[in] sender VCMTP sender. * @param[in] data Data to send. * @param[in] nbytes Amount of data in bytes. * @param[out] iProd Index of the sent product. * @retval 0 Success. * @retval EIO Failure. `log_start()` called. */ int mcastSender_send( void* const sender, const void* const data, const size_t nbytes, const void* const metadata, const unsigned metaSize, McastProdIndex* const iProd) { try { /* * The signature of the product is sent to the receiver as metadata in * order to allow duplicate rejection. */ *iProd = ((vcmtpSendv3*)sender)->sendProduct((void*)data, nbytes, (void*)metadata, metaSize); // safe to cast away `const`s return 0; } catch (const std::exception& e) { LOG_START1("%s", e.what()); return EIO; } }
/** * @retval LDM7_INVAL No multicast sender child process exists. */ static int sender_terminate(void) { int retval = 0; int status; #if CANCEL_SENDER udebug("Canceling sender thread"); status = pthread_cancel(sender.thread); if (status) { LOG_ERRNUM0(status, "Couldn't cancel sender thread"); retval = status; } #else udebug("Writing to termination pipe"); status = write(sender.fds[1], &status, sizeof(int)); if (status == -1) { LOG_SERROR0("Couldn't write to termination pipe"); retval = status; } #endif void* statusPtr; udebug("Joining sender thread"); status = pthread_join(sender.thread, &statusPtr); if (status) { LOG_ERRNUM0(status, "Couldn't join sender thread"); retval = status; } if (statusPtr != PTHREAD_CANCELED) { status = *(int*)statusPtr; if (status) { LOG_START1("Sender task exit-status was %d", status); retval = status; } } (void)close(sender.sock); udebug("Terminating multicast sender"); status = terminateMcastSender(); if (status) { LOG_ADD0("Couldn't terminate multicast sender process"); retval = status; } udebug("Clearing multicast LDM sender manager"); status = mlsm_clear(); if (status) { LOG_ADD0("mlsm_clear() failure"); retval = status; } status = pq_close(pq); if (status) { LOG_ADD0("pq_close() failure"); retval = status; } status = deleteProductQueue(UP7_PQ_PATHNAME); if (status) { LOG_ADD0("deleteProductQueue() failure"); retval = status; } return retval; }
/* * Returns a new instance of an LDM proxy. Can take a while because it * establishes a connection to the LDM. * * Arguments: * host Identifier of the host on which an LDM server is * running. * instance Pointer to a pointer to the new instance. "*instance" * is set upon successful return. * Returns: * 0 Success. "*instance" is set. * LP_SYSTEM System error. "log_start()" called. * LP_TIMEDOUT Connection attempt timed-out. "log_start()" called. * LP_HOSTUNREACH Host is unreachable. "log_start()" called. * LP_RPC_ERROR RPC error. "log_start()" called. * LP_LDM_ERROR LDM error. "log_start()" called. */ LdmProxyStatus lp_new( const char* const host, LdmProxy** const instance) { LdmProxyStatus status = 0; /* success */ size_t nbytes = sizeof(LdmProxy); LdmProxy* proxy = (LdmProxy*)malloc(nbytes); if (NULL == proxy) { log_serror("Couldn't allocate %lu bytes for new LdmProxy", nbytes); status = LP_SYSTEM; } else { proxy->host = strdup(host); if (NULL == proxy->host) { LOG_SERROR1("Couldn't duplicate string \"%s\"", host); status = LP_SYSTEM; } else { CLIENT* clnt = NULL; ErrorObj* error = ldm_clnttcp_create_vers(host, LDM_PORT, 6, &clnt, NULL, NULL); if (!error) { proxy->version = 6; proxy->hiya = my_hiya_6; proxy->send = my_send_6; proxy->flush = my_flush_6; } else if (LDM_CLNT_BAD_VERSION == err_code(error)) { /* Couldn't connect due to protocol version. */ err_free(error); error = ldm_clnttcp_create_vers(host, LDM_PORT, 5, &clnt, NULL, NULL); if (!error) { proxy->version = 5; proxy->hiya = my_hiya_5; proxy->send = my_send_5; proxy->flush = my_flush_5; } } if (error) { LOG_START1("%s", err_message(error)); err_free(error); free(proxy->host); status = convertStatus(error); } else { proxy->clnt = clnt; proxy->rpcTimeout = rpcTimeout; } } /* "proxy->host" allocated */ if (LP_OK == status) { *instance = proxy; } else { free(proxy); } } /* "proxy" allocated */ return status; }
/** * 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; }
/** * 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; }