vlc | branch: master | Hugo Beauzée-Luyssen <[email protected]> | Wed Mar 1 14:23:48 2017 +0100| [03fd6667349211f63cf69e0c47e68d8c618cd82c] | committer: Hugo Beauzée-Luyssen
chromecast: Refactor network interactions fix #18050 > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=03fd6667349211f63cf69e0c47e68d8c618cd82c --- modules/stream_out/chromecast/chromecast.h | 2 +- .../chromecast/chromecast_communication.cpp | 86 ++++++++++------------ modules/stream_out/chromecast/chromecast_ctrl.cpp | 67 ++++++++++++----- 3 files changed, 88 insertions(+), 67 deletions(-) diff --git a/modules/stream_out/chromecast/chromecast.h b/modules/stream_out/chromecast/chromecast.h index d60e43e..d187061 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 d880a36..1aa3051 100644 --- a/modules/stream_out/chromecast/chromecast_communication.cpp +++ b/modules/stream_out/chromecast/chromecast_communication.cpp @@ -117,68 +117,60 @@ 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; + } + 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 292926b..fc7f84b 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 many 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); _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
