Commit f6463fa6 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[878] Replaced Addr6 class with asiolink::IOAddress.

parent 51a7361a
......@@ -31,8 +31,8 @@ spec_config.h: spec_config.h.pre
BUILT_SOURCES = spec_config.h
pkglibexec_PROGRAMS = b10-dhcp6
b10_dhcp6_SOURCES = main.cc addr6.cc iface_mgr.cc pkt6.cc dhcp6_srv.cc
b10_dhcp6_SOURCES += addr6.h iface_mgr.h pkt6.h dhcp6_srv.h dhcp6.h
b10_dhcp6_SOURCES = main.cc iface_mgr.cc pkt6.cc dhcp6_srv.cc
b10_dhcp6_SOURCES += iface_mgr.h pkt6.h dhcp6_srv.h dhcp6.h
b10_dhcp6_LDADD = $(top_builddir)/src/lib/datasrc/libdatasrc.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
......
// Copyright (C) 2011 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 <string.h>
#include <arpa/inet.h>
#include <ostream>
#include "dhcp6/addr6.h"
std::ostream&
isc::operator << (std::ostream & out, const isc::Addr6& addr) {
out << addr.getPlain();
return out;
}
using namespace std;
using namespace isc;
Addr6::Addr6(const char* addr, bool plain /*=false*/) {
if (plain) {
inet_pton(AF_INET6, addr, addr_);
} else {
memcpy(addr_, addr, 16);
}
}
Addr6::Addr6() {
memset(addr_, 0, 16);
}
Addr6::Addr6(in6_addr* addr) {
memcpy(addr_, addr, 16);
}
Addr6::Addr6(sockaddr_in6* addr) {
memcpy(addr_, &addr->sin6_addr, 16);
}
bool
Addr6::linkLocal() const {
if ( ( (unsigned char)addr_[0]==0xfe) &&
( (unsigned char)addr_[1]==0x80) ) {
return (true);
} else {
return (false);
}
}
bool
Addr6::multicast() const {
if ( (unsigned char)addr_[0]==0xff) {
return (true);
} else {
return (false);
}
}
std::string
Addr6::getPlain() const {
char buf[MAX_ADDRESS_STRING_LEN];
inet_ntop(AF_INET6, addr_, buf, MAX_ADDRESS_STRING_LEN);
return (string(buf));
}
bool
Addr6::equals(const Addr6& other) const {
if (!memcmp(addr_, other.addr_, 16)) {
return (true);
} else {
return (false);
}
// return !memcmp() would be shorter, but less readable
}
bool
Addr6::operator==(const Addr6& other) const {
return (equals(other));
}
// Copyright (C) 2011 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 ADDR6_H
#define ADDR6_H
#include <ostream>
#include <string>
#include <list>
namespace isc {
static const int MAX_ADDRESS_STRING_LEN =
sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255");
/// \brief The implementation class for IPv6 address.
///
/// There are no virtual methods to avoid virtual funtions
/// table. There are no extra fields, other than the address
/// itself. As a result, instances of this class are memory
/// optimal (sizeof(Addr6) == 16).
///
/// Extra care should be taken, when extending this class
/// to keep low memory footprint.
class Addr6 {
public:
Addr6(const char* addr, bool plain=false);
Addr6(struct in6_addr* addr);
Addr6(struct sockaddr_in6* addr);
Addr6();
inline const char * get() const { return addr_; }
std::string getPlain() const;
char* getAddr() { return addr_; }
bool equals(const Addr6& other) const;
bool operator==(const Addr6& other) const;
bool linkLocal() const;
bool multicast() const;
// no dtor necessary (no allocations done)
private:
char addr_[16];
};
std::ostream& operator << (std::ostream & out, const Addr6& addr);
// TODO may need to also define map for faster access
typedef std::list<Addr6> Addr6Lst;
};
#endif
......@@ -12,7 +12,6 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "dhcp6/addr6.h"
#include "dhcp6/pkt6.h"
#include "dhcp6/iface_mgr.h"
#include "dhcp6/dhcp6_srv.h"
......
......@@ -17,8 +17,6 @@
#include <iostream>
#include "dhcp6/addr6.h"
namespace isc {
class Dhcpv6Srv {
private:
......
......@@ -19,13 +19,13 @@
#include <arpa/inet.h>
#include <net/if.h>
#include "addr6.h"
#include "dhcp6/iface_mgr.h"
#include "dhcp6/dhcp6.h"
#include "exceptions/exceptions.h"
using namespace std;
using namespace isc;
using namespace isc::asiolink;
namespace isc {
......@@ -135,7 +135,7 @@ IfaceMgr::detectIfaces() {
cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
Addr6 addr(linkLocal.c_str(), true);
IOAddress addr(linkLocal);
iface.addrs_.push_back(addr);
ifaces_.push_back(iface);
interfaces.close();
......@@ -167,7 +167,7 @@ IfaceMgr::openSockets() {
sendsock_ = sock;
sock = openSocket(iface->name_,
Addr6(ALL_DHCP_RELAY_AGENTS_AND_SERVERS, true),
IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
DHCP6_SERVER_PORT, true);
if (sock<0) {
cout << "Failed to open multicast socket." << endl;
......@@ -190,7 +190,7 @@ IfaceMgr::printIfaces() {
for (Addr6Lst::const_iterator addr=iface->addrs_.begin();
addr != iface->addrs_.end();
++addr) {
cout << " " << *addr << endl;
cout << " " << addr->toText() << endl;
}
cout << " mac: " << iface->getPlainMac() << endl;
}
......@@ -209,7 +209,7 @@ IfaceMgr::getIface(int ifindex) {
}
IfaceMgr::Iface*
IfaceMgr::getIface(const std::string &ifname) {
IfaceMgr::getIface(const std::string& ifname) {
for (IfaceLst::iterator iface=ifaces_.begin();
iface!=ifaces_.end();
++iface) {
......@@ -221,25 +221,27 @@ IfaceMgr::getIface(const std::string &ifname) {
}
int
IfaceMgr::openSocket(const std::string &ifname,
const Addr6 &addr,
int port,
bool mcast) {
IfaceMgr::openSocket(const std::string& ifname,
const IOAddress & addr,
int port,
bool mcast) {
struct sockaddr_storage name;
int name_len;
struct sockaddr_in6 *addr6;
cout << "Creating socket on " << ifname << "/" << addr << "/port="
<< port << endl;
cout << "Creating socket on " << ifname << "/" << addr.toText()
<< "/port=" << port << endl;
memset(&name, 0, sizeof(name));
addr6 = (struct sockaddr_in6 *)&name;
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(port);
addr6->sin6_scope_id = if_nametoindex(ifname.c_str());
memcpy(&addr6->sin6_addr,
addr.get(),
addr.getAddress().to_v6().to_bytes().data(),
sizeof(addr6->sin6_addr));
#ifdef HAVE_SA_LEN
addr6->sin6_len = sizeof(*addr6);
#endif
......@@ -264,7 +266,7 @@ IfaceMgr::openSocket(const std::string &ifname,
}
if (bind(sock, (struct sockaddr *)&name, name_len) < 0) {
cout << "Failed to bind socket " << sock << " to " << addr.getPlain()
cout << "Failed to bind socket " << sock << " to " << addr.toText()
<< "/port=" << port << endl;
return (-1);
}
......@@ -299,8 +301,8 @@ IfaceMgr::openSocket(const std::string &ifname,
}
}
cout << "Created socket " << sock << " on " << ifname << "/" << addr
<< "/port=" << port << endl;
cout << "Created socket " << sock << " on " << ifname << "/" <<
addr.toText() << "/port=" << port << endl;
return (sock);
}
......@@ -351,7 +353,9 @@ IfaceMgr::send(Pkt6 &pkt) {
memset(&to, 0, sizeof(to));
to.sin6_family = AF_INET6;
to.sin6_port = htons(pkt.remote_port_);
memcpy(&to.sin6_addr, pkt.remote_addr_.get(), 16);
memcpy(&to.sin6_addr,
pkt.remote_addr_.getAddress().to_v6().to_bytes().data(),
16);
to.sin6_scope_id = pkt.ifindex_;
m.msg_name = &to;
......@@ -394,7 +398,8 @@ IfaceMgr::send(Pkt6 &pkt) {
cout << "Sent " << pkt.data_len_ << " bytes over "
<< pkt.iface_ << "/" << pkt.ifindex_ << " interface: "
<< " dst=" << pkt.remote_addr_ << ", src=" << pkt.local_addr_
<< " dst=" << pkt.remote_addr_.toText()
<< ", src=" << pkt.local_addr_.toText()
<< endl;
return (result);
......@@ -410,6 +415,7 @@ IfaceMgr::receive() {
struct sockaddr_in6 from;
struct in6_addr to_addr;
Pkt6* pkt;
char addr_str[INET6_ADDRSTRLEN];
try {
pkt = new Pkt6(1500);
......@@ -489,8 +495,15 @@ IfaceMgr::receive() {
return (0);
}
pkt->local_addr_ = Addr6(&to_addr);
pkt->remote_addr_ = Addr6(&from);
// That's ugly.
// TODO add IOAddress constructor that will take struct in6_addr* parameter
inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
pkt->local_addr_ = IOAddress(string(addr_str));
inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
pkt->remote_addr_ = IOAddress(string(addr_str));
pkt->remote_port_ = ntohs(from.sin6_port);
Iface* received = getIface(pkt->ifindex_);
......@@ -507,7 +520,8 @@ IfaceMgr::receive() {
// TODO Move this to LOG_DEBUG
cout << "Received " << pkt->data_len_ << " bytes over "
<< pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
<< " src=" << pkt->remote_addr_ << ", dst=" << pkt->local_addr_
<< " src=" << pkt->remote_addr_.toText()
<< ", dst=" << pkt->local_addr_.toText()
<< endl;
return (pkt);
......
......@@ -16,7 +16,7 @@
#define IFACE_MGR_H
#include <list>
#include "dhcp6/addr6.h"
#include "io_address.h"
#include "dhcp6/pkt6.h"
namespace isc {
......@@ -29,6 +29,7 @@ namespace isc {
*/
class IfaceMgr {
public:
typedef std::list<isc::asiolink::IOAddress> Addr6Lst;
struct Iface { // XXX: could be a class as well
std::string name_;
int ifindex_;
......@@ -58,7 +59,7 @@ namespace isc {
void printIfaces();
int openSocket(const std::string& ifname,
const Addr6& addr,
const isc::asiolink::IOAddress& addr,
int port, bool multicast);
bool joinMcast(int sock, const std::string& ifname,
const std::string& mcast);
......
......@@ -73,6 +73,8 @@ main(int argc, char* argv[]) {
}
}
cout << "My pid=" << getpid() << endl;
if (argc - optind > 0) {
usage();
}
......
......@@ -31,7 +31,10 @@ namespace isc {
/// \param data
/// \param dataLen
///
Pkt6::Pkt6(char * data, int dataLen) {
Pkt6::Pkt6(char * data, int dataLen)
:local_addr_("::"),
remote_addr_("::")
{
data_ = data;
data_len_ = dataLen;
}
......@@ -47,7 +50,9 @@ Pkt6::Pkt6(char * data, int dataLen) {
///
/// \param dataLen - length of the data to be allocated
///
Pkt6::Pkt6(int dataLen) {
Pkt6::Pkt6(int dataLen)
:local_addr_("::"),
remote_addr_("::") {
try {
data_ = new char[dataLen];
data_len_ = dataLen;
......
......@@ -16,7 +16,7 @@
#define PKT6_H
#include <iostream>
#include "dhcp6/addr6.h"
#include "io_address.h"
namespace isc {
......@@ -31,8 +31,8 @@ namespace isc {
char * data_;
int data_len_;
Addr6 local_addr_;
Addr6 remote_addr_;
isc::asiolink::IOAddress local_addr_;
isc::asiolink::IOAddress remote_addr_;
std::string iface_;
int ifindex_;
......
......@@ -26,6 +26,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
AM_CPPFLAGS += -I$(top_srcdir)/src/bin
AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/testutils/testdata\"
......@@ -42,12 +43,10 @@ if HAVE_GTEST
TESTS += dhcp6_unittests
dhcp6_unittests_SOURCES = ../addr6.h ../addr6.cc
dhcp6_unittests_SOURCES += ../pkt6.h ../pkt6.cc
dhcp6_unittests_SOURCES = ../pkt6.h ../pkt6.cc
dhcp6_unittests_SOURCES += ../iface_mgr.h ../iface_mgr.cc
dhcp6_unittests_SOURCES += ../dhcp6_srv.h ../dhcp6_srv.cc
dhcp6_unittests_SOURCES += dhcp6_unittests.cc
dhcp6_unittests_SOURCES += addr6_unittest.cc
dhcp6_unittests_SOURCES += pkt6_unittest.cc
dhcp6_unittests_SOURCES += iface_mgr_unittest.cc
dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
......
// Copyright (C) 2011 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 <iostream>
#include <sstream>
#include <arpa/inet.h>
#include <gtest/gtest.h>
#include "dhcp6/addr6.h"
using namespace std;
using namespace isc;
namespace {
// empty class for now, but may be extended once Addr6 becomes bigger
class Addr6Test : public ::testing::Test {
public:
Addr6Test() {
}
};
TEST_F(Addr6Test, constructor) {
char buf[16];
string addr1("2001:db8:1::abcd");
inet_pton(AF_INET6, addr1.c_str(), buf);
Addr6 test1(addr1.c_str(), true);
EXPECT_EQ(test1.getPlain(), addr1);
EXPECT_EQ(memcmp(test1.get(),buf, 16), 0);
Addr6 test2(buf, false);
EXPECT_EQ(test2.getPlain(), addr1);
EXPECT_EQ(memcmp(test2.get(),buf, 16), 0);
}
TEST_F(Addr6Test, mcast_linklocal) {
Addr6 mcast("ff00:2001:db8:1::abcd", true);
Addr6 global("2001:db8:1::dead:beef", true);
Addr6 local("fe80::face:b00c", true);
EXPECT_TRUE(mcast.multicast());
EXPECT_FALSE(mcast.linkLocal());
EXPECT_FALSE(global.multicast());
EXPECT_FALSE(global.linkLocal());
EXPECT_FALSE(local.multicast());
EXPECT_TRUE(local.linkLocal());
}
TEST_F(Addr6Test, equal) {
Addr6 one("2001:db8:1::abcd");
Addr6 two("2001:db8:1::abcd");
Addr6 three("2001:db8:1::4321");
EXPECT_TRUE( one==two );
EXPECT_FALSE( one==three );
}
TEST_F(Addr6Test, stream) {
string plain("2001:db8:1::abcd");
Addr6 addr(plain.c_str(), true);
stringstream tmp;
tmp << addr;
EXPECT_STREQ( tmp.str().c_str(), plain.c_str() );
}
}
......@@ -20,12 +20,13 @@
#include <arpa/inet.h>
#include <gtest/gtest.h>
#include "dhcp6/addr6.h"
#include "io_address.h"
#include "dhcp6/pkt6.h"
#include "dhcp6/iface_mgr.h"
using namespace std;
using namespace isc;
using namespace isc::asiolink;
namespace {
class NakedIfaceMgr: public IfaceMgr {
......@@ -121,10 +122,10 @@ TEST_F(IfaceMgrTest, detectIfaces) {
// there should be one address
EXPECT_EQ(1, eth0->addrs_.size());
Addr6 * addr = &(*eth0->addrs_.begin());
IOAddress * addr = &(*eth0->addrs_.begin());
ASSERT_TRUE( addr != NULL );
EXPECT_STREQ( "fe80::1234", addr->getPlain().c_str() );
EXPECT_STREQ( "fe80::1234", addr->toText().c_str() );
}
TEST_F(IfaceMgrTest, sockets) {
......@@ -133,7 +134,7 @@ TEST_F(IfaceMgrTest, sockets) {
IfaceMgr & ifacemgr = IfaceMgr::instance();
Addr6 loAddr("::1", true);
IOAddress loAddr("::1");
// bind multicast socket to port 10547
int socket1 = ifacemgr.openSocket("lo", loAddr, 10547, true);
......@@ -156,7 +157,7 @@ TEST_F(IfaceMgrTest, sendReceive) {
NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
// let's assume that every supported OS have lo interface
Addr6 loAddr("::1", true);
IOAddress loAddr("::1");
int socket1 = ifacemgr->openSocket("lo", loAddr, 10547, true);
int socket2 = ifacemgr->openSocket("lo", loAddr, 10546, false);
......@@ -171,7 +172,7 @@ TEST_F(IfaceMgrTest, sendReceive) {
}
sendPkt.remote_port_ = 10547;
sendPkt.remote_addr_ = Addr6("::1", true);
sendPkt.remote_addr_ = IOAddress("::1");
sendPkt.ifindex_ = 1;
sendPkt.iface_ = "lo";
......
......@@ -63,5 +63,10 @@ IOAddress::getFamily() const {
}
}
const asio::ip::address&
IOAddress::getAddress() const {
return asio_address_;
}
} // namespace asiolink
} // namespace isc
......@@ -74,6 +74,14 @@ public:
/// \return A string representation of the address.
std::string toText() const;
/// \brief Returns const reference to the underlying address object.
///
/// This is useful, when access to interface offerted by
// asio::ip::address_v4 and asio::ip::address_v6 is beneficial.
///
/// \return A const reference to asio::ip::address object
const asio::ip::address& getAddress() const;
/// \brief Returns the address family
///
/// \return AF_INET for IPv4 or AF_INET6 for IPv6.
......