static void* nak_routine ( void* arg ) { /* dispatch loop */ pgm_sock_t* nak_sock = (pgm_sock_t*)arg; int efd = epoll_create (IP_MAX_MEMBERSHIPS); if (efd < 0) { fprintf (stderr, "epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); } int retval = pgm_epoll_ctl (nak_sock, efd, EPOLL_CTL_ADD, EPOLLIN); if (retval < 0) { fprintf (stderr, "pgm_epoll_ctl failed."); } struct epoll_event events[1]; /* wait for maximum 1 event */ do { struct timeval tv; int timeout; char buf[4064]; pgm_error_t* pgm_err = NULL; fprintf (stdout, "===========================L:%d\n", __LINE__); const int status = pgm_recv (nak_sock, buf, sizeof(buf), 0, NULL, &pgm_err); fprintf (stdout, "===========================L:%d\n", __LINE__); switch (status) { case PGM_IO_STATUS_TIMER_PENDING: { socklen_t optlen = sizeof (tv); pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); } goto block; case PGM_IO_STATUS_RATE_LIMITED: { socklen_t optlen = sizeof (tv); pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); } case PGM_IO_STATUS_WOULD_BLOCK: block: timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); break; default: if (pgm_err) { fprintf (stderr, "%s\n", pgm_err->message ? pgm_err->message : "(null)"); pgm_error_free (pgm_err); pgm_err = NULL; } if (PGM_IO_STATUS_ERROR == status) break; } } while (1); return NULL; }
static void *nak_routine(void *arg) { /* This thread makes sure we get the NAKs from the receivers */ pgm_sock_t *pgm_sock = (pgm_sock_t*)arg; pgm_error_t* pgm_err = NULL; int fds = 0; fd_set readfds; char recv_buf[PGMBUF_SIZE]; size_t bytes_read = 0; int run_receiver = m_run_receiver; while (run_receiver) { memset(&recv_buf, 0, PGMBUF_SIZE); bytes_read = 0; struct timeval tv; struct pgm_sockaddr_t from; socklen_t from_sz = sizeof(from); const int pgm_status = pgm_recvfrom(pgm_sock, recv_buf, PGMBUF_SIZE, MSG_DONTWAIT, &bytes_read, &from, &from_sz, &pgm_err); //PRINT_ERR("pgm_status: %d", pgm_status); switch (pgm_status) { case PGM_IO_STATUS_TIMER_PENDING: { socklen_t optlen = sizeof(tv); pgm_getsockopt (pgm_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); if (0 == (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000)) break; goto block; } case PGM_IO_STATUS_RATE_LIMITED: { socklen_t optlen = sizeof(tv); pgm_getsockopt (pgm_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); if (0 == (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000)) break; /* No accidental fallthrough! */ } block: case PGM_IO_STATUS_WOULD_BLOCK: FD_ZERO(&readfds); pgm_select_info(pgm_sock, &readfds, NULL, &fds); fds = select(fds, &readfds, NULL, NULL, pgm_status == PGM_IO_STATUS_WOULD_BLOCK ? NULL : &tv); break; default : if (pgm_err) { fprintf(stderr, "%s\n", pgm_err->message); pgm_error_free(pgm_err); pgm_err = NULL; } break; } pthread_mutex_lock(&m_pftp_mutex); run_receiver = m_run_receiver; pthread_mutex_unlock(&m_pftp_mutex); } pthread_exit(NULL); }
void *zmq_init (int io_threads_) { if (io_threads_ < 0) { errno = EINVAL; return NULL; } #if defined ZMQ_HAVE_OPENPGM // Init PGM transport. Ensure threading and timer are enabled. Find PGM // protocol ID. Note that if you want to use gettimeofday and sleep for // openPGM timing, set environment variables PGM_TIMER to "GTOD" and // PGM_SLEEP to "USLEEP". pgm_error_t *pgm_error = NULL; const bool ok = pgm_init (&pgm_error); if (ok != TRUE) { // Invalid parameters don't set pgm_error_t zmq_assert (pgm_error != NULL); if (pgm_error->domain == PGM_ERROR_DOMAIN_TIME && ( pgm_error->code == PGM_ERROR_FAILED)) { // Failed to access RTC or HPET device. pgm_error_free (pgm_error); errno = EINVAL; return NULL; } // PGM_ERROR_DOMAIN_ENGINE: WSAStartup errors or missing WSARecvMsg. zmq_assert (false); } #endif #ifdef ZMQ_HAVE_WINDOWS // Intialise Windows sockets. Note that WSAStartup can be called multiple // times given that WSACleanup will be called for each WSAStartup. // We do this before the ctx constructor since its embedded mailbox_t // object needs Winsock to be up and running. WORD version_requested = MAKEWORD (2, 2); WSADATA wsa_data; int rc = WSAStartup (version_requested, &wsa_data); zmq_assert (rc == 0); zmq_assert (LOBYTE (wsa_data.wVersion) == 2 && HIBYTE (wsa_data.wVersion) == 2); #endif // Create 0MQ context. zmq::ctx_t *ctx = new (std::nothrow) zmq::ctx_t ((uint32_t) io_threads_); alloc_assert (ctx); return (void*) ctx; }
int main ( int argc, char *argv[] ) { pgm_error_t* pgm_err = NULL; setlocale (LC_ALL, ""); if (!pgm_init (&pgm_err)) { fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); pgm_error_free (pgm_err); return EXIT_FAILURE; } pgm_sock_t* sock = NULL; const char* network = argv[1]; int udp_encap_port = 7510; int xxx = 0; char buf[4196]; memset(buf, 0, 4196); sock = create_sock(network, udp_encap_port); int p_status = pthread_create (&nak_thread, NULL, &nak_routine, sock); if ((sock != NULL) && (p_status == 0)) { do { sprintf(buf, "%d", xxx); const int status = pgm_send (sock, buf, 4196, NULL); if (PGM_IO_STATUS_NORMAL != status) { fprintf (stderr, "pgm_send() failed.\n"); } xxx ++; usleep(10*1000); } while(1); } /* cleanup */ if (sock) { pgm_close (sock, TRUE); sock = NULL; } pgm_shutdown(); return EXIT_SUCCESS; }
// Resolve PGM socket address. // network_ of the form <interface & multicast group decls>:<IP port> // e.g. eth0;239.192.0.1:7500 // link-local;224.250.0.1,224.250.0.2;224.250.0.3:8000 // ;[fe80::1%en0]:7500 int zmq::pgm_socket_t::init_address (const char *network_, struct pgm_addrinfo_t **res, uint16_t *port_number) { // Parse port number, start from end for IPv6 const char *port_delim = strrchr (network_, ':'); if (!port_delim) { errno = EINVAL; return -1; } *port_number = atoi (port_delim + 1); char network [256]; if (port_delim - network_ >= (int) sizeof (network) - 1) { errno = EINVAL; return -1; } memset (network, '\0', sizeof (network)); memcpy (network, network_, port_delim - network_); pgm_error_t *pgm_error = NULL; struct pgm_addrinfo_t hints; memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; if (!pgm_getaddrinfo (network, NULL, res, &pgm_error)) { // Invalid parameters don't set pgm_error_t. zmq_assert (pgm_error != NULL); if (pgm_error->domain == PGM_ERROR_DOMAIN_IF && // NB: cannot catch EAI_BADFLAGS. ( pgm_error->code != PGM_ERROR_SERVICE && pgm_error->code != PGM_ERROR_SOCKTNOSUPPORT)) { // User, host, or network configuration or transient error. pgm_error_free (pgm_error); errno = EINVAL; return -1; } // Fatal OpenPGM internal error. zmq_assert (false); } return 0; }
END_TEST /* target: * void * pgm_error_free ( * pgm_error_t* err * ) */ START_TEST (test_error_free_pass_001) { pgm_error_t* err = NULL; const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; const gint err_code = 100; pgm_set_error (&err, err_domain, err_code, "an error occurred."); fail_unless (NULL != err, "set_error failed"); pgm_error_free (err); }
bool zmq::initialize_network () { #if defined ZMQ_HAVE_OPENPGM // Init PGM transport. Ensure threading and timer are enabled. Find PGM // protocol ID. Note that if you want to use gettimeofday and sleep for // openPGM timing, set environment variables PGM_TIMER to "GTOD" and // PGM_SLEEP to "USLEEP". pgm_error_t *pgm_error = NULL; const bool ok = pgm_init (&pgm_error); if (ok != TRUE) { // Invalid parameters don't set pgm_error_t zmq_assert (pgm_error != NULL); if (pgm_error->domain == PGM_ERROR_DOMAIN_TIME && (pgm_error->code == PGM_ERROR_FAILED)) { // Failed to access RTC or HPET device. pgm_error_free (pgm_error); errno = EINVAL; return false; } // PGM_ERROR_DOMAIN_ENGINE: WSAStartup errors or missing WSARecvMsg. zmq_assert (false); } #endif #ifdef ZMQ_HAVE_WINDOWS // Intialise Windows sockets. Note that WSAStartup can be called multiple // times given that WSACleanup will be called for each WSAStartup. WORD version_requested = MAKEWORD (2, 2); WSADATA wsa_data; int rc = WSAStartup (version_requested, &wsa_data); zmq_assert (rc == 0); zmq_assert (LOBYTE (wsa_data.wVersion) == 2 && HIBYTE (wsa_data.wVersion) == 2); #endif return true; }
void *zmq_init (int io_threads_) { if (io_threads_ < 0) { errno = EINVAL; return NULL; } #if defined ZMQ_HAVE_OPENPGM // Init PGM transport. Ensure threading and timer are enabled. Find PGM // protocol ID. Note that if you want to use gettimeofday and sleep for // openPGM timing, set environment variables PGM_TIMER to "GTOD" and // PGM_SLEEP to "USLEEP". pgm_error_t *pgm_error = NULL; const bool rc = pgm_init (&pgm_error); if (rc != TRUE) { // Invalid parameters don't set pgm_error_t zmq_assert (pgm_error != NULL); if (pgm_error->domain == PGM_ERROR_DOMAIN_TIME && ( pgm_error->code == PGM_ERROR_FAILED)) { // Failed to access RTC or HPET device. pgm_error_free (pgm_error); errno = EINVAL; return NULL; } // PGM_ERROR_DOMAIN_ENGINE: WSAStartup errors or missing WSARecvMsg. zmq_assert (false); } #endif // Create 0MQ context. zmq::ctx_t *ctx = new (std::nothrow) zmq::ctx_t ((uint32_t) io_threads_); zmq_assert (ctx); return (void*) ctx; }
static void session_create ( char* session_name ) { pgm_error_t* pgm_err = NULL; /* check for duplicate */ struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); if (sess != NULL) { printf ("FAILED: duplicate session name '%s'\n", session_name); return; } /* create new and fill in bits */ sess = g_new0(struct app_session, 1); sess->name = g_memdup (session_name, strlen(session_name)+1); if (!pgm_socket (&sess->sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { printf ("FAILED: pgm_socket(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); pgm_error_free (pgm_err); goto err_free; } /* success */ g_hash_table_insert (g_sessions, sess->name, sess); printf ("created new session \"%s\"\n", sess->name); puts ("READY"); return; err_free: g_free(sess->name); g_free(sess); }
END_TEST START_TEST (test_error_free_pass_002) { pgm_error_free (NULL); }
// Create, bind and connect PGM socket. // network_ of the form <interface & multicast group decls>:<IP port> // e.g. eth0;239.192.0.1:7500 // link-local;224.250.0.1,224.250.0.2;224.250.0.3:8000 // ;[fe80::1%en0]:7500 int zmq::pgm_socket_t::init (bool udp_encapsulation_, const char *network_) { // Can not open transport before destroying old one. zmq_assert (sock == NULL); // Parse port number, start from end for IPv6 const char *port_delim = strrchr (network_, ':'); if (!port_delim) { errno = EINVAL; return -1; } uint16_t port_number = atoi (port_delim + 1); char network [256]; if (port_delim - network_ >= (int) sizeof (network) - 1) { errno = EINVAL; return -1; } memset (network, '\0', sizeof (network)); memcpy (network, network_, port_delim - network_); // Validate socket options // Data rate is in [B/s]. options.rate is in [kb/s]. if (options.rate <= 0) { errno = EINVAL; return -1; } // Recovery interval [s]. if (options.recovery_ivl <= 0) { errno = EINVAL; return -1; } // Zero counter used in msgrecv. nbytes_rec = 0; nbytes_processed = 0; pgm_msgv_processed = 0; bool rc; pgm_error_t *pgm_error = NULL; struct pgm_addrinfo_t hints, *res = NULL; sa_family_t sa_family; memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; if (!pgm_getaddrinfo (network, NULL, &res, &pgm_error)) { // Invalid parameters don't set pgm_error_t zmq_assert (pgm_error != NULL); if (pgm_error->domain == PGM_ERROR_DOMAIN_IF && ( // NB: cannot catch EAI_BADFLAGS pgm_error->code != PGM_ERROR_SERVICE && pgm_error->code != PGM_ERROR_SOCKTNOSUPPORT)) // User, host, or network configuration or transient error goto err_abort; // Fatal OpenPGM internal error zmq_assert (false); } 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)) || !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, sndbuf = (int) options.sndbuf, max_tpdu = (int) pgm_max_tpdu; if (rcvbuf) { if (!pgm_setsockopt (sock, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof (rcvbuf))) goto err_abort; } if (sndbuf) { if (!pgm_setsockopt (sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof (sndbuf))) goto err_abort; } // Set maximum transport protocol data unit size (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_rte = options.rate * 1000 / 8, rxw_secs = options.recovery_ivl, peer_expiry = 5 * pgm_msecs (8192), 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 = 5, nak_ncf_retries = 2; if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof (recv_only)) || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_RXW_MAX_RTE, &rxw_max_rte, sizeof (rxw_max_rte)) || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_RXW_SECS, &rxw_secs, sizeof (rxw_secs)) || !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, txw_max_rte = options.rate * 1000 / 8, txw_secs = options.recovery_ivl, ambient_spm = pgm_msecs (8192), heartbeat_spm[] = { pgm_msecs (4), pgm_msecs (4), pgm_msecs (8), pgm_msecs (16), pgm_msecs (32), pgm_msecs (64), pgm_msecs (128), pgm_msecs (256), pgm_msecs (512), pgm_msecs (1024), pgm_msecs (2048), pgm_msecs (4096), pgm_msecs (8192) }; if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_only, sizeof (send_only)) || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_MAX_RTE, &txw_max_rte, sizeof (txw_max_rte)) || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_SECS, &txw_secs, sizeof (txw_secs)) || !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; if (options.identity.size () > 0) { // Create gsi from identity. if (!pgm_gsi_create_from_data (&addr.sa_addr.gsi, options.identity.data (), options.identity.size ())) goto err_abort; } else { // Generate random gsi. std::string gsi_base = uuid_t ().to_string (); if (!pgm_gsi_create_from_string (&addr.sa_addr.gsi, gsi_base.c_str (), -1)) 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 { const int nonblocking = 1, multicast_loop = options.use_multicast_loop ? 1 : 0, multicast_hops = 16, dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ if (!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))) goto err_abort; if (AF_INET6 != sa_family && !pgm_setsockopt (sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof (dscp))) goto err_abort; 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); } 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; }
int main ( int argc, char *argv[] ) { pgm_error_t* pgm_err = NULL; setlocale (LC_ALL, ""); /* pre-initialise PGM messages module to add hook for GLib logging */ pgm_messages_init(); log_init(); if (!pgm_init (&pgm_err)) { g_error ("Unable to start PGM engine: %s", pgm_err->message); pgm_error_free (pgm_err); pgm_messages_shutdown(); return EXIT_FAILURE; } /* parse program arguments */ const char* binary_name = strrchr (argv[0], '/'); int c; while ((c = getopt (argc, argv, "s:n:p:r:f:K:N:lih")) != -1) { switch (c) { case 'n': g_network = optarg; break; case 's': g_port = atoi (optarg); break; case 'p': g_udp_encap_port = atoi (optarg); break; case 'r': g_max_rte = atoi (optarg); break; case 'f': g_fec = TRUE; break; case 'K': g_k = atoi (optarg); break; case 'N': g_n = atoi (optarg); break; case 'l': g_multicast_loop = TRUE; break; case 'i': pgm_if_print_all(); pgm_messages_shutdown(); return EXIT_SUCCESS; case 'h': case '?': pgm_messages_shutdown(); usage (binary_name); } } if (g_fec && ( !g_k || !g_n )) { pgm_messages_shutdown(); g_error ("Invalid Reed-Solomon parameters RS(%d, %d).", g_n, g_k); usage (binary_name); } /* setup signal handlers */ signal (SIGSEGV, on_sigsegv); #ifdef SIGHUP signal (SIGHUP, SIG_IGN); #endif if (create_pgm_socket()) { while (optind < argc) { const int status = pgm_send (g_sock, argv[optind], strlen(argv[optind]) + 1, NULL); if (PGM_IO_STATUS_NORMAL != status) { g_warning ("pgm_send failed."); } optind++; } } /* cleanup */ if (g_sock) { pgm_close (g_sock, TRUE); g_sock = NULL; } pgm_shutdown(); pgm_messages_shutdown(); return EXIT_SUCCESS; }
int main ( int argc, char* argv[] ) { pgm_error_t* pgm_err = NULL; setlocale (LC_ALL, ""); log_init (); g_message ("blocksyncrecv"); if (!pgm_init (&pgm_err)) { g_error ("Unable to start PGM engine: %s", pgm_err->message); pgm_error_free (pgm_err); return EXIT_FAILURE; } /* parse program arguments */ const char* binary_name = strrchr (argv[0], '/'); int c; while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) { switch (c) { case 'n': g_network = optarg; break; case 's': g_port = atoi (optarg); break; case 'p': g_udp_encap_port = atoi (optarg); break; case 'l': g_multicast_loop = TRUE; break; case 'h': case '?': usage (binary_name); } } /* setup signal handlers */ signal(SIGSEGV, on_sigsegv); #ifdef SIGHUP signal(SIGHUP, SIG_IGN); #endif #ifdef G_OS_UNIX signal(SIGINT, on_signal); signal(SIGTERM, on_signal); #else SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); setvbuf (stdout, (char *) NULL, _IONBF, 0); #endif on_startup(); /* dispatch loop */ g_message ("entering PGM message loop ... "); do { char buffer[4096]; size_t len; struct pgm_sockaddr_t from; socklen_t fromlen = sizeof(from); const int status = pgm_recvfrom (g_sock, buffer, sizeof(buffer), 0, &len, &from, &fromlen, &pgm_err); if (PGM_IO_STATUS_NORMAL == status) on_data (buffer, len, &from); else { if (pgm_err) { g_warning ("%s", pgm_err->message); pgm_error_free (pgm_err); pgm_err = NULL; } if (PGM_IO_STATUS_ERROR == status) break; } } while (!g_quit); g_message ("message loop terminated, cleaning up."); /* cleanup */ if (g_sock) { g_message ("closing PGM socket."); pgm_close (g_sock, TRUE); g_sock = NULL; } g_message ("PGM engine shutdown."); pgm_shutdown (); g_message ("finished."); return EXIT_SUCCESS; }
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"); }
// 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; }
static gpointer receiver_thread ( gpointer data ) { pgm_sock_t* rx_sock = (pgm_sock_t*)data; const long iov_len = 20; const long ev_len = 1; struct pgm_msgv_t msgv[iov_len]; #ifdef CONFIG_HAVE_EPOLL struct epoll_event events[ev_len]; /* wait for maximum 1 event */ const int efd = epoll_create (IP_MAX_MEMBERSHIPS); if (efd < 0) { g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); g_main_loop_quit (g_loop); return NULL; } if (pgm_epoll_ctl (rx_sock, efd, EPOLL_CTL_ADD, EPOLLIN) < 0) { g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); g_main_loop_quit (g_loop); return NULL; } struct epoll_event event; event.events = EPOLLIN; event.data.fd = g_quit_pipe[0]; if (epoll_ctl (efd, EPOLL_CTL_ADD, g_quit_pipe[0], &event) < 0) { g_error ("epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); g_main_loop_quit (g_loop); return NULL; } #elif defined(CONFIG_HAVE_POLL) int n_fds = 2; struct pollfd fds[ 1 + n_fds ]; #elif defined(G_OS_UNIX) /* HAVE_SELECT */ int n_fds; fd_set readfds; #else /* G_OS_WIN32 */ SOCKET recv_sock, pending_sock; DWORD cEvents = PGM_RECV_SOCKET_READ_COUNT + 1; WSAEVENT waitEvents[ PGM_RECV_SOCKET_READ_COUNT + 1 ]; socklen_t socklen = sizeof (SOCKET); waitEvents[0] = g_quit_event; waitEvents[1] = WSACreateEvent (); pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_RECV_SOCK, &recv_sock, &socklen); WSAEventSelect (recv_sock, waitEvents[1], FD_READ); waitEvents[2] = WSACreateEvent (); pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_PENDING_SOCK, &pending_sock, &socklen); WSAEventSelect (pending_sock, waitEvents[2], FD_READ); #endif /* !CONFIG_HAVE_EPOLL */ do { struct timeval tv; #ifndef _WIN32 int timeout; #else DWORD dwTimeout, dwEvents; #endif size_t len; pgm_error_t* pgm_err = NULL; const int status = pgm_recvmsgv (rx_sock, msgv, G_N_ELEMENTS(msgv), 0, &len, &pgm_err); switch (status) { case PGM_IO_STATUS_NORMAL: on_msgv (msgv, len); break; case PGM_IO_STATUS_TIMER_PENDING: { socklen_t optlen = sizeof (tv); pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); } goto block; case PGM_IO_STATUS_RATE_LIMITED: { socklen_t optlen = sizeof (tv); pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); } /* fall through */ case PGM_IO_STATUS_WOULD_BLOCK: block: #ifdef CONFIG_HAVE_EPOLL timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); #elif defined(CONFIG_HAVE_POLL) timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); memset (fds, 0, sizeof(fds)); fds[0].fd = g_quit_pipe[0]; fds[0].events = POLLIN; pgm_poll_info (rx_sock, &fds[1], &n_fds, POLLIN); poll (fds, 1 + n_fds, timeout /* ms */); #elif defined(G_OS_UNIX) /* HAVE_SELECT */ FD_ZERO(&readfds); FD_SET(g_quit_pipe[0], &readfds); n_fds = g_quit_pipe[0] + 1; pgm_select_info (rx_sock, &readfds, NULL, &n_fds); select (n_fds, &readfds, NULL, NULL, PGM_IO_STATUS_RATE_LIMITED == status ? &tv : NULL); #else /* G_OS_WIN32 */ dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? WSA_INFINITE : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); dwEvents = WSAWaitForMultipleEvents (cEvents, waitEvents, FALSE, dwTimeout, FALSE); switch (dwEvents) { case WSA_WAIT_EVENT_0+1: WSAResetEvent (waitEvents[1]); break; case WSA_WAIT_EVENT_0+2: WSAResetEvent (waitEvents[2]); break; default: break; } #endif /* !CONFIG_HAVE_EPOLL */ break; default: if (pgm_err) { g_warning ("%s", pgm_err->message); pgm_error_free (pgm_err); pgm_err = NULL; } if (PGM_IO_STATUS_ERROR == status) break; } } while (!g_quit); #ifdef CONFIG_HAVE_EPOLL close (efd); #elif defined(G_OS_WIN32) WSACloseEvent (waitEvents[1]); WSACloseEvent (waitEvents[2]); # if (__STDC_VERSION__ < 199901L) g_free (waitHandles); # endif #endif return NULL; }
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; }
int main(int argc, char **argv) { int ncmds, i; const char *tmp; pgm_error_t *pgm_err = NULL; /* FIXME */ signal(SIGPIPE, SIG_IGN); setup_signal_handlers(); cmds = table_new(cmpstr, hashmurmur2, NULL, NULL); ncmds = sizeof commands / sizeof (struct cmd); for (i = 0; i < ncmds; ++i) { struct cmd *cmd = commands + i; table_insert(cmds, cmd->name, cmd); } if (argc != 2 && argc != 3) usage(); else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) usage(); else if (argc == 3 && strcmp(argv[1], "-f")) usage(); if (argc == 2 && daemon(1, 0) == -1) fprintf(stderr, "Error daemonizing: %s\n", strerror(errno)); /* FIXME */ if (init_logger("/var/log/xcb/xcb-dp2.log", __LOG_DEBUG) == -1) { fprintf(stderr, "Error initializing logger\n"); exit(1); } cfg_path = argc == 2 ? argv[1] : argv[2]; if ((cfg = config_load(cfg_path)) == NULL) exit(1); if ((tmp = variable_retrieve(cfg, "general", "log_level"))) { if (!strcasecmp(tmp, "info")) set_logger_level(__LOG_INFO); else if (!strcasecmp(tmp, "notice")) set_logger_level(__LOG_NOTICE); else if (!strcasecmp(tmp, "warning")) set_logger_level(__LOG_WARNING); } /* FIXME */ if (addms) times = table_new(cmpstr, hashmurmur2, kfree, vfree); clients_to_close = dlist_new(NULL, NULL); clients = dlist_new(NULL, NULL); monitors = dlist_new(NULL, NULL); tp = thrpool_new(16, 512, 200, NULL); if (!pgm_init(&pgm_err)) { xcb_log(XCB_LOG_ERROR, "Error starting PGM engine: %s", pgm_err->message); pgm_error_free(pgm_err); goto err; } /* FIXME */ if (NEW(pgm_send_cfg) == NULL) { xcb_log(XCB_LOG_ERROR, "Error allocating memory for PGM cfg"); goto err; } pgm_send_cfg->network = NULL; pgm_send_cfg->port = 0; init_pgm_send_cfg(pgm_send_cfg); if (pgm_send_cfg->network == NULL) { xcb_log(XCB_LOG_ERROR, "PGM network can't be NULL"); goto err; } if (pgm_send_cfg->port == 0) { xcb_log(XCB_LOG_ERROR, "PGM port can't be zero"); goto err; } if ((pgm_sender = pgmsock_create(pgm_send_cfg->network, pgm_send_cfg->port, PGMSOCK_SENDER)) == NULL) goto err; /* FIXME */ if ((el = create_event_loop(1024 + 1000)) == NULL) { xcb_log(XCB_LOG_ERROR, "Error creating event loop"); goto err; } create_time_event(el, 1, server_cron, NULL, NULL); if ((tmp = variable_retrieve(cfg, "general", "udp_port")) && strcmp(tmp, "")) { if ((udpsock = net_udp_server(NULL, atoi(tmp), neterr, sizeof neterr)) == -1) { xcb_log(XCB_LOG_ERROR, "Opening port '%s': %s", tmp, neterr); goto err; } if (net_nonblock(udpsock, neterr, sizeof neterr) == -1) { xcb_log(XCB_LOG_ERROR, "Setting port '%s' nonblocking: %s", tmp, neterr); goto err; } } if ((tmp = variable_retrieve(cfg, "general", "tcp_port")) && strcmp(tmp, "")) if ((tcpsock = net_tcp_server(NULL, atoi(tmp), neterr, sizeof neterr)) == -1) { xcb_log(XCB_LOG_ERROR, "Opening port '%s': %s", tmp, neterr); goto err; } if (udpsock > 0 && create_file_event(el, udpsock, EVENT_READABLE, read_quote, NULL) == -1) { xcb_log(XCB_LOG_ERROR, "Unrecoverable error creating udpsock '%d' file event", udpsock); goto err; } if (tcpsock > 0 && create_file_event(el, tcpsock, EVENT_READABLE, tcp_accept_handler, NULL) == -1) { xcb_log(XCB_LOG_ERROR, "Unrecoverable error creating tcpsock '%d' file event", tcpsock); goto err; } xcb_log(XCB_LOG_NOTICE, "Server dispatcher started"); start_event_loop(el, ALL_EVENTS); delete_event_loop(el); pgm_shutdown(); return 0; err: close_logger(); exit(1); }
int main ( int argc, char* argv[] ) { pgm_error_t* pgm_err = NULL; #ifdef CONFIG_WITH_HTTP gboolean enable_http = FALSE; #endif #ifdef CONFIG_WITH_SNMP gboolean enable_snmpx = FALSE; #endif setlocale (LC_ALL, ""); /* pre-initialise PGM messages module to add hook for GLib logging */ pgm_messages_init(); log_init (); g_message ("pgmrecv"); if (!pgm_init (&pgm_err)) { g_error ("Unable to start PGM engine: %s", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); pgm_error_free (pgm_err); pgm_messages_shutdown(); return EXIT_FAILURE; } g_thread_init (NULL); /* parse program arguments */ const char* binary_name = strrchr (argv[0], '/'); static struct option long_options[] = { { "network", required_argument, NULL, 'n' }, { "service", required_argument, NULL, 's' }, { "port", required_argument, NULL, 'p' }, { "enable-loop", no_argument, NULL, 'l' }, #ifdef CONFIG_WITH_HTTP { "enable-http", no_argument, NULL, 'H' }, #endif #ifdef CONFIG_WITH_SNMP { "enable-snmp", no_argument, NULL, 'S' }, #endif { "list", no_argument, NULL, 'i' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; int c; while ((c = getopt_long (argc, argv, "a:s:n:p:lih" #ifdef CONFIG_WITH_HTTP "H" #endif #ifdef CONFIG_WITH_SNMP "S" #endif , long_options, NULL)) != -1) { switch (c) { case 'n': g_network = optarg; break; case 'a': g_source = optarg; break; case 's': g_port = atoi (optarg); break; case 'p': g_udp_encap_port = atoi (optarg); break; case 'l': g_multicast_loop = TRUE; break; #ifdef CONFIG_WITH_HTTP case 'H': enable_http = TRUE; break; #endif #ifdef CONFIG_WITH_SNMP case 'S': enable_snmpx = TRUE; break; #endif case 'i': pgm_if_print_all(); pgm_messages_shutdown(); return EXIT_SUCCESS; case 'h': case '?': pgm_messages_shutdown(); usage (binary_name); } } #ifdef CONFIG_WITH_HTTP if (enable_http) { if (!pgm_http_init (PGM_HTTP_DEFAULT_SERVER_PORT, &pgm_err)) { g_error ("Unable to start HTTP interface: %s", pgm_err->message); pgm_error_free (pgm_err); pgm_shutdown(); pgm_messages_shutdown(); return EXIT_FAILURE; } } #endif #ifdef CONFIG_WITH_SNMP if (enable_snmpx) { if (!pgm_snmp_init (&pgm_err)) { g_error ("Unable to start SNMP interface: %s", pgm_err->message); pgm_error_free (pgm_err); #ifdef CONFIG_WITH_HTTP if (enable_http) pgm_http_shutdown (); #endif pgm_shutdown (); pgm_messages_shutdown(); return EXIT_FAILURE; } } #endif g_loop = g_main_loop_new (NULL, FALSE); g_quit = FALSE; /* setup signal handlers */ signal (SIGSEGV, on_sigsegv); #ifdef SIGHUP signal (SIGHUP, SIG_IGN); #endif #ifdef G_OS_UNIX const int e = pipe (g_quit_pipe); g_assert (0 == e); pgm_signal_install (SIGINT, on_signal, g_loop); pgm_signal_install (SIGTERM, on_signal, g_loop); #else g_quit_event = CreateEvent (NULL, TRUE, FALSE, TEXT("QuitEvent")); SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); setvbuf (stdout, (char *) NULL, _IONBF, 0); #endif /* delayed startup */ g_message ("scheduling startup."); g_timeout_add (0, (GSourceFunc)on_startup, NULL); /* dispatch loop */ g_message ("entering main event loop ... "); g_main_loop_run (g_loop); g_message ("event loop terminated, cleaning up."); /* cleanup */ g_quit = TRUE; #ifdef G_OS_UNIX const char one = '1'; const size_t writelen = write (g_quit_pipe[1], &one, sizeof(one)); g_assert (sizeof(one) == writelen); g_thread_join (g_thread); close (g_quit_pipe[0]); close (g_quit_pipe[1]); #else WSASetEvent (g_quit_event); g_thread_join (g_thread); WSACloseEvent (g_quit_event); #endif g_main_loop_unref (g_loop); g_loop = NULL; if (g_sock) { g_message ("closing PGM socket."); pgm_close (g_sock, TRUE); g_sock = NULL; } #ifdef CONFIG_WITH_HTTP if (enable_http) pgm_http_shutdown(); #endif #ifdef CONFIG_WITH_SNMP if (enable_snmpx) pgm_snmp_shutdown(); #endif g_message ("PGM engine shutdown."); pgm_shutdown(); g_message ("finished."); pgm_messages_shutdown(); return EXIT_SUCCESS; }
int main ( int argc, char* argv[] ) { pgm_error_t* pgm_err = NULL; setlocale (LC_ALL, ""); #ifndef _WIN32 puts ("プリン プリン"); #else _putws (L"プリン プリン"); #endif if (!pgm_init (&pgm_err)) { fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); pgm_error_free (pgm_err); return EXIT_FAILURE; } /* parse program arguments */ const char* binary_name = strrchr (argv[0], '/'); int c; while ((c = getopt (argc, argv, "s:n:p:f:K:N:lih")) != -1) { switch (c) { case 'n': network = optarg; break; case 's': port = atoi (optarg); break; case 'p': udp_encap_port = atoi (optarg); break; case 'f': use_fec = TRUE; break; case 'K': rs_k = atoi (optarg); break; case 'N': rs_n = atoi (optarg); break; case 'l': use_multicast_loop = TRUE; break; case 'i': pgm_if_print_all(); return EXIT_SUCCESS; case 'h': case '?': usage (binary_name); } } if (use_fec && ( !rs_n || !rs_k )) { fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); usage (binary_name); } /* setup signal handlers */ #ifdef SIGHUP signal (SIGHUP, SIG_IGN); #endif #ifndef _WIN32 int e = pipe (terminate_pipe); assert (0 == e); signal (SIGINT, on_signal); signal (SIGTERM, on_signal); #else terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent")); SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); #endif /* !_WIN32 */ if (!on_startup()) { fprintf (stderr, "Startup failed\n"); return EXIT_FAILURE; } /* dispatch loop */ #ifndef _WIN32 int fds; fd_set readfds; #else int n_handles = 3, recv_sock, pending_sock; HANDLE waitHandles[ 3 ]; DWORD dwTimeout, dwEvents; WSAEVENT recvEvent, pendingEvent; recvEvent = WSACreateEvent (); pgm_getsockopt (sock, PGM_RECV_SOCK, &recv_sock, sizeof(recv_sock)); WSAEventSelect (recv_sock, recvEvent, FD_READ); pendingEvent = WSACreateEvent (); pgm_getsockopt (sock, PGM_PENDING_SOCK, &pending_sock, sizeof(pending_sock)); WSAEventSelect (pending_sock, pendingEvent, FD_READ); waitHandles[0] = terminate_event; waitHandles[1] = recvEvent; waitHandles[2] = pendingEvent; #endif /* !_WIN32 */ puts ("Entering PGM message loop ... "); do { struct timeval tv; char buffer[4096]; size_t len; pgm_tsi_t from; const int status = pgm_recvfrom (sock, buffer, sizeof(buffer), 0, &len, &from, &pgm_err); switch (status) { case PGM_IO_STATUS_NORMAL: on_data (buffer, len, &from); break; case PGM_IO_STATUS_TIMER_PENDING: pgm_getsockopt (sock, PGM_TIME_REMAIN, &tv, sizeof(tv)); goto block; case PGM_IO_STATUS_RATE_LIMITED: pgm_getsockopt (sock, PGM_RATE_REMAIN, &tv, sizeof(tv)); case PGM_IO_STATUS_WOULD_BLOCK: /* select for next event */ block: #ifndef _WIN32 fds = terminate_pipe[0] + 1; FD_ZERO(&readfds); FD_SET(terminate_pipe[0], &readfds); pgm_select_info (sock, &readfds, NULL, &fds); fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); #else dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); switch (dwEvents) { case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; default: break; } #endif /* !_WIN32 */ break; default: if (pgm_err) { fprintf (stderr, "%s\n", pgm_err->message); pgm_error_free (pgm_err); pgm_err = NULL; } if (PGM_IO_STATUS_ERROR == status) break; } } while (!is_terminated); puts ("Message loop terminated, cleaning up."); /* cleanup */ #ifndef _WIN32 close (terminate_pipe[0]); close (terminate_pipe[1]); #else WSACloseEvent (recvEvent); WSACloseEvent (pendingEvent); CloseHandle (terminate_event); #endif /* !_WIN32 */ if (sock) { puts ("Destroying PGM socket."); pgm_close (sock, TRUE); sock = NULL; } puts ("PGM engine shutdown."); pgm_shutdown (); puts ("finished."); return EXIT_SUCCESS; }
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 pgm_sock_t* create_sock ( const char* network, int udp_encap_port) { struct pgm_addrinfo_t* res = NULL; pgm_sock_t* sock; 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 (!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)); /* 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)); addr.sa_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)); 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); goto err_abort; } /* 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); goto err_abort; } return sock; 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; }
int main ( int argc, char* argv[] ) { pgm_error_t* pgm_err = NULL; setlocale (LC_ALL, ""); #ifndef _WIN32 puts ("いちごのショートケーキ"); #else puts ("ichigo no shōtokēki"); #endif if (!pgm_init (&pgm_err)) { fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); pgm_error_free (pgm_err); return EXIT_FAILURE; } /* parse program arguments */ #ifdef _WIN32 const char* binary_name = strrchr (argv[0], '\\'); #else const char* binary_name = strrchr (argv[0], '/'); #endif if (NULL == binary_name) binary_name = argv[0]; else binary_name++; int c; while ((c = getopt (argc, argv, "s:n:p:f:K:N:lih")) != -1) { switch (c) { case 'n': network = optarg; break; case 's': port = atoi (optarg); break; case 'p': udp_encap_port = atoi (optarg); break; case 'f': use_fec = TRUE; break; case 'K': rs_k = atoi (optarg); break; case 'N': rs_n = atoi (optarg); break; case 'l': use_multicast_loop = TRUE; break; case 'i': pgm_if_print_all(); return EXIT_SUCCESS; case 'h': case '?': usage (binary_name); } } if (use_fec && ( !rs_n || !rs_k )) { fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); usage (binary_name); } /* setup signal handlers */ #ifdef SIGHUP signal (SIGHUP, SIG_IGN); #endif #ifndef _WIN32 int e = pipe (terminate_pipe); assert (0 == e); signal (SIGINT, on_signal); signal (SIGTERM, on_signal); #else terminateEvent = WSACreateEvent (); SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); setvbuf (stdout, (char *) NULL, _IONBF, 0); #endif /* !_WIN32 */ if (!on_startup()) { fprintf (stderr, "Startup failed\n"); return EXIT_FAILURE; } /* dispatch loop */ #ifndef _WIN32 int fds, read_fd = async_get_socket (async); fd_set readfds; #else DWORD cEvents = 2; WSAEVENT waitEvents[ 2 ]; DWORD dwEvents; waitEvents[0] = terminateEvent; waitEvents[1] = async_get_event (async); #endif /* !_WIN32 */ puts ("Entering PGM message loop ... "); do { char buffer[4096]; struct pgm_sockaddr_t from; socklen_t fromlen = sizeof (from); const ssize_t len = async_recvfrom (async, buffer, sizeof(buffer), &from, &fromlen); if (len >= 0) { on_data (buffer, len, &from); } else { #ifndef _WIN32 fds = MAX(terminate_pipe[0], read_fd) + 1; FD_ZERO(&readfds); FD_SET(terminate_pipe[0], &readfds); FD_SET(read_fd, &readfds); fds = select (fds, &readfds, NULL, NULL, NULL); #else dwEvents = WSAWaitForMultipleEvents (cEvents, waitEvents, FALSE, WSA_INFINITE, FALSE); switch (dwEvents) { case WSA_WAIT_EVENT_0+1: WSAResetEvent (waitEvents[1]); break; default: break; } #endif /* _WIN32 */ } } while (!is_terminated); puts ("Message loop terminated, cleaning up."); /* cleanup */ #ifndef _WIN32 close (terminate_pipe[0]); close (terminate_pipe[1]); #else WSACloseEvent (terminateEvent); #endif /* !_WIN32 */ if (async) { puts ("Destroying asynchronous queue."); async_destroy (async); async = NULL; } if (sock) { puts ("Closing PGM socket."); pgm_close (sock, TRUE); sock = NULL; } puts ("PGM engine shutdown."); pgm_shutdown (); puts ("finished."); return EXIT_SUCCESS; }
int main ( int argc, char *argv[] ) { pgm_error_t* err = NULL; /* pre-initialise PGM messages module to add hook for GLib logging */ pgm_messages_init(); log_init (); g_message ("app"); if (!pgm_init (&err)) { g_error ("Unable to start PGM engine: %s", (err && err->message) ? err->message : "(null)"); pgm_error_free (err); pgm_messages_shutdown(); return EXIT_FAILURE; } /* parse program arguments */ #ifdef _WIN32 const char* binary_name = strrchr (argv[0], '\\'); #else const char* binary_name = strrchr (argv[0], '/'); #endif if (NULL == binary_name) binary_name = argv[0]; else binary_name++; int c; while ((c = getopt (argc, argv, "s:n:h")) != -1) { switch (c) { case 'n': g_network = optarg; break; case 's': g_port = atoi (optarg); break; case 'h': case '?': pgm_messages_shutdown(); usage (binary_name); } } g_loop = g_main_loop_new (NULL, FALSE); /* setup signal handlers */ #ifndef _WIN32 signal (SIGSEGV, on_sigsegv); signal (SIGHUP, SIG_IGN); pgm_signal_install (SIGINT, on_signal, g_loop); pgm_signal_install (SIGTERM, on_signal, g_loop); #else SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); setvbuf (stdout, (char *) NULL, _IONBF, 0); #endif /* !_WIN32 */ /* delayed startup */ g_message ("scheduling startup."); g_timeout_add (0, (GSourceFunc)on_startup, NULL); /* dispatch loop */ g_message ("entering main event loop ... "); g_main_loop_run (g_loop); g_message ("event loop terminated, cleaning up."); /* cleanup */ g_main_loop_unref(g_loop); g_loop = NULL; if (g_sessions) { g_message ("destroying sessions."); g_hash_table_foreach_remove (g_sessions, (GHRFunc)destroy_session, NULL); g_hash_table_unref (g_sessions); g_sessions = NULL; } if (g_stdin_channel) { puts ("unbinding stdin."); g_io_channel_unref (g_stdin_channel); g_stdin_channel = NULL; } g_message ("PGM engine shutdown."); pgm_shutdown(); g_message ("finished."); pgm_messages_shutdown(); return EXIT_SUCCESS; }
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; }
int main ( int argc, char* argv[] ) { pgm_error_t* pgm_err = NULL; setlocale (LC_ALL, ""); log_init (); g_message ("enonblocksyncrecvmsgv"); if (!pgm_init (&pgm_err)) { g_error ("Unable to start PGM engine: %s", pgm_err->message); pgm_error_free (pgm_err); return EXIT_FAILURE; } /* parse program arguments */ const char* binary_name = strrchr (argv[0], '/'); int c; while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) { switch (c) { case 'n': g_network = optarg; break; case 's': g_port = atoi (optarg); break; case 'p': g_udp_encap_port = atoi (optarg); break; case 'l': g_multicast_loop = TRUE; break; case 'h': case '?': usage (binary_name); } } /* setup signal handlers */ signal (SIGSEGV, on_sigsegv); signal (SIGINT, on_signal); signal (SIGTERM, on_signal); #ifdef SIGHUP signal (SIGHUP, SIG_IGN); #endif if (!on_startup ()) { g_error ("startup failed"); return EXIT_FAILURE; } /* incoming message buffer, iov_len must be less than SC_IOV_MAX */ const long iov_len = 8; const long ev_len = 1; g_message ("Using iov_len %li ev_len %li", iov_len, ev_len); struct pgm_msgv_t msgv[iov_len]; struct epoll_event events[ev_len]; /* wait for maximum 1 event */ /* epoll file descriptor */ const int efd = epoll_create (IP_MAX_MEMBERSHIPS); if (efd < 0) { g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); return EXIT_FAILURE; } const int retval = pgm_epoll_ctl (g_sock, efd, EPOLL_CTL_ADD, EPOLLIN); if (retval < 0) { g_error ("pgm_epoll_ctl failed."); return EXIT_FAILURE; } /* dispatch loop */ g_message ("entering PGM message loop ... "); do { struct timeval tv; int timeout; size_t len; const int status = pgm_recvmsgv (g_sock, msgv, iov_len, 0, &len, &pgm_err); switch (status) { case PGM_IO_STATUS_NORMAL: on_msgv (msgv, len); break; case PGM_IO_STATUS_TIMER_PENDING: { socklen_t optlen = sizeof (tv); pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); } goto block; case PGM_IO_STATUS_RATE_LIMITED: { socklen_t optlen = sizeof (tv); pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); } /* fall through */ case PGM_IO_STATUS_WOULD_BLOCK: /* poll for next event */ block: timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); break; default: if (pgm_err) { g_warning ("%s", pgm_err->message); pgm_error_free (pgm_err); pgm_err = NULL; } if (PGM_IO_STATUS_ERROR == status) break; } } while (!g_quit); g_message ("message loop terminated, cleaning up."); /* cleanup */ close (efd); if (g_sock) { g_message ("closing PGM socket."); pgm_close (g_sock, TRUE); g_sock = NULL; } g_message ("PGM engine shutdown."); pgm_shutdown (); g_message ("finished."); return EXIT_SUCCESS; }
int main ( int argc, char *argv[] ) { pgm_error_t* pgm_err = NULL; setlocale (LC_ALL, ""); puts ("PGM daytime service"); if (!pgm_init (&pgm_err)) { fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); pgm_error_free (pgm_err); return EXIT_FAILURE; } /* parse program arguments */ #ifdef _WIN32 const char* binary_name = strrchr (argv[0], '\\'); #else const char* binary_name = strrchr (argv[0], '/'); #endif if (NULL == binary_name) binary_name = argv[0]; else binary_name++; static struct option long_options[] = { { "network", required_argument, NULL, 'n' }, { "service", required_argument, NULL, 's' }, { "port", required_argument, NULL, 'p' }, { "speed-limit", required_argument, NULL, 'r' }, { "enable-pgmcc", no_argument, NULL, 'c' }, { "enable-loop", no_argument, NULL, 'l' }, { "enable-fec", required_argument, NULL, 'f' }, { "list", no_argument, NULL, 'i' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; int c; while ((c = getopt_long (argc, argv, "s:n:p:r:cf:N:K:P:lih", long_options, NULL)) != -1) { switch (c) { case 'n': network = optarg; break; case 's': port = atoi (optarg); break; case 'p': udp_encap_port = atoi (optarg); break; case 'r': max_rte = atoi (optarg); break; case 'c': use_pgmcc = TRUE; break; case 'f': use_fec = TRUE; switch (optarg[0]) { case 'p': case 'P': proactive_packets = 1; break; case 'b': case 'B': proactive_packets = 1; case 'o': case 'O': use_ondemand_parity = TRUE; break; } break; case 'N': rs_n = atoi (optarg); break; case 'K': rs_k = atoi (optarg); break; case 'P': proactive_packets = atoi (optarg); break; case 'l': use_multicast_loop = TRUE; break; case 'i': pgm_if_print_all(); return EXIT_SUCCESS; case 'h': case '?': usage (binary_name); } } if (use_fec && ( !rs_n || !rs_k )) { fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); usage (binary_name); } /* setup signal handlers */ #ifdef SIGHUP signal (SIGHUP, SIG_IGN); #endif #ifndef _WIN32 int e = pipe (terminate_pipe); assert (0 == e); const int flags = fcntl (terminate_pipe[0], F_GETFL); fcntl (terminate_pipe[0], F_SETFL, flags | O_NONBLOCK); signal (SIGINT, on_signal); signal (SIGTERM, on_signal); #else terminateEvent = WSACreateEvent(); SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); setvbuf (stdout, (char *) NULL, _IONBF, 0); #endif /* !_WIN32 */ if (!on_startup()) { fprintf (stderr, "Startup failed\n"); return EXIT_FAILURE; } /* service loop */ do { time_t now; time (&now); const struct tm* time_ptr = localtime(&now); #ifndef _WIN32 char s[1024]; const size_t slen = strftime (s, sizeof(s), TIME_FORMAT, time_ptr); const int status = pgm_send (sock, s, slen + 1, NULL); #else char s[1024]; const size_t slen = strftime (s, sizeof(s), TIME_FORMAT, time_ptr); wchar_t ws[1024]; size_t wslen = MultiByteToWideChar (CP_ACP, 0, s, slen, ws, 1024); char us[1024]; size_t uslen = WideCharToMultiByte (CP_UTF8, 0, ws, wslen + 1, us, sizeof(us), NULL, NULL); const int status = pgm_send (sock, us, uslen + 1, NULL); #endif if (PGM_IO_STATUS_NORMAL != status) { fprintf (stderr, "pgm_send() failed.\n"); } #ifndef _WIN32 sleep (1); #else Sleep (1 * 1000); #endif } while (!is_terminated); /* cleanup */ puts ("Waiting for NAK thread."); #ifndef _WIN32 pthread_join (nak_thread, NULL); close (terminate_pipe[0]); close (terminate_pipe[1]); #else WaitForSingleObject (nak_thread, INFINITE); CloseHandle (nak_thread); WSACloseEvent (terminateEvent); #endif /* !_WIN32 */ if (sock) { puts ("Closing PGM sock."); pgm_close (sock, TRUE); sock = NULL; } puts ("PGM engine shutdown."); pgm_shutdown(); puts ("finished."); return EXIT_SUCCESS; }
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; }
unsigned __stdcall #endif nak_routine ( void* arg ) { /* dispatch loop */ pgm_sock_t* nak_sock = (pgm_sock_t*)arg; #ifndef _WIN32 int fds; fd_set readfds; #else SOCKET recv_sock, repair_sock, pending_sock; DWORD cEvents = PGM_SEND_SOCKET_READ_COUNT + 1; WSAEVENT waitEvents[ PGM_SEND_SOCKET_READ_COUNT + 1 ]; DWORD dwTimeout, dwEvents; socklen_t socklen = sizeof (SOCKET); waitEvents[0] = terminateEvent; waitEvents[1] = WSACreateEvent(); waitEvents[2] = WSACreateEvent(); waitEvents[3] = WSACreateEvent(); assert (3 == PGM_SEND_SOCKET_READ_COUNT); pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_RECV_SOCK, &recv_sock, &socklen); WSAEventSelect (recv_sock, waitEvents[1], FD_READ); pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_REPAIR_SOCK, &repair_sock, &socklen); WSAEventSelect (repair_sock, waitEvents[2], FD_READ); pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_PENDING_SOCK, &pending_sock, &socklen); WSAEventSelect (pending_sock, waitEvents[3], FD_READ); #endif /* !_WIN32 */ do { struct timeval tv; char buf[4064]; pgm_error_t* pgm_err = NULL; const int status = pgm_recv (nak_sock, buf, sizeof(buf), 0, NULL, &pgm_err); switch (status) { case PGM_IO_STATUS_TIMER_PENDING: { socklen_t optlen = sizeof (tv); pgm_getsockopt (sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); } goto block; case PGM_IO_STATUS_RATE_LIMITED: { socklen_t optlen = sizeof (tv); pgm_getsockopt (sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); } case PGM_IO_STATUS_WOULD_BLOCK: block: #ifndef _WIN32 fds = terminate_pipe[0] + 1; FD_ZERO(&readfds); FD_SET(terminate_pipe[0], &readfds); pgm_select_info (nak_sock, &readfds, NULL, &fds); fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); #else dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? WSA_INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); dwEvents = WSAWaitForMultipleEvents (cEvents, waitEvents, FALSE, dwTimeout, FALSE); switch (dwEvents) { case WSA_WAIT_EVENT_0+1: WSAResetEvent (waitEvents[1]); break; case WSA_WAIT_EVENT_0+2: WSAResetEvent (waitEvents[2]); break; case WSA_WAIT_EVENT_0+3: WSAResetEvent (waitEvents[3]); break; default: break; } #endif /* !_WIN32 */ break; default: if (pgm_err) { fprintf (stderr, "%s\n", pgm_err->message ? pgm_err->message : "(null)"); pgm_error_free (pgm_err); pgm_err = NULL; } if (PGM_IO_STATUS_ERROR == status) break; } } while (!is_terminated); #ifndef _WIN32 return NULL; #else WSACloseEvent (waitEvents[1]); WSACloseEvent (waitEvents[2]); WSACloseEvent (waitEvents[3]); _endthread(); return 0; #endif }
int main ( int argc, char* argv[] ) { int e; pgm_error_t* pgm_err = NULL; setlocale (LC_ALL, ""); log_init (); g_message ("syncrecv"); if (!pgm_init (&pgm_err)) { g_error ("Unable to start PGM engine: %s", pgm_err->message); pgm_error_free (pgm_err); return EXIT_FAILURE; } /* parse program arguments */ const char* binary_name = strrchr (argv[0], '/'); int c; while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) { switch (c) { case 'n': g_network = optarg; break; case 's': g_port = atoi (optarg); break; case 'p': g_udp_encap_port = atoi (optarg); break; case 'l': g_multicast_loop = TRUE; break; case 'h': case '?': usage (binary_name); } } g_quit = FALSE; #ifdef G_OS_UNIX e = pipe (g_quit_pipe); #else e = _pipe (g_quit_pipe, 4096, _O_BINARY | _O_NOINHERIT); #endif g_assert (0 == e); /* setup signal handlers */ signal(SIGSEGV, on_sigsegv); signal(SIGINT, on_signal); signal(SIGTERM, on_signal); #ifdef SIGHUP signal(SIGHUP, SIG_IGN); #endif if (!on_startup()) { g_error ("startup failed"); exit(1); } /* dispatch loop */ g_message ("entering PGM message loop ... "); do { struct timeval tv; int timeout; int n_fds = 2; struct pollfd fds[ 1 + n_fds ]; char buffer[4096]; gsize len; pgm_tsi_t from; const int status = pgm_recvfrom (g_transport, buffer, sizeof(buffer), 0, &len, &from, &pgm_err); switch (status) { case PGM_IO_STATUS_NORMAL: on_data (buffer, len, &from); break; case PGM_IO_STATUS_TIMER_PENDING: pgm_transport_get_timer_pending (g_transport, &tv); goto block; case PGM_IO_STATUS_RATE_LIMITED: pgm_transport_get_rate_remaining (g_transport, &tv); case PGM_IO_STATUS_WOULD_BLOCK: /* poll for next event */ block: timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); memset (fds, 0, sizeof(fds)); fds[0].fd = g_quit_pipe[0]; fds[0].events = POLLIN; pgm_transport_poll_info (g_transport, &fds[1], &n_fds, POLLIN); poll (fds, 1 + n_fds, timeout /* ms */); break; default: if (pgm_err) { g_warning ("%s", pgm_err->message); pgm_error_free (pgm_err); pgm_err = NULL; } if (PGM_IO_STATUS_ERROR == status) break; } } while (!g_quit); g_message ("message loop terminated, cleaning up."); /* cleanup */ close (g_quit_pipe[0]); close (g_quit_pipe[1]); if (g_transport) { g_message ("destroying transport."); pgm_transport_destroy (g_transport, TRUE); g_transport = NULL; } g_message ("PGM engine shutdown."); pgm_shutdown (); g_message ("finished."); return EXIT_SUCCESS; }