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

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

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

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

            case 'b': {
                unsigned long   n;

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

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

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

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

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

                    logFacility = logFacilities[i];

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

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

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

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

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

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

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

                        param.sched_priority =
                            sched_get_priority_max(SCHED_POLICY) - 1;

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

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

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

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

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

                    set_sigactions();

                    (void)pthread_join(readerThread, NULL);

                    status = readerStatus(reader);

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

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

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

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

    return status;
}