]> git.tdb.fi Git - netvis.git/blobdiff - source/address.cpp
Handle addresses in a more generic way
[netvis.git] / source / address.cpp
diff --git a/source/address.cpp b/source/address.cpp
new file mode 100644 (file)
index 0000000..3a49971
--- /dev/null
@@ -0,0 +1,109 @@
+#include <algorithm>
+#include <stdexcept>
+#include <arpa/inet.h>
+#include <netinet/ether.h>
+#include "address.h"
+
+using namespace std;
+
+Address::Address():
+       type(0),
+       length(0),
+       mask_bits(0)
+{ }
+
+Address::Address(uint32_t a):
+       type(ETH_P_IP),
+       length(4),
+       mask_bits(32)
+{
+       for(unsigned i=0; i<4; ++i)
+               data[i] = a>>(24-i*8);
+}
+
+Address::Address(unsigned short t, const unsigned char *d, unsigned char l):
+       type(t),
+       length(l)
+{
+       copy(d, d+l, data);
+}
+
+void Address::set_mask(const Address &mask)
+{
+       if(mask.length!=length)
+               throw invalid_argument("Address::set_mask");
+
+       mask_bits = 0;
+       for(unsigned i=0; (i<length && mask.data[i]); ++i)
+       {
+               mask_bits += 8;
+               if(mask.data[i]!=0xFF)
+               {
+                       for(unsigned d=mask.data[i]; !(d&1); d>>=1)
+                               --mask_bits;
+                       break;
+               }
+       }
+}
+
+string Address::str() const
+{
+       if(type==ETH_P_IP)
+       {
+               char buf[INET_ADDRSTRLEN];
+               return inet_ntop(AF_INET, data, buf, INET_ADDRSTRLEN);
+       }
+       else
+               return "<unknown>";
+}
+
+unsigned Address::common_prefix_length(const Address &other) const
+{
+       if(length!=other.length)
+               return 0;
+
+       unsigned prefix = 0;
+       for(unsigned i=0; i<length; ++i)
+       {
+               prefix += 8;
+               if(data[i]!=other.data[i])
+               {
+                       unsigned mismatch = data[i]^other.data[i];
+                       for(; mismatch; mismatch>>=1)
+                               --prefix;
+                       break;
+               }
+       }
+
+       return prefix;
+}
+
+bool Address::masked_match(const Address &other) const
+{
+       unsigned prefix = common_prefix_length(other);
+       unsigned mask = min(mask_bits, other.mask_bits);
+       return prefix>=mask;
+}
+
+void Address::to_sockaddr(sockaddr_storage &sa) const
+{
+       if(type==ETH_P_IP)
+       {
+               sockaddr_in &sa_in = reinterpret_cast<sockaddr_in &>(sa);
+               sa_in.sin_family = AF_INET;
+               sa_in.sin_port = 0;
+               sa_in.sin_addr.s_addr = *(uint32_t *)data;
+       }
+       else
+               throw runtime_error("Unknown type");
+}
+
+bool Address::operator<(const Address &other) const
+{
+       if(length!=other.length)
+               return length<other.length;
+       for(unsigned i=0; i<length; ++i)
+               if(data[i]!=other.data[i])
+                       return data[i]<other.data[i];
+       return false;
+}