// Copyright (c) 2009 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. // This file contains some protocol structures for use with Flip. #ifndef NET_FLIP_FLIP_PROTOCOL_H_ #define NET_FLIP_FLIP_PROTOCOL_H_ #ifdef WIN32 #include #else #include #endif #include "base/basictypes.h" #include "base/logging.h" #include "flip_bitmasks.h" // cross-google3 directory naming. // Data Frame Format // +----------------------------------+ // |0| Stream-ID (31bits) | // +----------------------------------+ // | flags (8) | Length (24 bits) | // +----------------------------------+ // | Data | // +----------------------------------+ // // Control Frame Format // +----------------------------------+ // |1| Version(15bits) | Type(16bits) | // +----------------------------------+ // | flags (8) | Length (24 bits) | // +----------------------------------+ // | Data | // +----------------------------------+ // // Control Frame: SYN_STREAM // +----------------------------------+ // |1|000000000000001|0000000000000001| // +----------------------------------+ // | flags (8) | Length (24 bits) | >= 8 // +----------------------------------+ // |X| Stream-ID(31bits) | // +----------------------------------+ // |Pri| unused | Length (16bits)| // +----------------------------------+ // // Control Frame: SYN_REPLY // +----------------------------------+ // |1|000000000000001|0000000000000010| // +----------------------------------+ // | flags (8) | Length (24 bits) | >= 8 // +----------------------------------+ // |X| Stream-ID(31bits) | // +----------------------------------+ // | unused (16 bits)| Length (16bits)| // +----------------------------------+ // // Control Frame: FIN_STREAM // +----------------------------------+ // |1|000000000000001|0000000000000011| // +----------------------------------+ // | flags (8) | Length (24 bits) | >= 4 // +----------------------------------+ // |X| Stream-ID(31bits) | // +----------------------------------+ // | Status (32 bits) | // +----------------------------------+ // // Control Frame: SetMaxStreams // +----------------------------------+ // |1|000000000000001|0000000000000100| // +----------------------------------+ // | flags (8) | Length (24 bits) | >= 4 // +----------------------------------+ // |X| Stream-ID(31bits) | // +----------------------------------+ // TODO(fenix): add ChangePriority support. namespace flip { // This implementation of Flip is version 1. const int kFlipProtocolVersion = 1; // Note: all protocol data structures are on-the-wire format. That means that // data is stored in network-normalized order. Readers must use the // accessors provided or call ntohX() functions. // Types of Flip Control Frames. enum FlipControlType { SYN_STREAM = 1, SYN_REPLY, FIN_STREAM, NOOP }; // Flags on data packets enum FlipDataFlags { DATA_FLAG_NONE = 0, DATA_FLAG_FIN = 1, DATA_FLAG_COMPRESSED = 2 // TODO(mbelshe): remove me. }; // Flags on control packets enum FlipControlFlags { CONTROL_FLAG_NONE = 0, CONTROL_FLAG_FIN = 1 }; // A FLIP stream id is a 31 bit entity. typedef uint32 FlipStreamId; // FLIP Priorities. (there are only 2 bits) #define FLIP_PRIORITY_LOWEST 3 #define FLIP_PRIORITY_HIGHEST 0 // ------------------------------------------------------------------------- // These structures mirror the protocol structure definitions. // For the control data structures, we pack so that sizes match the // protocol over-the-wire sizes. #pragma pack(push) #pragma pack(1) // A special structure for the 8 bit flags and 24 bit length fields. union FlagsAndLength { uint8 flags_[4]; // 8 bits uint32 length_; // 24 bits }; // The basic FLIP Frame structure. struct FlipFrameBlock { union { struct { uint16 version_; uint16 type_; } control_; struct { FlipStreamId stream_id_; } data_; }; FlagsAndLength flags_length_; }; // A Control Frame structure. struct FlipControlFrameBlock : FlipFrameBlock { FlipStreamId stream_id_; }; // A SYN_STREAM Control Frame structure. struct FlipSynStreamControlFrameBlock : FlipControlFrameBlock { uint8 priority_; uint8 unused_; }; // A SYN_REPLY Control Frame structure. struct FlipSynReplyControlFrameBlock : FlipControlFrameBlock { uint16 unused_; }; // A FNI_STREAM Control Frame structure. struct FlipFinStreamControlFrameBlock : FlipControlFrameBlock { uint32 status_; }; #pragma pack(pop) // ------------------------------------------------------------------------- // Wrapper classes for various FLIP frames. // All Flip Frame types derive from this FlipFrame class. class FlipFrame { public: // Create a FlipFrame for a given sized buffer. explicit FlipFrame(size_t size) : frame_(NULL), owns_buffer_(true) { DCHECK_GE(size, sizeof(struct FlipFrameBlock)); char* buffer = new char[size]; memset(buffer, 0, size); frame_ = reinterpret_cast(buffer); } // Create a FlipFrame using a pre-created buffer. // If |owns_buffer| is true, this class takes ownership of the buffer // and will delete it on cleanup. The buffer must have been created using // new char[]. // If |owns_buffer| is false, the caller retains ownership of the buffer and // is responsible for making sure the buffer outlives this frame. In other // words, this class does NOT create a copy of the buffer. FlipFrame(char* data, bool owns_buffer) : frame_(reinterpret_cast(data)), owns_buffer_(owns_buffer) { DCHECK(frame_); } virtual ~FlipFrame() { if (owns_buffer_) { char* buffer = reinterpret_cast(frame_); delete [] buffer; } frame_ = NULL; } // Provides access to the frame bytes, which is a buffer containing // the frame packed as expected for sending over the wire. char* data() const { return reinterpret_cast(frame_); } uint8 flags() const { return frame_->flags_length_.flags_[0]; } void set_flags(uint8 flags) { frame_->flags_length_.flags_[0] = flags; } uint32 length() const { return ntohl(frame_->flags_length_.length_) & kLengthMask; } void set_length(uint32 length) { DCHECK_EQ(0u, (length & ~kLengthMask)); length = htonl(length & kLengthMask); frame_->flags_length_.length_ = flags() | length; } bool is_control_frame() const { return (ntohs(frame_->control_.version_) & kControlFlagMask) == kControlFlagMask; } // Returns the size of the FlipFrameBlock structure. // Note: this is not the size of the FlipFrame class. // Every FlipFrame* class has a static size() method for accessing // the size of the data structure which will be sent over the wire. // Note: this is not the same as sizeof(FlipFrame). static size_t size() { return sizeof(struct FlipFrameBlock); } protected: FlipFrameBlock* frame_; private: bool owns_buffer_; DISALLOW_COPY_AND_ASSIGN(FlipFrame); }; // A Data Frame. class FlipDataFrame : public FlipFrame { public: FlipDataFrame() : FlipFrame(size()) {} FlipDataFrame(char* data, bool owns_buffer) : FlipFrame(data, owns_buffer) {} virtual ~FlipDataFrame() {} FlipStreamId stream_id() const { return ntohl(frame_->data_.stream_id_) & kStreamIdMask; } // Note that setting the stream id sets the control bit to false. // As stream id should always be set, this means the control bit // should always be set correctly. void set_stream_id(FlipStreamId id) { DCHECK_EQ(0u, (id & ~kStreamIdMask)); frame_->data_.stream_id_ = htonl(id & kStreamIdMask); } // Returns the size of the FlipFrameBlock structure. // Note: this is not the size of the FlipDataFrame class. static size_t size() { return FlipFrame::size(); } private: DISALLOW_COPY_AND_ASSIGN(FlipDataFrame); }; // A Control Frame. class FlipControlFrame : public FlipFrame { public: explicit FlipControlFrame(size_t size) : FlipFrame(size) {} FlipControlFrame(char* data, bool owns_buffer) : FlipFrame(data, owns_buffer) {} virtual ~FlipControlFrame() {} uint16 version() const { const int kVersionMask = 0x7fff; return ntohs(block()->control_.version_) & kVersionMask; } FlipControlType type() const { uint16 type = ntohs(block()->control_.type_); DCHECK(type >= SYN_STREAM && type <= NOOP); return static_cast(type); } FlipStreamId stream_id() const { return ntohl(block()->stream_id_) & kStreamIdMask; } void set_stream_id(FlipStreamId id) { block()->stream_id_ = htonl(id & kStreamIdMask); } // Returns the size of the FlipControlFrameBlock structure. // Note: this is not the size of the FlipControlFrame class. static size_t size() { return sizeof(FlipControlFrameBlock); } private: struct FlipControlFrameBlock* block() const { return static_cast(frame_); } DISALLOW_COPY_AND_ASSIGN(FlipControlFrame); }; // A SYN_STREAM frame. class FlipSynStreamControlFrame : public FlipControlFrame { public: FlipSynStreamControlFrame() : FlipControlFrame(size()) {} FlipSynStreamControlFrame(char* data, bool owns_buffer) : FlipControlFrame(data, owns_buffer) {} virtual ~FlipSynStreamControlFrame() {} uint8 priority() const { return (block()->priority_ & kPriorityMask) >> 6; } // The number of bytes in the header block beyond the frame header length. int header_block_len() const { return length() - (size() - FlipFrame::size()); } const char* header_block() const { return reinterpret_cast(block()) + size(); } // Returns the size of the FlipSynStreamControlFrameBlock structure. // Note: this is not the size of the FlipSynStreamControlFrame class. static size_t size() { return sizeof(FlipSynStreamControlFrameBlock); } private: struct FlipSynStreamControlFrameBlock* block() const { return static_cast(frame_); } DISALLOW_COPY_AND_ASSIGN(FlipSynStreamControlFrame); }; // A SYN_REPLY frame. class FlipSynReplyControlFrame : public FlipControlFrame { public: FlipSynReplyControlFrame() : FlipControlFrame(size()) {} FlipSynReplyControlFrame(char* data, bool owns_buffer) : FlipControlFrame(data, owns_buffer) {} virtual ~FlipSynReplyControlFrame() {} int header_block_len() const { return length() - (size() - FlipFrame::size()); } const char* header_block() const { return reinterpret_cast(block()) + size(); } // Returns the size of the FlipSynReplyControlFrameBlock structure. // Note: this is not the size of the FlipSynReplyControlFrame class. static size_t size() { return sizeof(FlipSynReplyControlFrameBlock); } private: struct FlipSynReplyControlFrameBlock* block() const { return static_cast(frame_); } DISALLOW_COPY_AND_ASSIGN(FlipSynReplyControlFrame); }; // A FIN_STREAM frame. class FlipFinStreamControlFrame : public FlipControlFrame { public: FlipFinStreamControlFrame() : FlipControlFrame(size()) {} FlipFinStreamControlFrame(char* data, bool owns_buffer) : FlipControlFrame(data, owns_buffer) {} virtual ~FlipFinStreamControlFrame() {} uint32 status() const { return ntohl(block()->status_); } void set_status(uint32 status) { block()->status_ = htonl(status); } // Returns the size of the FlipFinStreamControlFrameBlock structure. // Note: this is not the size of the FlipFinStreamControlFrame class. static size_t size() { return sizeof(FlipFinStreamControlFrameBlock); } private: struct FlipFinStreamControlFrameBlock* block() const { return static_cast(frame_); } DISALLOW_COPY_AND_ASSIGN(FlipFinStreamControlFrame); }; } // namespace flip #endif // NET_FLIP_FLIP_PROTOCOL_H_