blob: 75522771fdbc0a958ef9d54ba77a27f86ce4d43d [file] [log] [blame]
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/quic/quic_buffered_packet_store.h"
#include <list>
#include "base/stl_util.h"
namespace net {
typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;
typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
// Max number of connections this store can keep track.
static const size_t kDefaultMaxConnectionsInStore = 100;
namespace {
// This alarm removes expired entries in map each time this alarm fires.
class ConnectionExpireAlarm : public QuicAlarm::Delegate {
public:
explicit ConnectionExpireAlarm(QuicBufferedPacketStore* store)
: connection_store_(store) {}
void OnAlarm() override { connection_store_->OnExpirationTimeout(); }
// Disallow copy and asign.
ConnectionExpireAlarm(const ConnectionExpireAlarm&) = delete;
ConnectionExpireAlarm& operator=(const ConnectionExpireAlarm&) = delete;
private:
QuicBufferedPacketStore* connection_store_;
};
} // namespace
BufferedPacket::BufferedPacket(std::unique_ptr<QuicEncryptedPacket> packet,
IPEndPoint server_address,
IPEndPoint client_address)
: packet(std::move(packet)),
server_address(server_address),
client_address(client_address) {}
BufferedPacket::BufferedPacket(BufferedPacket&& other) = default;
BufferedPacket& BufferedPacket::operator=(BufferedPacket&& other) = default;
BufferedPacket::~BufferedPacket() {}
BufferedPacketList::BufferedPacketList() : creation_time(QuicTime::Zero()) {}
BufferedPacketList::BufferedPacketList(BufferedPacketList&& other) = default;
BufferedPacketList& BufferedPacketList::operator=(BufferedPacketList&& other) =
default;
BufferedPacketList::~BufferedPacketList() {}
QuicBufferedPacketStore::QuicBufferedPacketStore(
VisitorInterface* visitor,
QuicClock* clock,
QuicAlarmFactory* alarm_factory)
: connection_life_span_(
QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)),
visitor_(visitor),
clock_(clock),
expiration_alarm_(
alarm_factory->CreateAlarm(new ConnectionExpireAlarm(this))) {}
QuicBufferedPacketStore::~QuicBufferedPacketStore() {}
EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket(
QuicConnectionId connection_id,
const QuicEncryptedPacket& packet,
IPEndPoint server_address,
IPEndPoint client_address) {
if (!ContainsKey(undecryptable_packets_, connection_id) &&
undecryptable_packets_.size() >= kDefaultMaxConnectionsInStore) {
// Drop the packet if store can't keep track of more connections.
return TOO_MANY_CONNECTIONS;
} else if (!ContainsKey(undecryptable_packets_, connection_id)) {
undecryptable_packets_.emplace(
std::make_pair(connection_id, BufferedPacketList()));
}
CHECK(ContainsKey(undecryptable_packets_, connection_id));
BufferedPacketList& queue =
undecryptable_packets_.find(connection_id)->second;
if (queue.buffered_packets.size() >= kDefaultMaxUndecryptablePackets) {
// If there are kMaxBufferedPacketsPerConnection packets buffered up for
// this connection, drop the current packet.
return TOO_MANY_PACKETS;
}
if (queue.buffered_packets.empty()) {
// If this is the first packet arrived on a new connection, initialize the
// creation time.
queue.creation_time = clock_->ApproximateNow();
}
BufferedPacket new_entry(std::unique_ptr<QuicEncryptedPacket>(packet.Clone()),
server_address, client_address);
queue.buffered_packets.push_back(std::move(new_entry));
if (!expiration_alarm_->IsSet()) {
expiration_alarm_->Set(clock_->ApproximateNow().Add(connection_life_span_));
}
return SUCCESS;
}
std::list<BufferedPacket> QuicBufferedPacketStore::DeliverPackets(
QuicConnectionId connection_id) {
std::list<BufferedPacket> packets_to_deliver;
auto it = undecryptable_packets_.find(connection_id);
if (it != undecryptable_packets_.end()) {
packets_to_deliver = std::move(it->second.buffered_packets);
undecryptable_packets_.erase(connection_id);
}
return packets_to_deliver;
}
void QuicBufferedPacketStore::OnExpirationTimeout() {
QuicTime expiration_time =
clock_->ApproximateNow().Subtract(connection_life_span_);
while (!undecryptable_packets_.empty()) {
auto& entry = undecryptable_packets_.front();
if (entry.second.creation_time > expiration_time) {
break;
}
visitor_->OnExpiredPackets(entry.first, std::move(entry.second));
undecryptable_packets_.erase(undecryptable_packets_.begin());
}
if (!undecryptable_packets_.empty()) {
expiration_alarm_->Set(clock_->ApproximateNow().Add(connection_life_span_));
}
}
} // namespace net