Exemple #1
0
int zmq::pgm_socket_t::init (bool udp_encapsulation_, const char *network_)
{
    //  Can not open transport before destroying old one. 
    zmq_assert (transport == NULL);
 
    //  Parse port number.
    const char *port_delim = strchr (network_, ':');
    if (!port_delim) {
        errno = EINVAL;
        return -1;
    }

    uint16_t port_number = atoi (port_delim + 1);
  
    char network [256];
    if (port_delim - network_ >= (int) sizeof (network) - 1) {
        errno = EINVAL;
        return -1;
    }
    memset (network, '\0', sizeof (network));
    memcpy (network, network_, port_delim - network_);
    
    //  Zero counter used in msgrecv.
    nbytes_rec = 0;
    nbytes_processed = 0;
    pgm_msgv_processed = 0;

    GError *pgm_error = NULL;

    //  Init PGM transport.
    //  Ensure threading enabled, ensure timer enabled and find PGM protocol id.
    //
    //  Note that if you want to use gettimeofday and sleep for openPGM timing,
    //  set environment variables PGM_TIMER to "GTOD" 
    //  and PGM_SLEEP to "USLEEP".
    int rc = pgm_init ();
    if (rc != 0) {
        errno = EINVAL;
        return -1;
    }

    //  PGM transport GSI.
    pgm_gsi_t gsi;
 
    std::string gsi_base;

    if (options.identity.size () > 0) {

        //  Create gsi from identity string.
        gsi_base = options.identity;
    } else {

        //  Generate random gsi.
        gsi_base = uuid_t ().to_string ();
    }

    rc = pgm_gsi_create_from_string (&gsi, gsi_base.c_str (), -1);
    if (rc != TRUE) {
        errno = EINVAL;
        return -1;
    }

    struct pgm_transport_info_t *res = NULL;

    if (!pgm_if_get_transport_info (network, NULL, &res, &pgm_error)) {

        if (pgm_error->domain == PGM_IF_ERROR && (
              pgm_error->code == PGM_IF_ERROR_INVAL ||
              pgm_error->code == PGM_IF_ERROR_XDEV ||
              pgm_error->code == PGM_IF_ERROR_NODEV ||
              pgm_error->code == PGM_IF_ERROR_NOTUNIQ ||
              pgm_error->code == PGM_IF_ERROR_ADDRFAMILY ||
              pgm_error->code == PGM_IF_ERROR_FAMILY ||
              pgm_error->code == PGM_IF_ERROR_NODATA ||
              pgm_error->code == PGM_IF_ERROR_NONAME ||
              pgm_error->code == PGM_IF_ERROR_SERVICE)) {
            errno = EINVAL;
	        g_error_free (pgm_error);
            return -1;
        }

        zmq_assert (false);
    }

    res->ti_gsi = gsi;
    res->ti_dport = port_number;

    //  If we are using UDP encapsulation update gsr or res. 
    if (udp_encapsulation_) {
        res->ti_udp_encap_ucast_port = port_number;
        res->ti_udp_encap_mcast_port = port_number;
    }

    if (!pgm_transport_create (&transport, res, &pgm_error)) {
        if (pgm_error->domain == PGM_TRANSPORT_ERROR && (
              pgm_error->code == PGM_TRANSPORT_ERROR_INVAL ||
              pgm_error->code == PGM_TRANSPORT_ERROR_PERM ||
              pgm_error->code == PGM_TRANSPORT_ERROR_NODEV)) {
            pgm_if_free_transport_info (res);
            g_error_free (pgm_error);
            errno = EINVAL;
            return -1;
        }

        zmq_assert (false);
    }

    pgm_if_free_transport_info (res);

    //  Common parameters for receiver and sender.

    //  Set maximum transport protocol data unit size (TPDU).
    rc = pgm_transport_set_max_tpdu (transport, pgm_max_tpdu);
    if (rc != TRUE) {
        errno = EINVAL;
        return -1;
    }

    //  Set maximum number of network hops to cross.
    rc = pgm_transport_set_hops (transport, 16);
    if (rc != TRUE) {
        errno = EINVAL;
        return -1;
    }

    //  Set nonblocking send/recv sockets.
    if (!pgm_transport_set_nonblocking (transport, true)) {
        errno = EINVAL;
        return -1;
    }

    if (receiver) {

        //  Receiver transport.
        
        //  Note that NAKs are still generated by the transport.
        rc = pgm_transport_set_recv_only (transport, true, false);
        zmq_assert (rc == TRUE);

        if (options.rcvbuf) {
            rc = pgm_transport_set_rcvbuf (transport, (int) options.rcvbuf);
            if (rc != TRUE)
                return -1;
        }

        //  Set NAK transmit back-off interval [us].
        rc = pgm_transport_set_nak_bo_ivl (transport, 50 * 1000);
        zmq_assert (rc == TRUE);

        //  Set timeout before repeating NAK [us].
        rc = pgm_transport_set_nak_rpt_ivl (transport, 200 * 1000);
        zmq_assert (rc == TRUE);

        //  Set timeout for receiving RDATA.
        rc = pgm_transport_set_nak_rdata_ivl (transport, 200 * 1000);
        zmq_assert (rc == TRUE);

        //  Set retries for NAK without NCF/DATA (NAK_DATA_RETRIES).
        rc = pgm_transport_set_nak_data_retries (transport, 5);
        zmq_assert (rc == TRUE);

        //  Set retries for NCF after NAK (NAK_NCF_RETRIES).
        rc = pgm_transport_set_nak_ncf_retries (transport, 2);
        zmq_assert (rc == TRUE);

        //  Set timeout for removing a dead peer [us].
        rc = pgm_transport_set_peer_expiry (transport, 5 * 8192 * 1000);
        zmq_assert (rc == TRUE);

        //  Set expiration time of SPM Requests [us].
        rc = pgm_transport_set_spmr_expiry (transport, 25 * 1000);
        zmq_assert (rc == TRUE);

        //  Set the size of the receive window.
        //  Data rate is in [B/s]. options.rate is in [kb/s].
        if (options.rate <= 0) {
            errno = EINVAL;
            return -1;
        }
        rc = pgm_transport_set_rxw_max_rte (transport, 
            options.rate * 1000 / 8);
        if (rc != TRUE) {
            errno = EINVAL;
            return -1;
        }

        //  Recovery interval [s]. 
        if (options.recovery_ivl <= 0) {
            errno = EINVAL;
            return -1;
        }
        rc = pgm_transport_set_rxw_secs (transport, options.recovery_ivl);
        if (rc != TRUE) {
            errno = EINVAL;
            return -1;
        }

    } else {

        //  Sender transport.

        //  Waiting pipe won't be read.
        rc = pgm_transport_set_send_only (transport, TRUE);
        zmq_assert (rc == TRUE);

        if (options.sndbuf) {
            rc = pgm_transport_set_sndbuf (transport, (int) options.sndbuf);
            if (rc != TRUE)
                return -1;
        }

        //  Set the size of the send window.
        //  Data rate is in [B/s] options.rate is in [kb/s].
        if (options.rate <= 0) {
            errno = EINVAL;
            return -1;
        }
        rc = pgm_transport_set_txw_max_rte (transport, 
            options.rate * 1000 / 8);
        if (rc != TRUE) {
            errno = EINVAL;
            return -1;
        }

        //  Recovery interval [s]. 
        if (options.recovery_ivl <= 0) {
            errno = EINVAL;
            return -1;
        }
        rc = pgm_transport_set_txw_secs (transport, options.recovery_ivl);
        if (rc != TRUE) {
            errno = EINVAL;
            return -1;
        }

        //  Set interval of background SPM packets [us].
        rc = pgm_transport_set_ambient_spm (transport, 8192 * 1000);
        zmq_assert (rc == TRUE);

        //  Set intervals of data flushing SPM packets [us].
        guint spm_heartbeat[] = {4 * 1000, 4 * 1000, 8 * 1000, 16 * 1000, 
            32 * 1000, 64 * 1000, 128 * 1000, 256 * 1000, 512 * 1000, 
            1024 * 1000, 2048 * 1000, 4096 * 1000, 8192 * 1000};
        rc = pgm_transport_set_heartbeat_spm (transport, spm_heartbeat, 
            G_N_ELEMENTS(spm_heartbeat));
        zmq_assert (rc == TRUE);
    }
    
    //  Enable multicast loopback.
    if (options.use_multicast_loop) {
        rc = pgm_transport_set_multicast_loop (transport, true);
        zmq_assert (rc == TRUE);
    }

    //  Bind a transport to the specified network devices.
    if (!pgm_transport_bind (transport, &pgm_error)) {
        if (pgm_error->domain == PGM_IF_ERROR && (
              pgm_error->code == PGM_IF_ERROR_INVAL ||
              pgm_error->code == PGM_IF_ERROR_XDEV ||
              pgm_error->code == PGM_IF_ERROR_NODEV ||
              pgm_error->code == PGM_IF_ERROR_NOTUNIQ ||
              pgm_error->code == PGM_IF_ERROR_ADDRFAMILY ||
              pgm_error->code == PGM_IF_ERROR_FAMILY ||
              pgm_error->code == PGM_IF_ERROR_NODATA ||
              pgm_error->code == PGM_IF_ERROR_NONAME ||
              pgm_error->code == PGM_IF_ERROR_SERVICE)) {
            g_error_free (pgm_error);
            errno = EINVAL;
            return -1;
        }

        zmq_assert (false);
    }

    //  For receiver transport preallocate pgm_msgv array.
    //  TODO: ?
    if (receiver) {
        zmq_assert (in_batch_size > 0);
        size_t max_tsdu_size = get_max_tsdu_size ();
        pgm_msgv_len = (int) in_batch_size / max_tsdu_size;
        if ((int) in_batch_size % max_tsdu_size)
            pgm_msgv_len++;
        zmq_assert (pgm_msgv_len);

        pgm_msgv = (pgm_msgv_t*) malloc (sizeof (pgm_msgv_t) * pgm_msgv_len);
    }

    return 0;
}
Exemple #2
0
int zmq::pgm_socket_t::open_transport ()
{
    //  Can not open transport before destroying old one. 
    zmq_assert (transport == NULL);

    //  Zero counter used in msgrecv.
    nbytes_rec = 0;
    nbytes_processed = 0;
    pgm_msgv_processed = 0;

    //  TODO: Converting bool to int? Not nice.
    int pgm_ok = true;
    GError *pgm_error = NULL;

    //  Init PGM transport.
    //  Ensure threading enabled, ensure timer enabled and find PGM protocol id.
    //
    //  Note that if you want to use gettimeofday and sleep for openPGM timing,
    //  set environment variables PGM_TIMER to "GTOD" 
    //  and PGM_SLEEP to "USLEEP".
    int rc = pgm_init ();
    if (rc != 0) {
        errno = EINVAL;
        return -1;
    }

    //  PGM transport GSI.
    pgm_gsi_t gsi;
 
    std::string gsi_base;

    if (options.identity.size () > 0) {

        //  Create gsi from identity string.
        gsi_base = options.identity;
    } else {

        //  Generate random gsi.
        gsi_base = uuid_t ().to_string ();
    }

    rc = pgm_gsi_create_from_string (&gsi, gsi_base.c_str (), -1);

    if (rc != pgm_ok) {
        errno = EINVAL;
        return -1;
    }

    //zmq_log (1, "Transport GSI: %s, %s(%i)\n", pgm_print_gsi (&gsi),
    //    __FILE__, __LINE__);

    struct pgm_transport_info_t *res = NULL;

    if (!pgm_if_get_transport_info (network, NULL, &res, &pgm_error)) {
        errno = EINVAL;
        return -1;
    }

    res->ti_gsi = gsi;
    res->ti_dport = port_number;

    //  If we are using UDP encapsulation update gsr or res. 
    if (udp_encapsulation) {
        res->ti_udp_encap_ucast_port = port_number;
        res->ti_udp_encap_mcast_port = port_number;
    }

    if (!pgm_transport_create (&transport, res, &pgm_error)) { 
        pgm_if_free_transport_info (res);
        //  TODO: tranlate errors from glib into errnos.
        errno = EINVAL;
        return -1;
    }

    pgm_if_free_transport_info (res);

    //  Common parameters for receiver and sender.

    //  Set maximum transport protocol data unit size (TPDU).
    rc = pgm_transport_set_max_tpdu (transport, pgm_max_tpdu);
    if (rc != pgm_ok) {
        errno = EINVAL;
        return -1;
    }

    //  Set maximum number of network hops to cross.
    rc = pgm_transport_set_hops (transport, 16);
    if (rc != pgm_ok) {
        errno = EINVAL;
        return -1;
    }

    //  Set nonblocking send/recv sockets.
    if (!pgm_transport_set_nonblocking (transport, true)) {
        errno = EINVAL;
        return -1;
    }

    if (receiver) {

         //  Receiver transport.
        
        //  Set transport->can_send_data = FALSE.
        //  Note that NAKs are still generated by the transport.
        rc = pgm_transport_set_recv_only (transport, true, false);
        zmq_assert (rc == pgm_ok);

        if (options.rcvbuf) {
            rc = pgm_transport_set_rcvbuf (transport, (int) options.rcvbuf);
            if (rc != pgm_ok)
                return -1;
        }

        //  Set NAK transmit back-off interval [us].
        rc = pgm_transport_set_nak_bo_ivl (transport, 50 * 1000);
        zmq_assert (rc == pgm_ok);

        //  Set timeout before repeating NAK [us].
        rc = pgm_transport_set_nak_rpt_ivl (transport, 200 * 1000);
        zmq_assert (rc == pgm_ok);

        //  Set timeout for receiving RDATA.
        rc = pgm_transport_set_nak_rdata_ivl (transport, 200 * 1000);
        zmq_assert (rc == pgm_ok);

        //  Set retries for NAK without NCF/DATA (NAK_DATA_RETRIES).
        rc = pgm_transport_set_nak_data_retries (transport, 5);
        zmq_assert (rc == pgm_ok);

        //  Set retries for NCF after NAK (NAK_NCF_RETRIES).
        rc = pgm_transport_set_nak_ncf_retries (transport, 2);
        zmq_assert (rc == pgm_ok);

        //  Set timeout for removing a dead peer [us].
        rc = pgm_transport_set_peer_expiry (transport, 5 * 8192 * 1000);
        zmq_assert (rc == pgm_ok);

        //  Set expiration time of SPM Requests [us].
        rc = pgm_transport_set_spmr_expiry (transport, 25 * 1000);
        zmq_assert (rc == pgm_ok);

        //  Set the size of the receive window.
        //  Data rate is in [B/s]. options.rate is in [kb/s].
        if (options.rate <= 0) {
            errno = EINVAL;
            return -1;
        }
        rc = pgm_transport_set_rxw_max_rte (transport, 
            options.rate * 1000 / 8);
        if (rc != pgm_ok) {
            errno = EINVAL;
            return -1;
        }

        //  Recovery interval [s]. 
        if (options.recovery_ivl <= 0) {
            errno = EINVAL;
            return -1;
        }
        rc = pgm_transport_set_rxw_secs (transport, options.recovery_ivl);
        if (rc != pgm_ok) {
            errno = EINVAL;
            return -1;
        }

    } else {

        //  Sender transport.

        //  Set transport->can_recv = FALSE, waiting_pipe will not be read.
        rc = pgm_transport_set_send_only (transport, TRUE);
        zmq_assert (rc == pgm_ok);

        if (options.sndbuf) {
            rc = pgm_transport_set_sndbuf (transport, (int) options.sndbuf);
            if (rc != pgm_ok)
                return -1;
        }

        //  Set the size of the send window.
        //  Data rate is in [B/s] options.rate is in [kb/s].
        if (options.rate <= 0) {
            errno = EINVAL;
            return -1;
        }
        rc = pgm_transport_set_txw_max_rte (transport, 
            options.rate * 1000 / 8);
        if (rc != pgm_ok) {
            errno = EINVAL;
            return -1;
        }

        //  Recovery interval [s]. 
        if (options.recovery_ivl <= 0) {
            errno = EINVAL;
            return -1;
        }
        rc = pgm_transport_set_txw_secs (transport, options.recovery_ivl);
        if (rc != pgm_ok) {
            errno = EINVAL;
            return -1;
        }

        //  Set interval of background SPM packets [us].
        rc = pgm_transport_set_ambient_spm (transport, 8192 * 1000);
        zmq_assert (rc == pgm_ok);

        //  Set intervals of data flushing SPM packets [us].
        guint spm_heartbeat[] = {4 * 1000, 4 * 1000, 8 * 1000, 16 * 1000, 
            32 * 1000, 64 * 1000, 128 * 1000, 256 * 1000, 512 * 1000, 
            1024 * 1000, 2048 * 1000, 4096 * 1000, 8192 * 1000};
        rc = pgm_transport_set_heartbeat_spm (transport, spm_heartbeat, 
            G_N_ELEMENTS(spm_heartbeat));
        zmq_assert (rc == pgm_ok);
    }
    
    //  Enable multicast loopback.
    if (options.use_multicast_loop) {
        rc = pgm_transport_set_multicast_loop (transport, true);
        zmq_assert (rc == pgm_ok);
    }

    //  Bind a transport to the specified network devices.
    if (!pgm_transport_bind (transport, &pgm_error)) {
        //  TODO: tranlate errors from glib into errnos.
        return -1;
    }

    return 0;
}