Example #1
0
int RTCPCompoundPacket::ParseData(uint8_t *data, size_t datalen)
{
	bool first;
	
	if (datalen < sizeof(RTCPCommonHeader))
		return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;

	first = true;
	
	do
	{
		RTCPCommonHeader *rtcphdr;
		size_t length;
		
		rtcphdr = (RTCPCommonHeader *)data;
		if (rtcphdr->version != RTP_VERSION) // check version
		{
			ClearPacketList();
			return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
		}
		if (first)
		{
			// Check if first packet is SR or RR
			
			first = false;
			if ( ! (rtcphdr->packettype == RTP_RTCPTYPE_SR || rtcphdr->packettype == RTP_RTCPTYPE_RR))
			{
				ClearPacketList();
				return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
			}
		}
		
		length = (size_t)ntohs(rtcphdr->length);
		length++;
		length *= sizeof(uint32_t);

		if (length > datalen) // invalid length field
		{
			ClearPacketList();
			return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
		}
		
		if (rtcphdr->padding)
		{
			// check if it's the last packet
			if (length != datalen)
			{
				ClearPacketList();
				return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
			}
		}

		RTCPPacket *p;
		
		switch (rtcphdr->packettype)
		{
		case RTP_RTCPTYPE_SR:
			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPSRPACKET) RTCPSRPacket(data,length);
			break;
		case RTP_RTCPTYPE_RR:
			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPRRPACKET) RTCPRRPacket(data,length);
			break;
		case RTP_RTCPTYPE_SDES:
			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPSDESPACKET) RTCPSDESPacket(data,length);
			break;
		case RTP_RTCPTYPE_BYE:
			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPBYEPACKET) RTCPBYEPacket(data,length);
			break;
		case RTP_RTCPTYPE_APP:
			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPAPPPACKET) RTCPAPPPacket(data,length);
			break;
		default:
			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPUNKNOWNPACKET) RTCPUnknownPacket(data,length);
		}

		if (p == 0)
		{
			ClearPacketList();
			return ERR_RTP_OUTOFMEM;
		}

		rtcppacklist.push_back(p);
		
		datalen -= length;
		data += length;
	} while (datalen >= (size_t)sizeof(RTCPCommonHeader));

	if (datalen != 0) // some remaining bytes
	{
		ClearPacketList();
		return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
	}
	return 0;
}
int RTCPCompoundPacketBuilder::EndBuild()
{
	if (!arebuilding)
		return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
	if (report.headerlength == 0)
		return ERR_RTP_RTCPCOMPPACKBUILDER_NOREPORTPRESENT;
	
	uint8_t *buf;
	size_t len;
	
#ifndef RTP_SUPPORT_RTCPUNKNOWN
	len = appsize+byesize+report.NeededBytes()+sdes.NeededBytes();
#else
	len = appsize+unknownsize+byesize+report.NeededBytes()+sdes.NeededBytes();
#endif // RTP_SUPPORT_RTCPUNKNOWN 
	
	if (!external)
	{
		buf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTCPCOMPOUNDPACKET) uint8_t[len];
		if (buf == 0)
			return ERR_RTP_OUTOFMEM;
	}
	else
		buf = buffer;
	
	uint8_t *curbuf = buf;
	RTCPPacket *p;

	// first, we'll add all report info
	
	{
		bool firstpacket = true;
		bool done = false;
		std::list<Buffer>::const_iterator it = report.reportblocks.begin();
		do
		{
			RTCPCommonHeader *hdr = (RTCPCommonHeader *)curbuf;
			size_t offset;
			
			hdr->version = 2;
			hdr->padding = 0;

			if (firstpacket && report.isSR)
			{
				hdr->packettype = RTP_RTCPTYPE_SR;
				memcpy((curbuf+sizeof(RTCPCommonHeader)),report.headerdata,report.headerlength);
				offset = sizeof(RTCPCommonHeader)+report.headerlength;
			}
			else
			{
				hdr->packettype = RTP_RTCPTYPE_RR;
				memcpy((curbuf+sizeof(RTCPCommonHeader)),report.headerdata,sizeof(uint32_t));
				offset = sizeof(RTCPCommonHeader)+sizeof(uint32_t);
			}
			firstpacket = false;
			
			uint8_t count = 0;

			while (it != report.reportblocks.end() && count < 31)
			{
				memcpy(curbuf+offset,(*it).packetdata,(*it).packetlength);
				offset += (*it).packetlength;
				count++;
				it++;
			}

			size_t numwords = offset/sizeof(uint32_t);

			hdr->length = htons((uint16_t)(numwords-1));
			hdr->count = count;

			// add entry in parent's list
			if (hdr->packettype == RTP_RTCPTYPE_SR)
				p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPSRPACKET) RTCPSRPacket(curbuf,offset);
			else
				p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPRRPACKET) RTCPRRPacket(curbuf,offset);
			if (p == 0)
			{
				if (!external)
					RTPDeleteByteArray(buf,GetMemoryManager());
				ClearPacketList();
				return ERR_RTP_OUTOFMEM;
			}
			rtcppacklist.push_back(p);

			curbuf += offset;
			if (it == report.reportblocks.end())
				done = true;
		} while (!done);
	}
		
	// then, we'll add the sdes info

	if (!sdes.sdessources.empty())
	{
		bool done = false;
		std::list<SDESSource *>::const_iterator sourceit = sdes.sdessources.begin();
		
		do
		{
			RTCPCommonHeader *hdr = (RTCPCommonHeader *)curbuf;
			size_t offset = sizeof(RTCPCommonHeader);
			
			hdr->version = 2;
			hdr->padding = 0;
			hdr->packettype = RTP_RTCPTYPE_SDES;

			uint8_t sourcecount = 0;
			
			while (sourceit != sdes.sdessources.end() && sourcecount < 31)
			{
				uint32_t *ssrc = (uint32_t *)(curbuf+offset);
				*ssrc = htonl((*sourceit)->ssrc);
				offset += sizeof(uint32_t);
				
				std::list<Buffer>::const_iterator itemit,itemend;

				itemit = (*sourceit)->items.begin();
				itemend = (*sourceit)->items.end();
				while (itemit != itemend)
				{
					memcpy(curbuf+offset,(*itemit).packetdata,(*itemit).packetlength);
					offset += (*itemit).packetlength;
					itemit++;
				}

				curbuf[offset] = 0; // end of item list;
				offset++;

				size_t r = offset&0x03;
				if (r != 0) // align to 32 bit boundary
				{
					size_t num = 4-r;
					size_t i;

					for (i = 0 ; i < num ; i++)
						curbuf[offset+i] = 0;
					offset += num;
				}
				
				sourceit++;
				sourcecount++;
			}

			size_t numwords = offset/4;
			
			hdr->count = sourcecount;
			hdr->length = htons((uint16_t)(numwords-1));

			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPSDESPACKET) RTCPSDESPacket(curbuf,offset);
			if (p == 0)
			{
				if (!external)
					RTPDeleteByteArray(buf,GetMemoryManager());
				ClearPacketList();
				return ERR_RTP_OUTOFMEM;
			}
			rtcppacklist.push_back(p);
			
			curbuf += offset;
			if (sourceit == sdes.sdessources.end())
				done = true;
		} while (!done);
	}
	
	// adding the app data
	
	{
		std::list<Buffer>::const_iterator it;

		for (it = apppackets.begin() ; it != apppackets.end() ; it++)
		{
			memcpy(curbuf,(*it).packetdata,(*it).packetlength);
			
			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPAPPPACKET) RTCPAPPPacket(curbuf,(*it).packetlength);
			if (p == 0)
			{
				if (!external)
					RTPDeleteByteArray(buf,GetMemoryManager());
				ClearPacketList();
				return ERR_RTP_OUTOFMEM;
			}
			rtcppacklist.push_back(p);
	
			curbuf += (*it).packetlength;
		}
	}

#ifdef RTP_SUPPORT_RTCPUNKNOWN

	// adding the unknown data
	
	{
		std::list<Buffer>::const_iterator it;

		for (it = unknownpackets.begin() ; it != unknownpackets.end() ; it++)
		{
			memcpy(curbuf,(*it).packetdata,(*it).packetlength);
			
			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPUNKNOWNPACKET) RTCPUnknownPacket(curbuf,(*it).packetlength);
			if (p == 0)
			{
				if (!external)
					RTPDeleteByteArray(buf,GetMemoryManager());
				ClearPacketList();
				return ERR_RTP_OUTOFMEM;
			}
			rtcppacklist.push_back(p);
	
			curbuf += (*it).packetlength;
		}
	}

#endif // RTP_SUPPORT_RTCPUNKNOWN 

	// adding bye packets
	
	{
		std::list<Buffer>::const_iterator it;

		for (it = byepackets.begin() ; it != byepackets.end() ; it++)
		{
			memcpy(curbuf,(*it).packetdata,(*it).packetlength);
			
			p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPBYEPACKET) RTCPBYEPacket(curbuf,(*it).packetlength);
			if (p == 0)
			{
				if (!external)
					RTPDeleteByteArray(buf,GetMemoryManager());
				ClearPacketList();
				return ERR_RTP_OUTOFMEM;
			}
			rtcppacklist.push_back(p);
	
			curbuf += (*it).packetlength;
		}
	}
	
	compoundpacket = buf;
	compoundpacketlength = len;
	arebuilding = false;
	ClearBuildBuffers();
	return 0;
}