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); }
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; }
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); }
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); }
// 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; }
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; }
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; }
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; }
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; }
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"); }
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); }
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); }
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); }
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; }
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; }
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; }
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; }