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);
}
////////////////////////////////////////
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 (<tt>from_</tt> members)
instead of ordinarily overloaded constructors for one simple reason: <tt>char *</tt>
{
public:
///////////////////////////////////////////////////////////////////////////
- // Types
-
- ///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
///@{
/**< 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:
BOOST_CHECK( ! net2.match(senf::INet4Network("192.0.0.0/15")) );
BOOST_CHECK_EQUAL( boost::lexical_cast<std::string>(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<std::string>(net2.subnet(2u,24u)), "192.0.2.0/24" );
}
///////////////////////////////cc.e////////////////////////////////////////
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
+#include <boost/lexical_cast.hpp>
//#include "INet6Address.mpp"
#define prefix_
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<unsigned>(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"
/** \file
\brief INet6Address inline non-template implementation */
+#include "INet6Address.ih"
+
// Custom includes
#include <algorithm>
#include <boost/lambda/lambda.hpp>
(*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<boost::uint8_t>((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<<bits)-1);
+}
+
///////////////////////////////cci.e///////////////////////////////////////
#undef prefix_
return addr;
}
+///////////////////////////////////////////////////////////////////////////
+// namespace senf::detail members
+
+template <class ForwardIterator, class Function>
+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 <class ForwardIterator1, class ForwardIterator2, class Function>
+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_
#include <boost/cstdint.hpp>
#include <boost/function.hpp>
#include <boost/array.hpp>
+#include <boost/operators.hpp>
#include "Utils/SafeBool.hh"
#include "INet4Address.hh"
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 (<tt>from_</tt> members)
: public detail::CheckINet6Network_impl<a0,a1,a2,a3,a4,a5,a6,a7,a8>
{};
+ /** \brief IpV6 network prefix
+
+ This class represents an IpV6 network prefix in CIDR notation.
+ */
+ class INet6Network
+ : public boost::equality_comparable<INet6Network>,
+ public ComparableSafeBool<INet6Network>
+ {
+ 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////////////////////////////////////////
: public CheckINet6Network_impl2<a0,0,0,0,0,0,0,0,a1>
{};
- template <boost::uint64_t net, boost::uint64_t id, unsigned bits, unsigned bytes>
- struct IsINet6Network_impl
- {};
-
# endif
+ boost::uint8_t low_bits_mask(unsigned bits);
+
+ template <class ForwardIterator, class Function>
+ void apply_mask(unsigned bits, ForwardIterator b, ForwardIterator e, Function fn);
+
+ template <class ForwardIterator1, class ForwardIterator2, class Function>
+ ForwardIterator1 find_if_mask(unsigned bits,
+ ForwardIterator1 b1, ForwardIterator1 e1, ForwardIterator2 b2,
+ Function fn);
+
}}
///////////////////////////////ih.e////////////////////////////////////////
}
}
+BOOST_AUTO_UNIT_TEST(inet6Network)
+{
+ senf::INet6Network net (senf::INet6Address(0xFF14u,0x1234u),32u);
+ BOOST_CHECK_EQUAL( boost::lexical_cast<std::string>(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<std::string>(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<std::string>(net2.subnet(2u,48u)),
+ "2001:db8:1232::/48" );
+}
+
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_