icmp_header.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. //
  2. // icmp_header.hpp
  3. // ~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef __ASIO2_ICMP_HEADER_HPP__
  11. #define __ASIO2_ICMP_HEADER_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <istream>
  16. #include <ostream>
  17. #include <algorithm>
  18. // ICMP header for both IPv4 and IPv6.
  19. //
  20. // The wire format of an ICMP header is:
  21. //
  22. // 0 8 16 31
  23. // +---------------+---------------+------------------------------+ ---
  24. // | | | | ^
  25. // | type | code | checksum | |
  26. // | | | | |
  27. // +---------------+---------------+------------------------------+ 8 bytes
  28. // | | | |
  29. // | identifier | sequence number | |
  30. // | | | v
  31. // +-------------------------------+------------------------------+ ---
  32. namespace asio2::detail
  33. {
  34. class icmp_header
  35. {
  36. public:
  37. enum {
  38. echo_reply = 0,
  39. destination_unreachable = 3,
  40. source_quench = 4,
  41. redirect = 5,
  42. echo_request = 8,
  43. time_exceeded = 11,
  44. parameter_problem = 12,
  45. timestamp_request = 13,
  46. timestamp_reply = 14,
  47. info_request = 15,
  48. info_reply = 16,
  49. address_request = 17,
  50. address_reply = 18
  51. };
  52. icmp_header()
  53. {
  54. std::fill(rep_, rep_ + sizeof(rep_), static_cast<unsigned char>(0));
  55. }
  56. inline unsigned char type() const { return rep_[0]; }
  57. inline unsigned char code() const { return rep_[1]; }
  58. inline unsigned short checksum() const { return decode(2, 3); }
  59. inline unsigned short identifier() const { return decode(4, 5); }
  60. inline unsigned short sequence_number() const { return decode(6, 7); }
  61. inline void type(unsigned char n) { rep_[0] = n; }
  62. inline void code(unsigned char n) { rep_[1] = n; }
  63. inline void checksum(unsigned short n) { encode(2, 3, n); }
  64. inline void identifier(unsigned short n) { encode(4, 5, n); }
  65. inline void sequence_number(unsigned short n) { encode(6, 7, n); }
  66. // if you overloads cereal's operator>>(...) like this:
  67. // void operator>>(cereal::BinaryInputArchive& dr, nlohmann::json& j)
  68. // then the cereal's operator>>(...) will doesn't work.
  69. // if you want the cereal's operator>>(...) work properly, you should't include the "icmp_header.hpp"
  70. inline friend std::istream& operator>>(std::istream& is, icmp_header& header)
  71. {
  72. return is.read(reinterpret_cast<char*>(header.rep_), 8);
  73. }
  74. // if you overloads cereal's operator<<(...) like this:
  75. // void operator<<(cereal::BinaryOutputArchive& sr, nlohmann::json& j)
  76. // then the cereal's operator<<(...) will doesn't work.
  77. // if you want the cereal's operator<<(...) work properly, you should't include the "icmp_header.hpp"
  78. inline friend std::ostream& operator<<(std::ostream& os, const icmp_header& header)
  79. {
  80. return os.write(reinterpret_cast<const char*>(header.rep_), 8);
  81. }
  82. private:
  83. inline unsigned short decode(int a, int b) const
  84. {
  85. return (unsigned short)((rep_[a] << 8) + rep_[b]);
  86. }
  87. inline void encode(int a, int b, unsigned short n)
  88. {
  89. rep_[a] = static_cast<unsigned char>(n >> 8);
  90. rep_[b] = static_cast<unsigned char>(n & 0xFF);
  91. }
  92. unsigned char rep_[8];
  93. };
  94. template <typename Iterator>
  95. void compute_checksum(icmp_header& header, Iterator body_begin, Iterator body_end)
  96. {
  97. unsigned int sum = (header.type() << 8) + header.code() + header.identifier() + header.sequence_number();
  98. Iterator body_iter = body_begin;
  99. while (body_iter != body_end)
  100. {
  101. sum += (static_cast<unsigned char>(*body_iter++) << 8);
  102. if (body_iter != body_end)
  103. sum += static_cast<unsigned char>(*body_iter++);
  104. }
  105. sum = (sum >> 16) + (sum & 0xFFFF);
  106. sum += (sum >> 16);
  107. header.checksum(static_cast<unsigned short>(~sum));
  108. }
  109. }
  110. #endif // __ASIO2_ICMP_HEADER_HPP__