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; }