Exemplo n.º 1
0
void zmq::pgm_socket_t::open_transport (void)
{

    zmq_log (1, "Opening PGM: network  %s, port %i, udp encaps. %s, %s(%i)\n",
        network, port_number, udp_encapsulation ? "yes" : "no", 
        __FILE__, __LINE__);

    //  Can not open transport before destroying old one. 
    assert (g_transport == NULL);

    //  Set actual_tsi and prev_tsi to zeros.
    memset (&tsi, '\0', sizeof (pgm_tsi_t));
    memset (&retired_tsi, '\0', sizeof (pgm_tsi_t));

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

    //  Init PGM transport.
    //  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".
    pgm_init ();

    pgm_gsi_t gsi;

    int rc = pgm_create_md5_gsi (&gsi);
	assert (rc == 0);

    struct group_source_req recv_gsr, send_gsr;
    gsize recv_len = 1;
  
    rc = pgm_if_parse_transport (network, AF_INET, &recv_gsr, 
        &recv_len, &send_gsr);
    assert (rc == 0);
    assert (recv_len == 1);

    //  If we are using UDP encapsulation update send_gsr & recv_gsr 
    //  structures. Note that send_gsr & recv_gsr has to be updated after 
    //  pgm_if_parse_transport call.
    if (udp_encapsulation) {

        //  Use the same port for UDP encapsulation.
        ((struct sockaddr_in*)&send_gsr.gsr_group)->sin_port = 
            g_htons (port_number);
	((struct sockaddr_in*)&recv_gsr.gsr_group)->sin_port = 
            g_htons (port_number);
    }

    rc = pgm_transport_create (&g_transport, &gsi, 0, port_number, &recv_gsr, 
        1, &send_gsr);
    errno_assert (rc == 0);

    //  Common parameters for receiver and sender.

    //  Set maximum transport protocol data unit size (TPDU).
    rc = pgm_transport_set_max_tpdu (g_transport, pgm_max_tpdu);
    assert (rc == 0);

    //  Set maximum number of network hops to cross.
    rc = pgm_transport_set_hops (g_transport, 16);
    assert (rc == 0);

    //  Receiver transport.
    if (receiver) {

        //  When using UDP-encapsulation enables socket address sharing via 
        //  SO_REUSEADDR to allow multiple applications to bind to the same 
        //  UDP port. 
        if (udp_encapsulation) {
            rc = pgm_transport_set_multicast_loop (g_transport, TRUE);
            assert (rc == 0);
        }

        //  Set transport->may_close_on_failure to true,
        //  after data los recvmsgv returns -1 errno set to ECONNRESET.
        rc = pgm_transport_set_close_on_failure (g_transport, TRUE);
        assert (rc == 0);

        //  Set transport->can_send_data = FALSE.
        //  Note that NAKs are still generated by the transport.
        rc = pgm_transport_set_recv_only (g_transport, false);
        assert (rc == 0);

        //  Set NAK transmit back-off interval [us].
        rc = pgm_transport_set_nak_bo_ivl (g_transport, 50*1000);
        assert (rc ==0);
    
        //  Set timeout before repeating NAK [us].
        rc = pgm_transport_set_nak_rpt_ivl (g_transport, 200*1000);
        assert (rc == 0);

        //  Set timeout for receiving RDATA.
        rc = pgm_transport_set_nak_rdata_ivl (g_transport, 200*1000);
        assert (rc == 0);

        //  Set retries for NAK without NCF/DATA (NAK_DATA_RETRIES).
        rc = pgm_transport_set_nak_data_retries (g_transport, 5);
        assert (rc == 0);

        //  Set retries for NCF after NAK (NAK_NCF_RETRIES).
        rc = pgm_transport_set_nak_ncf_retries (g_transport, 2);
        assert (rc == 0);

        //  Set timeout for removing a dead peer [us].
        rc = pgm_transport_set_peer_expiry (g_transport, 5*8192*1000);
        assert (rc == 0);

        //  Set expiration time of SPM Requests [us].
        rc = pgm_transport_set_spmr_expiry (g_transport, 25*1000);
        assert (rc == 0);

        if (pgm_window_size > 0) {
            //  Set receive window size in sequence numbers.
            rc = pgm_transport_set_rxw_sqns (g_transport, pgm_window_size);
            assert (rc == 0);

        } else {

            //  Set the size of the receive window size by max
            //  data rate in bytes per second.
            assert (pgm_max_rte > 0);
            rc = pgm_transport_set_rxw_max_rte (g_transport, pgm_max_rte);
            assert (rc ==0);

            //  Set receive window size in seconds. 
            assert (pgm_secs > 0);
            rc = pgm_transport_set_rxw_secs (g_transport, pgm_secs);
            assert (rc == 0);
        }

    //  Sender transport.
    } else {

        //  Set transport->can_recv = FALSE, waiting_pipe wont not be read.
        rc = pgm_transport_set_send_only (g_transport, TRUE);
        assert (rc == 0);

        int to_preallocate = 0;

        if (pgm_window_size > 0) {
            //  Set send window size in sequence numbers.
            rc = pgm_transport_set_txw_sqns (g_transport, pgm_window_size);
            assert (rc == 0);

            //  Preallocate full window.
            to_preallocate = pgm_window_size;

        } else {

            //  Set the size of the send window size by 
            //  data rate in bytes per second.
            assert (pgm_max_rte > 0);
            rc = pgm_transport_set_txw_max_rte (g_transport, pgm_max_rte);
            assert (rc ==0);

            //  Set send window size in seconds. 
            assert (pgm_secs > 0);
            rc = pgm_transport_set_txw_secs (g_transport, pgm_secs);
            assert (rc == 0);

            //  Preallocate full transmit window. For simplification always 
            //  worst case is used (40 bytes ipv6 header and 20 bytes UDP 
            //  encapsulation).
            to_preallocate = pgm_secs * pgm_max_rte / (pgm_max_tpdu - 40 - 20);
        }

        rc = pgm_transport_set_txw_preallocate (g_transport, to_preallocate);
        assert (rc == 0);

        zmq_log (1, "Preallocated %i slices in TX window. %s(%i)\n", 
            to_preallocate, __FILE__, __LINE__);

        //  Set interval of background SPM packets [us].
        rc = pgm_transport_set_ambient_spm (g_transport, 8192 * 1000);
        assert (rc == 0);

        //  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 (g_transport, spm_heartbeat, 
            G_N_ELEMENTS(spm_heartbeat));
        assert (rc == 0);
    }
    
    //  Bind a transport to the specified network devices.
    rc = pgm_transport_bind (g_transport);
    assert (rc == 0);

}
Exemplo n.º 2
0
static gboolean
on_startup (
	G_GNUC_UNUSED gpointer data
	)
{
	g_message ("startup.");
	g_message ("create transport.");

	pgm_gsi_t gsi;
	int e = pgm_create_md5_gsi (&gsi);
	g_assert (e == 0);

	struct group_source_req recv_gsr, send_gsr;
	gsize recv_len = 1;
	e = pgm_if_parse_transport (g_network, AF_UNSPEC, &recv_gsr, &recv_len, &send_gsr);
	g_assert (e == 0);
	g_assert (recv_len == 1);

	if (g_source[0]) {
		((struct sockaddr_in*)&recv_gsr.gsr_source)->sin_addr.s_addr = inet_addr(g_source);
	}

	if (g_udp_encap_port) {
		((struct sockaddr_in*)&send_gsr.gsr_group)->sin_port = g_htons (g_udp_encap_port);
		((struct sockaddr_in*)&recv_gsr.gsr_group)->sin_port = g_htons (g_udp_encap_port);
	}

	pgm_transport_list = NULL;
	e = pgm_transport_create (&g_transport, &gsi, 0, g_port, &recv_gsr, 1, &send_gsr);
	g_assert (e == 0);

	pgm_transport_set_recv_only (g_transport, FALSE);
	pgm_transport_set_max_tpdu (g_transport, g_max_tpdu);
	pgm_transport_set_rxw_sqns (g_transport, g_sqns);
	pgm_transport_set_multicast_loop (g_transport, g_multicast_loop);
	pgm_transport_set_hops (g_transport, 16);
	pgm_transport_set_peer_expiry (g_transport, pgm_secs(300));
	pgm_transport_set_spmr_expiry (g_transport, pgm_msecs(250));
	pgm_transport_set_nak_bo_ivl (g_transport, pgm_msecs(50));
	pgm_transport_set_nak_rpt_ivl (g_transport, pgm_secs(2));
	pgm_transport_set_nak_rdata_ivl (g_transport, pgm_secs(2));
	pgm_transport_set_nak_data_retries (g_transport, 50);
	pgm_transport_set_nak_ncf_retries (g_transport, 50);

	e = pgm_transport_bind (g_transport);
	if (e < 0) {
		if      (e == -1)
			g_critical ("pgm_transport_bind failed errno %i: \"%s\"", errno, strerror(errno));
		else if (e == -2)
			g_critical ("pgm_transport_bind failed h_errno %i: \"%s\"", h_errno, hstrerror(h_errno));
		else
			g_critical ("pgm_transport_bind failed e %i", e);
		g_main_loop_quit(g_loop);
		return FALSE;
	}
	g_assert (e == 0);

/* create receiver thread */
	GError* err;
	g_thread = g_thread_create_full (receiver_thread,
					g_transport,
					0,
					TRUE,
					TRUE,
					G_THREAD_PRIORITY_HIGH,
					&err);
	if (!g_thread) {
		g_critical ("g_thread_create_full failed errno %i: \"%s\"", err->code, err->message);
		g_main_loop_quit(g_loop);
		return FALSE;
	}

/* period timer to indicate some form of life */
// TODO: Gnome 2.14: replace with g_timeout_add_seconds()
	g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL);

	g_message ("startup complete.");
	return FALSE;
}