[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