*/
#include "icmp/icmppacket.h"
+#include <iostream>
//-----------------------------------------------------------------------------
// IcmpPacket
IcmpPacket::~IcmpPacket()
{
}
+
+/**
+ *
+ *
+ */
+{
+
+
+}
+
+/**
+ * @brief create packet from data in @a is; calls IcmpPacket::read
+ *
+ * @param is input stream with hopefully sufficient data
+ *
+ * @returns stream with less data; failbit is set if read returns other than ReadReturnCode_OK
+ */
+std::istream& operator>>(
+ std::istream &is,
+ IcmpPacket &packet
+)
+{
+ IcmpPacket::ReadReturnCode return_code = packet.read(is);
+ if ( return_code != IcmpPacket::ReadReturnCode_OK )
+ is.setstate( std::ios::failbit );
+
+ return is;
+}
+
+
+std::ostream& operator<<(
+ std::ostream& os,
+ const IcmpPacket& packet
+)
+{
+ packet.write( os );
+ return os;
+}
) const = 0;
virtual void print_destination_unreachable() const = 0;
- virtual bool read( std::istream &is ) = 0;
+ enum ReadReturnCode {
+ ReadReturnCode_OK = 0,
+ ReadReturnCode_FAIL,
+ ReadReturnCode_NOT_ENOUGH_DATA,
+ ReadReturnCode_BAD_STREAM,
+ ReadReturnCode_INVALID_SIZE
+ };
+
+ virtual ReadReturnCode read( std::istream &is ) = 0;
virtual bool write( std::ostream &os ) const = 0;
+ friend std::istream& operator>>(
+ std::istream &is,
+ IcmpPacket &packet
+ );
+ friend std::ostream& operator<<(
+ std::ostream &os,
+ const IcmpPacket &packet
+ );
+
protected:
IcmpPacket();
virtual ~IcmpPacket();
}
/**
- * @brief Read the ICMP packet from the @c istream.
+ * @brief Read (part of) the ICMP packet from the input stream @a is
*
* @param is The input stream.
*
- * @return @c true if the read was successful, or @c false if an error occurred.
+ * @return result of the read, currently one of {ok, fail, not enough data}
*/
-bool Icmpv4Packet::read( istream &is )
+IcmpPacket::ReadReturnCode Icmpv4Packet::read( istream &is )
{
- is.clear();
+ if ( !is.good() )
+ return IcmpPacket::ReadReturnCode_BAD_STREAM;
- is >> *this;
+ // try to read ip header
+ is >> IpHeader;
- return !is.fail();
+ if ( is.eof() )
+ return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA;
+ else if ( !is.good() )
+ return IcmpPacket::ReadReturnCode_BAD_STREAM;
+
+ // try to read the icmp header
+ is >> IcmpPayloadHeader;
+
+ if ( is.eof() )
+ return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA;
+ else if ( !is.good() )
+ return IcmpPacket::ReadReturnCode_BAD_STREAM;
+
+ // calculate the size of the ICMP data
+ streamsize data_length = static_cast<streamsize>( IpHeader.get_total_length() )
+ - static_cast<streamsize>( IpHeader.get_header_length() )
+ - static_cast<streamsize>( IcmpPayloadHeader.get_header_length() );
+
+ // try to read that amount of data
+ if ( data_length < 0 )
+ {
+ GlobalLogger.error() << "Error: invalid size for optional ICMP data: "
+ << data_length << endl;
+ is.setstate( ios::failbit );
+ return IcmpPacket::ReadReturnCode_INVALID_SIZE;
+ }
+ else if ( data_length > 0 )
+ {
+ size_t options_size = static_cast<size_t>( data_length );
+ scoped_array<uint8_t> scoped_data( new uint8_t[options_size+1] ); // need a 0 after data
+ memset(scoped_data.get(), 0, (options_size+1)*sizeof(uint8_t));
+ char *char_data = reinterpret_cast<char *>( scoped_data.get() );
+
+ (void) is.read( char_data, data_length ); // leave 0 at the end
+ IcmpPayloadData = char_data; // implicit cast
+ }
+
+ if ( is.eof() )
+ return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA;
+ else if ( !is.good() )
+ return IcmpPacket::ReadReturnCode_BAD_STREAM;
+ else
+ return IcmpPacket::ReadReturnCode_OK;
}
/**
*
* @return @c true if the write was successful, or @c false if an error occurred.
*/
-bool Icmpv4Packet::write( ostream &os ) const
+bool Icmpv4Packet::write( std::ostream &os ) const
{
os.clear();
- os << *this;
+ os << IcmpPayloadHeader << IcmpPayloadData;
return !os.fail();
}
-istream& operator>>(
- istream &is,
- Icmpv4Packet &packet
-)
-{
- if (is.good())
- is >> packet.IpHeader;
- if (is.good())
- is >> packet.IcmpPayloadHeader;
- if (is.good())
- {
- streamsize data_length = static_cast<streamsize>( packet.IpHeader.get_total_length() )
- - static_cast<streamsize>( packet.IpHeader.get_header_length() )
- - static_cast<streamsize>( packet.IcmpPayloadHeader.get_header_length() );
-
- if ( data_length < 0 )
- {
- GlobalLogger.error() << "Error: invalid size for optional ICMP data: "
- << data_length << endl;
- is.setstate( ios::failbit );
- }
- else if ( data_length > 0 )
- {
- size_t options_size = static_cast<size_t>( data_length );
- scoped_array<uint8_t> scoped_data( new uint8_t[options_size+1] ); // need a 0 after data
- memset(scoped_data.get(), 0, (options_size+1)*sizeof(uint8_t));
- char *char_data = reinterpret_cast<char *>( scoped_data.get() );
-
- (void) is.read( char_data, data_length );
- packet.IcmpPayloadData = char_data;
- }
- }
-
- return is;
-}
-
-ostream& operator<<(
- ostream& os,
- const Icmpv4Packet& packet
-)
-{
- os << packet.IcmpPayloadHeader << packet.IcmpPayloadData;
-
- return os;
-}
) const;
virtual void print_destination_unreachable() const;
- virtual bool read( std::istream &is );
- virtual bool write( std::ostream &os ) const;
+ virtual ReadReturnCode read( std::istream &is );
+ bool write( std::ostream &os ) const;
- friend std::istream& operator>>(
- std::istream &is,
- Icmpv4Packet &packet
- );
- friend std::ostream& operator<<(
- std::ostream &os,
- const Icmpv4Packet &packet
- );
private:
bool match(
#include <iostream>
#include <logfunc.hpp>
+#include <boost/scoped_array.hpp>
#include "boost_assert_handler.h"
using boost::date_time::time_resolution_traits_adapted64_impl;
using boost::posix_time::ptime;
using boost::posix_time::microsec_clock;
+using boost::scoped_array;
using I2n::Logger::GlobalLogger;
//-----------------------------------------------------------------------------
}
/**
- * @brief Read the ICMP packet from the @c istream.
+ * @brief Read (part of) the ICMP packet from the input stream @a is
*
* @param is The input stream.
*
- * @return @c true if the read was successful, or @c false if an error occurred.
+ * @return result of the read, currently one of {ok, fail, not enough data}
*/
-bool Icmpv6Packet::read( istream &is )
+IcmpPacket::ReadReturnCode Icmpv6Packet::read( istream &is )
{
- is.clear();
+ if ( !is.good() )
+ return IcmpPacket::ReadReturnCode_BAD_STREAM;
- is >> *this;
+#ifdef IPV6_DATA_PRESENT_IN_ISTREAM
+ //TODO WHY IPv6 does not come like IPv4????
+ // try to read ip header
+ is >> IpHeader;
+
+ if ( is.eof() )
+ return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA;
+ else if ( !is.good() )
+ return IcmpPacket::ReadReturnCode_BAD_STREAM;
+#endif
- return !is.fail();
+ // try to read the icmp header
+ is >> IcmpPayloadHeader;
+
+ if ( is.eof() )
+ return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA;
+ else if ( !is.good() )
+ return IcmpPacket::ReadReturnCode_BAD_STREAM;
+
+ // calculate the size of the ICMP data
+ streamsize data_length = static_cast<streamsize>( IpHeader.get_payload_length() )
+ - static_cast<streamsize>( IcmpPayloadHeader.get_header_length() );
+
+ // try to read that amount of data
+ if ( data_length < 0 )
+ {
+ GlobalLogger.error() << "Error: invalid size for optional ICMP data: "
+ << data_length << endl;
+ is.setstate( ios::failbit );
+ return IcmpPacket::ReadReturnCode_INVALID_SIZE;
+ }
+ else if ( data_length > 0 )
+ {
+ size_t options_size = static_cast<size_t>( data_length );
+ scoped_array<uint8_t> scoped_data( new uint8_t[options_size+1] ); // need a 0 after data
+ memset(scoped_data.get(), 0, (options_size+1)*sizeof(uint8_t));
+ char *char_data = reinterpret_cast<char *>( scoped_data.get() );
+
+ (void) is.read( char_data, data_length ); // leave 0 at the end
+ IcmpPayloadData = char_data; // implicit cast
+ }
+
+ if ( is.eof() )
+ return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA;
+ else if ( !is.good() )
+ return IcmpPacket::ReadReturnCode_BAD_STREAM;
+ else
+ return IcmpPacket::ReadReturnCode_OK;
}
/**
*
* @return @c true if the write was successful, or @c false if an error occurred.
*/
-bool Icmpv6Packet::write( ostream &os ) const
+bool Icmpv6Packet::write( std::ostream &os ) const
{
os.clear();
- os << *this;
+ os << IcmpPayloadHeader << IcmpPayloadData;
return !os.fail();
}
-istream& operator>>(
- istream &is,
- Icmpv6Packet &packet
-)
-{
-#ifdef IPV6_DATA_PRESENT_IN_ISTREAM
- //TODO WHY IPv6 does not come like IPv4????
- if (is.good())
- is >> packet.IpHeader;
- if (is.good())
- is >> packet.IcmpPayloadHeader;
- if (is.good())
- is >> packet.IcmpPayloadData;
-#else
- if (is.good())
- is >> packet.IcmpPayloadHeader;
- if (is.good())
- is >> packet.IcmpPayloadData;
-#endif
-
- return is;
-}
-
-ostream& operator<<(
- ostream& os,
- const Icmpv6Packet& packet
-)
-{
- os << packet.IcmpPayloadHeader << packet.IcmpPayloadData;
-
- return os;
-}
) const;
virtual void print_destination_unreachable() const;
- virtual bool read( std::istream &is );
- virtual bool write( std::ostream &os ) const;
+ virtual ReadReturnCode read( std::istream &is );
+ bool write( std::ostream &os ) const;
- friend std::istream& operator>>(
- std::istream &is,
- Icmpv6Packet &packet
- );
- friend std::ostream& operator<<(
- std::ostream &os,
- const Icmpv6Packet &packet
- );
private:
bool match(