Socket/Protocols/INet: Implemented INet4Network
g0dil [Mon, 6 Aug 2007 14:44:13 +0000 (14:44 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@379 270642c3-0616-0410-b53a-bc976706d245

Socket/Protocols/INet/INet4Address.cc
Socket/Protocols/INet/INet4Address.cci
Socket/Protocols/INet/INet4Address.hh
Socket/Protocols/INet/INet4Address.test.cc
Socket/Protocols/INet/INetAddressing.test.cc

index ad51600..f6b5362 100644 (file)
@@ -30,6 +30,7 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <sys/socket.h>
+#include <boost/lexical_cast.hpp>
 #ifdef _REENTRANT
 #include <boost/thread/mutex.hpp>
 #endif
@@ -118,6 +119,21 @@ senf::INet4Address const senf::INet4Address::None;
 senf::INet4Address const senf::INet4Address::Loopback (0x7F000001u);
 senf::INet4Address const senf::INet4Address::Broadcast (0xFFFFFFFFu);
 
+///////////////////////////////////////////////////////////////////////////
+// senf::INet4Network
+
+prefix_ senf::INet4Network::INet4Network(std::string s)
+{
+    std::string::size_type i (s.find('/'));
+    if (i == std::string::npos)
+        throw INet4Address::SyntaxException();
+    try {
+        prefix_len_ = boost::lexical_cast<unsigned>(std::string(s,i+1));
+    } catch (boost::bad_lexical_cast const &) {
+        throw INet4Address::SyntaxException();
+    }
+    address_ = INet4Address(INet4Address::from_string(std::string(s, 0, i)).address() & mask());
+}
 
 ///////////////////////////////////////////////////////////////////////////
 // namespace members
index 61b328f..ebf5615 100644 (file)
@@ -78,6 +78,73 @@ prefix_ senf::INet4Address::inaddr_type senf::INet4Address::iref()
     return *reinterpret_cast<inaddr_type const *>(&(*this)[0]);
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::INet4Network
+
+prefix_ senf::INet4Network::INet4Network()
+    : prefix_len_(), address_()
+{}
+
+prefix_ senf::INet4Network::INet4Network(INet4Address address, unsigned prefix_len)
+    : prefix_len_(prefix_len), address_(INet4Address(address.address() & mask()))
+{}
+
+prefix_ senf::INet4Address const & senf::INet4Network::address()
+    const
+{
+    return address_;
+}
+
+prefix_ unsigned senf::INet4Network::prefix_len()
+    const
+{
+    return prefix_len_;
+}
+
+prefix_ bool senf::INet4Network::boolean_test()
+    const
+{
+    return address() || prefix_len();
+}
+
+prefix_ bool senf::INet4Network::operator==(INet4Network const & other)
+    const
+{
+    return address() == other.address() && prefix_len() == other.prefix_len();
+}
+
+prefix_ bool senf::INet4Network::match(INet4Address addr)
+    const
+{
+    return (addr.address() & mask()) == address_.address();
+}
+
+prefix_ bool senf::INet4Network::match(INet4Network net)
+    const
+{
+    return net.prefix_len() >= prefix_len() &&
+        (net.address().address() & mask()) == address_.address();
+}
+
+////////////////////////////////////////
+// private members
+
+prefix_ boost::uint32_t senf::INet4Network::mask()
+    const
+{
+    // This is correct as long as the system is using 2-complement arithmetic ...
+    return (~((boost::uint32_t(1u)<<(32u-prefix_len()))-1u)) & 0xFFFFFFFFu;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// namespace members
+
+prefix_ std::ostream & senf::operator<<(std::ostream & os, INet4Network const & addr)
+{
+    os << addr.address() << '/' << addr.prefix_len();
+    return os;
+}
+
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
index 1ed57e8..818ffbe 100644 (file)
@@ -32,6 +32,7 @@
 #include <boost/cstdint.hpp>
 #include <boost/function.hpp>
 #include <boost/array.hpp>
+#include <boost/operators.hpp>
 #include "Utils/SafeBool.hh"
 
 //#include "INet4Address.mpp"
@@ -58,7 +59,6 @@ namespace senf {
     class INet4Address
         : public boost::array<boost::uint8_t,4>, 
           public ComparableSafeBool<INet4Address>
-
     {
     public:
         ///////////////////////////////////////////////////////////////////////////
@@ -195,6 +195,56 @@ namespace senf {
         static bool match(INet4Address const & addr);
     };
 
+    /** \brief IpV4 network prefix
+
+        This class represents an IpV4 network prefix in CIDR notation. 
+      */
+    class INet4Network
+        : public boost::equality_comparable<INet4Network>, 
+          public ComparableSafeBool<INet4Network>
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        INet4Network();                 ///< Construct empty (0.0.0.0/0) network
+        INet4Network(INet4Address address, unsigned prefix_len);
+                                        ///< Construct network from given address and prefix length
+        explicit INet4Network(std::string s); ///< Construct network from CIDR notation
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+        INet4Address const & address() const; ///< Get the networks address
+        unsigned prefix_len() const;    ///< Get the networks prefix length
+
+        bool boolean_test() const;      ///< \c true, if INet4Network is non-empty
+        bool operator==(INet4Network const & other) const;
+                                        ///< Compare to networks for equality
+        
+        bool match(INet4Address addr) const; ///< \c true, if the network includes \a addr
+        bool match(INet4Network 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. */
+
+    protected:
+
+    private:
+        boost::uint32_t mask() const;
+
+        unsigned prefix_len_;
+        INet4Address address_;
+    };
+
+    /** \brief Output INet4Network instance as it's string representation
+        \related INet4Network
+     */
+    std::ostream & operator<<(std::ostream & os, INet4Network const & addr);
+        
 }
 
 ///////////////////////////////hh.e////////////////////////////////////////
index 6b7f84a..c1a8211 100644 (file)
@@ -28,6 +28,7 @@
 
 // Custom includes
 #include <arpa/inet.h>
+#include <boost/lexical_cast.hpp>
 #include <sstream>
 #include "INet4Address.hh"
 
@@ -68,6 +69,28 @@ BOOST_AUTO_UNIT_TEST(inet4Address)
     BOOST_CHECK_EQUAL( str.str(), "128.129.130.131" );
 }
 
+BOOST_AUTO_UNIT_TEST(inet4Network)
+{
+    senf::INet4Network net (senf::INet4Address::Loopback,8);
+    BOOST_CHECK_EQUAL( net.address().address(), 0x7F000000u );
+    BOOST_CHECK_EQUAL( net.prefix_len(), 8u );
+    BOOST_CHECK( net );
+    BOOST_CHECK( ! senf::INet4Network() );
+    
+    senf::INet4Network net2 ("192.0.111.222/16");
+    BOOST_CHECK_EQUAL( net2.address(), senf::INet4Address::from_string("192.0.0.0") );
+    BOOST_CHECK_EQUAL( net2.prefix_len(), 16u );
+
+    BOOST_CHECK( net != net2 );
+    BOOST_CHECK( net.match(senf::INet4Address::from_string("127.0.0.1")) );
+    BOOST_CHECK( ! net2.match(senf::INet4Address::from_string("127.0.0.1")) );
+    BOOST_CHECK( ! net.match(net2) );
+    BOOST_CHECK( net2.match(senf::INet4Network("192.0.111.0/24")) );
+    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" );
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 
index ee68de8..61cc302 100644 (file)
@@ -45,7 +45,7 @@ BOOST_AUTO_UNIT_TEST(inet4SocketAddress)
         BOOST_CHECK( ! addr );
 
         addr = INet4SocketAddress("127.0.0.1:12345");
-        BOOST_CHECK ( addr != INet4SocketAddress() );
+        BOOST_CHECK ( addr != INet4SocketAddress("127.0.0.2:12345") );
     }
 
     {