|
@@ -22,67 +22,85 @@
|
|
#include "addr6.h"
|
|
#include "addr6.h"
|
|
#include "dhcp6/iface_mgr.h"
|
|
#include "dhcp6/iface_mgr.h"
|
|
#include "dhcp6/dhcp6.h"
|
|
#include "dhcp6/dhcp6.h"
|
|
|
|
+#include "exceptions/exceptions.h"
|
|
|
|
|
|
using namespace std;
|
|
using namespace std;
|
|
using namespace isc;
|
|
using namespace isc;
|
|
|
|
|
|
|
|
+namespace isc {
|
|
|
|
+
|
|
// IfaceMgr is a singleton implementation
|
|
// IfaceMgr is a singleton implementation
|
|
-IfaceMgr * IfaceMgr::instance_ = 0;
|
|
|
|
|
|
+IfaceMgr* IfaceMgr::instance_ = 0;
|
|
|
|
|
|
-void IfaceMgr::instanceCreate() {
|
|
|
|
|
|
+void
|
|
|
|
+IfaceMgr::instanceCreate() {
|
|
if (instance_) {
|
|
if (instance_) {
|
|
- // XXX: throw exception here
|
|
|
|
|
|
+ // TODO throw exception here
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
instance_ = new IfaceMgr();
|
|
instance_ = new IfaceMgr();
|
|
}
|
|
}
|
|
|
|
|
|
-IfaceMgr& IfaceMgr::instance() {
|
|
|
|
|
|
+IfaceMgr&
|
|
|
|
+IfaceMgr::instance() {
|
|
if (instance_ == 0)
|
|
if (instance_ == 0)
|
|
instanceCreate();
|
|
instanceCreate();
|
|
- return *instance_;
|
|
|
|
|
|
+ return (*instance_);
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
IfaceMgr::Iface::Iface()
|
|
IfaceMgr::Iface::Iface()
|
|
- : name_(""), ifindex_(0), macLen_(0) {
|
|
|
|
|
|
+ : name_(""), ifindex_(0), mac_len_(0) {
|
|
memset(mac_, 0, 20);
|
|
memset(mac_, 0, 20);
|
|
}
|
|
}
|
|
|
|
|
|
-IfaceMgr::Iface::Iface(const std::string name, int ifindex)
|
|
|
|
- :name_(name), ifindex_(ifindex), macLen_(0) {
|
|
|
|
|
|
+IfaceMgr::Iface::Iface(const std::string& name, int ifindex)
|
|
|
|
+ :name_(name), ifindex_(ifindex), mac_len_(0) {
|
|
memset(mac_, 0, 20);
|
|
memset(mac_, 0, 20);
|
|
}
|
|
}
|
|
|
|
|
|
-std::string IfaceMgr::Iface::getFullName() const {
|
|
|
|
|
|
+std::string
|
|
|
|
+IfaceMgr::Iface::getFullName() const {
|
|
ostringstream tmp;
|
|
ostringstream tmp;
|
|
tmp << name_ << "/" << ifindex_;
|
|
tmp << name_ << "/" << ifindex_;
|
|
- return tmp.str();
|
|
|
|
|
|
+ return (tmp.str());
|
|
}
|
|
}
|
|
|
|
|
|
-std::string IfaceMgr::Iface::getPlainMac() const {
|
|
|
|
|
|
+std::string
|
|
|
|
+IfaceMgr::Iface::getPlainMac() const {
|
|
ostringstream tmp;
|
|
ostringstream tmp;
|
|
- for (int i=0; i<macLen_; i++) {
|
|
|
|
|
|
+ for (int i=0; i<mac_len_; i++) {
|
|
tmp.fill('0');
|
|
tmp.fill('0');
|
|
tmp.width(2);
|
|
tmp.width(2);
|
|
tmp << (hex) << (int) mac_[i];
|
|
tmp << (hex) << (int) mac_[i];
|
|
- if (i<macLen_-1) {
|
|
|
|
|
|
+ if (i<mac_len_-1) {
|
|
tmp << ":";
|
|
tmp << ":";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- return tmp.str();
|
|
|
|
|
|
+ return (tmp.str());
|
|
}
|
|
}
|
|
|
|
|
|
IfaceMgr::IfaceMgr() {
|
|
IfaceMgr::IfaceMgr() {
|
|
|
|
|
|
- control_buf_len_ = CMSG_SPACE(sizeof(struct in6_pktinfo));
|
|
|
|
- control_buf_ = (char*) new char[control_buf_len_];
|
|
|
|
|
|
+ cout << "IfaceMgr initialization." << endl;
|
|
|
|
|
|
- cout << "IfaceMgr initialization." << endl;
|
|
|
|
|
|
+ try {
|
|
|
|
+ control_buf_len_ = CMSG_SPACE(sizeof(struct in6_pktinfo));
|
|
|
|
+ control_buf_ = new char[control_buf_len_];
|
|
|
|
|
|
- detectIfaces();
|
|
|
|
|
|
+ detectIfaces();
|
|
|
|
|
|
- openSockets();
|
|
|
|
|
|
+ if (!openSockets()) {
|
|
|
|
+ isc_throw(Unexpected, "Failed to open/bind sockets.");
|
|
|
|
+ }
|
|
|
|
+ } catch (std::exception& ex) {
|
|
|
|
+ cout << "IfaceMgr creation failed:" << ex.what() << endl;
|
|
|
|
+
|
|
|
|
+ // TODO Uncomment this (or call LOG_FATAL) once
|
|
|
|
+ // interface detection is implemented. Otherwise
|
|
|
|
+ // it is not possible to run tests in a portable
|
|
|
|
+ // way (see detectIfaces() method).
|
|
|
|
+ // throw ex;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
IfaceMgr::~IfaceMgr() {
|
|
IfaceMgr::~IfaceMgr() {
|
|
@@ -93,36 +111,49 @@ IfaceMgr::~IfaceMgr() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-void IfaceMgr::detectIfaces() {
|
|
|
|
|
|
+void
|
|
|
|
+IfaceMgr::detectIfaces() {
|
|
string ifaceName, linkLocal;
|
|
string ifaceName, linkLocal;
|
|
|
|
|
|
- // XXX: do the actual detection
|
|
|
|
|
|
+ // TODO do the actual detection. Currently interface detection is faked
|
|
|
|
+ // by reading a text file.
|
|
|
|
|
|
cout << "Interface detection is not implemented yet. "
|
|
cout << "Interface detection is not implemented yet. "
|
|
<< "Reading interfaces.txt file instead." << endl;
|
|
<< "Reading interfaces.txt file instead." << endl;
|
|
cout << "Please use format: interface-name link-local-address" << endl;
|
|
cout << "Please use format: interface-name link-local-address" << endl;
|
|
|
|
|
|
- ifstream interfaces("interfaces.txt");
|
|
|
|
- interfaces >> ifaceName;
|
|
|
|
- interfaces >> linkLocal;
|
|
|
|
|
|
+ try {
|
|
|
|
+ ifstream interfaces("interfaces.txt");
|
|
|
|
|
|
- cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
|
|
|
|
-
|
|
|
|
- Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
|
|
|
|
- Addr6 addr(linkLocal.c_str(), true);
|
|
|
|
- iface.addrs_.push_back(addr);
|
|
|
|
- ifaces_.push_back(iface);
|
|
|
|
- interfaces.close();
|
|
|
|
|
|
+ if (!interfaces.good()) {
|
|
|
|
+ cout << "Failed to read interfaces.txt file." << endl;
|
|
|
|
+ isc_throw(Unexpected, "Failed to read interfaces.txt");
|
|
|
|
+ }
|
|
|
|
+ interfaces >> ifaceName;
|
|
|
|
+ interfaces >> linkLocal;
|
|
|
|
+
|
|
|
|
+ cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
|
|
|
|
+
|
|
|
|
+ Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
|
|
|
|
+ Addr6 addr(linkLocal.c_str(), true);
|
|
|
|
+ iface.addrs_.push_back(addr);
|
|
|
|
+ ifaces_.push_back(iface);
|
|
|
|
+ interfaces.close();
|
|
|
|
+ } catch (std::exception& ex) {
|
|
|
|
+ // TODO Do LOG_FATAL here
|
|
|
|
+ std::cerr << "Interface detection failed." << std::endl;
|
|
|
|
+ throw ex;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-bool IfaceMgr::openSockets() {
|
|
|
|
|
|
+bool
|
|
|
|
+IfaceMgr::openSockets() {
|
|
int sock;
|
|
int sock;
|
|
|
|
|
|
for (IfaceLst::iterator iface=ifaces_.begin();
|
|
for (IfaceLst::iterator iface=ifaces_.begin();
|
|
iface!=ifaces_.end();
|
|
iface!=ifaces_.end();
|
|
++iface) {
|
|
++iface) {
|
|
|
|
|
|
-
|
|
|
|
for (Addr6Lst::iterator addr=iface->addrs_.begin();
|
|
for (Addr6Lst::iterator addr=iface->addrs_.begin();
|
|
addr!=iface->addrs_.end();
|
|
addr!=iface->addrs_.end();
|
|
++addr) {
|
|
++addr) {
|
|
@@ -131,7 +162,7 @@ bool IfaceMgr::openSockets() {
|
|
DHCP6_SERVER_PORT, false);
|
|
DHCP6_SERVER_PORT, false);
|
|
if (sock<0) {
|
|
if (sock<0) {
|
|
cout << "Failed to open unicast socket." << endl;
|
|
cout << "Failed to open unicast socket." << endl;
|
|
- return false;
|
|
|
|
|
|
+ return (false);
|
|
}
|
|
}
|
|
sendsock_ = sock;
|
|
sendsock_ = sock;
|
|
|
|
|
|
@@ -140,16 +171,17 @@ bool IfaceMgr::openSockets() {
|
|
DHCP6_SERVER_PORT, true);
|
|
DHCP6_SERVER_PORT, true);
|
|
if (sock<0) {
|
|
if (sock<0) {
|
|
cout << "Failed to open multicast socket." << endl;
|
|
cout << "Failed to open multicast socket." << endl;
|
|
- return false;
|
|
|
|
|
|
+ return (false);
|
|
}
|
|
}
|
|
recvsock_ = sock;
|
|
recvsock_ = sock;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- return true;
|
|
|
|
|
|
+ return (true);
|
|
}
|
|
}
|
|
|
|
|
|
-void IfaceMgr::printIfaces() {
|
|
|
|
|
|
+void
|
|
|
|
+IfaceMgr::printIfaces() {
|
|
for (IfaceLst::const_iterator iface=ifaces_.begin();
|
|
for (IfaceLst::const_iterator iface=ifaces_.begin();
|
|
iface!=ifaces_.end();
|
|
iface!=ifaces_.end();
|
|
++iface) {
|
|
++iface) {
|
|
@@ -164,29 +196,32 @@ void IfaceMgr::printIfaces() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-IfaceMgr::Iface* IfaceMgr::getIface(int ifindex) {
|
|
|
|
|
|
+IfaceMgr::Iface*
|
|
|
|
+IfaceMgr::getIface(int ifindex) {
|
|
for (IfaceLst::iterator iface=ifaces_.begin();
|
|
for (IfaceLst::iterator iface=ifaces_.begin();
|
|
iface!=ifaces_.end();
|
|
iface!=ifaces_.end();
|
|
++iface) {
|
|
++iface) {
|
|
if (iface->ifindex_ == ifindex)
|
|
if (iface->ifindex_ == ifindex)
|
|
- return &(*iface);
|
|
|
|
|
|
+ return (&(*iface));
|
|
}
|
|
}
|
|
|
|
|
|
return 0; // not found
|
|
return 0; // not found
|
|
}
|
|
}
|
|
|
|
|
|
-IfaceMgr::Iface* IfaceMgr::getIface(const std::string &ifname) {
|
|
|
|
|
|
+IfaceMgr::Iface*
|
|
|
|
+IfaceMgr::getIface(const std::string &ifname) {
|
|
for (IfaceLst::iterator iface=ifaces_.begin();
|
|
for (IfaceLst::iterator iface=ifaces_.begin();
|
|
iface!=ifaces_.end();
|
|
iface!=ifaces_.end();
|
|
++iface) {
|
|
++iface) {
|
|
if (iface->name_ == ifname)
|
|
if (iface->name_ == ifname)
|
|
- return &(*iface);
|
|
|
|
|
|
+ return (&(*iface));
|
|
}
|
|
}
|
|
|
|
|
|
- return 0; // not found
|
|
|
|
|
|
+ return (0); // not found
|
|
}
|
|
}
|
|
|
|
|
|
-int IfaceMgr::openSocket(const std::string &ifname,
|
|
|
|
|
|
+int
|
|
|
|
+IfaceMgr::openSocket(const std::string &ifname,
|
|
const Addr6 &addr,
|
|
const Addr6 &addr,
|
|
int port,
|
|
int port,
|
|
bool mcast) {
|
|
bool mcast) {
|
|
@@ -194,7 +229,7 @@ int IfaceMgr::openSocket(const std::string &ifname,
|
|
int name_len;
|
|
int name_len;
|
|
struct sockaddr_in6 *addr6;
|
|
struct sockaddr_in6 *addr6;
|
|
|
|
|
|
- cout << "Creating socket on " << ifname << "/" << addr << "/port="
|
|
|
|
|
|
+ cout << "Creating socket on " << ifname << "/" << addr << "/port="
|
|
<< port << endl;
|
|
<< port << endl;
|
|
|
|
|
|
memset(&name, 0, sizeof(name));
|
|
memset(&name, 0, sizeof(name));
|
|
@@ -216,7 +251,7 @@ int IfaceMgr::openSocket(const std::string &ifname,
|
|
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
|
|
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
|
|
if (sock < 0) {
|
|
if (sock < 0) {
|
|
cout << "Failed to create UDP6 socket." << endl;
|
|
cout << "Failed to create UDP6 socket." << endl;
|
|
- return -1;
|
|
|
|
|
|
+ return (-1);
|
|
}
|
|
}
|
|
|
|
|
|
/* Set the REUSEADDR option so that we don't fail to start if
|
|
/* Set the REUSEADDR option so that we don't fail to start if
|
|
@@ -225,13 +260,13 @@ int IfaceMgr::openSocket(const std::string &ifname,
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
|
(char *)&flag, sizeof(flag)) < 0) {
|
|
(char *)&flag, sizeof(flag)) < 0) {
|
|
cout << "Can't set SO_REUSEADDR option on dhcpv6 socket." << endl;
|
|
cout << "Can't set SO_REUSEADDR option on dhcpv6 socket." << endl;
|
|
- return -1;
|
|
|
|
|
|
+ return (-1);
|
|
}
|
|
}
|
|
|
|
|
|
if (bind(sock, (struct sockaddr *)&name, name_len) < 0) {
|
|
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.getPlain()
|
|
<< "/port=" << port << endl;
|
|
<< "/port=" << port << endl;
|
|
- return -1;
|
|
|
|
|
|
+ return (-1);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef IPV6_RECVPKTINFO
|
|
#ifdef IPV6_RECVPKTINFO
|
|
@@ -239,14 +274,14 @@ int IfaceMgr::openSocket(const std::string &ifname,
|
|
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
|
|
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
|
|
&flag, sizeof(flag)) != 0) {
|
|
&flag, sizeof(flag)) != 0) {
|
|
cout << "setsockopt: IPV6_RECVPKTINFO failed." << endl;
|
|
cout << "setsockopt: IPV6_RECVPKTINFO failed." << endl;
|
|
- return -1;
|
|
|
|
|
|
+ return (-1);
|
|
}
|
|
}
|
|
#else
|
|
#else
|
|
/* RFC2292 - an old way */
|
|
/* RFC2292 - an old way */
|
|
if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
|
|
if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
|
|
&flag, sizeof(flag)) != 0) {
|
|
&flag, sizeof(flag)) != 0) {
|
|
cout << "setsockopt: IPV6_PKTINFO: failed." << endl;
|
|
cout << "setsockopt: IPV6_PKTINFO: failed." << endl;
|
|
- return -1;
|
|
|
|
|
|
+ return (-1);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
@@ -257,212 +292,225 @@ int IfaceMgr::openSocket(const std::string &ifname,
|
|
// are link and site-scoped, so there is no sense to join those them
|
|
// are link and site-scoped, so there is no sense to join those them
|
|
// with global addressed.
|
|
// with global addressed.
|
|
|
|
|
|
- if ( !joinMcast( sock, ifname,
|
|
|
|
|
|
+ if ( !joinMcast( sock, ifname,
|
|
string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
|
|
string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
|
|
close(sock);
|
|
close(sock);
|
|
- return -1;
|
|
|
|
|
|
+ return (-1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- cout << "Created socket " << sock << " on " << ifname << "/" << addr
|
|
|
|
|
|
+ cout << "Created socket " << sock << " on " << ifname << "/" << addr
|
|
<< "/port=" << port << endl;
|
|
<< "/port=" << port << endl;
|
|
|
|
|
|
- return sock;
|
|
|
|
|
|
+ return (sock);
|
|
}
|
|
}
|
|
|
|
|
|
-bool IfaceMgr::joinMcast(int sock, const std::string& ifname,
|
|
|
|
- const std::string & mcast) {
|
|
|
|
|
|
+bool
|
|
|
|
+IfaceMgr::joinMcast(int sock, const std::string& ifname,
|
|
|
|
+const std::string & mcast) {
|
|
|
|
|
|
struct ipv6_mreq mreq;
|
|
struct ipv6_mreq mreq;
|
|
|
|
|
|
- if (inet_pton(AF_INET6, mcast.c_str(),
|
|
|
|
- &mreq.ipv6mr_multiaddr) <= 0) {
|
|
|
|
- cout << "Failed to convert " << ifname
|
|
|
|
- << " to IPv6 multicast address." << endl;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
|
|
|
|
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
|
|
|
|
- &mreq, sizeof(mreq)) < 0) {
|
|
|
|
- cout << "Failed to join " << mcast << " multicast group." << endl;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- cout << "Joined multicast " << mcast << " group." << endl;
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
|
|
+ if (inet_pton(AF_INET6, mcast.c_str(),
|
|
|
|
+ &mreq.ipv6mr_multiaddr) <= 0) {
|
|
|
|
+ cout << "Failed to convert " << ifname
|
|
|
|
+ << " to IPv6 multicast address." << endl;
|
|
|
|
+ return (false);
|
|
}
|
|
}
|
|
|
|
|
|
- bool IfaceMgr::send(Pkt6 &pkt) {
|
|
|
|
- struct msghdr m;
|
|
|
|
- struct iovec v;
|
|
|
|
- int result;
|
|
|
|
- struct in6_pktinfo *pktinfo;
|
|
|
|
- struct cmsghdr *cmsg;
|
|
|
|
- memset(control_buf_, 0, control_buf_len_);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Initialize our message header structure.
|
|
|
|
- */
|
|
|
|
- memset(&m, 0, sizeof(m));
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Set the target address we're sending to.
|
|
|
|
- */
|
|
|
|
- sockaddr_in6 to;
|
|
|
|
- memset(&to, 0, sizeof(to));
|
|
|
|
- to.sin6_family = AF_INET6;
|
|
|
|
- to.sin6_port = htons(pkt.remotePort);
|
|
|
|
- memcpy(&to.sin6_addr, pkt.remoteAddr.get(), 16);
|
|
|
|
- to.sin6_scope_id = pkt.ifindex;
|
|
|
|
-
|
|
|
|
- m.msg_name = &to;
|
|
|
|
- m.msg_namelen = sizeof(to);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * 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.)
|
|
|
|
- */
|
|
|
|
- v.iov_base = (char *) pkt.data_;
|
|
|
|
- v.iov_len = pkt.dataLen_;
|
|
|
|
- m.msg_iov = &v;
|
|
|
|
- m.msg_iovlen = 1;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Setting the interface is a bit more involved.
|
|
|
|
- *
|
|
|
|
- * We have to create a "control message", and set that to
|
|
|
|
- * define the IPv6 packet information. We could set the
|
|
|
|
- * source address if we wanted, but we can safely let the
|
|
|
|
- * kernel decide what that should be.
|
|
|
|
- */
|
|
|
|
- m.msg_control = control_buf_;
|
|
|
|
- m.msg_controllen = control_buf_len_;
|
|
|
|
- cmsg = CMSG_FIRSTHDR(&m);
|
|
|
|
- cmsg->cmsg_level = IPPROTO_IPV6;
|
|
|
|
- cmsg->cmsg_type = IPV6_PKTINFO;
|
|
|
|
- cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
|
|
|
|
- pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
|
|
|
|
- memset(pktinfo, 0, sizeof(*pktinfo));
|
|
|
|
- pktinfo->ipi6_ifindex = pkt.ifindex;
|
|
|
|
- m.msg_controllen = cmsg->cmsg_len;
|
|
|
|
-
|
|
|
|
- result = sendmsg(sendsock_, &m, 0);
|
|
|
|
- if (result < 0) {
|
|
|
|
- cout << "Send packet failed." << endl;
|
|
|
|
- }
|
|
|
|
- cout << "Sent " << result << " bytes." << endl;
|
|
|
|
-
|
|
|
|
- cout << "Sent " << pkt.dataLen_ << " bytes over "
|
|
|
|
- << pkt.iface << "/" << pkt.ifindex << " interface: "
|
|
|
|
- << " dst=" << pkt.remoteAddr << ", src=" << pkt.localAddr
|
|
|
|
- << endl;
|
|
|
|
-
|
|
|
|
- return result;
|
|
|
|
|
|
+ mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
|
|
|
|
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
|
|
|
|
+ &mreq, sizeof(mreq)) < 0) {
|
|
|
|
+ cout << "Failed to join " << mcast << " multicast group." << endl;
|
|
|
|
+ return (false);
|
|
}
|
|
}
|
|
|
|
|
|
- Pkt6 * IfaceMgr::receive() {
|
|
|
|
- struct msghdr m;
|
|
|
|
- struct iovec v;
|
|
|
|
- int result;
|
|
|
|
- struct cmsghdr *cmsg;
|
|
|
|
- struct in6_pktinfo *pktinfo;
|
|
|
|
- int found_pktinfo;
|
|
|
|
- struct sockaddr_in6 from;
|
|
|
|
- struct in6_addr to_addr;
|
|
|
|
-
|
|
|
|
- Pkt6 * pkt = new Pkt6(1500);
|
|
|
|
|
|
+ cout << "Joined multicast " << mcast << " group." << endl;
|
|
|
|
|
|
- memset(control_buf_, 0, control_buf_len_);
|
|
|
|
|
|
+ return (true);
|
|
|
|
+}
|
|
|
|
|
|
- memset(&from, 0, sizeof(from));
|
|
|
|
- memset(&to_addr, 0, sizeof(to_addr));
|
|
|
|
|
|
+bool
|
|
|
|
+IfaceMgr::send(Pkt6 &pkt) {
|
|
|
|
+ struct msghdr m;
|
|
|
|
+ struct iovec v;
|
|
|
|
+ int result;
|
|
|
|
+ struct in6_pktinfo *pktinfo;
|
|
|
|
+ struct cmsghdr *cmsg;
|
|
|
|
+ memset(control_buf_, 0, control_buf_len_);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Initialize our message header structure.
|
|
|
|
+ */
|
|
|
|
+ memset(&m, 0, sizeof(m));
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Set the target address we're sending to.
|
|
|
|
+ */
|
|
|
|
+ sockaddr_in6 to;
|
|
|
|
+ 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);
|
|
|
|
+ to.sin6_scope_id = pkt.ifindex_;
|
|
|
|
+
|
|
|
|
+ m.msg_name = &to;
|
|
|
|
+ m.msg_namelen = sizeof(to);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * 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.)
|
|
|
|
+ */
|
|
|
|
+ v.iov_base = (char *) pkt.data_;
|
|
|
|
+ v.iov_len = pkt.data_len_;
|
|
|
|
+ m.msg_iov = &v;
|
|
|
|
+ m.msg_iovlen = 1;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Setting the interface is a bit more involved.
|
|
|
|
+ *
|
|
|
|
+ * We have to create a "control message", and set that to
|
|
|
|
+ * define the IPv6 packet information. We could set the
|
|
|
|
+ * source address if we wanted, but we can safely let the
|
|
|
|
+ * kernel decide what that should be.
|
|
|
|
+ */
|
|
|
|
+ m.msg_control = control_buf_;
|
|
|
|
+ m.msg_controllen = control_buf_len_;
|
|
|
|
+ cmsg = CMSG_FIRSTHDR(&m);
|
|
|
|
+ cmsg->cmsg_level = IPPROTO_IPV6;
|
|
|
|
+ cmsg->cmsg_type = IPV6_PKTINFO;
|
|
|
|
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
|
|
|
|
+ pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
|
|
|
|
+ memset(pktinfo, 0, sizeof(*pktinfo));
|
|
|
|
+ pktinfo->ipi6_ifindex = pkt.ifindex_;
|
|
|
|
+ m.msg_controllen = cmsg->cmsg_len;
|
|
|
|
+
|
|
|
|
+ result = sendmsg(sendsock_, &m, 0);
|
|
|
|
+ if (result < 0) {
|
|
|
|
+ cout << "Send packet failed." << endl;
|
|
|
|
+ }
|
|
|
|
+ cout << "Sent " << result << " bytes." << endl;
|
|
|
|
|
|
- /*
|
|
|
|
- * Initialize our message header structure.
|
|
|
|
- */
|
|
|
|
- memset(&m, 0, sizeof(m));
|
|
|
|
|
|
+ cout << "Sent " << pkt.data_len_ << " bytes over "
|
|
|
|
+ << pkt.iface_ << "/" << pkt.ifindex_ << " interface: "
|
|
|
|
+ << " dst=" << pkt.remote_addr_ << ", src=" << pkt.local_addr_
|
|
|
|
+ << endl;
|
|
|
|
|
|
- /*
|
|
|
|
- * Point so we can get the from address.
|
|
|
|
- */
|
|
|
|
- m.msg_name = &from;
|
|
|
|
- m.msg_namelen = sizeof(from);
|
|
|
|
|
|
+ return (result);
|
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
|
- * 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 = pkt->data_;
|
|
|
|
- v.iov_len = pkt->dataLen_;
|
|
|
|
- m.msg_iov = &v;
|
|
|
|
- m.msg_iovlen = 1;
|
|
|
|
|
|
+Pkt6*
|
|
|
|
+IfaceMgr::receive() {
|
|
|
|
+ struct msghdr m;
|
|
|
|
+ struct iovec v;
|
|
|
|
+ int result;
|
|
|
|
+ struct cmsghdr* cmsg;
|
|
|
|
+ struct in6_pktinfo* pktinfo;
|
|
|
|
+ struct sockaddr_in6 from;
|
|
|
|
+ struct in6_addr to_addr;
|
|
|
|
+ Pkt6* pkt;
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ pkt = new Pkt6(1500);
|
|
|
|
+ } catch (std::exception& ex) {
|
|
|
|
+ cout << "Failed to create new packet." << endl;
|
|
|
|
+ return (0);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ memset(control_buf_, 0, control_buf_len_);
|
|
|
|
+
|
|
|
|
+ memset(&from, 0, sizeof(from));
|
|
|
|
+ memset(&to_addr, 0, sizeof(to_addr));
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Initialize our message header structure.
|
|
|
|
+ */
|
|
|
|
+ memset(&m, 0, sizeof(m));
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Point so we can get the from address.
|
|
|
|
+ */
|
|
|
|
+ m.msg_name = &from;
|
|
|
|
+ m.msg_namelen = sizeof(from);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * 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 = pkt->data_;
|
|
|
|
+ v.iov_len = pkt->data_len_;
|
|
|
|
+ m.msg_iov = &v;
|
|
|
|
+ m.msg_iovlen = 1;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Getting the interface is a bit more involved.
|
|
|
|
+ *
|
|
|
|
+ * We set up some space for a "control message". We have
|
|
|
|
+ * previously asked the kernel to give us packet
|
|
|
|
+ * information (when we initialized the interface), so we
|
|
|
|
+ * should get the destination address from that.
|
|
|
|
+ */
|
|
|
|
+ m.msg_control = control_buf_;
|
|
|
|
+ m.msg_controllen = control_buf_len_;
|
|
|
|
+
|
|
|
|
+ result = recvmsg(recvsock_, &m, 0);
|
|
|
|
+
|
|
|
|
+ if (result >= 0) {
|
|
/*
|
|
/*
|
|
- * Getting the interface is a bit more involved.
|
|
|
|
|
|
+ * If we did read successfully, then we need to loop
|
|
|
|
+ * through the control messages we received and
|
|
|
|
+ * find the one with our destination address.
|
|
*
|
|
*
|
|
- * We set up some space for a "control message". We have
|
|
|
|
- * previously asked the kernel to give us packet
|
|
|
|
- * information (when we initialized the interface), so we
|
|
|
|
- * should get the destination address from that.
|
|
|
|
|
|
+ * We also keep a flag to see if we found it. If we
|
|
|
|
+ * didn't, then we consider this to be an error.
|
|
*/
|
|
*/
|
|
- m.msg_control = control_buf_;
|
|
|
|
- m.msg_controllen = control_buf_len_;
|
|
|
|
-
|
|
|
|
- result = recvmsg(recvsock_, &m, 0);
|
|
|
|
-
|
|
|
|
- if (result >= 0) {
|
|
|
|
- /*
|
|
|
|
- * If we did read successfully, then we need to loop
|
|
|
|
- * through the control messages we received and
|
|
|
|
- * find the one with our destination address.
|
|
|
|
- *
|
|
|
|
- * We also keep a flag to see if we found it. If we
|
|
|
|
- * didn't, then we consider this to be an error.
|
|
|
|
- */
|
|
|
|
- found_pktinfo = 0;
|
|
|
|
- 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);
|
|
|
|
- to_addr = pktinfo->ipi6_addr;
|
|
|
|
- pkt->ifindex = pktinfo->ipi6_ifindex;
|
|
|
|
- found_pktinfo = 1;
|
|
|
|
- }
|
|
|
|
- cmsg = CMSG_NXTHDR(&m, cmsg);
|
|
|
|
- }
|
|
|
|
- if (!found_pktinfo) {
|
|
|
|
- cout << "Unable to find pktinfo" << endl;
|
|
|
|
- delete pkt;
|
|
|
|
- return 0;
|
|
|
|
|
|
+ int found_pktinfo = 0;
|
|
|
|
+ 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);
|
|
|
|
+ to_addr = pktinfo->ipi6_addr;
|
|
|
|
+ pkt->ifindex_ = pktinfo->ipi6_ifindex;
|
|
|
|
+ found_pktinfo = 1;
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- cout << "Failed to receive data." << endl;
|
|
|
|
-
|
|
|
|
|
|
+ cmsg = CMSG_NXTHDR(&m, cmsg);
|
|
|
|
+ }
|
|
|
|
+ if (!found_pktinfo) {
|
|
|
|
+ cout << "Unable to find pktinfo" << endl;
|
|
delete pkt;
|
|
delete pkt;
|
|
- return 0;
|
|
|
|
|
|
+ return (0);
|
|
}
|
|
}
|
|
|
|
+ } else {
|
|
|
|
+ cout << "Failed to receive data." << endl;
|
|
|
|
+ delete pkt;
|
|
|
|
+ return (0);
|
|
|
|
+ }
|
|
|
|
|
|
- pkt->localAddr = Addr6(&to_addr);
|
|
|
|
- pkt->remoteAddr = Addr6(&from);
|
|
|
|
- pkt->remotePort = ntohs(from.sin6_port);
|
|
|
|
-
|
|
|
|
- Iface * received = getIface(pkt->ifindex);
|
|
|
|
- if (received) {
|
|
|
|
- pkt->iface = received->name_;
|
|
|
|
- }
|
|
|
|
|
|
+ pkt->local_addr_ = Addr6(&to_addr);
|
|
|
|
+ pkt->remote_addr_ = Addr6(&from);
|
|
|
|
+ pkt->remote_port_ = ntohs(from.sin6_port);
|
|
|
|
+
|
|
|
|
+ Iface* received = getIface(pkt->ifindex_);
|
|
|
|
+ if (received) {
|
|
|
|
+ pkt->iface_ = received->name_;
|
|
|
|
+ } else {
|
|
|
|
+ cout << "Received packet over unknown interface (ifindex="
|
|
|
|
+ << pkt->ifindex_ << endl;
|
|
|
|
+ pkt->iface_ = "[unknown]";
|
|
|
|
+ }
|
|
|
|
|
|
- pkt->dataLen_ = result;
|
|
|
|
|
|
+ pkt->data_len_ = result;
|
|
|
|
|
|
- cout << "Received " << pkt->dataLen_ << " bytes over "
|
|
|
|
- << pkt->iface << "/" << pkt->ifindex << " interface: "
|
|
|
|
- << " src=" << pkt->remoteAddr << ", dst=" << pkt->localAddr
|
|
|
|
- << endl;
|
|
|
|
|
|
+ // 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_
|
|
|
|
+ << endl;
|
|
|
|
|
|
- return pkt;
|
|
|
|
|
|
+ return (pkt);
|
|
|
|
+}
|
|
|
|
|
|
- }
|
|
|
|
|
|
+}
|