[vlc-devel] [PATCH 1/4] chromecast: Refactor network interactions

Hugo Beauzée-Luyssen hugo at beauzee.fr
Thu Mar 2 14:30:42 CET 2017


On Thu, Mar 2, 2017, at 02:23 PM, Rémi Denis-Courmont wrote:
> On March 2, 2017 11:46:45 AM GMT+02:00, "Hugo Beauzée-Luyssen"
> <hugo at beauzee.fr> wrote:
> >fix #18050
> >---
> > modules/stream_out/chromecast/chromecast.h         |  2 +-
> >.../chromecast/chromecast_communication.cpp        | 79
> >++++++++++------------
> >modules/stream_out/chromecast/chromecast_ctrl.cpp  | 63
> >++++++++++++-----
> > 3 files changed, 81 insertions(+), 63 deletions(-)
> >
> >diff --git a/modules/stream_out/chromecast/chromecast.h
> >b/modules/stream_out/chromecast/chromecast.h
> >index d60e43e4b7..fe63ee4072 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, 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..6331f6d336 100644
> >--- a/modules/stream_out/chromecast/chromecast_communication.cpp
> >+++ b/modules/stream_out/chromecast/chromecast_communication.cpp
> >@@ -122,63 +122,54 @@ void ChromecastCommunication::buildMessage(const
> >std::string & namespace_,
> >* @param i_payloadSize returns the payload size of the message received
> >  * @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, 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;
> >+            }
> >+            ssize_t val = vlc_poll_i11e(ufd, 1, PING_WAIT_TIME);
> >+            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..3434aa89a0 100644
> >--- a/modules/stream_out/chromecast/chromecast_ctrl.cpp
> >+++ b/modules/stream_out/chromecast/chromecast_ctrl.cpp
> >@@ -538,7 +538,9 @@ 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;
> > 
> >   if ( m_requested_stop.exchange(false) && !m_mediaSessionId.empty() )
> >     {
> >@@ -559,24 +561,32 @@ 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 )
> >+    /* Packet structure:
> >+     *
> >+------------------------------------+------------------------------+
> >+     * | Payload size (uint32_t big endian) |         Payload data    
> >    |
> >+     *
> >+------------------------------------+------------------------------+
> >+     */
> >+    while ( true )
> >     {
> >-        // 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 )
> >+        // 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,
> >+                                         &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 +597,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
> >
> >_______________________________________________
> >vlc-devel mailing list
> >To unsubscribe or modify your subscription options:
> >https://mailman.videolan.org/listinfo/vlc-devel
> 
> The time-out is reset at every interruption or partial read. I doubt that
> this would be correct.
> -- 
> Rémi Denis-Courmont
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel

Hi,

I thought it would be overkill to decrement the timeout each time data
is received/interrupt happens, though to be honest I don't know how the
chromecast will tolerate that. I can fix this, but I'm not sure how
worth it that is.

Regards,


-- 
  Hugo Beauzée-Luyssen
  hugo at beauzee.fr


More information about the vlc-devel mailing list