[vlc-devel] [PATCH 1/4] chromecast: Refactor network interactions
Hugo Beauzée-Luyssen
hugo at beauzee.fr
Fri Mar 3 14:24:41 CET 2017
fix #18050
---
modules/stream_out/chromecast/chromecast.h | 2 +-
.../chromecast/chromecast_communication.cpp | 87 ++++++++++------------
modules/stream_out/chromecast/chromecast_ctrl.cpp | 67 ++++++++++++-----
3 files changed, 89 insertions(+), 67 deletions(-)
diff --git a/modules/stream_out/chromecast/chromecast.h b/modules/stream_out/chromecast/chromecast.h
index d60e43e4b7..d1870617ca 100644
--- a/modules/stream_out/chromecast/chromecast.h
+++ b/modules/stream_out/chromecast/chromecast.h
@@ -113,7 +113,7 @@ public:
const std::string & currentTime );
void msgPlayerSetVolume( const std::string& destinationId, const std::string& mediaSessionId,
float volume, bool mute);
- ssize_t recvPacket( uint8_t *p_data);
+ ssize_t receive( uint8_t *p_data, size_t i_size, int i_timeout, bool *pb_timeout );
private:
int sendMessage(const castchannel::CastMessage &msg);
diff --git a/modules/stream_out/chromecast/chromecast_communication.cpp b/modules/stream_out/chromecast/chromecast_communication.cpp
index d880a368e8..af388f5524 100644
--- a/modules/stream_out/chromecast/chromecast_communication.cpp
+++ b/modules/stream_out/chromecast/chromecast_communication.cpp
@@ -117,68 +117,61 @@ void ChromecastCommunication::buildMessage(const std::string & namespace_,
/**
* @brief Receive a data packet from the Chromecast
- * @param p_module the module to log with
- * @param b_msgReceived returns true if a message has been entirely received else false
- * @param i_payloadSize returns the payload size of the message received
+ * @param p_data the buffer in which to store the data
+ * @param i_size the size of the buffer
+ * @param i_timeout maximum time to wait for a packet, in millisecond
+ * @param pb_timeout Output parameter that will contain true if no packet was received due to a timeout
* @return the number of bytes received of -1 on error
*/
-ssize_t ChromecastCommunication::recvPacket( uint8_t *p_data )
+ssize_t ChromecastCommunication::receive( uint8_t *p_data, size_t i_size, int i_timeout, bool *pb_timeout )
{
- ssize_t i_payloadSize = -1;
+ ssize_t i_received = 0;
struct pollfd ufd[1];
ufd[0].fd = m_sock_fd;
ufd[0].events = POLLIN;
+ struct iovec iov;
+ iov.iov_base = p_data;
+ iov.iov_len = i_size;
+
/* The Chromecast normally sends a PING command every 5 seconds or so.
* If we do not receive one after 6 seconds, we send a PING.
* If after this PING, we do not receive a PONG, then we consider the
* connection as dead. */
- ssize_t val = vlc_poll_i11e(ufd, 1, PING_WAIT_TIME);
- if ( val == -1 )
+ do
{
- if ( errno != EINTR )
- return -1;
- return 0;
- }
- if ( val == 0 )
- return 0;
-
- if ( ufd[0].revents & POLLIN )
- {
- /* we have received stuff */
-
- /* Packet structure:
- * +------------------------------------+------------------------------+
- * | Payload size (uint32_t big endian) | Payload data |
- * +------------------------------------+------------------------------+ */
- // We receive the header.
- ssize_t i_ret = vlc_tls_Read(m_tls, p_data, PACKET_HEADER_LEN, true);
- if (i_ret < PACKET_HEADER_LEN)
- return -1;
-
- // We receive the payload.
-
- // Get the size of the payload
- i_payloadSize = U32_AT( p_data );
- const uint32_t i_maxPayloadSize = PACKET_MAX_LEN - PACKET_HEADER_LEN;
-
- if (i_payloadSize > i_maxPayloadSize)
+ ssize_t i_ret = m_tls->readv( m_tls, &iov, 1 );
+ if ( i_ret < 0 )
{
- // Error case: the packet sent by the Chromecast is too long: we drop it.
- msg_Err( m_module, "Packet too long: dropping its data");
-
- i_ret = vlc_tls_Read(m_tls, p_data + PACKET_HEADER_LEN,
- i_maxPayloadSize, false);
- return i_ret ? i_ret : -1;
+#ifdef _WIN32
+ if ( WSAGetLastError() != WSAEWOULDBLOCK )
+#else
+ if ( errno != EAGAIN )
+#endif
+ {
+ return -1;
+ }
+ msg_Err( m_module, "Timeout: %d", i_timeout);
+ ssize_t val = vlc_poll_i11e(ufd, 1, i_timeout);
+ if ( val < 0 )
+ return -1;
+ else if ( val == 0 )
+ {
+ *pb_timeout = true;
+ return i_received;
+ }
+ assert( ufd[0].revents & POLLIN );
+ continue;
}
-
- // Normal case
- i_ret = vlc_tls_Read(m_tls, p_data + PACKET_HEADER_LEN, i_payloadSize,
- false);
- if (i_ret < i_payloadSize)
+ else if ( i_ret == 0 )
return -1;
- }
- return i_payloadSize;
+ assert( i_size >= (size_t)i_ret );
+ i_size -= i_ret;
+ i_received += i_ret;
+ iov.iov_base = (uint8_t*)iov.iov_base + i_ret;
+ iov.iov_len = i_size;
+ } while ( i_size > 0 );
+ return i_received;
}
diff --git a/modules/stream_out/chromecast/chromecast_ctrl.cpp b/modules/stream_out/chromecast/chromecast_ctrl.cpp
index 292926b089..5857144f07 100644
--- a/modules/stream_out/chromecast/chromecast_ctrl.cpp
+++ b/modules/stream_out/chromecast/chromecast_ctrl.cpp
@@ -538,7 +538,10 @@ void intf_sys_t::processConnectionMessage( const castchannel::CastMessage& msg )
bool intf_sys_t::handleMessages()
{
uint8_t p_packet[PACKET_MAX_LEN];
- ssize_t i_payloadSize = 0;
+ size_t i_payloadSize = 0;
+ size_t i_received = 0;
+ bool b_timeout = false;
+ mtime_t i_begin_time = mdate();
if ( m_requested_stop.exchange(false) && !m_mediaSessionId.empty() )
{
@@ -559,24 +562,33 @@ bool intf_sys_t::handleMessages()
m_communication.msgPlayerSeek( m_appTransportId, m_mediaSessionId, current_time );
}
- i_payloadSize = m_communication.recvPacket( p_packet );
-#if defined(_WIN32)
- if ( i_payloadSize < 0 && WSAGetLastError() != WSAEWOULDBLOCK )
-#else
- if ( i_payloadSize < 0 )
-#endif
- {
- // An error occured, we give up
- msg_Err( m_module, "The connection to the Chromecast died (receiving).");
- vlc_mutex_locker locker(&m_lock);
- setState( Dead );
- return false;
- }
- if ( i_payloadSize == 0 )
- {
- // If no commands were queued to be sent, we timed out. Let's ping the chromecast
- if ( m_requested_seek == false && m_requested_stop == false )
+ /* Packet structure:
+ * +------------------------------------+------------------------------+
+ * | Payload size (uint32_t big endian) | Payload data |
+ * +------------------------------------+------------------------------+
+ */
+ while ( true )
+ {
+ // If we haven't received the payload size yet, let's wait for it. Otherwise, we know
+ // how much bytes to read
+ ssize_t i_ret = m_communication.receive( p_packet + i_received,
+ i_payloadSize + PACKET_HEADER_LEN - i_received,
+ PING_WAIT_TIME - ( mdate() - i_begin_time ) / CLOCK_FREQ,
+ &b_timeout );
+ if ( i_ret < 0 )
+ {
+ // If we need to process a command, let it happen at next iteration
+ if ( errno == EINTR )
+ return true;
+ // An error occured, we give up
+ msg_Err( m_module, "The connection to the Chromecast died (receiving).");
+ vlc_mutex_locker locker(&m_lock);
+ setState( Dead );
+ return false;
+ }
+ else if ( b_timeout == true )
{
+ // If no commands were queued to be sent, we timed out. Let's ping the chromecast
if ( m_pingRetriesLeft == 0 )
{
vlc_mutex_locker locker(&m_lock);
@@ -587,8 +599,25 @@ bool intf_sys_t::handleMessages()
--m_pingRetriesLeft;
m_communication.msgPing();
m_communication.msgReceiverGetStatus();
+ return true;
}
- return true;
+ assert( i_ret != 0 );
+ i_received += i_ret;
+ if ( i_payloadSize == 0 )
+ {
+ i_payloadSize = U32_AT( p_packet );
+ if ( i_payloadSize > PACKET_MAX_LEN - PACKET_HEADER_LEN )
+ {
+ msg_Err( m_module, "Payload size is too long: dropping conection" );
+ vlc_mutex_locker locker(&m_lock);
+ m_state = Dead;
+ return false;
+ }
+ continue;
+ }
+ assert( i_received <= i_payloadSize + PACKET_HEADER_LEN );
+ if ( i_received == i_payloadSize + PACKET_HEADER_LEN )
+ break;
}
castchannel::CastMessage msg;
msg.ParseFromArray(p_packet + PACKET_HEADER_LEN, i_payloadSize);
--
2.11.0
More information about the vlc-devel
mailing list