io_address.cc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright (C) 2010-2012, 2014-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <unistd.h> // for some IPC/network system calls
  16. #include <stdint.h>
  17. #include <sys/socket.h>
  18. #include <netinet/in.h>
  19. #include <asio.hpp>
  20. #include <exceptions/exceptions.h>
  21. #include <asiolink/io_address.h>
  22. #include <asiolink/io_error.h>
  23. #include <boost/static_assert.hpp>
  24. using namespace asio;
  25. using asio::ip::udp;
  26. using asio::ip::tcp;
  27. using namespace std;
  28. namespace isc {
  29. namespace asiolink {
  30. // XXX: we cannot simply construct the address in the initialization list,
  31. // because we'd like to throw our own exception on failure.
  32. IOAddress::IOAddress(const std::string& address_str) {
  33. asio::error_code err;
  34. asio_address_ = ip::address::from_string(address_str, err);
  35. if (err) {
  36. isc_throw(IOError, "Failed to convert string to address '"
  37. << address_str << "': " << err.message());
  38. }
  39. }
  40. IOAddress::IOAddress(const asio::ip::address& asio_address) :
  41. asio_address_(asio_address)
  42. {}
  43. IOAddress::IOAddress(uint32_t v4address):
  44. asio_address_(asio::ip::address_v4(v4address)) {
  45. }
  46. string
  47. IOAddress::toText() const {
  48. return (asio_address_.to_string());
  49. }
  50. IOAddress
  51. IOAddress::fromBytes(short family, const uint8_t* data) {
  52. if (data == NULL) {
  53. isc_throw(BadValue, "NULL pointer received.");
  54. } else
  55. if ( (family != AF_INET) && (family != AF_INET6) ) {
  56. isc_throw(BadValue, "Invalid family type. Only AF_INET and AF_INET6"
  57. << "are supported");
  58. }
  59. BOOST_STATIC_ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
  60. char addr_str[INET6_ADDRSTRLEN];
  61. inet_ntop(family, data, addr_str, INET6_ADDRSTRLEN);
  62. return IOAddress(string(addr_str));
  63. }
  64. std::vector<uint8_t>
  65. IOAddress::toBytes() const {
  66. if (asio_address_.is_v4()) {
  67. const asio::ip::address_v4::bytes_type bytes4 =
  68. asio_address_.to_v4().to_bytes();
  69. return (std::vector<uint8_t>(bytes4.begin(), bytes4.end()));
  70. }
  71. // Not V4 address, so must be a V6 address (else we could never construct
  72. // this object).
  73. const asio::ip::address_v6::bytes_type bytes6 =
  74. asio_address_.to_v6().to_bytes();
  75. return (std::vector<uint8_t>(bytes6.begin(), bytes6.end()));
  76. }
  77. short
  78. IOAddress::getFamily() const {
  79. if (asio_address_.is_v4()) {
  80. return (AF_INET);
  81. } else {
  82. return (AF_INET6);
  83. }
  84. }
  85. bool
  86. IOAddress::isV6LinkLocal() const {
  87. if (!asio_address_.is_v6()) {
  88. return (false);
  89. }
  90. return (asio_address_.to_v6().is_link_local());
  91. }
  92. bool
  93. IOAddress::isV6Multicast() const {
  94. if (!asio_address_.is_v6()) {
  95. return (false);
  96. }
  97. return (asio_address_.to_v6().is_multicast());
  98. }
  99. IOAddress::operator uint32_t() const {
  100. if (asio_address_.is_v4()) {
  101. return (asio_address_.to_v4().to_ulong());
  102. } else {
  103. isc_throw(BadValue, "Can't convert " << toText()
  104. << " address to IPv4.");
  105. }
  106. }
  107. std::ostream&
  108. operator<<(std::ostream& os, const IOAddress& address) {
  109. os << address.toText();
  110. return (os);
  111. }
  112. IOAddress
  113. IOAddress::subtract(const IOAddress& a, const IOAddress& b) {
  114. if (a.getFamily() != b.getFamily()) {
  115. isc_throw(BadValue, "Both addresses have to be the same family");
  116. }
  117. if (a.isV4()) {
  118. // Subtracting v4 is easy. We have uint32_t operator.
  119. return (IOAddress(static_cast<uint32_t>(a) - static_cast<uint32_t>(b)));
  120. } else {
  121. // v6 is more involved.
  122. // Let's extract the raw data first.
  123. const vector<uint8_t>& a_vec(a.toBytes());
  124. const vector<uint8_t>& b_vec(b.toBytes());
  125. // ... and prepare the result
  126. vector<uint8_t> result(V6ADDRESS_LEN,0);
  127. // Carry is a boolean, but to avoid its frequent casting, let's
  128. // use uint8_t. Also, some would prefer to call it borrow, but I prefer
  129. // carry. Somewhat relevant discussion here:
  130. // http://en.wikipedia.org/wiki/Carry_flag#Carry_flag_vs._Borrow_flag
  131. uint8_t carry = 0;
  132. // Now perform subtraction with borrow.
  133. for (int i = a_vec.size(); i >= 0; --i) {
  134. result[i] = a_vec[i] - b_vec[i] - carry;
  135. carry = (a_vec[i] < b_vec[i] + carry);
  136. }
  137. return (fromBytes(AF_INET6, &result[0]));
  138. }
  139. }
  140. IOAddress
  141. IOAddress::increase(const IOAddress& addr) {
  142. // Get a buffer holding an address.
  143. const std::vector<uint8_t>& vec = addr.toBytes();
  144. // Get the address length.
  145. const int len = vec.size();
  146. // Since the same array will be used to hold the IPv4 and IPv6
  147. // address we have to make sure that the size of the array
  148. // we allocate will work for both types of address.
  149. BOOST_STATIC_ASSERT(V4ADDRESS_LEN <= V6ADDRESS_LEN);
  150. uint8_t packed[V6ADDRESS_LEN];
  151. // Copy the address. It can be either V4 or V6.
  152. std::memcpy(packed, &vec[0], len);
  153. // Start increasing the least significant byte
  154. for (int i = len - 1; i >= 0; --i) {
  155. // if we haven't overflowed (0xff -> 0x0), than we are done
  156. if (++packed[i] != 0) {
  157. break;
  158. }
  159. }
  160. return (IOAddress::fromBytes(addr.getFamily(), packed));
  161. }
  162. } // namespace asiolink
  163. } // namespace isc