1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/quic/quic_fec_group.h" 6 7 #include <limits> 8 9 #include "base/logging.h" 10 11 using base::StringPiece; 12 using std::numeric_limits; 13 using std::set; 14 15 namespace net { 16 17 namespace { 18 const QuicPacketSequenceNumber kNoSequenceNumber = kuint64max; 19 } // namespace 20 21 QuicFecGroup::QuicFecGroup() 22 : min_protected_packet_(kNoSequenceNumber), 23 max_protected_packet_(kNoSequenceNumber), 24 payload_parity_len_(0), 25 entropy_parity_(false) { 26 } 27 28 QuicFecGroup::~QuicFecGroup() {} 29 30 bool QuicFecGroup::Update(const QuicPacketHeader& header, 31 StringPiece decrypted_payload) { 32 if (received_packets_.count(header.packet_sequence_number) != 0) { 33 return false; 34 } 35 if (min_protected_packet_ != kNoSequenceNumber && 36 max_protected_packet_ != kNoSequenceNumber && 37 (header.packet_sequence_number < min_protected_packet_ || 38 header.packet_sequence_number > max_protected_packet_)) { 39 DLOG(ERROR) << "FEC group does not cover received packet: " 40 << header.packet_sequence_number; 41 return false; 42 } 43 if (!UpdateParity(decrypted_payload, header.entropy_flag)) { 44 return false; 45 } 46 received_packets_.insert(header.packet_sequence_number); 47 return true; 48 } 49 50 bool QuicFecGroup::UpdateFec( 51 QuicPacketSequenceNumber fec_packet_sequence_number, 52 bool fec_packet_entropy, 53 const QuicFecData& fec) { 54 if (min_protected_packet_ != kNoSequenceNumber) { 55 return false; 56 } 57 SequenceNumberSet::const_iterator it = received_packets_.begin(); 58 while (it != received_packets_.end()) { 59 if ((*it < fec.fec_group) || 60 (*it >= fec_packet_sequence_number)) { 61 DLOG(ERROR) << "FEC group does not cover received packet: " << *it; 62 return false; 63 } 64 ++it; 65 } 66 if (!UpdateParity(fec.redundancy, fec_packet_entropy)) { 67 return false; 68 } 69 min_protected_packet_ = fec.fec_group; 70 max_protected_packet_ = fec_packet_sequence_number - 1; 71 return true; 72 } 73 74 bool QuicFecGroup::CanRevive() const { 75 // We can revive if we're missing exactly 1 packet. 76 return NumMissingPackets() == 1; 77 } 78 79 bool QuicFecGroup::IsFinished() const { 80 // We are finished if we are not missing any packets. 81 return NumMissingPackets() == 0; 82 } 83 84 size_t QuicFecGroup::Revive(QuicPacketHeader* header, 85 char* decrypted_payload, 86 size_t decrypted_payload_len) { 87 if (!CanRevive()) { 88 return 0; 89 } 90 91 // Identify the packet sequence number to be resurrected. 92 QuicPacketSequenceNumber missing = kNoSequenceNumber; 93 for (QuicPacketSequenceNumber i = min_protected_packet_; 94 i <= max_protected_packet_; ++i) { 95 // Is this packet missing? 96 if (received_packets_.count(i) == 0) { 97 missing = i; 98 break; 99 } 100 } 101 DCHECK_NE(kNoSequenceNumber, missing); 102 103 DCHECK_LE(payload_parity_len_, decrypted_payload_len); 104 if (payload_parity_len_ > decrypted_payload_len) { 105 return 0; 106 } 107 for (size_t i = 0; i < payload_parity_len_; ++i) { 108 decrypted_payload[i] = payload_parity_[i]; 109 } 110 111 header->packet_sequence_number = missing; 112 header->entropy_flag = entropy_parity_; 113 114 received_packets_.insert(missing); 115 return payload_parity_len_; 116 } 117 118 bool QuicFecGroup::ProtectsPacketsBefore(QuicPacketSequenceNumber num) const { 119 if (max_protected_packet_ != kNoSequenceNumber) { 120 return max_protected_packet_ < num; 121 } 122 // Since we might not yet have recevied the FEC packet, we must check 123 // the packets we have received. 124 return *received_packets_.begin() < num; 125 } 126 127 bool QuicFecGroup::UpdateParity(StringPiece payload, bool entropy) { 128 DCHECK_LE(payload.size(), kMaxPacketSize); 129 if (payload.size() > kMaxPacketSize) { 130 DLOG(ERROR) << "Illegal payload size: " << payload.size(); 131 return false; 132 } 133 if (payload_parity_len_ < payload.size()) { 134 payload_parity_len_ = payload.size(); 135 } 136 DCHECK_LE(payload.size(), kMaxPacketSize); 137 if (received_packets_.empty() && 138 min_protected_packet_ == kNoSequenceNumber) { 139 // Initialize the parity to the value of this payload 140 memcpy(payload_parity_, payload.data(), payload.size()); 141 if (payload.size() < kMaxPacketSize) { 142 // TODO(rch): expand as needed. 143 memset(payload_parity_ + payload.size(), 0, 144 kMaxPacketSize - payload.size()); 145 } 146 entropy_parity_ = entropy; 147 return true; 148 } 149 // Update the parity by XORing in the data (padding with 0s if necessary). 150 for (size_t i = 0; i < kMaxPacketSize; ++i) { 151 uint8 byte = i < payload.size() ? payload[i] : 0x00; 152 payload_parity_[i] ^= byte; 153 } 154 // xor of boolean values. 155 entropy_parity_ = (entropy_parity_ != entropy); 156 return true; 157 } 158 159 size_t QuicFecGroup::NumMissingPackets() const { 160 if (min_protected_packet_ == kNoSequenceNumber) 161 return numeric_limits<size_t>::max(); 162 return (max_protected_packet_ - min_protected_packet_ + 1) - 163 received_packets_.size(); 164 } 165 166 } // namespace net 167