#include <limits>
+#include <boost/scoped_array.hpp>
+
using namespace std;
using boost::asio::ip::address_v4;
+using boost::scoped_array;
//-----------------------------------------------------------------------------
// Ipv4Header
static const size_t Ipv4HeaderSizeInBytes = 20;
-Ipv4Header::Ipv4Header()
+Ipv4Header::Ipv4Header() :
+ Payload( Ipv4HeaderSizeInBytes )
{
- fill( Payload, Payload + sizeof(Payload), 0 );
}
uint8_t Ipv4Header::get_version() const
{
- return ( Payload[ 0 ] >> 4 ) & 0xF;
+ return ( Payload[ 0 ] >> 4 ) & 0x0F;
}
uint16_t Ipv4Header::get_header_length() const
{
- return static_cast<uint16_t>( (Payload[ 0 ] & 0xF) * 4 );
+ // The Internet Header Length tells the number of 32-bit words in the
+ // header. Since an IPv4 header may contain a variable number of options,
+ // this field specifies the size of the header (this also coincides with
+ // the offset to the data). The minimum value for this field is 5 (RFC 791),
+ // which is a length of 5×32 = 160 bits = 20 bytes. Being a 4-bit value,
+ // the maximum length is 15 words (15×32 bits) or 480 bits = 60 bytes.
+ return static_cast<uint16_t>( (Payload[ 0 ] & 0x0F) * 4 );
}
uint8_t Ipv4Header::get_type_of_service() const
uint16_t Ipv4Header::get_total_length() const
{
- return decode( 2, 3 );
+ return Payload.decode16( 2, 3 );
}
uint16_t Ipv4Header::get_identification() const
{
- return decode( 4, 5 );
+ return Payload.decode16( 4, 5 );
}
bool Ipv4Header::dont_fragment() const
uint16_t Ipv4Header::get_fragment_offset() const
{
- return decode( 6, 7 ) & 0x1FFF;
+ return Payload.decode16( 6, 7 ) & 0x1FFF;
}
uint8_t Ipv4Header::get_time_to_live() const
uint16_t Ipv4Header::get_header_checksum() const
{
- return decode( 10, 11 );
+ return Payload.decode16( 10, 11 );
}
address_v4 Ipv4Header::get_source_address() const
{
- address_v4::bytes_type bytes = { {
- Payload[ 12 ],
- Payload[ 13 ],
- Payload[ 14 ],
- Payload[ 15 ]
- } };
- return address_v4( bytes );
+ uint32_t address = Payload.decode32( 12, 15 );
+
+ return address_v4( address );
}
address_v4 Ipv4Header::get_destination_address() const
{
- address_v4::bytes_type bytes = { {
- Payload[ 16 ],
- Payload[ 17 ],
- Payload[ 18 ],
- Payload[ 19 ]
- } };
- return address_v4( bytes );
+ uint32_t address = Payload.decode32( 16, 19 );
+
+ return address_v4( address );
}
istream &operator>>(
Ipv4Header &header
)
{
- (void) is.read(
- reinterpret_cast<char*> ( header.Payload ),
- Ipv4HeaderSizeInBytes
- );
+ // read the first 20 bytes (mandatory for IP header) from the input stream
+ // and stores in the buffer object
+ header.Payload.read( is );
if ( header.get_version() != 4 )
+ {
is.setstate( ios::failbit );
- streamsize options_length =
- (streamsize) header.get_header_length() -
- Ipv4HeaderSizeInBytes;
- if ( options_length < 0 || 40 < options_length )
+ }
+
+ // read the consecutive N bytes (for options field) from the input stream
+ // and stores in the buffer object
+ streamsize options_length = (streamsize) header.get_header_length() -
+ Ipv4HeaderSizeInBytes;
+ if ( ( options_length < 0 ) || ( 40 < options_length ) )
{
is.setstate( ios::failbit );
}
else
{
- (void) is.read(
- reinterpret_cast<char*> ( header.Payload ) +
- Ipv4HeaderSizeInBytes,
- options_length
- );
- }
+ scoped_array<uint8_t> options_data(new uint8_t[options_length]);
+ char *options_data_array = reinterpret_cast<char *>( options_data.get() );
- return is;
-}
-
-uint16_t Ipv4Header::decode( int left_byte, int right_byte ) const
-{
- uint32_t value = ( Payload[ left_byte ] << 8 ) + Payload[ right_byte ];
+ is.read( options_data_array, options_length );
- BOOST_ASSERT( value <= numeric_limits<uint16_t>::max() );
+ header.Payload.append( options_data.get(), options_length );
+ }
- return static_cast<uint16_t>( value );
+ return is;
}