void zmq::pgm_socket_t::process_upstream (void) { zmq_log (1, "On upstream packet, %s(%i)\n", __FILE__, __LINE__); // We acctually do not want to read any data here we are going to // process NAK. pgm_msgv_t dummy_msg; ssize_t dummy_bytes = pgm_transport_recvmsgv (g_transport, &dummy_msg, 1, MSG_DONTWAIT); // No data should be returned. assert (dummy_bytes == -1 && errno == EAGAIN); }
// pgm_transport_recvmsgv is called to fill the pgm_msgv array up to // pgm_msgv_len. In subsequent calls data from pgm_msgv structure are // returned. ssize_t zmq::pgm_socket_t::receive (void **raw_data_) { // We just sent all data from pgm_transport_recvmsgv up // and have to return 0 that another engine in this thread is scheduled. if (nbytes_rec == nbytes_processed && nbytes_rec > 0) { // Reset all the counters. nbytes_rec = 0; nbytes_processed = 0; pgm_msgv_processed = 0; return 0; } // If we have are going first time or if we have processed all pgm_msgv_t // structure previaously read from the pgm socket. if (nbytes_rec == nbytes_processed) { // Check program flow. assert (pgm_msgv_processed == 0); assert (nbytes_processed == 0); assert (nbytes_rec == 0); // Receive a vector of Application Protocol Domain Unit's (APDUs) // from the transport. nbytes_rec = pgm_transport_recvmsgv (g_transport, pgm_msgv, pgm_msgv_len, MSG_DONTWAIT); // In a case when no ODATA/RDATA fired POLLIN event (SPM...) // pgm_transport_recvmsg returns -1 with errno == EAGAIN. if (nbytes_rec == -1 && errno == EAGAIN) { // In case if no RDATA/ODATA caused POLLIN 0 is // returned. nbytes_rec = 0; return 0; } // For data loss nbytes_rec == -1 errno == ECONNRESET. if (nbytes_rec == -1 && errno == ECONNRESET) { // In case of dala loss -1 is returned. zmq_log (1, "Data loss detected, %s(%i)\n", __FILE__, __LINE__); nbytes_rec = 0; return -1; } // Catch the rest of the errors. if (nbytes_rec <= 0) { zmq_log (1, "received %i B, errno %i, %s(%i)", (int)nbytes_rec, errno, __FILE__, __LINE__); errno_assert (nbytes_rec > 0); } zmq_log (4, "received %i bytes\n", (int)nbytes_rec); } assert (nbytes_rec > 0); // Only one APDU per pgm_msgv_t structure is allowed. assert (pgm_msgv [pgm_msgv_processed].msgv_iovlen == 1); // Take pointers from pgm_msgv_t structure. *raw_data_ = pgm_msgv[pgm_msgv_processed].msgv_iov->iov_base; size_t raw_data_len = pgm_msgv[pgm_msgv_processed].msgv_iov->iov_len; // Check if peer TSI did not change, this is detection of peer restart. const pgm_tsi_t *current_tsi = pgm_msgv [pgm_msgv_processed].msgv_tsi; // If empty store new TSI. if (tsi_empty (&tsi)) { // Store current peer TSI. memcpy (&tsi, current_tsi, sizeof (pgm_tsi_t)); #ifdef PGM_SOCKET_DEBUG uint8_t *gsi = (uint8_t*)(&tsi)->gsi.identifier; #endif zmq_log (1, "First peer TSI: %i.%i.%i.%i.%i.%i.%i, %s(%i)\n", gsi [0], gsi [1], gsi [2], gsi [3], gsi [4], gsi [5], ntohs (tsi.sport), __FILE__, __LINE__); } // Compare stored TSI with actual. if (!tsi_equal (&tsi, current_tsi)) { // Peer change detected. zmq_log (1, "Peer change detected, %s(%i)\n", __FILE__, __LINE__); // Compare with retired TSI, in case of match ignore APDU. if (tsi_equal (&retired_tsi, current_tsi)) { zmq_log (1, "Retired TSI - ignoring APDU, %s(%i)\n", __FILE__, __LINE__); // Move the the next pgm_msgv_t structure. pgm_msgv_processed++; nbytes_processed +=raw_data_len; return 0; } else { zmq_log (1, "New TSI, %s(%i)\n", __FILE__, __LINE__); // Store new TSI and move last valid to retired_tsi memcpy (&retired_tsi, &tsi, sizeof (pgm_tsi_t)); memcpy (&tsi, current_tsi, sizeof (pgm_tsi_t)); #ifdef PGM_SOCKET_DEBUG uint8_t *gsi = (uint8_t*)(&retired_tsi)->gsi.identifier; #endif zmq_log (1, "retired TSI: %i.%i.%i.%i.%i.%i.%i, %s(%i)\n", gsi [0], gsi [1], gsi [2], gsi [3], gsi [4], gsi [5], ntohs (retired_tsi.sport), __FILE__, __LINE__); #ifdef PGM_SOCKET_DEBUG gsi = (uint8_t*)(&tsi)->gsi.identifier; #endif zmq_log (1, " TSI: %i.%i.%i.%i.%i.%i.%i, %s(%i)\n", gsi [0], gsi [1], gsi [2], gsi [3], gsi [4], gsi [5], ntohs (tsi.sport), __FILE__, __LINE__); // Peers change is recognized as a GAP. return -1; } } // Move the the next pgm_msgv_t structure. pgm_msgv_processed++; nbytes_processed +=raw_data_len; zmq_log (4, "sendig up %i bytes\n", (int)raw_data_len); return raw_data_len; }
static gpointer receiver_thread ( gpointer data ) { pgm_transport_t* transport = (pgm_transport_t*)data; long iov_max = sysconf( SC_IOV_MAX ); pgm_msgv_t msgv[iov_max]; #ifdef CONFIG_HAVE_EPOLL 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; } int retval = pgm_transport_epoll_ctl (g_transport, efd, EPOLL_CTL_ADD, EPOLLIN); if (retval < 0) { g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); g_main_loop_quit(g_loop); return NULL; } #else int n_fds = 2; struct pollfd fds[ n_fds ]; #endif /* !CONFIG_HAVE_EPOLL */ do { gssize len = pgm_transport_recvmsgv (transport, msgv, iov_max, MSG_DONTWAIT /* non-blocking */); if (len >= 0) { on_msgv (msgv, len, NULL); } else if (errno == EAGAIN) /* len == -1, an error occured */ { #ifdef CONFIG_HAVE_EPOLL struct epoll_event events[1]; /* wait for maximum 1 event */ epoll_wait (efd, events, G_N_ELEMENTS(events), 1000 /* ms */); #else memset (fds, 0, sizeof(fds)); pgm_transport_poll_info (g_transport, fds, &n_fds, POLLIN); poll (fds, n_fds, 1000 /* ms */); #endif /* !CONFIG_HAVE_EPOLL */ } else if (errno == ECONNRESET) { pgm_sock_err_t* pgm_sock_err = (pgm_sock_err_t*)msgv[0].msgv_iov->iov_base; g_warning ("pgm socket lost %" G_GUINT32_FORMAT " packets detected from %s", pgm_sock_err->lost_count, pgm_print_tsi(&pgm_sock_err->tsi)); continue; } else if (errno == ENOTCONN) /* socket(s) closed */ { g_error ("pgm socket closed."); g_main_loop_quit(g_loop); break; } else { g_error ("pgm socket failed errno %i: \"%s\"", errno, strerror(errno)); g_main_loop_quit(g_loop); break; } } while (!g_quit); #ifdef CONFIG_HAVE_EPOLL close (efd); #endif return NULL; }