Пример #1
0
END_TEST

/* 003: millisecond resolution should initiate millisecond fills.
 */

START_TEST (test_check_pass_003)
{
	pgm_rate_t rate;
	memset (&rate, 0, sizeof(rate));
	pgm_rate_create (&rate, 2*1010*1000, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
/* duplicate check at same time point */
	fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
/* advance time causing a millisecond fill to occur */
	mock_pgm_time_now += pgm_msecs(1);
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
/* advance time to fill bucket enough for only one packet */
	mock_pgm_time_now += pgm_usecs(500);
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
/* advance time to fill the bucket a little but not enough for one packet */
	mock_pgm_time_now += pgm_usecs(100);
	fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
/* advance time a lot, should be limited to millisecond fill rate */
	mock_pgm_time_now += pgm_secs(10);
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	pgm_rate_destroy (&rate);
}
Пример #2
0
static
struct pgm_sock_t*
generate_sock (void)
{
	const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, g_htons(1000) };
	struct pgm_sock_t* sock = g_new0 (struct pgm_sock_t, 1);
	memcpy (&sock->tsi, &tsi, sizeof(pgm_tsi_t));
	sock->is_bound = FALSE;
	sock->is_destroyed = FALSE;
	((struct sockaddr*)&sock->send_addr)->sa_family = AF_INET;
	((struct sockaddr_in*)&sock->send_addr)->sin_addr.s_addr = inet_addr ("127.0.0.2");
	((struct sockaddr*)&sock->send_gsr.gsr_group)->sa_family = AF_INET;
	((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_addr.s_addr = inet_addr ("239.192.0.1");
	sock->dport = g_htons(TEST_PORT);
	sock->window = g_malloc0 (sizeof(pgm_txw_t));
	sock->txw_sqns = TEST_TXW_SQNS;
	sock->max_tpdu = TEST_MAX_TPDU;
	sock->max_tsdu = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (FALSE, FALSE);
	sock->max_tsdu_fragment = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (TRUE, FALSE);
	sock->max_apdu = MIN(TEST_TXW_SQNS, PGM_MAX_FRAGMENTS) * sock->max_tsdu_fragment;
	sock->iphdr_len = sizeof(struct pgm_ip);
	sock->spm_heartbeat_interval = g_malloc0 (sizeof(guint) * (2+2));
	sock->spm_heartbeat_interval[0] = pgm_secs(1);
	pgm_spinlock_init (&sock->txw_spinlock);
	pgm_mutex_init (&sock->source_mutex);
	pgm_mutex_init (&sock->timer_mutex);
	pgm_rwlock_init (&sock->lock);
	return sock;
}
Пример #3
0
END_TEST

/* 002: assert that only one packet should pass through small bucket 
 */

START_TEST (test_check_pass_002)
{
	pgm_rate_t rate;
	memset (&rate, 0, sizeof(rate));
	pgm_rate_create (&rate, 2*900, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	pgm_rate_destroy (&rate);
}
Пример #4
0
END_TEST

/* target:
 *	bool
 *	pgm_rate_check (
 *		pgm_rate_t*		bucket,
 *		const size_t		data_size,
 *		const bool		is_nonblocking
 *	)
 *
 * 001: should use seconds resolution to allow 2 packets through then fault.
 */

START_TEST (test_check_pass_001)
{
	pgm_rate_t rate;
	memset (&rate, 0, sizeof(rate));
	pgm_rate_create (&rate, 2*1010, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed");
	pgm_rate_destroy (&rate);
}
Пример #5
0
//  Create, bind and connect PGM socket.
int zmq::pgm_socket_t::init (bool udp_encapsulation_, const char *network_)
{
    //  Can not open transport before destroying old one.
    zmq_assert (sock == NULL);
    zmq_assert (options.rate > 0);

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

    uint16_t port_number;
    struct pgm_addrinfo_t *res = NULL;
    sa_family_t sa_family;

    pgm_error_t *pgm_error = NULL;

    if (init_address(network_, &res, &port_number) < 0) {
        goto err_abort;
    }

    zmq_assert (res != NULL);

    //  Pick up detected IP family.
    sa_family = res->ai_send_addrs[0].gsr_group.ss_family;

    //  Create IP/PGM or UDP/PGM socket.
    if (udp_encapsulation_) {
        if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP,
              &pgm_error)) {

            //  Invalid parameters don't set pgm_error_t.
            zmq_assert (pgm_error != NULL);
            if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET && (
                  pgm_error->code != PGM_ERROR_BADF &&
                  pgm_error->code != PGM_ERROR_FAULT &&
                  pgm_error->code != PGM_ERROR_NOPROTOOPT &&
                  pgm_error->code != PGM_ERROR_FAILED))

                //  User, host, or network configuration or transient error.
                goto err_abort;

            //  Fatal OpenPGM internal error.
            zmq_assert (false);
        }

        //  All options are of data type int
        const int encapsulation_port = port_number;
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT,
                &encapsulation_port, sizeof (encapsulation_port)))
            goto err_abort;
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT,
                &encapsulation_port, sizeof (encapsulation_port)))
            goto err_abort;
    }
    else {
        if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM,
              &pgm_error)) {

            //  Invalid parameters don't set pgm_error_t.
            zmq_assert (pgm_error != NULL);
            if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET && (
                  pgm_error->code != PGM_ERROR_BADF &&
                  pgm_error->code != PGM_ERROR_FAULT &&
                  pgm_error->code != PGM_ERROR_NOPROTOOPT &&
                  pgm_error->code != PGM_ERROR_FAILED))

                //  User, host, or network configuration or transient error.
                goto err_abort;

            //  Fatal OpenPGM internal error.
            zmq_assert (false);
        }
    }

    {
		const int rcvbuf = (int) options.rcvbuf;
		if (rcvbuf) {
		    if (!pgm_setsockopt (sock, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
		          sizeof (rcvbuf)))
		        goto err_abort;
		}

		const int sndbuf = (int) options.sndbuf;
		if (sndbuf) {
		    if (!pgm_setsockopt (sock, SOL_SOCKET, SO_SNDBUF, &sndbuf,
		          sizeof (sndbuf)))
		        goto err_abort;
		}

		const int max_tpdu = (int) pgm_max_tpdu;
		if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_MTU, &max_tpdu,
		      sizeof (max_tpdu)))
		    goto err_abort;
    }

    if (receiver) {
        const int recv_only        = 1,
                  rxw_max_tpdu     = (int) pgm_max_tpdu,
                  rxw_sqns         = compute_sqns (rxw_max_tpdu),
                  peer_expiry      = pgm_secs (300),
                  spmr_expiry      = pgm_msecs (25),
                  nak_bo_ivl       = pgm_msecs (50),
                  nak_rpt_ivl      = pgm_msecs (200),
                  nak_rdata_ivl    = pgm_msecs (200),
                  nak_data_retries = 50,
                  nak_ncf_retries  = 50;

        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only,
                sizeof (recv_only)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_RXW_SQNS, &rxw_sqns,
                sizeof (rxw_sqns)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry,
                sizeof (peer_expiry)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry,
                sizeof (spmr_expiry)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl,
                sizeof (nak_bo_ivl)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl,
                sizeof (nak_rpt_ivl)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL,
                &nak_rdata_ivl, sizeof (nak_rdata_ivl)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES,
                &nak_data_retries, sizeof (nak_data_retries)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES,
                &nak_ncf_retries, sizeof (nak_ncf_retries)))
            goto err_abort;
    }
    else {
        const int send_only        = 1,
                  max_rte      = (int) ((options.rate * 1000) / 8),
                  txw_max_tpdu     = (int) pgm_max_tpdu,
                  txw_sqns         = compute_sqns (txw_max_tpdu),
                  ambient_spm      = pgm_secs (30),
                  heartbeat_spm[]  = { pgm_msecs (100),
                                       pgm_msecs (100),
                                       pgm_msecs (100),
                                       pgm_msecs (100),
                                       pgm_msecs (1300),
                                       pgm_secs  (7),
                                       pgm_secs  (16),
                                       pgm_secs  (25),
                                       pgm_secs  (30) };

        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_ONLY,
                &send_only, sizeof (send_only)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_ODATA_MAX_RTE,
                &max_rte, sizeof (max_rte)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_SQNS,
                &txw_sqns, sizeof (txw_sqns)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_AMBIENT_SPM,
                &ambient_spm, sizeof (ambient_spm)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM,
                &heartbeat_spm, sizeof (heartbeat_spm)))
            goto err_abort;
    }

    //  PGM transport GSI.
    struct pgm_sockaddr_t addr;

    memset (&addr, 0, sizeof(addr));
    addr.sa_port = port_number;
    addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT;

    //  Create random GSI.
    uint32_t buf [2];
    buf [0] = generate_random ();
    buf [1] = generate_random ();
    if (!pgm_gsi_create_from_data (&addr.sa_addr.gsi, (uint8_t*) buf, 8))
        goto err_abort;


    //  Bind a transport to the specified network devices.
    struct pgm_interface_req_t if_req;
    memset (&if_req, 0, sizeof(if_req));
    if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface;
    if_req.ir_scope_id  = 0;
    if (AF_INET6 == sa_family) {
        struct sockaddr_in6 sa6;
        memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof (sa6));
        if_req.ir_scope_id = sa6.sin6_scope_id;
    }
    if (!pgm_bind3 (sock, &addr, sizeof (addr), &if_req, sizeof (if_req),
          &if_req, sizeof (if_req), &pgm_error)) {

        //  Invalid parameters don't set pgm_error_t.
        zmq_assert (pgm_error != NULL);
        if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
             pgm_error->domain == PGM_ERROR_DOMAIN_IF) && (
             pgm_error->code != PGM_ERROR_INVAL &&
             pgm_error->code != PGM_ERROR_BADF &&
             pgm_error->code != PGM_ERROR_FAULT))

            //  User, host, or network configuration or transient error.
            goto err_abort;

        //  Fatal OpenPGM internal error.
        zmq_assert (false);
    }

    //  Join IP multicast groups.
    for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) {
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_JOIN_GROUP,
              &res->ai_recv_addrs [i], sizeof (struct group_req)))
            goto err_abort;
    }
    if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_GROUP,
          &res->ai_send_addrs [0], sizeof (struct group_req)))
        goto err_abort;

    pgm_freeaddrinfo (res);
    res = NULL;

    //  Set IP level parameters.
    {
		// Multicast loopback disabled by default
		const int multicast_loop = 0;
		if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_LOOP,
		      &multicast_loop, sizeof (multicast_loop)))
		    goto err_abort;

		const int multicast_hops = options.multicast_hops;
		if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_HOPS,
		        &multicast_hops, sizeof (multicast_hops)))
		    goto err_abort;

		//  Expedited Forwarding PHB for network elements, no ECN.
		//  Ignore return value due to varied runtime support.
		const int dscp = 0x2e << 2;
		if (AF_INET6 != sa_family)
		    pgm_setsockopt (sock, IPPROTO_PGM, PGM_TOS,
		       &dscp, sizeof (dscp));

		const int nonblocking = 1;
		if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_NOBLOCK,
		      &nonblocking, sizeof (nonblocking)))
		    goto err_abort;
    }

    //  Connect PGM transport to start state machine.
    if (!pgm_connect (sock, &pgm_error)) {

        //  Invalid parameters don't set pgm_error_t.
        zmq_assert (pgm_error != NULL);
        goto err_abort;
    }

    //  For receiver transport preallocate pgm_msgv array.
    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);
        alloc_assert (pgm_msgv);
    }

    return 0;

err_abort:
    if (sock != NULL) {
        pgm_close (sock, FALSE);
        sock = NULL;
    }
    if (res != NULL) {
        pgm_freeaddrinfo (res);
        res = NULL;
    }
    if (pgm_error != NULL) {
        pgm_error_free (pgm_error);
        pgm_error = NULL;
    }
    errno = EINVAL;
    return -1;
}
Пример #6
0
pgm_sock_t* PgmConnector::createPgmSocket (const SockAddr& sockaddr)
{
	struct pgm_addrinfo_t* res = NULL;
	pgm_sock_t* sock;
	pgm_error_t* pgm_err = NULL;
	sa_family_t sa_family = AF_UNSPEC;

    string localaddr;
    ErrorCode ec;
    if (!SocketHelper::getLocalIP(localaddr, &ec))
    {
        LOG(error, "getLocalIP " << ec);
        return NULL;
    }
    string pgm_addr = localaddr + ";" + sockaddr.getAddr();
    int udp_encap_port = sockaddr.getPort();

/* parse network parameter into PGM socket address structure */
	if (!pgm_getaddrinfo (pgm_addr.data(), NULL, &res, &pgm_err)) {
		fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message);
		FREE_SOCK_VARS();
            return NULL;
	} 

	sa_family = res->ai_send_addrs[0].gsr_group.ss_family;

	if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) {
	    fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message);
	    FREE_SOCK_VARS();
            return NULL;
	}
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port));

	/* Use RFC 2113 tagging for PGM Router Assist */
	const int no_router_assist = 0;
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist));

/*Android shell程序需要root才可以访问网络*/
#if !defined( __ANDROID_API__ )
	pgm_drop_superuser();
#endif
 int		max_tpdu = 1500;
 int		max_rte = 400*1000;		/* very conservative rate, 2.5mb/s */
 int		sqns = 100;

/* set PGM parameters */
	const int send_only = 1,
		  ambient_spm = pgm_secs (30),
		  heartbeat_spm[] = { pgm_msecs (100),
				      pgm_msecs (100),
                      pgm_msecs (100),
				      pgm_msecs (100),
				      pgm_msecs (1300),
				      pgm_secs  (7),
				      pgm_secs  (16),
				      pgm_secs  (25),
				      pgm_secs  (30) };

	pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_only, sizeof(send_only));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_MTU, &max_tpdu, sizeof(max_tpdu));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_SQNS, &sqns, sizeof(sqns));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_MAX_RTE, &max_rte, sizeof(max_rte));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm));

/* create global session identifier */
	struct pgm_sockaddr_t addr;
	memset (&addr, 0, sizeof(addr));
    const int dest_port = 0;
	addr.sa_port =  dest_port ? dest_port : DEFAULT_DATA_DESTINATION_PORT;
	addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT;
	if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) {
		fprintf (stderr, "Creating GSI: %s\n", pgm_err->message);
		FREE_SOCK_VARS();
            return NULL;
	}

/* assign socket to specified address */
	struct pgm_interface_req_t if_req;
	memset (&if_req, 0, sizeof(if_req));
	if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface;
	if_req.ir_scope_id  = 0;
	if (AF_INET6 == sa_family) {
		struct sockaddr_in6 sa6;
		memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6));
		if_req.ir_scope_id = sa6.sin6_scope_id;
	}
	if (!pgm_bind3 (sock,
			&addr, sizeof(addr),
			&if_req, sizeof(if_req),	/* tx interface */
			&if_req, sizeof(if_req),	/* rx interface */
			&pgm_err))
	{
		fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message);
		FREE_SOCK_VARS();
            return NULL;
	}

/* join IP multicast groups */
	unsigned i;
	for (i = 0; i < res->ai_recv_addrs_len; i++)
		pgm_setsockopt (sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req));
	pgm_freeaddrinfo (res);

/* set IP parameters */
	const int blocking = 1,
		  multicast_loop = 1,
		  multicast_hops = 16,
		  dscp = 0x2e << 2;		/* Expedited Forwarding PHB for network elements, no ECN. */

	pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops));
	if (AF_INET6 != sa_family)
		pgm_setsockopt (sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_NOBLOCK, &blocking, sizeof(blocking));

	if (!pgm_connect (sock, &pgm_err)) {
		fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message);
		FREE_SOCK_VARS();
            return NULL;
	}

    pthread_t tid;
    pthread_create(&tid, NULL, nakRoutine, sock);
	return sock;
}
Пример #7
0
static gboolean
on_startup (void)
{
	struct pgm_transport_info_t* res = NULL;
	pgm_error_t* pgm_err = NULL;

	g_message ("startup.");
	g_message ("create transport.");

/* parse network parameter into transport address structure */
	char network[1024];
	sprintf (network, "%s", g_network);
	if (!pgm_if_get_transport_info (network, NULL, &res, &pgm_err)) {
		g_error ("parsing network parameter: %s", pgm_err->message);
		pgm_error_free (pgm_err);
		return FALSE;
	}
/* create global session identifier */
	if (!pgm_gsi_create_from_hostname (&res->ti_gsi, &pgm_err)) {
		g_error ("creating GSI: %s", pgm_err->message);
		pgm_error_free (pgm_err);
		pgm_if_free_transport_info (res);
		return FALSE;
	}
	if (g_udp_encap_port) {
		res->ti_udp_encap_ucast_port = g_udp_encap_port;
		res->ti_udp_encap_mcast_port = g_udp_encap_port;
	}
	if (g_port)
		res->ti_dport = g_port;
	if (!pgm_transport_create (&g_transport, res, &pgm_err)) {
		g_error ("creating transport: %s", pgm_err->message);
		pgm_error_free (pgm_err);
		pgm_if_free_transport_info (res);
		return FALSE;
	}
	pgm_if_free_transport_info (res);

/* set PGM parameters */
	pgm_transport_set_nonblocking (g_transport, TRUE);
	pgm_transport_set_recv_only (g_transport, TRUE, FALSE);
	pgm_transport_set_max_tpdu (g_transport, g_max_tpdu);
	pgm_transport_set_rxw_sqns (g_transport, g_sqns);
	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);

/* assign transport to specified address */
	if (!pgm_transport_bind (g_transport, &pgm_err)) {
		g_error ("binding transport: %s", pgm_err->message);
		pgm_error_free (pgm_err);
		pgm_transport_destroy (g_transport, FALSE);
		g_transport = NULL;
		return FALSE;
	}

	g_message ("startup complete.");
	return TRUE;
}
Пример #8
0
PGM_GNUC_INTERNAL
bool
pgm_rate_check2 (
	pgm_rate_t*		major_bucket,
	pgm_rate_t*		minor_bucket,
	const size_t		data_size,
	const bool		is_nonblocking
	)
{
	int64_t new_major_limit, new_minor_limit;
	pgm_time_t now;

/* pre-conditions */
	pgm_assert (NULL != major_bucket);
	pgm_assert (NULL != minor_bucket);
	pgm_assert (data_size > 0);

	if (0 == major_bucket->rate_per_sec && 0 == minor_bucket->rate_per_sec)
		return TRUE;

	if (0 != major_bucket->rate_per_sec)
	{
		pgm_spinlock_lock (&major_bucket->spinlock);
		now = pgm_time_update_now();

		if (major_bucket->rate_per_msec)
		{
			const pgm_time_t time_since_last_rate_check = now - major_bucket->last_rate_check;
			if (time_since_last_rate_check > pgm_msecs(1)) 
				new_major_limit = major_bucket->rate_per_msec;
			else {
				new_major_limit = major_bucket->rate_limit + ((major_bucket->rate_per_msec * time_since_last_rate_check) / 1000UL);
				if (new_major_limit > major_bucket->rate_per_msec)
					new_major_limit = major_bucket->rate_per_msec;
			}
		}
		else
		{
			const pgm_time_t time_since_last_rate_check = now - major_bucket->last_rate_check;
			if (time_since_last_rate_check > pgm_secs(1)) 
				new_major_limit = major_bucket->rate_per_sec;
			else {
				new_major_limit = major_bucket->rate_limit + ((major_bucket->rate_per_sec * time_since_last_rate_check) / 1000000UL);
				if (new_major_limit > major_bucket->rate_per_sec)
					new_major_limit = major_bucket->rate_per_sec;
			}
		}

		new_major_limit -= ( major_bucket->iphdr_len + data_size );
		if (is_nonblocking && new_major_limit < 0) {
			pgm_spinlock_unlock (&major_bucket->spinlock);
			return FALSE;
		}

		if (new_major_limit < 0) {
			const pgm_time_t wait_start = now;
			ssize_t sleep_amount;
			do {
				pgm_thread_yield();
				now = pgm_time_update_now();
				sleep_amount = (ssize_t)pgm_to_secs (major_bucket->rate_per_sec * (now - wait_start));
			} while (sleep_amount + new_major_limit < 0);
			new_major_limit += sleep_amount;
		} 
	}
	else
	{
/* ensure we have a timestamp */
		now = pgm_time_update_now();
	}

	if (0 != minor_bucket->rate_per_sec)
	{
		if (minor_bucket->rate_per_msec)
		{
			const pgm_time_t time_since_last_rate_check = now - minor_bucket->last_rate_check;
			if (time_since_last_rate_check > pgm_msecs(1)) 
				new_minor_limit = minor_bucket->rate_per_msec;
			else {
				new_minor_limit = minor_bucket->rate_limit + ((minor_bucket->rate_per_msec * time_since_last_rate_check) / 1000UL);
				if (new_minor_limit > minor_bucket->rate_per_msec)
					new_minor_limit = minor_bucket->rate_per_msec;
			}
		}
		else
		{
			const pgm_time_t time_since_last_rate_check = now - minor_bucket->last_rate_check;
			if (time_since_last_rate_check > pgm_secs(1)) 
				new_minor_limit = minor_bucket->rate_per_sec;
			else {
				new_minor_limit = minor_bucket->rate_limit + ((minor_bucket->rate_per_sec * time_since_last_rate_check) / 1000000UL);
				if (new_minor_limit > minor_bucket->rate_per_sec)
					new_minor_limit = minor_bucket->rate_per_sec;
			}
		}

		new_minor_limit -= ( minor_bucket->iphdr_len + data_size );
		if (is_nonblocking && new_minor_limit < 0) {
			if (0 != major_bucket->rate_per_sec)
				pgm_spinlock_unlock (&major_bucket->spinlock);
			return FALSE;
		}

/* commit new rate limit */
		minor_bucket->rate_limit = new_minor_limit;
		minor_bucket->last_rate_check = now;
	}

	if (0 != major_bucket->rate_per_sec) {
		major_bucket->rate_limit = new_major_limit;
		major_bucket->last_rate_check = now;
		pgm_spinlock_unlock (&major_bucket->spinlock);
	}

/* sleep on minor bucket outside of lock */
	if (minor_bucket->rate_limit < 0) {
		ssize_t sleep_amount;
		do {
			pgm_thread_yield();
			now = pgm_time_update_now();
			sleep_amount = (ssize_t)pgm_to_secs (minor_bucket->rate_per_sec * (now - minor_bucket->last_rate_check));
		} while (sleep_amount + minor_bucket->rate_limit < 0);
		minor_bucket->rate_limit += sleep_amount;
		minor_bucket->last_rate_check = now;
	} 

	return TRUE;
}
Пример #9
0
PGM_GNUC_INTERNAL
bool
pgm_rate_check (
	pgm_rate_t*		bucket,
	const size_t		data_size,
	const bool		is_nonblocking
	)
{
	int64_t new_rate_limit;

/* pre-conditions */
	pgm_assert (NULL != bucket);
	pgm_assert (data_size > 0);

	if (0 == bucket->rate_per_sec)
		return TRUE;

	pgm_spinlock_lock (&bucket->spinlock);
	pgm_time_t now = pgm_time_update_now();

	if (bucket->rate_per_msec)
	{
		const pgm_time_t time_since_last_rate_check = now - bucket->last_rate_check;
		if (time_since_last_rate_check > pgm_msecs(1)) 
			new_rate_limit = bucket->rate_per_msec;
		else {
			new_rate_limit = bucket->rate_limit + ((bucket->rate_per_msec * time_since_last_rate_check) / 1000UL);
			if (new_rate_limit > bucket->rate_per_msec)
				new_rate_limit = bucket->rate_per_msec;
		}
	}
	else
	{
		const pgm_time_t time_since_last_rate_check = now - bucket->last_rate_check;
		if (time_since_last_rate_check > pgm_secs(1)) 
			new_rate_limit = bucket->rate_per_sec;
		else {
			new_rate_limit = bucket->rate_limit + ((bucket->rate_per_sec * time_since_last_rate_check) / 1000000UL);
			if (new_rate_limit > bucket->rate_per_sec)
				new_rate_limit = bucket->rate_per_sec;
		}
	}

	new_rate_limit -= ( bucket->iphdr_len + data_size );
	if (is_nonblocking && new_rate_limit < 0) {
		pgm_spinlock_unlock (&bucket->spinlock);
		return FALSE;
	}

	bucket->rate_limit = new_rate_limit;
	bucket->last_rate_check = now;
	if (bucket->rate_limit < 0) {
		ssize_t sleep_amount;
		do {
			pgm_thread_yield();
			now = pgm_time_update_now();
			sleep_amount = (ssize_t)pgm_to_secs (bucket->rate_per_sec * (now - bucket->last_rate_check));
		} while (sleep_amount + bucket->rate_limit < 0);
		bucket->rate_limit += sleep_amount;
		bucket->last_rate_check = now;
	} 
	pgm_spinlock_unlock (&bucket->spinlock);
	return TRUE;
}
Пример #10
0
Файл: app.c Проект: g2p/libpgm
static
void
session_set_fec (
	char*		session_name,
	guint		block_size,
	guint		group_size
	)
{
/* check that session exists */
	struct app_session* sess = g_hash_table_lookup (g_sessions, session_name);
	if (sess == NULL) {
		printf ("FAILED: session '%s' not found\n", session_name);
		return;
	}

	if (block_size > UINT8_MAX ||
	    group_size > UINT8_MAX)
	{
		puts ("FAILED: value out of bounds");
		return;
	}

	const struct pgm_fecinfo_t fecinfo = {
		.block_size			= block_size,
		.proactive_packets		= 0,
		.group_size			= group_size,
		.ondemand_parity_enabled	= TRUE,
		.var_pktlen_enabled		= TRUE
	};
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)))
		printf ("FAILED: set FEC = RS(%d, %d)\n", block_size, group_size);
	else
		puts ("READY");
}

static
void
session_bind (
	char*		session_name
	)
{
	pgm_error_t* pgm_err = NULL;

/* check that session exists */
	struct app_session* sess = g_hash_table_lookup (g_sessions, session_name);
	if (sess == NULL) {
		printf ("FAILED: session '%s' not found\n", session_name);
		return;
	}

/* Use RFC 2113 tagging for PGM Router Assist */
	const int no_router_assist = 0;
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)))
		puts ("FAILED: disable IP_ROUTER_ALERT");

/* set PGM parameters */
	const int send_and_receive = 0,
		  active = 0,
		  mtu = g_max_tpdu,
		  txw_sqns = g_sqns,
		  rxw_sqns = g_sqns,
		  ambient_spm = pgm_secs (30),
		  heartbeat_spm[] = { pgm_msecs (100),
				      pgm_msecs (100),
                                      pgm_msecs (100),
				      pgm_msecs (100),
				      pgm_msecs (1300),
				      pgm_secs  (7),
				      pgm_secs  (16),
				      pgm_secs  (25),
				      pgm_secs  (30) },
		  peer_expiry = pgm_secs (300),
		  spmr_expiry = pgm_msecs (250),
		  nak_bo_ivl = pgm_msecs (50),
		  nak_rpt_ivl = pgm_secs (2),
		  nak_rdata_ivl = pgm_secs (2),
		  nak_data_retries = 50,
		  nak_ncf_retries = 50;

	g_assert (G_N_ELEMENTS(heartbeat_spm) > 0);

	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_and_receive, sizeof(send_and_receive)))
		puts ("FAILED: set bi-directional transport");
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_RECV_ONLY, &send_and_receive, sizeof(send_and_receive)))
		puts ("FAILED: set bi-directional transport");
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_PASSIVE, &active, sizeof(active)))
		puts ("FAILED: set active transport");
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_MTU, &mtu, sizeof(mtu)))
		printf ("FAILED: set MAX_TPDU = %d bytes\n", mtu);
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_TXW_SQNS, &txw_sqns, sizeof(txw_sqns)))
		printf ("FAILED: set TXW_SQNS = %d\n", txw_sqns);
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_RXW_SQNS, &rxw_sqns, sizeof(rxw_sqns)))
		printf ("FAILED: set RXW_SQNS = %d\n", rxw_sqns);
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)))
		printf ("FAILED: set AMBIENT_SPM = %ds\n", (int)pgm_to_secs (ambient_spm));
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)))
	{
		char buffer[1024];
		sprintf (buffer, "%d", heartbeat_spm[0]);
		for (unsigned i = 1; i < G_N_ELEMENTS(heartbeat_spm); i++) {
			char t[1024];
			sprintf (t, ", %d", heartbeat_spm[i]);
			strcat (buffer, t);
		}
		printf ("FAILED: set HEARTBEAT_SPM = { %s }\n", buffer);
	}
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)))
		printf ("FAILED: set PEER_EXPIRY = %ds\n",(int) pgm_to_secs (peer_expiry));
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)))
		printf ("FAILED: set SPMR_EXPIRY = %dms\n", (int)pgm_to_msecs (spmr_expiry));
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)))
		printf ("FAILED: set NAK_BO_IVL = %dms\n", (int)pgm_to_msecs (nak_bo_ivl));
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)))
		printf ("FAILED: set NAK_RPT_IVL = %dms\n", (int)pgm_to_msecs (nak_rpt_ivl));
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)))
		printf ("FAILED: set NAK_RDATA_IVL = %dms\n", (int)pgm_to_msecs (nak_rdata_ivl));
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)))
		printf ("FAILED: set NAK_DATA_RETRIES = %d\n", nak_data_retries);
	if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)))
		printf ("FAILED: set NAK_NCF_RETRIES = %d\n", nak_ncf_retries);

/* create global session identifier */
	struct pgm_sockaddr_t addr;
	memset (&addr, 0, sizeof(addr));
	addr.sa_port = g_port;
	addr.sa_addr.sport = 0;
	if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) {
		printf ("FAILED: pgm_gsi_create_from_hostname(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)");
	}

{
	char buffer[1024];
	pgm_tsi_print_r (&addr.sa_addr, buffer, sizeof(buffer));
	printf ("pgm_bind (sock:%p addr:{port:%d tsi:%s} err:%p)\n",
		(gpointer)sess->sock,
		addr.sa_port, buffer,
		(gpointer)&pgm_err);
}
	if (!pgm_bind (sess->sock, &addr, sizeof(addr), &pgm_err)) {
		printf ("FAILED: pgm_bind(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)");
		pgm_error_free (pgm_err);
	} else 
		puts ("READY");
}
Пример #11
0
END_TEST

/* 003: millisecond resolution should initiate millisecond fills.
 */

START_TEST (test_check2_pass_003)
{
	pgm_rate_t major, minor;

/** major-only **/
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 2*1010*1000, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
/* duplicate check at same time point */
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
/* advance time causing a millisecond fill to occur */
	mock_pgm_time_now += pgm_msecs(1);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
/* advance time to fill bucket enough for only one packet */
	mock_pgm_time_now += pgm_usecs(500);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
/* advance time to fill the bucket a little but not enough for one packet */
	mock_pgm_time_now += pgm_usecs(100);
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
/* advance time a lot, should be limited to millisecond fill rate */
	mock_pgm_time_now += pgm_secs(10);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	pgm_rate_destroy (&major);

/** minor-only **/
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&minor, 2*1010*1000, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
/* duplicate check at same time point */
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
/* advance time causing a millisecond fill to occur */
	mock_pgm_time_now += pgm_msecs(1);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
/* advance time to fill bucket enough for only one packet */
	mock_pgm_time_now += pgm_usecs(500);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
/* advance time to fill the bucket a little but not enough for one packet */
	mock_pgm_time_now += pgm_usecs(100);
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
/* advance time a lot, should be limited to millisecond fill rate */
	mock_pgm_time_now += pgm_secs(10);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	pgm_rate_destroy (&minor);

/** major with large minor **/
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 2*1010*1000, 10, 1500);
	pgm_rate_create (&minor, 999*1010*1000, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
/* duplicate check at same time point */
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
/* advance time causing a millisecond fill to occur */
	mock_pgm_time_now += pgm_msecs(1);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
/* advance time to fill bucket enough for only one packet */
	mock_pgm_time_now += pgm_usecs(500);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
/* advance time to fill the bucket a little but not enough for one packet */
	mock_pgm_time_now += pgm_usecs(100);
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
/* advance time a lot, should be limited to millisecond fill rate */
	mock_pgm_time_now += pgm_secs(10);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	pgm_rate_destroy (&major);
	pgm_rate_destroy (&minor);

/** minor with large major **/
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 999*1010*1000, 10, 1500);
	pgm_rate_create (&minor, 2*1010*1000, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
/* duplicate check at same time point */
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
/* advance time causing a millisecond fill to occur */
	mock_pgm_time_now += pgm_msecs(1);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:>>2 failed");
/* advance time to fill bucket enough for only one packet */
	mock_pgm_time_now += pgm_usecs(500);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
/* advance time to fill the bucket a little but not enough for one packet */
	mock_pgm_time_now += pgm_usecs(100);
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
/* advance time a lot, should be limited to millisecond fill rate */
	mock_pgm_time_now += pgm_secs(10);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	pgm_rate_destroy (&major);
	pgm_rate_destroy (&minor);

/** major and minor **/
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 2*1010*1000, 10, 1500);
	pgm_rate_create (&minor, 2*1010*1000, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
/* duplicate check at same time point */
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
/* advance time causing a millisecond fill to occur */
	mock_pgm_time_now += pgm_msecs(1);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
/* advance time to fill bucket enough for only one packet */
	mock_pgm_time_now += pgm_usecs(500);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
/* advance time to fill the bucket a little but not enough for one packet */
	mock_pgm_time_now += pgm_usecs(100);
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
/* advance time a lot, should be limited to millisecond fill rate */
	mock_pgm_time_now += pgm_secs(10);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	pgm_rate_destroy (&major);
	pgm_rate_destroy (&minor);

}
Пример #12
0
END_TEST

/* 002: assert that only one packet should pass through small bucket 
 */

START_TEST (test_check2_pass_002)
{
	pgm_rate_t major, minor;

/** major-only **/
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 2*900, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major failed");
	pgm_rate_destroy (&major);

/* minor-only */
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&minor, 2*900, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	pgm_rate_destroy (&minor);

/* major with large minor */
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 2*900, 10, 1500);
	pgm_rate_create (&minor, 999*1010, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	pgm_rate_destroy (&major);
	pgm_rate_destroy (&minor);

/* minor with large major */
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 999*1010, 10, 1500);
	pgm_rate_create (&minor, 2*900, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	pgm_rate_destroy (&major);
	pgm_rate_destroy (&minor);

/* major and minor */
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 2*900, 10, 1500);
	pgm_rate_create (&minor, 2*900, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	pgm_rate_destroy (&major);
	pgm_rate_destroy (&minor);
}
Пример #13
0
END_TEST

/* target:
 *	bool
 *	pgm_rate_check2 (
 *		pgm_rate_t*		major_bucket,
 *		pgm_rate_t*		minor_bucket,
 *		const size_t		data_size,
 *		const bool		is_nonblocking
 *	)
 *
 * 001: should use seconds resolution to allow 2 packets through then fault.
 */

START_TEST (test_check2_pass_001)
{
	pgm_rate_t major, minor;

/* major-only */
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 2*1010, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major#1 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major#2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:major#3 failed");
	pgm_rate_destroy (&major);

/* minor-only */
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&minor, 2*1010, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:minor failed");
	pgm_rate_destroy (&minor);

/* major with large minor */
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 2*1010, 10, 1500);
	pgm_rate_create (&minor, 999*1010, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1<2 failed");
	pgm_rate_destroy (&major);
	pgm_rate_destroy (&minor);

/* minor with large major */
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 999*1010, 10, 1500);
	pgm_rate_create (&minor, 2*1010, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1>2 failed");
	pgm_rate_destroy (&major);
	pgm_rate_destroy (&minor);

/* major and minor */
	memset (&major, 0, sizeof(major));
	memset (&minor, 0, sizeof(minor));
	mock_pgm_time_now = 1;
	pgm_rate_create (&major, 2*1010, 10, 1500);
	pgm_rate_create (&minor, 2*1010, 10, 1500);
	mock_pgm_time_now += pgm_secs(2);
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (TRUE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	fail_unless (FALSE == pgm_rate_check2 (&major, &minor, 1000, TRUE), "rate_check2:1=2 failed");
	pgm_rate_destroy (&major);
	pgm_rate_destroy (&minor);
}
Пример #14
0
static
gboolean
on_startup (
	G_GNUC_UNUSED gpointer data
	)
{
	struct pgm_addrinfo_t* res = NULL;
	pgm_error_t* pgm_err = NULL;
	sa_family_t sa_family = AF_UNSPEC;

	g_message ("startup.");

/* parse network parameter into transport address structure */
	if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) {
		g_error ("parsing network parameter: %s", pgm_err->message);
		goto err_abort;
	}

	sa_family = res->ai_send_addrs[0].gsr_group.ss_family;

	if (g_udp_encap_port) {
		g_message ("create PGM/UDP socket.");
		if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) {
			g_error ("socket: %s", pgm_err->message);
			goto err_abort;
		}
		pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port));
		pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port));
	} else {
		g_message ("create PGM/IP socket.");
		if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) {
			g_error ("socket: %s", pgm_err->message);
			goto err_abort;
		}
	}

/* Use RFC 2113 tagging for PGM Router Assist */
	const int no_router_assist = 0;
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist));

	pgm_drop_superuser();

/* set PGM parameters */
	const int recv_only = 1,
		  passive = 0,
		  peer_expiry = pgm_secs (300),
		  spmr_expiry = pgm_msecs (250),
		  nak_bo_ivl = pgm_msecs (50),
		  nak_rpt_ivl = pgm_secs (2),
		  nak_rdata_ivl = pgm_secs (2),
		  nak_data_retries = 50,
		  nak_ncf_retries = 50;

	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries));

/* create global session identifier */
	struct pgm_sockaddr_t addr;
	memset (&addr, 0, sizeof(addr));
	addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT;
	addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT;
	if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) {
		g_error ("creating GSI: %s", pgm_err->message);
		goto err_abort;
	}

/* assign socket to specified address */
	struct pgm_interface_req_t if_req;
	memset (&if_req, 0, sizeof(if_req));
	if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface;
	memcpy (&if_req.ir_address, &res->ai_send_addrs[0].gsr_addr, sizeof(struct sockaddr_storage));
	if (!pgm_bind3 (g_sock,
			&addr, sizeof(addr),
			&if_req, sizeof(if_req),	/* tx interface */
			&if_req, sizeof(if_req),	/* rx interface */
			&pgm_err))
	{
		g_error ("binding PGM socket: %s", pgm_err->message);
		goto err_abort;
	}

/* join IP multicast groups */
	for (unsigned i = 0; i < res->ai_recv_addrs_len; i++)
		pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct pgm_group_source_req));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct pgm_group_source_req));
	pgm_freeaddrinfo (res);

/* set IP parameters */
	const int nonblocking = 1,
		  multicast_loop = g_multicast_loop ? 1 : 0,
		  multicast_hops = 16,
		  dscp = 0x2e << 2;		/* Expedited Forwarding PHB for network elements, no ECN. */

	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops));
	if (AF_INET6 != sa_family)
		pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp));
	pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking));

	if (!pgm_connect (g_sock, &pgm_err)) {
		g_error ("connecting PGM socket: %s", pgm_err->message);
		goto err_abort;
	}

/* create receiver thread */
	GError* glib_err = NULL;
	g_thread = g_thread_create_full (receiver_thread,
					 g_sock,
					 0,
					 TRUE,
					 TRUE,
					 G_THREAD_PRIORITY_HIGH,
					 &glib_err);
	if (!g_thread) {
		g_error ("g_thread_create_full failed errno %i: \"%s\"", glib_err->code, glib_err->message);
		g_error_free (glib_err);
		goto err_abort;
	}

/* 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;

err_abort:
	if (NULL != g_sock) {
		pgm_close (g_sock, FALSE);
		g_sock = NULL;
	}
	if (NULL != res) {
		pgm_freeaddrinfo (res);
		res = NULL;
	}
	if (NULL != pgm_err) {
		pgm_error_free (pgm_err);
		pgm_err = NULL;
	}
	g_main_loop_quit (g_loop);
	return FALSE;
}
Пример #15
0
static
bool
on_startup (void)
{
	struct pgm_addrinfo_t* res = NULL;
	pgm_error_t* pgm_err = NULL;
	sa_family_t sa_family = AF_UNSPEC;

/* parse network parameter into PGM socket address structure */
	if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) {
		fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message);
		goto err_abort;
	}

	sa_family = res->ai_send_addrs[0].gsr_group.ss_family;

	if (udp_encap_port) {
		puts ("Create PGM/UDP socket.");
		if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) {
			fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message);
			goto err_abort;
		}
		pgm_setsockopt (sock, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port));
		pgm_setsockopt (sock, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port));
	} else {
		puts ("Create PGM/IP socket.");
		if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) {
			fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message);
			goto err_abort;
		}
	}

/* Use RFC 2113 tagging for PGM Router Assist */
	const int no_router_assist = 0;
	pgm_setsockopt (sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist));

	pgm_drop_superuser();

/* set PGM parameters */
	const int recv_only = 1,
		  passive = 0,
		  peer_expiry = pgm_secs (300),
		  spmr_expiry = pgm_msecs (250),
		  nak_bo_ivl = pgm_msecs (50),
		  nak_rpt_ivl = pgm_secs (2),
		  nak_rdata_ivl = pgm_secs (2),
		  nak_data_retries = 50,
		  nak_ncf_retries = 50;

	pgm_setsockopt (sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only));
	pgm_setsockopt (sock, PGM_PASSIVE, &passive, sizeof(passive));
	pgm_setsockopt (sock, PGM_MTU, &max_tpdu, sizeof(max_tpdu));
	pgm_setsockopt (sock, PGM_RXW_SQNS, &sqns, sizeof(sqns));
	pgm_setsockopt (sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry));
	pgm_setsockopt (sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry));
	pgm_setsockopt (sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl));
	pgm_setsockopt (sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl));
	pgm_setsockopt (sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl));
	pgm_setsockopt (sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries));
	pgm_setsockopt (sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries));
	if (use_fec) {
		struct pgm_fecinfo_t fecinfo;
		fecinfo.block_size		= rs_n;
		fecinfo.proactive_packets	= 0;
		fecinfo.group_size		= rs_k;
		fecinfo.ondemand_parity_enabled	= TRUE;
		fecinfo.var_pktlen_enabled	= FALSE;
		pgm_setsockopt (sock, PGM_USE_FEC, &fecinfo, sizeof(fecinfo));
	}

/* create global session identifier */
	struct pgm_sockaddr_t addr;
	memset (&addr, 0, sizeof(addr));
	addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT;
	addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT;
	if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) {
		fprintf (stderr, "Creating GSI: %s\n", pgm_err->message);
		goto err_abort;
	}

/* assign socket to specified address */
	if (!pgm_bind (sock, &addr, sizeof(addr), &pgm_err)) {
		fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message);
		goto err_abort;
	}

/* join IP multicast groups */
	for (unsigned i = 0; i < res->ai_recv_addrs_len; i++)
		pgm_setsockopt (sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req));
	pgm_setsockopt (sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req));
	pgm_freeaddrinfo (res);

/* set IP parameters */
	const int nonblocking = 1,
		  multicast_loop = use_multicast_loop ? 1 : 0,
		  multicast_hops = 16,
		  dscp = 0x2e << 2;		/* Expedited Forwarding PHB for network elements, no ECN. */

	pgm_setsockopt (sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop));
	pgm_setsockopt (sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops));
	pgm_setsockopt (sock, PGM_TOS, &dscp, sizeof(dscp));
	pgm_setsockopt (sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking));

	if (!pgm_connect (sock, &pgm_err)) {
		fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message);
		goto err_abort;
	}

	puts ("Startup complete.");
	return TRUE;

err_abort:
	if (NULL != sock) {
		pgm_close (sock, FALSE);
		sock = NULL;
	}
	if (NULL != res) {
		pgm_freeaddrinfo (res);
		res = NULL;
	}
	if (NULL != pgm_err) {
		pgm_error_free (pgm_err);
		pgm_err = NULL;
	}
	if (NULL != sock) {
		pgm_close (sock, FALSE);
		sock = NULL;
	}
	return FALSE;
}
Пример #16
0
static
bool
create_sock (void)
{
	struct pgm_addrinfo_t* res = NULL;
	pgm_error_t* pgm_err = NULL;
	sa_family_t sa_family = AF_UNSPEC;

/* parse network parameter into sock address structure */
	if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) {
		fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message);
		goto err_abort;
	} else {
		char network[1024];
                printf ("Network parameter: { %s }\n", pgm_addrinfo_to_string (res, network, sizeof (network)));
	}

	sa_family = res->ai_send_addrs[0].gsr_group.ss_family;

	puts ("Create PGM socket.");
	if (udp_encap_port) {
		if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) {
			fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message);
			goto err_abort;
		}
		pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port));
		pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port));
	} else {
		if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) {
			fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message);
			goto err_abort;
		}
	}

/* Use RFC 2113 tagging for PGM Router Assist */
	const int no_router_assist = 0;
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist));

	pgm_drop_superuser();

/* set PGM parameters */
	const int send_only = 1,
		  ambient_spm = pgm_secs (30),
		  heartbeat_spm[] = { pgm_msecs (100),
				      pgm_msecs (100),
                                      pgm_msecs (100),
				      pgm_msecs (100),
				      pgm_msecs (1300),
				      pgm_secs  (7),
				      pgm_secs  (16),
				      pgm_secs  (25),
				      pgm_secs  (30) };

	pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_only, sizeof(send_only));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_MTU, &max_tpdu, sizeof(max_tpdu));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_SQNS, &sqns, sizeof(sqns));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_MAX_RTE, &max_rte, sizeof(max_rte));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm));

#ifdef I_UNDERSTAND_PGMCC_AND_FEC_ARE_NOT_SUPPORTED
	if (use_pgmcc) {
		struct pgm_pgmccinfo_t pgmccinfo;
		pgmccinfo.ack_bo_ivl		= pgm_msecs (50);
		pgmccinfo.ack_c			= 75;
		pgmccinfo.ack_c_p		= 500;
		pgm_setsockopt (sock, IPPROTO_PGM, PGM_USE_PGMCC, &pgmccinfo, sizeof(pgmccinfo));
	}
	if (use_fec) {
		struct pgm_fecinfo_t fecinfo; 
		fecinfo.block_size		= rs_n;
		fecinfo.proactive_packets	= proactive_packets;
		fecinfo.group_size		= rs_k;
		fecinfo.ondemand_parity_enabled	= use_ondemand_parity;
		fecinfo.var_pktlen_enabled	= TRUE;
		pgm_setsockopt (sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo));
	}
#endif

/* create global session identifier */
	struct pgm_sockaddr_t addr;
	memset (&addr, 0, sizeof(addr));
	addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT;
	addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT;
	if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) {
		fprintf (stderr, "Creating GSI: %s\n", pgm_err->message);
		goto err_abort;
	}

/* assign socket to specified address */
	struct pgm_interface_req_t if_req;
	memset (&if_req, 0, sizeof(if_req));
	memcpy (&if_req.ir_address, &res->ai_send_addrs[0].gsr_addr, sizeof(struct sockaddr_storage));
	if (!pgm_bind3 (sock,
			&addr, sizeof(addr),
			&if_req, sizeof(if_req),        /* tx interface */
			&if_req, sizeof(if_req),        /* rx interface */
			&pgm_err))
	{
		fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message);
		goto err_abort;
	}

/* join IP multicast groups */
	for (unsigned i = 0; i < res->ai_recv_addrs_len; i++)
		pgm_setsockopt (sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct pgm_group_source_req));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct pgm_group_source_req));
	pgm_freeaddrinfo (res);

/* set IP parameters */
	const int nonblocking = 1,
		  multicast_loop = use_multicast_loop ? 1 : 0,
		  multicast_hops = 16,
		  dscp = 0x2e << 2;		/* Expedited Forwarding PHB for network elements, no ECN. */

	pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops));
	if (AF_INET6 != sa_family)
		pgm_setsockopt (sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp));
	pgm_setsockopt (sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking));

	if (!pgm_connect (sock, &pgm_err)) {
		fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message);
		goto err_abort;
	}

	return TRUE;

err_abort:
	if (NULL != sock) {
		pgm_close (sock, FALSE);
		sock = NULL;
	}
	if (NULL != res) {
		pgm_freeaddrinfo (res);
		res = NULL;
	}
	if (NULL != pgm_err) {
		pgm_error_free (pgm_err);
		pgm_err = NULL;
	}
	return FALSE;
}
Пример #17
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;
}