Browse Source

[1540] Changes after review:

- several parameters are now const
- OS-specific code moved from iface_mgr.cc to iface_mgr_linux.cc
- C-style casts replaced with a casting framework
  (see lib/util/io/pktinfo_utilities.h)
- added lib/util/range_utilities.h for methods that operate on
  container's ranges (isRangeZero and fillRandom)
- many other minor corrections
Tomek Mrugalski 13 years ago
parent
commit
485f7966f5

+ 2 - 3
src/bin/dhcp4/dhcp4_srv.cc

@@ -59,10 +59,9 @@ Dhcpv4Srv::~Dhcpv4Srv() {
 bool
 Dhcpv4Srv::run() {
     while (!shutdown_) {
-
-        // client's message
+        // client's message and server's response
         Pkt4Ptr query = IfaceMgr::instance().receive4();
-        Pkt4Ptr rsp;   // server's response
+        Pkt4Ptr rsp;
 
         if (query) {
             try {

+ 16 - 12
src/bin/dhcp6/dhcp6_srv.cc

@@ -23,6 +23,7 @@
 #include <asiolink/io_address.h>
 #include <exceptions/exceptions.h>
 #include <util/io_utilities.h>
+#include <util/range_utilities.h>
 
 using namespace std;
 using namespace isc;
@@ -73,8 +74,9 @@ Dhcpv6Srv::~Dhcpv6Srv() {
 bool Dhcpv6Srv::run() {
     while (!shutdown) {
 
-        Pkt6Ptr query = IfaceMgr::instance().receive6(); // client's message
-        Pkt6Ptr rsp;   // server's response
+        // client's message and server's response
+        Pkt6Ptr query = IfaceMgr::instance().receive6();
+        Pkt6Ptr rsp;
 
         if (query) {
             if (!query->unpack()) {
@@ -153,7 +155,7 @@ void Dhcpv6Srv::setServerID() {
     // let's find suitable interface
     for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
          iface != ifaces.end(); ++iface) {
-        // all those conditions could be merged into one multi-condition
+        // All the following checks could be merged into one multi-condition
         // statement, but let's keep them separated as perhaps one day
         // we will grow knobs to selectively turn them on or off. Also,
         // this code is used only *once* during first start on a new machine
@@ -162,9 +164,12 @@ void Dhcpv6Srv::setServerID() {
 
         // I wish there was a this_is_a_real_physical_interface flag...
 
-        // mac at least 6 bytes. All decent physical interfaces (Ethernet,
-        // WiFi, Infiniband, etc.) have 6 bytes long MAC address
-        if (iface->mac_len_ < 6) {
+        // MAC address should be at least 6 bytes. Although there is no such
+        // requirement in any RFC, all decent physical interfaces (Ethernet,
+        // WiFi, Infiniband, etc.) have 6 bytes long MAC address. We want to
+        // base our DUID on real hardware address, rather than virtual
+        // interface that pretends that underlying IP address is its MAC.
+        if (iface->mac_len_ < MIN_MAC_LEN) {
             continue;
         }
 
@@ -213,15 +218,14 @@ void Dhcpv6Srv::setServerID() {
     // See Section 9.3 of RFC3315 for details.
 
     OptionBuffer srvid(12);
-    srand(time(NULL));
     writeUint16(DUID_EN, &srvid[0]);
     writeUint32(ENTERPRISE_ID_ISC, &srvid[2]);
 
-    // length of the identifier is company specific. I hereby declare
-    // ISC standard of 6 bytes long random numbers.
-    for (int i = 6; i < 12; i++) {
-        srvid[i] = static_cast<uint8_t>(rand());
-    }
+    // Length of the identifier is company specific. I hereby declare
+    // ISC "standard" of 6 bytes long pseudo-random numbers.
+    srand(time(NULL));
+    fillRandom(&srvid[6],&srvid[12]);
+
     serverid_ = OptionPtr(new Option(Option::V6, D6O_SERVERID,
                                      srvid.begin(), srvid.end()));
 }

+ 4 - 0
src/bin/dhcp6/dhcp6_srv.h

@@ -35,6 +35,10 @@ namespace dhcp {
 class Dhcpv6Srv : public boost::noncopyable {
 
 public:
+
+    /// @brief Minimum length of a MAC address to be used in DUID generation.
+    static const size_t MIN_MAC_LEN = 6;
+
     /// @brief Default constructor.
     ///
     /// Instantiates necessary services, required to run DHCPv6 server.

+ 2 - 2
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -24,6 +24,7 @@
 #include <dhcp/option6_ia.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <util/buffer.h>
+#include <util/range_utilities.h>
 
 using namespace std;
 using namespace isc;
@@ -136,9 +137,8 @@ TEST_F(Dhcpv6SrvTest, DUID) {
         // there's not much we can check. Just simple
         // check if it is not all zeros
         vector<uint8_t> content(len-2);
-        vector<uint8_t> zeros(0, len-2);
         data.readVector(content, len-2);
-        EXPECT_NE(content, zeros);
+        EXPECT_FALSE(isRangeZero(content.begin(), content.end()));
     }
     case DUID_LL: // not supported yet
     case DUID_UUID: // not supported yet

+ 43 - 24
src/lib/dhcp/iface_mgr.cc

@@ -23,9 +23,11 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/iface_mgr.h>
 #include <exceptions/exceptions.h>
+#include <util/io/pktinfo_utilities.h>
 
 using namespace std;
 using namespace isc::asiolink;
+using namespace isc::util::io::internal;
 
 namespace isc {
 namespace dhcp {
@@ -154,12 +156,12 @@ IfaceMgr::~IfaceMgr() {
     closeSockets();
 }
 
-void
-IfaceMgr::stubDetectIfaces() {
+void IfaceMgr::stubDetectIfaces() {
     string ifaceName, linkLocal;
 
-    // TODO do the actual detection. Currently interface detection is faked
-    //      by reading a text file.
+    // This is a stub implementation for interface detection. Actual detection
+    // is faked by reading a text file. It will eventually be removed once
+    // we have actual implementations for all supported systems.
 
     cout << "Interface detection is not implemented yet. "
          << "Reading interfaces.txt file instead." << endl;
@@ -177,7 +179,7 @@ IfaceMgr::stubDetectIfaces() {
 
         cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
 
-        Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
+        Iface iface(ifaceName, if_nametoindex(ifaceName.c_str()));
         iface.flag_up_ = true;
         iface.flag_running_ = true;
         iface.flag_loopback_ = false;
@@ -200,13 +202,16 @@ IfaceMgr::stubDetectIfaces() {
     }
 }
 
+/// @todo: Remove this once we have OS-specific interface detection
+/// routines (or at least OS-specific files, like iface_mgr_solaris.cc)
+/// for all OSes.
 #if !defined(OS_LINUX) && !defined(OS_BSD)
 void IfaceMgr::detectIfaces() {
     stubDetectIfaces();
 }
 #endif
 
-bool IfaceMgr::openSockets4(uint16_t port) {
+bool IfaceMgr::openSockets4(const uint16_t port) {
     int sock;
     int count = 0;
 
@@ -246,7 +251,7 @@ bool IfaceMgr::openSockets4(uint16_t port) {
 
 }
 
-bool IfaceMgr::openSockets6(uint16_t port) {
+bool IfaceMgr::openSockets6(const uint16_t port) {
     int sock;
     int count = 0;
 
@@ -288,9 +293,12 @@ bool IfaceMgr::openSockets6(uint16_t port) {
             }
 
             count++;
+
+            /// @todo: Remove this ifdef once we start supporting BSD systems.
 #if defined(OS_LINUX)
             // To receive multicast traffic, Linux requires binding socket to
             // a multicast group. That in turn doesn't work on NetBSD.
+
             int sock2 = openSocket(iface->getName(),
                                    IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
                                    port);
@@ -357,7 +365,8 @@ IfaceMgr::getIface(const std::string& ifname) {
     return (NULL); // not found
 }
 
-int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr, uint16_t port) {
+int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
+                         const uint16_t port) {
     Iface* iface = getIface(ifname);
     if (!iface) {
         isc_throw(BadValue, "There is no " << ifname << " interface present.");
@@ -557,6 +566,14 @@ IfaceMgr::send(const Pkt6Ptr& pkt) {
     // Set the data buffer we're sending. (Using this wacky
     // "scatter-gather" stuff... we only have a single chunk
     // of data to send, so we declare a single vector entry.)
+
+    // As v structure is a C-style is used for both sending and
+    // receiving data, it is shared between sending and receiving
+    // (sendmsg and recvmsg). It is also defined in system headers,
+    // so we have no control over its definition. To set iov_base
+    // (defined as void*) we must use const cast from void *.
+    // Otherwise C++ compiler would complain that we are trying
+    // to assign const void* to void*.
     v.iov_base = const_cast<void *>(pkt->getBuffer().getData());
     v.iov_len = pkt->getBuffer().getLength();
     m.msg_iov = &v;
@@ -574,7 +591,7 @@ IfaceMgr::send(const Pkt6Ptr& pkt) {
     cmsg->cmsg_level = IPPROTO_IPV6;
     cmsg->cmsg_type = IPV6_PKTINFO;
     cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
-    pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+    pktinfo = convertPktInfo6(CMSG_DATA(cmsg));
     memset(pktinfo, 0, sizeof(*pktinfo));
     pktinfo->ipi6_ifindex = pkt->getIndex();
     m.msg_controllen = cmsg->cmsg_len;
@@ -635,7 +652,7 @@ IfaceMgr::send(const Pkt4Ptr& pkt)
          << " over socket " << getSocket(*pkt) << " on interface "
          << getIface(pkt->getIface())->getFullName() << endl;
 
-        int result = sendmsg(getSocket(*pkt), &m, 0);
+    int result = sendmsg(getSocket(*pkt), &m, 0);
     if (result < 0) {
         isc_throw(Unexpected, "Pkt4 send failed.");
     }
@@ -754,15 +771,9 @@ IfaceMgr::receive4() {
 }
 
 Pkt6Ptr IfaceMgr::receive6() {
-    struct msghdr m;
-    struct iovec v;
     int result;
-    struct cmsghdr* cmsg;
-    struct in6_pktinfo* pktinfo;
     struct sockaddr_in6 from;
-    struct in6_addr to_addr;
     int ifindex = -1;
-    Pkt6Ptr pkt;
 
     // RFC3315 states that server responses may be
     // fragmented if they are over MTU. There is no
@@ -773,11 +784,10 @@ Pkt6Ptr IfaceMgr::receive6() {
     static uint8_t buf[RCVBUFSIZE];
 
     memset(&control_buf_[0], 0, control_buf_len_);
-
     memset(&from, 0, sizeof(from));
-    memset(&to_addr, 0, sizeof(to_addr));
 
     // Initialize our message header structure.
+    struct msghdr m;
     memset(&m, 0, sizeof(m));
 
     // Point so we can get the from address.
@@ -787,7 +797,9 @@ Pkt6Ptr IfaceMgr::receive6() {
     // Set the data buffer we're receiving. (Using this wacky
     // "scatter-gather" stuff... but we that doesn't really make
     // sense for us, so we use a single vector entry.)
-    v.iov_base = (void*)buf;
+    struct iovec v;
+    memset(&v, 0, sizeof(v));
+    v.iov_base = static_cast<void*>(buf);
     v.iov_len = RCVBUFSIZE;
     m.msg_iov = &v;
     m.msg_iovlen = 1;
@@ -839,7 +851,13 @@ Pkt6Ptr IfaceMgr::receive6() {
          << iface->getFullName() << endl;
     result = recvmsg(candidate->sockfd_, &m, 0);
 
+    struct in6_addr to_addr;
+    memset(&to_addr, 0, sizeof(to_addr));
+
     if (result >= 0) {
+        struct in6_pktinfo* pktinfo = NULL;
+
+
         // If we did read successfully, then we need to loop
         // through the control messages we received and
         // find the one with our destination address.
@@ -847,11 +865,11 @@ Pkt6Ptr IfaceMgr::receive6() {
         // We also keep a flag to see if we found it. If we
         // didn't, then we consider this to be an error.
         int found_pktinfo = 0;
-        cmsg = CMSG_FIRSTHDR(&m);
+        struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
         while (cmsg != NULL) {
             if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
                 (cmsg->cmsg_type == IPV6_PKTINFO)) {
-                pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+                pktinfo = convertPktInfo6(CMSG_DATA(cmsg));
                 to_addr = pktinfo->ipi6_addr;
                 ifindex = pktinfo->ipi6_ifindex;
                 found_pktinfo = 1;
@@ -867,7 +885,8 @@ Pkt6Ptr IfaceMgr::receive6() {
         return (Pkt6Ptr()); // NULL
     }
 
-
+    // Let's create a packet.
+    Pkt6Ptr pkt;
     try {
         pkt = Pkt6Ptr(new Pkt6(buf, result));
     } catch (const std::exception& ex) {
@@ -891,7 +910,7 @@ Pkt6Ptr IfaceMgr::receive6() {
         return (boost::shared_ptr<Pkt6>()); // NULL
     }
 
-    // TODO Move this to LOG_DEBUG
+    /// @todo: Move this to LOG_DEBUG
     cout << "Received " << pkt->getBuffer().getLength() << " bytes over "
          << pkt->getIface() << "/" << pkt->getIndex() << " interface: "
          << " src=" << pkt->getRemoteAddr().toText()
@@ -914,7 +933,7 @@ uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) {
              (!s->addr_.getAddress().to_v6().is_multicast()) ) {
             return (s->sockfd_);
         }
-        /// TODO: Add more checks here later. If remote address is
+        /// @todo: Add more checks here later. If remote address is
         /// not link-local, we can't use link local bound socket
         /// to send data.
     }

+ 7 - 3
src/lib/dhcp/iface_mgr.h

@@ -232,6 +232,10 @@ public:
 
     /// @brief Returns container with all interfaces.
     ///
+    /// This reference is only valid as long as IfaceMgr is valid. However,
+    /// since IfaceMgr is a singleton and is expected to be destroyed after
+    /// main() function completes, you should not worry much about this.
+    ///
     /// @return container with all interfaces.
     const IfaceCollection& getIfaces() { return ifaces_; }
 
@@ -330,7 +334,7 @@ public:
     /// @return socket descriptor, if socket creation, binding and multicast
     /// group join were all successful.
     int openSocket(const std::string& ifname,
-                   const isc::asiolink::IOAddress& addr, uint16_t port);
+                   const isc::asiolink::IOAddress& addr, const uint16_t port);
 
     /// Opens IPv6 sockets on detected interfaces.
     ///
@@ -339,7 +343,7 @@ public:
     /// @param port specifies port number (usually DHCP6_SERVER_PORT)
     ///
     /// @return true if any sockets were open
-    bool openSockets6(uint16_t port = DHCP6_SERVER_PORT);
+    bool openSockets6(const uint16_t port = DHCP6_SERVER_PORT);
 
     /// @brief Closes all open sockets.
     /// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
@@ -351,7 +355,7 @@ public:
     /// @param port specifies port number (usually DHCP4_SERVER_PORT)
     ///
     /// @return true if any sockets were open
-    bool openSockets4(uint16_t port = DHCP4_SERVER_PORT);
+    bool openSockets4(const uint16_t port = DHCP4_SERVER_PORT);
 
     /// @brief returns number of detected interfaces
     ///

+ 5 - 5
src/lib/dhcp/libdhcp++.cc

@@ -40,9 +40,9 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
     size_t end = buf.size();
 
     while (offset +4 <= end) {
-        uint16_t opt_type = buf[offset]*256 + buf[offset+1];
+        uint16_t opt_type = buf[offset] * 256 + buf[offset + 1];
         offset += 2;
-        uint16_t opt_len = buf[offset]*256 + buf[offset+1];
+        uint16_t opt_len = buf[offset] * 256 + buf[offset + 1];
         offset += 2;
 
         if (offset + opt_len > end) {
@@ -160,12 +160,12 @@ void LibDHCP::OptionFactoryRegister(Option::Universe u,
     }
     case Option::V4:
     {
-        // option 0 is special (a one octet-long, equal 0) PAD option. It is never
-        // instantiated as Option object, but rather consumer during packet parsing.
+        // Option 0 is special (a one octet-long, equal 0) PAD option. It is never
+        // instantiated as an Option object, but rather consumed during packet parsing.
         if (opt_type == 0) {
             isc_throw(BadValue, "Cannot redefine PAD option (code=0)");
         }
-        // option 255 is never instantiated as an option object. It is special
+        // Option 255 is never instantiated as an option object. It is special
         // (a one-octet equal 255) option that is added at the end of all options
         // during packet assembly. It is also silently consumed during packet parsing.
         if (opt_type > 254) {

+ 2 - 2
src/lib/dhcp/tests/libdhcp++_unittest.cc

@@ -64,7 +64,7 @@ TEST(LibDhcpTest, packOptions6) {
 
     OutputBuffer assembled(512);
 
-    EXPECT_NO_THROW ( LibDHCP::packOptions6(assembled, opts) );
+    EXPECT_NO_THROW(LibDHCP::packOptions6(assembled, opts));
     EXPECT_EQ(35, assembled.getLength()); // options should take 35 bytes
     EXPECT_EQ(0, memcmp(assembled.getData(), packed, 35) );
 }
@@ -164,7 +164,7 @@ TEST(LibDhcpTest, packOptions4) {
     vector<uint8_t> expVect(v4Opts, v4Opts + sizeof(v4Opts));
 
     OutputBuffer buf(100);
-    EXPECT_NO_THROW ( LibDHCP::packOptions(buf, opts) );
+    EXPECT_NO_THROW(LibDHCP::packOptions(buf, opts));
     ASSERT_EQ(buf.getLength(), sizeof(v4Opts));
     EXPECT_EQ(0, memcmp(v4Opts, buf.getData(), sizeof(v4Opts)));
 

+ 1 - 1
src/lib/dhcp/tests/option6_ia_unittest.cc

@@ -198,7 +198,7 @@ TEST_F(Option6IATest, suboptions_unpack) {
         0xca, 0xfe, // type
         0, 0 // len
     };
-    ASSERT_EQ(sizeof(expected), 48);
+    ASSERT_EQ(48, sizeof(expected));
 
     memcpy(&buf_[0], expected, sizeof(expected));
 

+ 51 - 0
src/lib/util/io/pktinfo_utilities.h

@@ -0,0 +1,51 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __PKTINFO_UTIL_H_
+#define __PKTINFO_UTIL_H_ 1
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+// These definitions in this file are for the convenience of internal
+// implementation and test code, and are not intended to be used publicly.
+// The namespace "internal" indicates the intent.
+
+namespace isc {
+namespace util {
+namespace io {
+namespace internal {
+
+// Lower level C-APIs require conversion between char* pointers
+// (like structures returned by CMSG_DATA macro) and in6_pktinfo,
+// which is not friendly with C++. The following templates
+// are a shortcut of common workaround conversion in such cases.
+inline struct in6_pktinfo*
+convertPktInfo6(char* pktinfo) {
+    return (static_cast<struct in6_pktinfo*>(static_cast<void*>(pktinfo)));
+}
+
+inline struct in6_pktinfo*
+convertPktInfo6(unsigned char* pktinfo) {
+    return (static_cast<struct in6_pktinfo*>(static_cast<void*>(pktinfo)));
+}
+
+/// @todo: Do we need const versions as well?
+
+}
+}
+}
+}
+
+#endif  // __PKTINFO_UTIL_H_

+ 1 - 1
src/lib/util/io/sockaddr_util.h

@@ -20,7 +20,7 @@
 
 #include <cassert>
 
-// This definitions in this file are for the convenience of internal
+// These definitions in this file are for the convenience of internal
 // implementation and test code, and are not intended to be used publicly.
 // The namespace "internal" indicates the intent.
 

+ 66 - 0
src/lib/util/range_utilities.h

@@ -0,0 +1,66 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __RANGE_UTIL_H_
+#define __RANGE_UTIL_H_ 1
+
+#include <algorithm>
+
+// This header contains useful methods for conduction operations on
+// a range of container elements. Currently the collection is limited,
+// but it is expected to grow.
+
+namespace isc {
+namespace util {
+
+/// @brief Checks if specified range in a container contains only zeros
+///
+/// @param begin beginning of the range
+/// @param end end of the range
+///
+/// @return true if there are only zeroes, false otherwise
+template <typename Iterator>
+bool
+isRangeZero(Iterator begin, Iterator end) {
+    return (std::find_if(begin, end,
+                         std::bind1st(std::not_equal_to<int>(), 0))
+            == end);
+}
+
+/// @brief Fill in specified range with a random data.
+///
+/// Make sure that random number generator is initialized properly. Otherwise you
+/// will get a the same pseudo-random sequence after every start of your process.
+/// Calling srand() is enough. This method uses default rand(), which is usually
+/// a LCG pseudo-random number generator, so it is not suitable for security
+/// purposes. Please get a decent PRNG implementation, like mersene twister, if
+/// you are doing anything related with security.
+///
+/// PRNG initialization is left out of this function on purpose. It may be
+/// initialized to specific value on purpose, e.g. to repeat exactly the same
+/// sequence in a test.
+///
+/// @param begin
+/// @param end
+template <typename Iterator>
+void fillRandom(Iterator begin, Iterator end) {
+    for (Iterator x=begin; x != end; ++x) {
+        *x = rand();
+    }
+}
+
+} // end of isc::util namespace
+} // end of isc namespace
+
+#endif  // __PKTINFO_UTIL_H_

+ 1 - 0
src/lib/util/tests/Makefile.am

@@ -34,6 +34,7 @@ run_unittests_SOURCES += sha1_unittest.cc
 run_unittests_SOURCES += socketsession_unittest.cc
 run_unittests_SOURCES += strutil_unittest.cc
 run_unittests_SOURCES += time_utilities_unittest.cc
+run_unittests_SOURCES += range_utilities_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)

+ 55 - 0
src/lib/util/tests/range_utilities_unittest.cc

@@ -0,0 +1,55 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+#include <vector>
+
+#include <util/range_utilities.h>
+
+using namespace std;
+using namespace isc::util;
+
+TEST(RangeUtilitiesTest, isZero) {
+
+    vector<uint8_t> vec(32,0);
+
+    EXPECT_TRUE(isRangeZero(vec.begin(), vec.end()));
+
+    EXPECT_TRUE(isRangeZero(vec.begin(), vec.begin()+1));
+
+    vec[5] = 1;
+    EXPECT_TRUE(isRangeZero(vec.begin(), vec.begin()+5));
+    EXPECT_FALSE(isRangeZero(vec.begin(), vec.begin()+6));
+}
+
+TEST(RangeUtilitiesTest, randomFill) {
+
+    vector<uint8_t> vec1(16,0);
+    vector<uint8_t> vec2(16,0);
+
+    // Testing if returned value is actually random is extraordinary difficult.
+    // Let's just generate bunch of vectors and see if we get the same
+    // value. If we manage to do that in 100 tries, pseudo-random generator
+    // really sucks.
+    fillRandom(vec1.begin(), vec1.end());
+    for (int i=0; i<100; i++) {
+        fillRandom(vec2.begin(), vec2.end());
+        if (vec1 == vec2)
+            FAIL();
+    }
+
+}