| Index: net/quic/quic_connection.cc
|
| diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
|
| index 49d6af61380853cd5a6a814d24a3f4cfe9251145..479373ed9a4e6e392e6c1eccf2c2ce8484fd1b8f 100644
|
| --- a/net/quic/quic_connection.cc
|
| +++ b/net/quic/quic_connection.cc
|
| @@ -166,7 +166,6 @@ QuicConnection::QuicConnection(QuicGuid guid,
|
| peer_address_(address),
|
| largest_seen_packet_with_ack_(0),
|
| pending_version_negotiation_packet_(false),
|
| - write_blocked_(false),
|
| received_packet_manager_(kTCP),
|
| ack_alarm_(helper->CreateAlarm(new AckAlarm(this))),
|
| retransmission_alarm_(helper->CreateAlarm(new RetransmissionAlarm(this))),
|
| @@ -772,9 +771,6 @@ void QuicConnection::SendVersionNegotiationPacket() {
|
| WriteResult result =
|
| writer_->WritePacket(version_packet->data(), version_packet->length(),
|
| self_address().address(), peer_address(), this);
|
| - if (result.status == WRITE_STATUS_BLOCKED) {
|
| - write_blocked_ = true;
|
| - }
|
| if (result.status == WRITE_STATUS_OK ||
|
| (result.status == WRITE_STATUS_BLOCKED &&
|
| writer_->IsWriteBlockedDataBuffered())) {
|
| @@ -881,21 +877,9 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
|
| }
|
|
|
| bool QuicConnection::OnCanWrite() {
|
| - write_blocked_ = false;
|
| - return DoWrite();
|
| -}
|
| -
|
| -bool QuicConnection::WriteIfNotBlocked() {
|
| - if (write_blocked_) {
|
| - return false;
|
| - }
|
| - return DoWrite();
|
| -}
|
| + DCHECK(!writer_->IsWriteBlocked());
|
|
|
| -bool QuicConnection::DoWrite() {
|
| - DCHECK(!write_blocked_);
|
| WriteQueuedPackets();
|
| -
|
| WritePendingRetransmissions();
|
|
|
| IsHandshake pending_handshake = visitor_->HasPendingHandshake() ?
|
| @@ -925,7 +909,13 @@ bool QuicConnection::DoWrite() {
|
| }
|
| }
|
|
|
| - return !write_blocked_;
|
| + return !writer_->IsWriteBlocked();
|
| +}
|
| +
|
| +void QuicConnection::WriteIfNotBlocked() {
|
| + if (!writer_->IsWriteBlocked()) {
|
| + OnCanWrite();
|
| + }
|
| }
|
|
|
| bool QuicConnection::ProcessValidatedPacket() {
|
| @@ -946,15 +936,16 @@ bool QuicConnection::ProcessValidatedPacket() {
|
| return true;
|
| }
|
|
|
| -bool QuicConnection::WriteQueuedPackets() {
|
| - DCHECK(!write_blocked_);
|
| +void QuicConnection::WriteQueuedPackets() {
|
| + DCHECK(!writer_->IsWriteBlocked());
|
|
|
| if (pending_version_negotiation_packet_) {
|
| SendVersionNegotiationPacket();
|
| }
|
|
|
| QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
|
| - while (!write_blocked_ && packet_iterator != queued_packets_.end()) {
|
| + while (!writer_->IsWriteBlocked() &&
|
| + packet_iterator != queued_packets_.end()) {
|
| if (WritePacket(packet_iterator->encryption_level,
|
| packet_iterator->sequence_number,
|
| packet_iterator->packet,
|
| @@ -962,15 +953,14 @@ bool QuicConnection::WriteQueuedPackets() {
|
| packet_iterator->retransmittable,
|
| packet_iterator->handshake,
|
| packet_iterator->forced)) {
|
| + delete packet_iterator->packet;
|
| packet_iterator = queued_packets_.erase(packet_iterator);
|
| } else {
|
| // Continue, because some queued packets may still be writable.
|
| - // This can happen if a retransmit send fail.
|
| + // This can happen if a retransmit send fails.
|
| ++packet_iterator;
|
| }
|
| }
|
| -
|
| - return !write_blocked_;
|
| }
|
|
|
| void QuicConnection::WritePendingRetransmissions() {
|
| @@ -1035,7 +1025,7 @@ bool QuicConnection::ShouldGeneratePacket(
|
| bool QuicConnection::CanWrite(TransmissionType transmission_type,
|
| HasRetransmittableData retransmittable,
|
| IsHandshake handshake) {
|
| - if (write_blocked_) {
|
| + if (writer_->IsWriteBlocked()) {
|
| return false;
|
| }
|
|
|
| @@ -1073,16 +1063,13 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
|
| IsHandshake handshake,
|
| Force forced) {
|
| if (ShouldDiscardPacket(level, sequence_number, retransmittable)) {
|
| - delete packet;
|
| return true;
|
| }
|
|
|
| - // If we're write blocked, we know we can't write.
|
| - if (write_blocked_) {
|
| - return false;
|
| - }
|
| -
|
| - // If we are not forced and we can't write, then simply return false;
|
| + // If the writer is blocked, we must not write. However, if the packet is
|
| + // forced (i.e., it's the ConnectionClose packet), we still need to encrypt it
|
| + // and hand it off to TimeWaitListManager.
|
| + // We check nonforced packets here and forced after encryption.
|
| if (forced == NO_FORCE &&
|
| !CanWrite(transmission_type, retransmittable, handshake)) {
|
| return false;
|
| @@ -1098,20 +1085,29 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
|
| sequence_number_of_last_inorder_packet_ = sequence_number;
|
| }
|
|
|
| - scoped_ptr<QuicEncryptedPacket> encrypted(
|
| - framer_.EncryptPacket(level, sequence_number, *packet));
|
| - if (encrypted.get() == NULL) {
|
| + QuicEncryptedPacket* encrypted =
|
| + framer_.EncryptPacket(level, sequence_number, *packet);
|
| + if (encrypted == NULL) {
|
| LOG(DFATAL) << ENDPOINT << "Failed to encrypt packet number "
|
| << sequence_number;
|
| + // CloseConnection does not send close packet, so no infinite loop here.
|
| CloseConnection(QUIC_ENCRYPTION_FAILURE, false);
|
| return false;
|
| }
|
|
|
| - // If it's the ConnectionClose packet, the only FORCED frame type,
|
| - // clone a copy for resending later by the TimeWaitListManager.
|
| - if (forced == FORCE) {
|
| + // Forced packets are eventually owned by TimeWaitListManager; nonforced are
|
| + // deleted at the end of this call.
|
| + scoped_ptr<QuicEncryptedPacket> encrypted_deleter;
|
| + if (forced == NO_FORCE) {
|
| + encrypted_deleter.reset(encrypted);
|
| + } else { // forced == FORCE
|
| DCHECK(connection_close_packet_.get() == NULL);
|
| - connection_close_packet_.reset(encrypted->Clone());
|
| + connection_close_packet_.reset(encrypted);
|
| + // This assures we won't try to write *forced* packets when blocked.
|
| + // Return true to stop processing.
|
| + if (writer_->IsWriteBlocked()) {
|
| + return true;
|
| + }
|
| }
|
|
|
| if (encrypted->length() > options()->max_packet_length) {
|
| @@ -1153,16 +1149,11 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
|
| debug_visitor_->OnPacketSent(sequence_number, level, *encrypted, result);
|
| }
|
| if (result.status == WRITE_STATUS_BLOCKED) {
|
| - // TODO(satyashekhar): It might be more efficient (fewer system calls), if
|
| - // all connections share this variable i.e this becomes a part of
|
| - // PacketWriterInterface.
|
| - write_blocked_ = true;
|
| // If the socket buffers the the data, then the packet should not
|
| // be queued and sent again, which would result in an unnecessary
|
| // duplicate packet being sent. The helper must call OnPacketSent
|
| // when the packet is actually sent.
|
| if (writer_->IsWriteBlockedDataBuffered()) {
|
| - delete packet;
|
| return true;
|
| }
|
| pending_write_.reset();
|
| @@ -1170,7 +1161,6 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
|
| }
|
|
|
| if (OnPacketSent(result)) {
|
| - delete packet;
|
| return true;
|
| }
|
| return false;
|
| @@ -1318,6 +1308,7 @@ bool QuicConnection::SendOrQueuePacket(EncryptionLevel level,
|
| packet.entropy_hash);
|
| if (WritePacket(level, packet.sequence_number, packet.packet,
|
| transmission_type, retransmittable, handshake, forced)) {
|
| + delete packet.packet;
|
| return true;
|
| }
|
| queued_packets_.push_back(QueuedPacket(packet.sequence_number, packet.packet,
|
| @@ -1487,9 +1478,9 @@ void QuicConnection::SendConnectionClose(QuicErrorCode error) {
|
|
|
| void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error,
|
| const string& details) {
|
| - if (!write_blocked_) {
|
| - SendConnectionClosePacket(error, details);
|
| - }
|
| + // If we're write blocked, WritePacket() will not send, but will capture the
|
| + // serialized packet.
|
| + SendConnectionClosePacket(error, details);
|
| CloseConnection(error, false);
|
| }
|
|
|
|
|