This source file includes following definitions.
- OnAlarm
- packet_
- server_address
- client_address
- packet
- visitor_
- AddConnectionIdToTimeWait
- IsConnectionIdInTimeWait
- GetQuicVersionFromConnectionId
- OnCanWrite
- ProcessPacket
- ShouldSendResponse
- SendPublicReset
- SendOrQueuePacket
- WriteToWire
- SetConnectionIdCleanUpAlarm
- CleanUpOldConnectionIds
#include "net/tools/quic/quic_time_wait_list_manager.h"
#include <errno.h>
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "net/base/ip_endpoint.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/quic_clock.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_utils.h"
#include "net/tools/quic/quic_server_session.h"
using base::StringPiece;
using std::make_pair;
namespace net {
namespace tools {
namespace {
const int kTimeWaitSeconds = 5;
}
class ConnectionIdCleanUpAlarm : public EpollAlarm {
public:
explicit ConnectionIdCleanUpAlarm(
QuicTimeWaitListManager* time_wait_list_manager)
: time_wait_list_manager_(time_wait_list_manager) {
}
virtual int64 OnAlarm() OVERRIDE {
EpollAlarm::OnAlarm();
time_wait_list_manager_->CleanUpOldConnectionIds();
return 0;
}
private:
QuicTimeWaitListManager* time_wait_list_manager_;
};
class QuicTimeWaitListManager::QueuedPacket {
public:
QueuedPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
QuicEncryptedPacket* packet)
: server_address_(server_address),
client_address_(client_address),
packet_(packet) {
}
const IPEndPoint& server_address() const { return server_address_; }
const IPEndPoint& client_address() const { return client_address_; }
QuicEncryptedPacket* packet() { return packet_.get(); }
private:
const IPEndPoint server_address_;
const IPEndPoint client_address_;
scoped_ptr<QuicEncryptedPacket> packet_;
DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
};
QuicTimeWaitListManager::QuicTimeWaitListManager(
QuicPacketWriter* writer,
QuicServerSessionVisitor* visitor,
EpollServer* epoll_server,
const QuicVersionVector& supported_versions)
: epoll_server_(epoll_server),
kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)),
clock_(epoll_server_),
writer_(writer),
visitor_(visitor) {
SetConnectionIdCleanUpAlarm();
}
QuicTimeWaitListManager::~QuicTimeWaitListManager() {
connection_id_clean_up_alarm_->UnregisterIfRegistered();
STLDeleteElements(&pending_packets_queue_);
for (ConnectionIdMap::iterator it = connection_id_map_.begin();
it != connection_id_map_.end();
++it) {
delete it->second.close_packet;
}
}
void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
QuicConnectionId connection_id,
QuicVersion version,
QuicEncryptedPacket* close_packet) {
int num_packets = 0;
ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
if (it != connection_id_map_.end()) {
num_packets = it->second.num_packets;
delete it->second.close_packet;
connection_id_map_.erase(it);
}
ConnectionIdData data(num_packets, version, clock_.ApproximateNow(),
close_packet);
connection_id_map_.insert(make_pair(connection_id, data));
}
bool QuicTimeWaitListManager::IsConnectionIdInTimeWait(
QuicConnectionId connection_id) const {
return ContainsKey(connection_id_map_, connection_id);
}
QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId(
QuicConnectionId connection_id) {
ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
DCHECK(it != connection_id_map_.end());
return (it->second).version;
}
void QuicTimeWaitListManager::OnCanWrite() {
while (!pending_packets_queue_.empty()) {
QueuedPacket* queued_packet = pending_packets_queue_.front();
if (!WriteToWire(queued_packet)) {
return;
}
pending_packets_queue_.pop_front();
delete queued_packet;
}
}
void QuicTimeWaitListManager::ProcessPacket(
const IPEndPoint& server_address,
const IPEndPoint& client_address,
QuicConnectionId connection_id,
QuicPacketSequenceNumber sequence_number) {
DCHECK(IsConnectionIdInTimeWait(connection_id));
ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
DCHECK(it != connection_id_map_.end());
++((it->second).num_packets);
if (!ShouldSendResponse((it->second).num_packets)) {
return;
}
if (it->second.close_packet) {
QueuedPacket* queued_packet =
new QueuedPacket(server_address,
client_address,
it->second.close_packet->Clone());
SendOrQueuePacket(queued_packet);
} else {
SendPublicReset(server_address,
client_address,
connection_id,
sequence_number);
}
}
bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
return (received_packet_count & (received_packet_count - 1)) == 0;
}
void QuicTimeWaitListManager::SendPublicReset(
const IPEndPoint& server_address,
const IPEndPoint& client_address,
QuicConnectionId connection_id,
QuicPacketSequenceNumber rejected_sequence_number) {
QuicPublicResetPacket packet;
packet.public_header.connection_id = connection_id;
packet.public_header.reset_flag = true;
packet.public_header.version_flag = false;
packet.rejected_sequence_number = rejected_sequence_number;
packet.nonce_proof = 1010101;
packet.client_address = client_address;
QueuedPacket* queued_packet = new QueuedPacket(
server_address,
client_address,
QuicFramer::BuildPublicResetPacket(packet));
SendOrQueuePacket(queued_packet);
}
void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
if (WriteToWire(packet)) {
delete packet;
} else {
pending_packets_queue_.push_back(packet);
}
}
bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
if (writer_->IsWriteBlocked()) {
visitor_->OnWriteBlocked(this);
return false;
}
WriteResult result = writer_->WritePacket(
queued_packet->packet()->data(),
queued_packet->packet()->length(),
queued_packet->server_address().address(),
queued_packet->client_address());
if (result.status == WRITE_STATUS_BLOCKED) {
DCHECK(writer_->IsWriteBlocked());
visitor_->OnWriteBlocked(this);
return writer_->IsWriteBlockedDataBuffered();
} else if (result.status == WRITE_STATUS_ERROR) {
LOG(WARNING) << "Received unknown error while sending reset packet to "
<< queued_packet->client_address().ToString() << ": "
<< strerror(result.error_code);
}
return true;
}
void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
connection_id_clean_up_alarm_->UnregisterIfRegistered();
int64 next_alarm_interval;
if (!connection_id_map_.empty()) {
QuicTime oldest_connection_id =
connection_id_map_.begin()->second.time_added;
QuicTime now = clock_.ApproximateNow();
if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
next_alarm_interval = oldest_connection_id.Add(kTimeWaitPeriod_)
.Subtract(now)
.ToMicroseconds();
} else {
LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod";
next_alarm_interval = 0;
}
} else {
next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
}
epoll_server_->RegisterAlarmApproximateDelta(
next_alarm_interval, connection_id_clean_up_alarm_.get());
}
void QuicTimeWaitListManager::CleanUpOldConnectionIds() {
QuicTime now = clock_.ApproximateNow();
while (!connection_id_map_.empty()) {
ConnectionIdMap::iterator it = connection_id_map_.begin();
QuicTime oldest_connection_id = it->second.time_added;
if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
break;
}
delete it->second.close_packet;
connection_id_map_.erase(it);
}
SetConnectionIdCleanUpAlarm();
}
}
}