// 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 <winsock2.h>
#else
#include <arpa/inet.h>
#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<struct FlipFrameBlock*>(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<struct FlipFrameBlock*>(data)),
owns_buffer_(owns_buffer) {
DCHECK(frame_);
}
virtual ~FlipFrame() {
if (owns_buffer_) {
char* buffer = reinterpret_cast<char*>(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<char*>(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<FlipControlType>(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<FlipControlFrameBlock*>(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<const char*>(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<FlipSynStreamControlFrameBlock*>(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<const char*>(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<FlipSynReplyControlFrameBlock*>(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<FlipFinStreamControlFrameBlock*>(frame_);
}
DISALLOW_COPY_AND_ASSIGN(FlipFinStreamControlFrame);
};
} // namespace flip
#endif // NET_FLIP_FLIP_PROTOCOL_H_