From: g0dil Date: Tue, 7 Aug 2007 08:23:23 +0000 (+0000) Subject: Socket/Protocols/INet: Add 'host' and 'subnet' methods to INet4Network X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=f47178d89402cc90b67143ceb6c0fd5b3fa2a976;p=senf.git Socket/Protocols/INet: Add 'host' and 'subnet' methods to INet4Network Socket/Protocols/INet: Implement INet6Network git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@381 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Socket/Protocols/INet/INet4Address.cci b/Socket/Protocols/INet/INet4Address.cci index ebf5615..a840eaf 100644 --- a/Socket/Protocols/INet/INet4Address.cci +++ b/Socket/Protocols/INet/INet4Address.cci @@ -122,8 +122,17 @@ prefix_ bool senf::INet4Network::match(INet4Address addr) prefix_ bool senf::INet4Network::match(INet4Network net) const { - return net.prefix_len() >= prefix_len() && - (net.address().address() & mask()) == address_.address(); + return net.prefix_len() >= prefix_len() && match(net.address()); +} + +prefix_ senf::INet4Address senf::INet4Network::host(boost::uint32_t number) +{ + return INet4Address(address_.address() | (number & ~mask())); +} + +prefix_ senf::INet4Network senf::INet4Network::subnet(boost::uint32_t net, unsigned prefix_len) +{ + return INet4Network(host(net << (32-prefix_len)),prefix_len); } //////////////////////////////////////// diff --git a/Socket/Protocols/INet/INet4Address.hh b/Socket/Protocols/INet/INet4Address.hh index 818ffbe..b638448 100644 --- a/Socket/Protocols/INet/INet4Address.hh +++ b/Socket/Protocols/INet/INet4Address.hh @@ -45,7 +45,7 @@ namespace senf { INet4Address represents a simple IP address. It is modelled as a fixed-size container/sequence of 4 bytes. - \see CheckINet4Network + \see CheckINet4Network \n INet4Network \implementation We awkwardly need to use static named constructors (from_ members) instead of ordinarily overloaded constructors for one simple reason: char * @@ -205,9 +205,6 @@ namespace senf { { public: /////////////////////////////////////////////////////////////////////////// - // Types - - /////////////////////////////////////////////////////////////////////////// ///\name Structors and default members ///@{ @@ -231,6 +228,26 @@ namespace senf { /**< The is true, if \a net is sub-network (or the same as) \c this. */ + INet4Address host(boost::uint32_t number); ///< Return the host with the given number + /**< Returns the host with the given number within the + network. If the number is larger than the maximum + host number in the network, it is truncated. So \c + host(0) is the networks own address, \c host(1) + customarily is the default router and \c host(-1) is + the broadcast address. */ + + INet4Network subnet(boost::uint32_t net, unsigned prefix_len); + ///< Return the given subnet of \c this + /**< The returned INet4Network will be a subnet of \c this + with the given network number. The network number is + comprised by the bits above \a prefix_len: + \code + INet4Network("192.168.0.0/16").subnet(111u,24u) == INet4Network("192.168.111.0/24") + INet4Network("192.168.111.0/24").subnet(1u,28u) == INet4Network("192.168.111.16/28") + \endcode + \param[in] net network number + \param[in] prefix_len length of subnet prefix */ + protected: private: diff --git a/Socket/Protocols/INet/INet4Address.test.cc b/Socket/Protocols/INet/INet4Address.test.cc index c1a8211..aaf58f8 100644 --- a/Socket/Protocols/INet/INet4Address.test.cc +++ b/Socket/Protocols/INet/INet4Address.test.cc @@ -89,6 +89,9 @@ BOOST_AUTO_UNIT_TEST(inet4Network) BOOST_CHECK( ! net2.match(senf::INet4Network("192.0.0.0/15")) ); BOOST_CHECK_EQUAL( boost::lexical_cast(net2), "192.0.0.0/16" ); + + BOOST_CHECK_EQUAL( net2.host(-1), senf::INet4Address::from_string("192.0.255.255") ); + BOOST_CHECK_EQUAL( boost::lexical_cast(net2.subnet(2u,24u)), "192.0.2.0/24" ); } ///////////////////////////////cc.e//////////////////////////////////////// diff --git a/Socket/Protocols/INet/INet6Address.cc b/Socket/Protocols/INet/INet6Address.cc index 7dfa642..8ece248 100644 --- a/Socket/Protocols/INet/INet6Address.cc +++ b/Socket/Protocols/INet/INet6Address.cc @@ -32,6 +32,7 @@ #include #include #include +#include //#include "INet6Address.mpp" #define prefix_ @@ -102,6 +103,25 @@ senf::INet6Address const senf::INet6Address::Loopback (0u,0u,0u,0u,0u,0u,0u,1u senf::INet6Address const senf::INet6Address::AllNodes (0xFF02u,0u,0u,0u,0u,0u,0u,1u); senf::INet6Address const senf::INet6Address::AllRouters (0xFF02u,0u,0u,0u,0u,0u,0u,2u); +/////////////////////////////////////////////////////////////////////////// +// senf::INet6Network + +prefix_ senf::INet6Network::INet6Network(std::string s) +{ + using boost::lambda::_1; + using boost::lambda::_2; + std::string::size_type i (s.find('/')); + if (i == std::string::npos) + throw INet6Address::SyntaxException(); + try { + prefix_len_ = boost::lexical_cast(std::string(s,i+1)); + } catch (boost::bad_lexical_cast const &) { + throw INet6Address::SyntaxException(); + } + address_ = INet6Address::from_string(std::string(s, 0, i)); + detail::apply_mask(prefix_len_, address_.begin(), address_.end(), _1 &= _2); +} + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ //#include "INet6Address.mpp" diff --git a/Socket/Protocols/INet/INet6Address.cci b/Socket/Protocols/INet/INet6Address.cci index c3072b0..5c09acc 100644 --- a/Socket/Protocols/INet/INet6Address.cci +++ b/Socket/Protocols/INet/INet6Address.cci @@ -23,6 +23,8 @@ /** \file \brief INet6Address inline non-template implementation */ +#include "INet6Address.ih" + // Custom includes #include #include @@ -216,6 +218,97 @@ prefix_ void senf::INet6Address::id(boost::uint64_t id) (*this)[15] = id ; } +/////////////////////////////////////////////////////////////////////////// +// senf::INet6Network + +prefix_ senf::INet6Network::INet6Network() + : prefix_len_(), address_() +{} + +prefix_ senf::INet6Network::INet6Network(INet6Address address, unsigned prefix_len) + : prefix_len_(prefix_len), address_(address) +{ + using boost::lambda::_1; + using boost::lambda::_2; + detail::apply_mask(prefix_len_, address_.begin(), address_.end(), _1 &= _2); +} + +prefix_ senf::INet6Address const & senf::INet6Network::address() + const +{ + return address_; +} + +prefix_ unsigned senf::INet6Network::prefix_len() + const +{ + return prefix_len_; +} + +prefix_ bool senf::INet6Network::boolean_test() + const +{ + return prefix_len() && address(); +} + +prefix_ bool senf::INet6Network::operator==(INet6Network const & other) + const +{ + return prefix_len() == other.prefix_len() && address() == other.address(); +} + +prefix_ bool senf::INet6Network::match(INet6Address addr) + const +{ + using boost::lambda::_1; + using boost::lambda::_2; + using boost::lambda::_3; + return detail::find_if_mask(prefix_len_, address_.begin(), address_.end(), addr.begin(), + _1 != (_2 & _3)) == address_.end(); +} + +prefix_ bool senf::INet6Network::match(INet6Network net) + const +{ + return net.prefix_len() >= prefix_len() && match(net.address()); +} + +prefix_ senf::INet6Address senf::INet6Network::host(boost::uint64_t id) +{ + INet6Address addr (address()); + addr.id(id); + return addr; +} + +prefix_ senf::INet6Network senf::INet6Network::subnet(boost::uint64_t net, unsigned prefix_len) +{ + using boost::lambda::_1; + using boost::lambda::_2; + using boost::lambda::_3; + using boost::lambda::var; + using boost::lambda::ret; + INet6Address addr (address()); + net <<= (64-prefix_len); + detail::apply_mask(prefix_len, addr.begin(), addr.end(), + ( ( _1 |= ret((var(net) >> 56) & _2) ), + ( var(net) <<= 8 ) )); + return INet6Network(addr, prefix_len); +} + +prefix_ std::ostream & senf::operator<<(std::ostream & os, INet6Network const & addr) +{ + os << addr.address() << '/' << addr.prefix_len(); + return os; +} + +/////////////////////////////////////////////////////////////////////////// +// namespace senf::detail members + +prefix_ boost::uint8_t senf::detail::low_bits_mask(unsigned bits) +{ + return ((1< +prefix_ void senf::detail::apply_mask(unsigned bits, ForwardIterator b, ForwardIterator e, + Function fn) +{ + for(; b != e; ++b) { + boost::uint8_t mask (0); + if (bits > 8) { + mask = 0xFFu; + bits -= 8; + } else if (bits > 0) { + mask = ~ low_bits_mask(8-bits); + bits = 0; + } + fn(*b,mask); + } +} + +template +prefix_ ForwardIterator1 senf::detail::find_if_mask(unsigned bits, ForwardIterator1 b1, + ForwardIterator1 e1, ForwardIterator2 b2, + Function fn) +{ + for(; b1 != e1; ++b1, ++b2) { + boost::uint8_t mask (0); + if (bits > 8) { + mask = 0xFFu; + bits -= 8; + } else if (bits > 0) { + mask = ~ low_bits_mask(8-bits); + bits = 0; + } + if (fn(*b1,*b2,mask)) + return b1; + } + return e1; +} + ///////////////////////////////ct.e//////////////////////////////////////// #undef prefix_ diff --git a/Socket/Protocols/INet/INet6Address.hh b/Socket/Protocols/INet/INet6Address.hh index 4ef43e7..2032aff 100644 --- a/Socket/Protocols/INet/INet6Address.hh +++ b/Socket/Protocols/INet/INet6Address.hh @@ -32,6 +32,7 @@ #include #include #include +#include #include "Utils/SafeBool.hh" #include "INet4Address.hh" @@ -86,7 +87,7 @@ namespace senf { The INet6Address class is based on \c boost::array and is built as a fixed-size sequence of 16 bytes. - \see CheckINet6Network Helper to check address against an arbitrary fixed network prefix + \see CheckINet6Network \n INet6Network \ingroup addr_group \implementation We awkwardly need to use static named constructors (from_ members) @@ -302,6 +303,66 @@ namespace senf { : public detail::CheckINet6Network_impl {}; + /** \brief IpV6 network prefix + + This class represents an IpV6 network prefix in CIDR notation. + */ + class INet6Network + : public boost::equality_comparable, + public ComparableSafeBool + { + public: + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + INet6Network(); ///< Construct empty (::/0) network + INet6Network(INet6Address address, unsigned prefix_len); + ///< Construct network from given address and prefix length + explicit INet6Network(std::string s); ///< Construct network from CIDR notation + + ///@} + /////////////////////////////////////////////////////////////////////////// + + INet6Address const & address() const; ///< Get the network address + unsigned prefix_len() const; ///< Get the network prefix length + + bool boolean_test() const; ///< \c true, if INet6Network is non-empty + bool operator==(INet6Network const & other) const; + ///< Compare two networks for equality + + bool match(INet6Address addr) const; ///< \c true, if the network includes \a addr + bool match(INet6Network net) const; ///< \c true, if the network includes \a net + /**< The is true, if \a net is sub-network (or the same as) + \c this. */ + INet6Address host(boost::uint64_t id); ///< Return the host with the given id + /**< Returns the host with the given number within the + network. This call replaces the lower 64 bits of the + network address with the given id. */ + + INet6Network subnet(boost::uint64_t net, unsigned prefix_len); + ///< Return the given subnet of \c this + /**< The returned INet6Network will be a subnet of \c this + with the given network number. The network number is + comprised by the bits above \a prefix_len: + \code + INet6Network("2001:db8::/32").subnet(0x12u,40u) == INet6Network("2001:db8:1200::/40") + INet6Network("2001:db8:1200::/40").subnet(0x2345,64u) == INet6Network("2001:db8:1200:2345::/64") + \endcode + \param[in] net network number + \param[in] prefix_len length of subnet prefix */ + + protected: + + private: + unsigned prefix_len_; + INet6Address address_; + }; + + /** \brief Output INet6Network instance as it's string representation + \related INet6Network + */ + std::ostream & operator<<(std::ostream & os, INet6Network const & addr); } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Socket/Protocols/INet/INet6Address.ih b/Socket/Protocols/INet/INet6Address.ih index 782880d..a41e8c6 100644 --- a/Socket/Protocols/INet/INet6Address.ih +++ b/Socket/Protocols/INet/INet6Address.ih @@ -182,12 +182,18 @@ namespace detail { : public CheckINet6Network_impl2 {}; - template - struct IsINet6Network_impl - {}; - # endif + boost::uint8_t low_bits_mask(unsigned bits); + + template + void apply_mask(unsigned bits, ForwardIterator b, ForwardIterator e, Function fn); + + template + ForwardIterator1 find_if_mask(unsigned bits, + ForwardIterator1 b1, ForwardIterator1 e1, ForwardIterator2 b2, + Function fn); + }} ///////////////////////////////ih.e//////////////////////////////////////// diff --git a/Socket/Protocols/INet/INet6Address.test.cc b/Socket/Protocols/INet/INet6Address.test.cc index 240e1d4..253c214 100644 --- a/Socket/Protocols/INet/INet6Address.test.cc +++ b/Socket/Protocols/INet/INet6Address.test.cc @@ -138,6 +138,32 @@ BOOST_AUTO_UNIT_TEST(inet6Address) } } +BOOST_AUTO_UNIT_TEST(inet6Network) +{ + senf::INet6Network net (senf::INet6Address(0xFF14u,0x1234u),32u); + BOOST_CHECK_EQUAL( boost::lexical_cast(net.address()), "ff14:1234::"); + BOOST_CHECK_EQUAL( net.prefix_len(), 32u ); + BOOST_CHECK( net ); + BOOST_CHECK( ! senf::INet6Network() ); + + senf::INet6Network net2 ("2001:db8:1234::/44"); + BOOST_CHECK_EQUAL( net2.address(), senf::INet6Address::from_string("2001:db8:1230::") ); + BOOST_CHECK_EQUAL( net2.prefix_len(), 44u ); + + BOOST_CHECK( net != net2 ); + BOOST_CHECK( net.match(senf::INet6Address::from_string("ff14:1234::1")) ); + BOOST_CHECK( ! net2.match(senf::INet6Address::from_string("ff13:1234::1")) ); + BOOST_CHECK( ! net.match(net2) ); + BOOST_CHECK( net2.match(senf::INet6Network("2001:db8:1234::/48")) ); + BOOST_CHECK( ! net2.match(senf::INet6Network("2001:db8:1234::/32")) ); + + BOOST_CHECK_EQUAL( boost::lexical_cast(net2), "2001:db8:1230::/44" ); + + BOOST_CHECK_EQUAL( net2.host(0x1234u), senf::INet6Address::from_string("2001:db8:1230::1234") ); + BOOST_CHECK_EQUAL( boost::lexical_cast(net2.subnet(2u,48u)), + "2001:db8:1232::/48" ); +} + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_