Kea  1.5.0
io_address.cc
Go to the documentation of this file.
1 // Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
9 #include <asiolink/io_address.h>
10 #include <asiolink/io_error.h>
11 #include <exceptions/exceptions.h>
12 
13 #include <boost/static_assert.hpp>
14 
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 
20 using namespace boost::asio;
21 using boost::asio::ip::udp;
22 using boost::asio::ip::tcp;
23 
24 using namespace std;
25 
26 namespace isc {
27 namespace asiolink {
28 
29 // XXX: we cannot simply construct the address in the initialization list,
30 // because we'd like to throw our own exception on failure.
31 IOAddress::IOAddress(const std::string& address_str) {
32  boost::system::error_code err;
33  asio_address_ = ip::address::from_string(address_str, err);
34  if (err) {
35  isc_throw(IOError, "Failed to convert string to address '"
36  << address_str << "': " << err.message());
37  }
38 }
39 
40 IOAddress::IOAddress(const boost::asio::ip::address& asio_address) :
41  asio_address_(asio_address)
42 {}
43 
44 IOAddress::IOAddress(uint32_t v4address):
45  asio_address_(boost::asio::ip::address_v4(v4address)) {
46 
47 }
48 
49 string
51  return (asio_address_.to_string());
52 }
53 
55 IOAddress::fromBytes(short family, const uint8_t* data) {
56  if (data == NULL) {
57  isc_throw(BadValue, "NULL pointer received.");
58  } else
59  if ( (family != AF_INET) && (family != AF_INET6) ) {
60  isc_throw(BadValue, "Invalid family type. Only AF_INET and AF_INET6"
61  << "are supported");
62  }
63 
64  BOOST_STATIC_ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
65  char addr_str[INET6_ADDRSTRLEN];
66  inet_ntop(family, data, addr_str, INET6_ADDRSTRLEN);
67  return IOAddress(string(addr_str));
68 }
69 
70 std::vector<uint8_t>
72  if (asio_address_.is_v4()) {
73  const boost::asio::ip::address_v4::bytes_type bytes4 =
74  asio_address_.to_v4().to_bytes();
75  return (std::vector<uint8_t>(bytes4.begin(), bytes4.end()));
76  }
77 
78  // Not V4 address, so must be a V6 address (else we could never construct
79  // this object).
80  const boost::asio::ip::address_v6::bytes_type bytes6 =
81  asio_address_.to_v6().to_bytes();
82  return (std::vector<uint8_t>(bytes6.begin(), bytes6.end()));
83 }
84 
85 short
87  if (asio_address_.is_v4()) {
88  return (AF_INET);
89  } else {
90  return (AF_INET6);
91  }
92 }
93 
94 bool
96  if (!asio_address_.is_v6()) {
97  return (false);
98  }
99  return (asio_address_.to_v6().is_link_local());
100 }
101 
102 bool
104  if (!asio_address_.is_v6()) {
105  return (false);
106  }
107  return (asio_address_.to_v6().is_multicast());
108 }
109 
110 uint32_t
112  if (asio_address_.is_v4()) {
113  return (asio_address_.to_v4().to_ulong());
114  } else {
115  isc_throw(BadValue, "Can't convert " << toText()
116  << " address to IPv4.");
117  }
118 }
119 
120 std::ostream&
121 operator<<(std::ostream& os, const IOAddress& address) {
122  os << address.toText();
123  return (os);
124 }
125 
126 IOAddress
128  if (a.getFamily() != b.getFamily()) {
129  isc_throw(BadValue, "Both addresses have to be the same family");
130  }
131  if (a.isV4()) {
132  // Subtracting v4 is easy. We have a conversion function to uint32_t.
133  return (IOAddress(a.toUint32() - b.toUint32()));
134  } else {
135  // v6 is more involved.
136 
137  // Let's extract the raw data first.
138  vector<uint8_t> a_vec = a.toBytes();
139  vector<uint8_t> b_vec = b.toBytes();
140 
141  // ... and prepare the result
142  vector<uint8_t> result(V6ADDRESS_LEN,0);
143 
144  // Carry is a boolean, but to avoid its frequent casting, let's
145  // use uint8_t. Also, some would prefer to call it borrow, but I prefer
146  // carry. Somewhat relevant discussion here:
147  // http://en.wikipedia.org/wiki/Carry_flag#Carry_flag_vs._Borrow_flag
148  uint8_t carry = 0;
149 
150  // Now perform subtraction with borrow.
151  for (int i = a_vec.size() - 1; i >= 0; --i) {
152  result[i] = a_vec[i] - b_vec[i] - carry;
153  carry = (a_vec[i] < b_vec[i] + carry);
154  }
155 
156  return (fromBytes(AF_INET6, &result[0]));
157  }
158 }
159 
160 IOAddress
162  std::vector<uint8_t> packed(addr.toBytes());
163 
164  // Start increasing the least significant byte
165  for (int i = packed.size() - 1; i >= 0; --i) {
166  // if we haven't overflowed (0xff -> 0x0), than we are done
167  if (++packed[i] != 0) {
168  break;
169  }
170  }
171 
172  return (IOAddress::fromBytes(addr.getFamily(), &packed[0]));
173 }
174 
175 
176 } // namespace asiolink
177 } // namespace isc
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Defines the logger used by the top-level component of kea-dhcp-ddns.