libtins  3.4
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Pages
hw_address.h
1 /*
2  * Copyright (c) 2016, Matias Fontanini
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #ifndef TINS_HWADDRESS_H
31 #define TINS_HWADDRESS_H
32 
33 #include <stdint.h>
34 #include <stdexcept>
35 #include <iterator>
36 #include <algorithm>
37 #include <iomanip>
38 #include <iostream>
39 #include <sstream>
40 #include "cxxstd.h"
41 
42 namespace Tins {
43 
64 template<size_t n, typename Storage = uint8_t>
65 class HWAddress {
66 public:
72  typedef Storage storage_type;
73 
78 
82  typedef const storage_type* const_iterator;
83 
88  static const size_t address_size = n;
89 
94 
110  HWAddress(const storage_type* ptr = 0) {
111  if (ptr) {
112  std::copy(ptr, ptr + address_size, buffer_);
113  }
114  else {
115  std::fill(begin(), end(), storage_type());
116  }
117  }
118 
130  HWAddress(const std::string& address) {
131  convert(address, buffer_);
132  }
133 
147  template<size_t i>
148  HWAddress(const char (&address)[i]) {
149  convert(address, buffer_);
150  }
151 
164  template<size_t i>
165  HWAddress(const HWAddress<i>& rhs) {
166  // Fill extra bytes
167  std::fill(
168  // Copy as most as we can
169  std::copy(
170  rhs.begin(),
171  rhs.begin() + std::min(i, n),
172  begin()
173  ),
174  end(),
175  0
176  );
177 
178  }
179 
187  return buffer_;
188  }
189 
197  return buffer_;
198  }
199 
207  return buffer_ + address_size;
208  }
209 
216  const_iterator end() const {
217  return buffer_ + address_size;
218  }
219 
227  bool operator==(const HWAddress& rhs) const {
228  return std::equal(begin(), end(), rhs.begin());
229  }
230 
238  bool operator!=(const HWAddress& rhs) const {
239  return !(*this == rhs);
240  }
241 
249  bool operator<(const HWAddress& rhs) const {
250  return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
251  }
252 
259  HWAddress operator&(const HWAddress& mask) const {
260  HWAddress<n> output = *this;
261  for (size_t i = 0; i < n; ++i) {
262  output[i] = output[i] & mask[i];
263  }
264  return output;
265  }
266 
272  const size_t size() const {
273  return address_size;
274  }
275 
279  bool is_broadcast() const {
280  return* this == broadcast;
281  }
282 
286  bool is_multicast() const {
287  return (*begin() & 0x01);
288  }
289 
293  bool is_unicast() const {
294  return !is_broadcast() && !is_multicast();
295  }
296 
302  std::string to_string() const {
303  std::ostringstream oss;
304  oss <<* this;
305  return oss.str();
306  }
307 
313  storage_type operator[](size_t i) const {
314  return begin()[i];
315  }
316 
323  return begin()[i];
324  }
325 
333  friend std::ostream& operator<<(std::ostream& os, const HWAddress& addr) {
334  std::transform(
335  addr.begin(),
336  addr.end() - 1,
337  std::ostream_iterator<std::string>(os, ":"),
338  &HWAddress::storage_to_string
339  );
340  return os << storage_to_string(addr.begin()[HWAddress::address_size - 1]);
341  }
342 
358  template<typename OutputIterator>
359  OutputIterator copy(OutputIterator output) const {
360  for (const_iterator iter = begin(); iter != end(); ++iter) {
361  *output++ = *iter;
362  }
363  return output;
364  }
365 private:
366  template<typename OutputIterator>
367  static void convert(const std::string& hw_addr, OutputIterator output);
368 
369  static HWAddress<n> make_broadcast_address() {
370  // Build a buffer made of n 0xff bytes
371  uint8_t buffer[n];
372  for (size_t i = 0; i < n; ++i) {
373  buffer[i] = 0xff;
374  }
375  return HWAddress<n>(buffer);
376  }
377 
378  static std::string storage_to_string(storage_type element) {
379  std::ostringstream oss;
380  oss << std::hex;
381  if (element < 0x10) {
382  oss << '0';
383  }
384  oss << (unsigned)element;
385  return oss.str();
386  }
387 
388  storage_type buffer_[n];
389 };
390 
391 template<size_t n, typename Storage>
392 template<typename OutputIterator>
393 void HWAddress<n, Storage>::convert(const std::string& hw_addr,
394  OutputIterator output) {
395  unsigned i(0);
396  size_t count(0);
397  storage_type tmp;
398  while (i < hw_addr.size() && count < n) {
399  const unsigned end = i+2;
400  tmp = storage_type();
401  while (i < end) {
402  if (hw_addr[i] >= 'a' && hw_addr[i] <= 'f') {
403  tmp = (tmp << 4) | (hw_addr[i] - 'a' + 10);
404  }
405  else if (hw_addr[i] >= 'A' && hw_addr[i] <= 'F') {
406  tmp = (tmp << 4) | (hw_addr[i] - 'A' + 10);
407  }
408  else if (hw_addr[i] >= '0' && hw_addr[i] <= '9') {
409  tmp = (tmp << 4) | (hw_addr[i] - '0');
410  }
411  else if (hw_addr[i] == ':') {
412  break;
413  }
414  else {
415  throw std::runtime_error("Invalid byte found");
416  }
417  i++;
418  }
419  *(output++) = tmp;
420  count++;
421  if (i < hw_addr.size()) {
422  if (hw_addr[i] == ':') {
423  i++;
424  }
425  else {
426  throw std::runtime_error("Invalid separator");
427  }
428  }
429  }
430  while (count++ < n) {
431  *(output++) = storage_type();
432  }
433 }
434 
435 template<size_t n, typename Storage>
436 const HWAddress<n, Storage> HWAddress<n, Storage>::broadcast = make_broadcast_address();
437 
438 } // namespace Tins
439 
440 #if TINS_IS_CXX11
441 namespace std {
442 
443 // Specialization of std::hash for HWAddress
444 template<size_t n>
445 struct hash<Tins::HWAddress<n>> {
446  size_t operator()(const Tins::HWAddress<n>& addr) const {
447  return std::hash<std::string>()(addr.to_string());
448  }
449 };
450 
451 } // namespace std
452 #endif // TINS_IS_CXX11
453 
454 #endif // TINS_HWADDRESS_H
bool operator<(const HWAddress &rhs) const
Compares this HWAddress for less-than inequality.
Definition: hw_address.h:249
iterator begin()
Retrieves an iterator pointing to the begining of the address.
Definition: hw_address.h:186
bool operator==(const HWAddress &rhs) const
Compares this HWAddress for equality.
Definition: hw_address.h:227
friend std::ostream & operator<<(std::ostream &os, const HWAddress &addr)
Writes this HWAddress in hex-notation to a std::ostream.
Definition: hw_address.h:333
bool is_multicast() const
Indicates whether this is a multicast address.
Definition: hw_address.h:286
Storage storage_type
The type of the elements stored in the hardware address.
Definition: hw_address.h:72
storage_type operator[](size_t i) const
Retrieves the i-th storage_type in this address.
Definition: hw_address.h:313
static const size_t address_size
Non-member constant indicating the amount of storage_type elements in this address.
Definition: hw_address.h:88
iterator end()
Retrieves an iterator pointing one-past-the-end of the address.
Definition: hw_address.h:206
storage_type * iterator
The random access iterator type.
Definition: hw_address.h:77
static const HWAddress< n, Storage > broadcast
The broadcast address.
Definition: hw_address.h:93
Represents a hardware address.
Definition: hw_address.h:65
bool is_broadcast() const
Indicates whether this is a broadcast address.
Definition: hw_address.h:279
bool is_unicast() const
Indicates whether this is an unicast address.
Definition: hw_address.h:293
const_iterator end() const
Retrieves a const iterator pointing one-past-the-end of the address.
Definition: hw_address.h:216
OutputIterator copy(OutputIterator output) const
Helper function which copies the address into an output iterator.
Definition: hw_address.h:359
const_iterator begin() const
Retrieves a const iterator pointing to the begining of the address.
Definition: hw_address.h:196
HWAddress(const HWAddress< i > &rhs)
Copy construct from a HWAddress of length i.
Definition: hw_address.h:165
const size_t size() const
Retrieves the size of this address.
Definition: hw_address.h:272
HWAddress(const char(&address)[i])
Overload provided basically for string literals.
Definition: hw_address.h:148
std::string to_string() const
Convert this address to a hex-notation std::string address.
Definition: hw_address.h:302
HWAddress operator&(const HWAddress &mask) const
Apply a mask to this address.
Definition: hw_address.h:259
const storage_type * const_iterator
Const iterator type.
Definition: hw_address.h:82
bool operator!=(const HWAddress &rhs) const
Compares this HWAddress for in-equality.
Definition: hw_address.h:238
HWAddress(const storage_type *ptr=0)
Constructor from a const storage_type*.
Definition: hw_address.h:110
HWAddress(const std::string &address)
Constructs an address from a hex-notation address.
Definition: hw_address.h:130
storage_type & operator[](size_t i)
Retrieves the i-th storage_type in this address.
Definition: hw_address.h:322