BIND 10 trac1540, updated. 485f7966f583f54cf2694f054de6accea9c19364 [1540] Changes after review:
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Mar 8 13:53:11 UTC 2012
The branch, trac1540 has been updated
via 485f7966f583f54cf2694f054de6accea9c19364 (commit)
from 4fd6efcde0f9cb8d7d1513530324a389e32a978d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 485f7966f583f54cf2694f054de6accea9c19364
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Thu Mar 8 14:52:46 2012 +0100
[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
-----------------------------------------------------------------------
Summary of changes:
src/bin/dhcp4/dhcp4_srv.cc | 5 +-
src/bin/dhcp6/dhcp6_srv.cc | 28 +++++----
src/bin/dhcp6/dhcp6_srv.h | 4 +
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 4 +-
src/lib/dhcp/iface_mgr.cc | 67 +++++++++++++-------
src/lib/dhcp/iface_mgr.h | 10 ++-
src/lib/dhcp/libdhcp++.cc | 10 ++--
src/lib/dhcp/tests/libdhcp++_unittest.cc | 4 +-
src/lib/dhcp/tests/option6_ia_unittest.cc | 2 +-
.../io/{sockaddr_util.h => pktinfo_utilities.h} | 50 +++++----------
src/lib/util/io/sockaddr_util.h | 2 +-
src/lib/util/range_utilities.h | 66 +++++++++++++++++++
src/lib/util/tests/Makefile.am | 1 +
src/lib/util/tests/range_utilities_unittest.cc | 55 ++++++++++++++++
14 files changed, 221 insertions(+), 87 deletions(-)
copy src/lib/util/io/{sockaddr_util.h => pktinfo_utilities.h} (51%)
create mode 100644 src/lib/util/range_utilities.h
create mode 100644 src/lib/util/tests/range_utilities_unittest.cc
-----------------------------------------------------------------------
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 638ae05..d065eda 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/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 {
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index a0e2b08..a4b0783 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/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()));
}
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index 1c137cb..b6ae637 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/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.
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index eb351ac..a42324f 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/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
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index 1ae77f9..672d21e 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/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.
}
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
index 4663048..12605bc 100644
--- a/src/lib/dhcp/iface_mgr.h
+++ b/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
///
diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc
index 23d1072..c054a4b 100644
--- a/src/lib/dhcp/libdhcp++.cc
+++ b/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) {
diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc
index 6930338..7e18be6 100644
--- a/src/lib/dhcp/tests/libdhcp++_unittest.cc
+++ b/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)));
diff --git a/src/lib/dhcp/tests/option6_ia_unittest.cc b/src/lib/dhcp/tests/option6_ia_unittest.cc
index 67c84a3..47af50e 100644
--- a/src/lib/dhcp/tests/option6_ia_unittest.cc
+++ b/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));
diff --git a/src/lib/util/io/pktinfo_utilities.h b/src/lib/util/io/pktinfo_utilities.h
new file mode 100644
index 0000000..9883c30
--- /dev/null
+++ b/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_
diff --git a/src/lib/util/io/sockaddr_util.h b/src/lib/util/io/sockaddr_util.h
index 4c9149e..940fdd9 100644
--- a/src/lib/util/io/sockaddr_util.h
+++ b/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.
diff --git a/src/lib/util/range_utilities.h b/src/lib/util/range_utilities.h
new file mode 100644
index 0000000..b5d63d9
--- /dev/null
+++ b/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_
diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am
index dc144bd..4aea951 100644
--- a/src/lib/util/tests/Makefile.am
+++ b/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)
diff --git a/src/lib/util/tests/range_utilities_unittest.cc b/src/lib/util/tests/range_utilities_unittest.cc
new file mode 100644
index 0000000..31f9f21
--- /dev/null
+++ b/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();
+ }
+
+}
More information about the bind10-changes
mailing list