3a2047da22dc4899adbf3e62e54238a7ea792875
[pingcheck] / src / icmp / icmpheader.cpp
1 /*
2  The software in this package is distributed under the GNU General
3  Public License version 2 (with a special exception described below).
4
5  A copy of GNU General Public License (GPL) is included in this distribution,
6  in the file COPYING.GPL.
7
8  As a special exception, if other files instantiate templates or use macros
9  or inline functions from this file, or you compile this file and link it
10  with other works to produce a work based on this file, this file
11  does not by itself cause the resulting work to be covered
12  by the GNU General Public License.
13
14  However the source code for this file must still be made available
15  in accordance with section (3) of the GNU General Public License.
16
17  This exception does not invalidate any other reasons why a work based
18  on this file might be covered by the GNU General Public License.
19
20  Christian Herdtweck, Intra2net AG 2015
21  Based on an example in Boost Documentation (by Christopher M. Kohlhoff)
22  and adaptation by Guilherme M. Ferreira
23  */
24
25 #include "icmp/icmpheader.h"
26 #include <sstream>
27 #include <boost/scoped_array.hpp>
28
29 IcmpHeader::IcmpHeader()
30     : type( 0 )
31     , code( 0 )
32     , checksum( 0 )
33 {}
34
35 IcmpHeader::IcmpHeader(const uint8_t type_arg, const uint8_t code_arg)
36     : type( type_arg )
37     , code( code_arg )
38     , checksum( 0 )
39 {}
40
41 uint16_t IcmpHeader::get_header_length() const { return 4; }
42 uint8_t  IcmpHeader::get_type()          const { return type; }
43 uint8_t  IcmpHeader::get_code()          const { return code; }
44 uint16_t IcmpHeader::get_checksum()      const { return checksum; }
45
46
47 std::istream& IcmpHeader::read(std::istream &is)
48 {
49     boost::scoped_array<char> buf( new char[4] );
50     is.read(buf.get(), 4);
51     type = static_cast<uint8_t>(buf[0]);
52     code = static_cast<uint8_t>(buf[1]);
53
54     // first make the 2 checksum byte unsigned with same size
55     uint8_t checksum_msb = static_cast<uint8_t>(buf[2]);
56     uint8_t checksum_lsb = static_cast<uint8_t>(buf[3]);
57
58     // now extend type, shift and add/or them
59     checksum = static_cast<uint16_t>(
60                             (static_cast<uint16_t>(checksum_msb) << 8)
61                           |  static_cast<uint16_t>(checksum_lsb)        );
62     // need the static_cast around the result since compiler casts everything
63     // to int before doing | or + if types are smaller than int
64
65     return is;
66 }
67
68 std::ostream& IcmpHeader::write(std::ostream &os) const
69 {
70     uint8_t checksum_lsb = static_cast<uint8_t>(checksum & 0x00FF);
71     uint8_t checksum_msb = static_cast<uint8_t>((checksum & 0xFF00) >> 8);
72     return os << type << code << checksum_msb << checksum_lsb;
73 }
74
75
76 // code adapted from boost icmp example by Christopher M. Kohlhoff
77 // --> boost license?!?
78 void IcmpHeader::calc_checksum( const uint32_t body_checksum_part )
79 {
80     uint32_t sum = (type << 8) + code;
81     sum += body_checksum_part;
82
83     sum = (sum >> 16) + (sum & 0xFFFF);
84     sum += (sum >> 16);
85
86     checksum = static_cast<uint16_t>( ~sum );
87 }
88
89
90 std::string IcmpHeader::to_string() const
91 {
92     std::stringstream buf;
93     buf << "[Icmp header type=" << static_cast<int>(type)
94         << ",code=" << static_cast<int>(code)
95     //    << " (cksum:" << std::showbase << std::hex << checksum << ")"
96         << "]";
97     return buf.str();
98 }
99
100
101 std::istream& operator>>(
102         std::istream &is,
103         IcmpHeader &header
104 )
105 {  return header.read( is );  }
106
107 std::ostream& operator<<(
108         std::ostream &os,
109         const IcmpHeader &header
110 )
111 {  return header.write( os );  }
112
113
114 // (created using vim -- the world's best text editor)
115