// Copyright (c) 2012 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. // // Accumulates frames for the next packet until more frames no longer fit or // it's time to create a packet from them. Also provides packet creation of // FEC packets based on previously created packets. #ifndef NET_QUIC_QUIC_PACKET_CREATOR_H_ #define NET_QUIC_QUIC_PACKET_CREATOR_H_ #include <utility> #include <vector> #include "base/memory/scoped_ptr.h" #include "base/strings/string_piece.h" #include "net/quic/quic_fec_group.h" #include "net/quic/quic_framer.h" #include "net/quic/quic_protocol.h" namespace net { namespace test { class QuicPacketCreatorPeer; } class QuicAckNotifier; class QuicRandom; class QuicRandomBoolSource; class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { public: // QuicRandom* required for packet entropy. QuicPacketCreator(QuicConnectionId connection_id, QuicFramer* framer, QuicRandom* random_generator); virtual ~QuicPacketCreator(); // QuicFecBuilderInterface virtual void OnBuiltFecProtectedPayload(const QuicPacketHeader& header, base::StringPiece payload) OVERRIDE; // Turn on FEC protection for subsequently created packets. FEC should be // enabled first (max_packets_per_fec_group should be non-zero) for FEC // protection to start. void StartFecProtectingPackets(); // Turn off FEC protection for subsequently created packets. If the creator // has any open FEC group, call will fail. It is the caller's responsibility // to flush out FEC packets in generation, and to verify with ShouldSendFec() // that there is no open FEC group. void StopFecProtectingPackets(); // Checks if it's time to send an FEC packet. |force_close| forces this to // return true if an FEC group is open. bool ShouldSendFec(bool force_close) const; // Returns true if an FEC packet is under construction. bool IsFecGroupOpen() const; // Makes the framer not serialize the protocol version in sent packets. void StopSendingVersion(); // Update the sequence number length to use in future packets as soon as it // can be safely changed. void UpdateSequenceNumberLength( QuicPacketSequenceNumber least_packet_awaited_by_peer, QuicByteCount congestion_window); // The overhead the framing will add for a packet with one frame. static size_t StreamFramePacketOverhead( QuicVersion version, QuicConnectionIdLength connection_id_length, bool include_version, QuicSequenceNumberLength sequence_number_length, QuicStreamOffset offset, InFecGroup is_in_fec_group); bool HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset) const; // Converts a raw payload to a frame which fits into the currently open // packet if there is one. Returns the number of bytes consumed from data. // If data is empty and fin is true, the expected behavior is to consume the // fin but return 0. size_t CreateStreamFrame(QuicStreamId id, const IOVector& data, QuicStreamOffset offset, bool fin, QuicFrame* frame); // As above, but keeps track of an QuicAckNotifier that should be called when // the packet that contains this stream frame is ACKed. // The |notifier| is not owned by the QuicPacketGenerator and must outlive the // generated packet. size_t CreateStreamFrameWithNotifier(QuicStreamId id, const IOVector& data, QuicStreamOffset offset, bool fin, QuicAckNotifier* notifier, QuicFrame* frame); // Serializes all frames into a single packet. All frames must fit into a // single packet. Also, sets the entropy hash of the serialized packet to a // random bool and returns that value as a member of SerializedPacket. // Never returns a RetransmittableFrames in SerializedPacket. SerializedPacket SerializeAllFrames(const QuicFrames& frames); // Re-serializes frames with the original packet's sequence number length. // Used for retransmitting packets to ensure they aren't too long. // Caller must ensure that any open FEC group is closed before calling this // method. SerializedPacket ReserializeAllFrames( const QuicFrames& frames, QuicSequenceNumberLength original_length); // Returns true if there are frames pending to be serialized. bool HasPendingFrames() const; // Returns true if there are retransmittable frames pending to be serialized. bool HasPendingRetransmittableFrames() const; // Returns whether FEC protection is currently enabled. Note: Enabled does not // mean that an FEC group is currently active; i.e., IsFecProtected() may // still return false. bool IsFecEnabled() const; // Returns true if subsequent packets will be FEC protected. Note: True does // not mean that an FEC packet is currently under construction; i.e., // fec_group_.get() may still be NULL, until MaybeStartFec() is called. bool IsFecProtected() const; // Returns the number of bytes which are available to be used by additional // frames in the packet. Since stream frames are slightly smaller when they // are the last frame in a packet, this method will return a different // value than max_packet_size - PacketSize(), in this case. size_t BytesFree() const; // Returns the number of bytes that the packet will expand by if a new frame // is added to the packet. If the last frame was a stream frame, it will // expand slightly when a new frame is added, and this method returns the // amount of expected expansion. If the packet is in an FEC group, no // expansion happens and this method always returns zero. size_t ExpansionOnNewFrame() const; // Returns the number of bytes in the current packet, including the header, // if serialized with the current frames. Adding a frame to the packet // may change the serialized length of existing frames, as per the comment // in BytesFree. size_t PacketSize() const; // TODO(jri): AddSavedFrame calls AddFrame, which only saves the frame // if it is a stream frame, not other types of frames. Fix this API; // add a AddNonSavedFrame method. // Adds |frame| to the packet creator's list of frames to be serialized. // Returns false if the frame doesn't fit into the current packet. bool AddSavedFrame(const QuicFrame& frame); // Serializes all frames which have been added and adds any which should be // retransmitted to |retransmittable_frames| if it's not NULL. All frames must // fit into a single packet. Sets the entropy hash of the serialized // packet to a random bool and returns that value as a member of // SerializedPacket. Also, sets |serialized_frames| in the SerializedPacket // to the corresponding RetransmittableFrames if any frames are to be // retransmitted. SerializedPacket SerializePacket(); // Packetize FEC data. All frames must fit into a single packet. Also, sets // the entropy hash of the serialized packet to a random bool and returns // that value as a member of SerializedPacket. SerializedPacket SerializeFec(); // Creates a packet with connection close frame. Caller owns the created // packet. Also, sets the entropy hash of the serialized packet to a random // bool and returns that value as a member of SerializedPacket. SerializedPacket SerializeConnectionClose( QuicConnectionCloseFrame* close_frame); // Creates a version negotiation packet which supports |supported_versions|. // Caller owns the created packet. Also, sets the entropy hash of the // serialized packet to a random bool and returns that value as a member of // SerializedPacket. QuicEncryptedPacket* SerializeVersionNegotiationPacket( const QuicVersionVector& supported_versions); // Sets the encryption level that will be applied to new packets. void set_encryption_level(EncryptionLevel level) { encryption_level_ = level; } // Sequence number of the last created packet, or 0 if no packets have been // created. QuicPacketSequenceNumber sequence_number() const { return sequence_number_; } void set_sequence_number(QuicPacketSequenceNumber s) { sequence_number_ = s; } QuicConnectionIdLength connection_id_length() const { return connection_id_length_; } QuicSequenceNumberLength next_sequence_number_length() const { return next_sequence_number_length_; } void set_next_sequence_number_length(QuicSequenceNumberLength length) { next_sequence_number_length_ = length; } size_t max_packet_length() const { return max_packet_length_; } void set_max_packet_length(size_t length) { // |max_packet_length_| should not be changed mid-packet or mid-FEC group. DCHECK(fec_group_.get() == NULL && queued_frames_.empty()); max_packet_length_ = length; } // Returns current max number of packets covered by an FEC group. size_t max_packets_per_fec_group() const { return max_packets_per_fec_group_; } // Sets creator's max number of packets covered by an FEC group. void set_max_packets_per_fec_group( size_t max_packets_per_fec_group) { // To turn off FEC protection, use StopFecProtectingPackets(). DCHECK_NE(0u, max_packets_per_fec_group); max_packets_per_fec_group_ = max_packets_per_fec_group; } private: friend class test::QuicPacketCreatorPeer; static bool ShouldRetransmit(const QuicFrame& frame); // Updates sequence number and max packet lengths on a packet or FEC group // boundary. void MaybeUpdateLengths(); // Updates lengths and also starts an FEC group if FEC protection is on and // there is not already an FEC group open. InFecGroup MaybeUpdateLengthsAndStartFec(); void FillPacketHeader(QuicFecGroupNumber fec_group, bool fec_flag, QuicPacketHeader* header); // Allows a frame to be added without creating retransmittable frames. // Particularly useful for retransmits using SerializeAllFrames(). bool AddFrame(const QuicFrame& frame, bool save_retransmittable_frames); // Adds a padding frame to the current packet only if the current packet // contains a handshake message, and there is sufficient room to fit a // padding frame. void MaybeAddPadding(); QuicConnectionId connection_id_; EncryptionLevel encryption_level_; QuicFramer* framer_; scoped_ptr<QuicRandomBoolSource> random_bool_source_; QuicPacketSequenceNumber sequence_number_; // If true, any created packets will be FEC protected. bool should_fec_protect_; QuicFecGroupNumber fec_group_number_; scoped_ptr<QuicFecGroup> fec_group_; // Controls whether protocol version should be included while serializing the // packet. bool send_version_in_packet_; // Maximum length including headers and encryption (UDP payload length.) size_t max_packet_length_; // 0 indicates FEC is disabled. size_t max_packets_per_fec_group_; // Length of connection_id to send over the wire. QuicConnectionIdLength connection_id_length_; // Staging variable to hold next packet sequence number length. When sequence // number length is to be changed, this variable holds the new length until // a packet or FEC group boundary, when the creator's sequence_number_length_ // can be changed to this new value. QuicSequenceNumberLength next_sequence_number_length_; // Sequence number length for the current packet and for the current FEC group // when FEC is enabled. Mutable so PacketSize() can adjust it when the packet // is empty. mutable QuicSequenceNumberLength sequence_number_length_; // packet_size_ is mutable because it's just a cache of the current size. // packet_size should never be read directly, use PacketSize() instead. mutable size_t packet_size_; QuicFrames queued_frames_; scoped_ptr<RetransmittableFrames> queued_retransmittable_frames_; DISALLOW_COPY_AND_ASSIGN(QuicPacketCreator); }; } // namespace net #endif // NET_QUIC_QUIC_PACKET_CREATOR_H_