1/* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h" 12 13#include "webrtc/base/checks.h" 14#include "webrtc/base/logging.h" 15#include "webrtc/modules/rtp_rtcp/source/byte_io.h" 16 17using webrtc::RTCPUtility::RtcpCommonHeader; 18 19namespace webrtc { 20namespace rtcp { 21 22// Bye packet (BYE) (RFC 3550). 23// 24// 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 25// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 26// |V=2|P| SC | PT=BYE=203 | length | 27// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28// | SSRC/CSRC | 29// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 30// : ... : 31// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 32// (opt) | length | reason for leaving ... 33// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 34Bye::Bye() : sender_ssrc_(0) {} 35 36bool Bye::Parse(const RtcpCommonHeader& header, const uint8_t* payload) { 37 RTC_DCHECK(header.packet_type == kPacketType); 38 39 const uint8_t src_count = header.count_or_format; 40 // Validate packet. 41 if (header.payload_size_bytes < 4u * src_count) { 42 LOG(LS_WARNING) 43 << "Packet is too small to contain CSRCs it promise to have."; 44 return false; 45 } 46 bool has_reason = (header.payload_size_bytes > 4u * src_count); 47 uint8_t reason_length = 0; 48 if (has_reason) { 49 reason_length = payload[4u * src_count]; 50 if (header.payload_size_bytes - 4u * src_count < 1u + reason_length) { 51 LOG(LS_WARNING) << "Invalid reason length: " << reason_length; 52 return false; 53 } 54 } 55 // Once sure packet is valid, copy values. 56 if (src_count == 0) { // A count value of zero is valid, but useless. 57 sender_ssrc_ = 0; 58 csrcs_.clear(); 59 } else { 60 sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(payload); 61 csrcs_.resize(src_count - 1); 62 for (size_t i = 1; i < src_count; ++i) 63 csrcs_[i - 1] = ByteReader<uint32_t>::ReadBigEndian(&payload[4 * i]); 64 } 65 66 if (has_reason) { 67 reason_.assign(reinterpret_cast<const char*>(&payload[4u * src_count + 1]), 68 reason_length); 69 } else { 70 reason_.clear(); 71 } 72 73 return true; 74} 75 76bool Bye::Create(uint8_t* packet, 77 size_t* index, 78 size_t max_length, 79 RtcpPacket::PacketReadyCallback* callback) const { 80 while (*index + BlockLength() > max_length) { 81 if (!OnBufferFull(packet, index, callback)) 82 return false; 83 } 84 const size_t index_end = *index + BlockLength(); 85 86 CreateHeader(1 + csrcs_.size(), kPacketType, HeaderLength(), packet, index); 87 // Store srcs of the leaving clients. 88 ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], sender_ssrc_); 89 *index += sizeof(uint32_t); 90 for (uint32_t csrc : csrcs_) { 91 ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], csrc); 92 *index += sizeof(uint32_t); 93 } 94 // Store the reason to leave. 95 if (!reason_.empty()) { 96 uint8_t reason_length = reason_.size(); 97 packet[(*index)++] = reason_length; 98 memcpy(&packet[*index], reason_.data(), reason_length); 99 *index += reason_length; 100 // Add padding bytes if needed. 101 size_t bytes_to_pad = index_end - *index; 102 RTC_DCHECK_LE(bytes_to_pad, 3u); 103 if (bytes_to_pad > 0) { 104 memset(&packet[*index], 0, bytes_to_pad); 105 *index += bytes_to_pad; 106 } 107 } 108 RTC_DCHECK_EQ(index_end, *index); 109 return true; 110} 111 112bool Bye::WithCsrc(uint32_t csrc) { 113 if (csrcs_.size() >= kMaxNumberOfCsrcs) { 114 LOG(LS_WARNING) << "Max CSRC size reached."; 115 return false; 116 } 117 csrcs_.push_back(csrc); 118 return true; 119} 120 121void Bye::WithReason(const std::string& reason) { 122 RTC_DCHECK_LE(reason.size(), 0xffu); 123 reason_ = reason; 124} 125 126size_t Bye::BlockLength() const { 127 size_t src_count = (1 + csrcs_.size()); 128 size_t reason_size_in_32bits = reason_.empty() ? 0 : (reason_.size() / 4 + 1); 129 return kHeaderLength + 4 * (src_count + reason_size_in_32bits); 130} 131 132} // namespace rtcp 133} // namespace webrtc 134