text: #define MS_CLASS "RTC::TcpConnection"
  // #define MS_LOG_DEV
  
  #include "RTC/TcpConnection.hpp"
  #include "Utils.hpp"
  #include "Logger.hpp"
  #include <cstring> // std::memmove()
  
  namespace RTC
  {
  	/* Instance methods. */
  
  	TcpConnection::TcpConnection(Listener* listener, size_t bufferSize) :
  		::TcpConnection::TcpConnection(bufferSize),
  		listener(listener)
  	{
  		MS_TRACE();
  	}
  
  	void TcpConnection::userOnTcpConnectionRead()
  	{
  		MS_TRACE();
  
  		MS_DEBUG_DEV("data received [local:%s :%" PRIu16 ", remote:%s :%" PRIu16 "]",
  			GetLocalIP().c_str(), GetLocalPort(),
  			GetPeerIP().c_str(), GetPeerPort());
  
  		/*
  		 * Framing RFC 4571
  		 *
  		 *     0                   1                   2                   3
  		 *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  		 *     ---------------------------------------------------------------
  		 *     |             LENGTH            |  STUN / DTLS / RTP / RTCP   |
  		 *     ---------------------------------------------------------------
  		 *
  		 * A 16-bit unsigned integer LENGTH field, coded in network byte order
  		 * (big-endian), begins the frame.  If LENGTH is non-zero, an RTP or
  		 * RTCP packet follows the LENGTH field.  The value coded in the LENGTH
  		 * field MUST equal the number of octets in the RTP or RTCP packet.
  		 * Zero is a valid value for LENGTH, and it codes the null packet.
  		 */
  
  		// Be ready to parse more than a single frame in a single TCP chunk.
  		while (true)
  		{
  			// We may receive multiple packets in the same TCP chunk. If one of them is
  			// a DTLS Close Alert this would be closed (Destroy() called) so we cannot call
  			// our listeners anymore.
  			if (IsClosing())
  				return;
  
  			size_t data_len = this->bufferDataLen - this->frameStart;
  			size_t packet_len;
  
  			if (data_len >= 2)
  				packet_len = (size_t)Utils::Byte::Get2Bytes(this->buffer + this->frameStart, 0);
  
  			// We have packet_len bytes.
  			if (data_len >= 2 && data_len >= 2 + packet_len)
  			{
  				const uint8_t* packet = this->buffer + this->frameStart + 2;
  
  				// Notify the listener.
  				if (packet_len != 0)
  				{
  					this->listener->onPacketRecv(this, packet, packet_len);
  				}
  
  				// If there is no more space available in the buffer and that is because
  				// the latest parsed frame filled it, then empty the full buffer.
  				if ((this->frameStart + 2 + packet_len) == this->bufferSize)
  				{
  					MS_DEBUG_DEV("no more space in the buffer, emptying the buffer data");
  
  					this->frameStart = 0;
  					this->bufferDataLen = 0;
  				}
  				// If there is still space in the buffer, set the beginning of the next
  				// frame to the next position after the parsed frame.
  				else
  				{
  					this->frameStart += 2 + packet_len;
  				}
  
  				// If there is more data in the buffer after the parsed frame then
  				// parse again. Otherwise break here and wait for more data.
  				if (this->bufferDataLen > this->frameStart)
  				{
  					MS_DEBUG_DEV("there is more data after the parsed frame, continue parsing");
  
  					continue;
  				}
  				else
  				{
  					break;
  				}
  			}
  
  			// Incomplete packet.
  			else
  			{
  				// Check if the buffer is full.
  				if (this->bufferDataLen == this->bufferSize)
  				{
  					// First case: the incomplete frame does not begin at position 0 of
  					// the buffer, so move the frame to the position 0.
  					if (this->frameStart != 0)
  					{
  						MS_DEBUG_DEV("no more space in the buffer, moving parsed bytes to the beginning of the buffer and wait for more data");
  
  						std::memmove(this->buffer, this->buffer + this->frameStart, this->bufferSize - this->frameStart);
  						this->bufferDataLen = this->bufferSize - this->frameStart;
  						this->frameStart = 0;
  					}
  					// Second case: the incomplete frame begins at position 0 of the buffer.
  					// The frame is too big, so close the connection.
  					else
  					{
  						MS_WARN_DEV("no more space in the buffer for the unfinished frame being parsed, closing the connection");
  
  						// Close the socket.
  						Destroy();
  					}
  				}
  				// The buffer is not full.
  				else
  				{
  					MS_DEBUG_DEV("frame not finished yet, waiting for more data");
  				}
  
  				// Exit the parsing loop.
  				break;
  			}
  		}
  	}
  
  	void TcpConnection::Send(const uint8_t* data, size_t len)
  	{
  		MS_TRACE();
  
  		// Write according to Framing RFC 4571.
  
  		uint8_t frame_len[2];
  
  		Utils::Byte::Set2Bytes(frame_len, 0, len);
  
  		Write(frame_len, 2, data, len);
  	}
  }
  