]> git.tdb.fi Git - netvis.git/blob - source/address.cpp
Handle addresses in a more generic way
[netvis.git] / source / address.cpp
1 #include <algorithm>
2 #include <stdexcept>
3 #include <arpa/inet.h>
4 #include <netinet/ether.h>
5 #include "address.h"
6
7 using namespace std;
8
9 Address::Address():
10         type(0),
11         length(0),
12         mask_bits(0)
13 { }
14
15 Address::Address(uint32_t a):
16         type(ETH_P_IP),
17         length(4),
18         mask_bits(32)
19 {
20         for(unsigned i=0; i<4; ++i)
21                 data[i] = a>>(24-i*8);
22 }
23
24 Address::Address(unsigned short t, const unsigned char *d, unsigned char l):
25         type(t),
26         length(l)
27 {
28         copy(d, d+l, data);
29 }
30
31 void Address::set_mask(const Address &mask)
32 {
33         if(mask.length!=length)
34                 throw invalid_argument("Address::set_mask");
35
36         mask_bits = 0;
37         for(unsigned i=0; (i<length && mask.data[i]); ++i)
38         {
39                 mask_bits += 8;
40                 if(mask.data[i]!=0xFF)
41                 {
42                         for(unsigned d=mask.data[i]; !(d&1); d>>=1)
43                                 --mask_bits;
44                         break;
45                 }
46         }
47 }
48
49 string Address::str() const
50 {
51         if(type==ETH_P_IP)
52         {
53                 char buf[INET_ADDRSTRLEN];
54                 return inet_ntop(AF_INET, data, buf, INET_ADDRSTRLEN);
55         }
56         else
57                 return "<unknown>";
58 }
59
60 unsigned Address::common_prefix_length(const Address &other) const
61 {
62         if(length!=other.length)
63                 return 0;
64
65         unsigned prefix = 0;
66         for(unsigned i=0; i<length; ++i)
67         {
68                 prefix += 8;
69                 if(data[i]!=other.data[i])
70                 {
71                         unsigned mismatch = data[i]^other.data[i];
72                         for(; mismatch; mismatch>>=1)
73                                 --prefix;
74                         break;
75                 }
76         }
77
78         return prefix;
79 }
80
81 bool Address::masked_match(const Address &other) const
82 {
83         unsigned prefix = common_prefix_length(other);
84         unsigned mask = min(mask_bits, other.mask_bits);
85         return prefix>=mask;
86 }
87
88 void Address::to_sockaddr(sockaddr_storage &sa) const
89 {
90         if(type==ETH_P_IP)
91         {
92                 sockaddr_in &sa_in = reinterpret_cast<sockaddr_in &>(sa);
93                 sa_in.sin_family = AF_INET;
94                 sa_in.sin_port = 0;
95                 sa_in.sin_addr.s_addr = *(uint32_t *)data;
96         }
97         else
98                 throw runtime_error("Unknown type");
99 }
100
101 bool Address::operator<(const Address &other) const
102 {
103         if(length!=other.length)
104                 return length<other.length;
105         for(unsigned i=0; i<length; ++i)
106                 if(data[i]!=other.data[i])
107                         return data[i]<other.data[i];
108         return false;
109 }