Commit 084c9790 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[1239] OpenSockets4() and receive4() implemented in IfaceMgr.

parent 1ee6d8e7
......@@ -31,6 +31,9 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port) {
IfaceMgr::instance();
/// @todo: instantiate LeaseMgr here once it is imlpemented.
IfaceMgr::instance().printIfaces();
IfaceMgr::instance().openSockets4();
setServerID();
......@@ -47,7 +50,7 @@ Dhcpv4Srv::run() {
boost::shared_ptr<Pkt4> query; // client's message
boost::shared_ptr<Pkt4> rsp; // server's response
#if 0
#if 1
// uncomment this once ticket 1239 is merged.
query = IfaceMgr::instance().receive4();
#endif
......@@ -99,9 +102,9 @@ Dhcpv4Srv::run() {
if (rsp->pack()) {
cout << "Packet assembled correctly." << endl;
}
#if 0
#if 1
// uncomment this once ticket 1240 is merged.
IfaceMgr::instance().send4(rsp);
IfaceMgr::instance().send(rsp);
#endif
}
}
......
......@@ -36,7 +36,7 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
IfaceMgr::instance();
// Now try to open IPv6 sockets on detected interfaces.
IfaceMgr::instance().openSockets(port);
IfaceMgr::instance().openSockets6(port);
/// @todo: instantiate LeaseMgr here once it is imlpemented.
......
......@@ -18,6 +18,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/iface_mgr.h>
#include <exceptions/exceptions.h>
......@@ -191,9 +192,52 @@ IfaceMgr::detectIfaces() {
}
}
void
IfaceMgr::openSockets(uint16_t port) {
bool IfaceMgr::openSockets4(uint16_t port) {
int sock;
int count = 0;
for (IfaceCollection::iterator iface=ifaces_.begin();
iface!=ifaces_.end();
++iface) {
cout << "Trying interface " << iface->getFullName() << endl;
#if 0
// uncomment when trac1237 (interface detection) is merged
if (iface->flag_loopback_ ||
!iface->flag_up_ ||
!iface->flag_running_) {
continue;
}
#endif
AddressCollection addrs = iface->getAddresses();
for (AddressCollection::iterator addr= addrs.begin();
addr != addrs.end();
++addr) {
// skip IPv4 addresses
if (addr->getFamily() != AF_INET) {
continue;
}
sock = openSocket(iface->getName(), *addr, port);
if (sock<0) {
cout << "Failed to open unicast socket." << endl;
return (false);
}
count++;
}
}
return (count > 0);
}
bool IfaceMgr::openSockets6(uint16_t port) {
int sock1, sock2;
int count = 0;
for (IfaceCollection::iterator iface = ifaces_.begin();
iface != ifaces_.end(); ++iface) {
......@@ -228,6 +272,8 @@ IfaceMgr::openSockets(uint16_t port) {
}
}
}
return (count > 0);
}
void
......@@ -514,10 +560,138 @@ IfaceMgr::send(boost::shared_ptr<Pkt4>& )
boost::shared_ptr<Pkt4>
IfaceMgr::receive4() {
isc_throw(NotImplemented, "Pkt4 reception not implemented yet.");
// TODO: To be implemented (ticket #1239)
return (boost::shared_ptr<Pkt4>()); // NULL
const SocketInfo* candidate = 0;
IfaceCollection::const_iterator iface;
for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
#if 0
// uncomment when trac1237 (interface detection) is merged
// Let's skip loopback and downed interfaces.
if (iface->flag_loopback_ ||
!iface->flag_up_ ||
!iface->flag_running_) {
continue;
}
#endif
SocketCollection::const_iterator s = iface->sockets_.begin();
while (s != iface->sockets_.end()) {
// We don't want IPv6 addresses here.
if (s->addr_.getFamily() != AF_INET) {
++s;
continue;
}
// This address looks good.
if (!candidate) {
candidate = &(*s);
break;
}
++s;
}
if (candidate) {
break;
}
}
if (!candidate) {
isc_throw(Unexpected, "Failed to find any suitable sockets on all interfaces.");
}
cout << "Trying to receive over UDP4 socket " << candidate->sockfd_ << " bound to "
<< candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
<< iface->getFullName() << endl;
// Now we have a socket, let's get some data from it!
struct msghdr m;
struct iovec v;
int result;
struct cmsghdr* cmsg;
struct in_pktinfo* pktinfo;
struct sockaddr_in from_addr;
struct in_addr to_addr;
unsigned int ifindex = 0;
boost::shared_ptr<Pkt4> pkt;
const uint32_t RCVBUFSIZE = 1500;
uint8_t buf[RCVBUFSIZE];
memset(&control_buf_[0], 0, control_buf_len_);
memset(&from_addr, 0, sizeof(from_addr));
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_addr;
m.msg_namelen = sizeof(from_addr);
v.iov_base = (void*)buf;
v.iov_len = RCVBUFSIZE;
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_[0];
m.msg_controllen = control_buf_len_;
result = recvmsg(candidate->sockfd_, &m, 0);
if (result < 0) {
cout << "Failed to receive UDP4 data." << endl;
return (boost::shared_ptr<Pkt4>()); // NULL
}
int found_pktinfo = 0;
cmsg = CMSG_FIRSTHDR(&m);
while (cmsg != NULL) {
if ((cmsg->cmsg_level == IPPROTO_IP) &&
(cmsg->cmsg_type == IP_PKTINFO)) {
pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
ifindex = pktinfo->ipi_ifindex;
to_addr = pktinfo->ipi_addr;
// to_addr = pktinfo->ipi_spec_dst;
found_pktinfo = 1;
}
cmsg = CMSG_NXTHDR(&m, cmsg);
}
if (!found_pktinfo) {
cout << "Unable to find pktinfo" << endl;
return (boost::shared_ptr<Pkt4>()); // NULL
}
IOAddress to(htonl(to_addr.s_addr));
IOAddress from(htonl(from_addr.sin_addr.s_addr));
uint16_t from_port = htons(from_addr.sin_port);
cout << "Received " << result << " bytes from " << from.toText()
<< "/port=" << from_port
<< " sent to " << to.toText() << " over interface "
<< iface->getFullName() << endl;
// we have all data let's create Pkt4 object
pkt = boost::shared_ptr<Pkt4>(new Pkt4(buf, result));
pkt->setLocalAddr(to);
pkt->setRemotePort(from_port);
pkt->setLocalPort(candidate->port_);
// pkt->setRemoteAddr(from);
return (pkt);
}
boost::shared_ptr<Pkt6>
......@@ -585,12 +759,16 @@ IfaceMgr::receive6() {
SocketCollection::const_iterator s = iface->sockets_.begin();
const SocketInfo* candidate = 0;
while (s != iface->sockets_.end()) {
if (s->addr_.getFamily() != AF_INET6) {
++s;
continue;
}
if (s->addr_.getAddress().to_v6().is_multicast()) {
candidate = &(*s);
break;
}
if (!candidate) {
candidate = &(*s); // it's not multicast, but it's better than none
candidate = &(*s); // it's not multicast, but it's better than nothing
}
++s;
}
......@@ -599,7 +777,7 @@ IfaceMgr::receive6() {
<< " does not have any sockets open.");
}
cout << "Trying to receive over socket " << candidate->sockfd_ << " bound to "
cout << "Trying to receive over UDP6 socket " << candidate->sockfd_ << " bound to "
<< candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
<< iface->getFullName() << endl;
result = recvmsg(candidate->sockfd_, &m, 0);
......
......@@ -20,6 +20,8 @@
#include <boost/scoped_array.hpp>
#include <boost/noncopyable.hpp>
#include <asiolink/io_address.h>
#include <dhcp/dhcp6.h>
#include <dhcp/dhcp4.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
......@@ -299,13 +301,22 @@ public:
/// Will throw exception if socket creation fails.
///
/// @param port specifies port number (usually DHCP6_SERVER_PORT)
void openSockets(uint16_t port);
///
/// @return true if any sockets were open
bool openSockets6(uint16_t port = DHCP6_SERVER_PORT);
/// @brief Closes all open sockets.
/// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
void closeSockets();
/// Opens IPv4 sockets on detected interfaces.
/// Will throw exception if socket creation fails.
///
/// @param port specifies port number (usually DHCP6_SERVER_PORT)
///
/// @return true if any sockets were open
bool openSockets4(uint16_t port = DHCP4_SERVER_PORT);
// don't use private, we need derived classes in tests
protected:
......
......@@ -77,8 +77,8 @@ Pkt4::Pkt4(const uint8_t* data, size_t len)
{
if (len < DHCPV4_PKT_HDR_LEN) {
isc_throw(OutOfRange, "Truncated DHCPv4 packet (len=" << len
<< " received, at least " << DHCPV4_PKT_HDR_LEN
<< "is expected");
<< ") received, at least " << DHCPV4_PKT_HDR_LEN
<< " is expected.");
}
data_.resize(len);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment