Commit f142802a authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[master] Merge branch 'trac2187'

parents 2adcf037 dfc79b64
......@@ -42,12 +42,22 @@ server is about to open sockets on the specified port.
The IPv4 DHCP server has received a packet that it is unable to
interpret. The reason why the packet is invalid is included in the message.
% DHCP4_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1
The IPv4 DHCP server tried to receive a packet but an error
occured during this attempt. The reason for the error is included in
the message.
% DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3
A debug message noting that the server has received the specified type of
packet on the specified interface. Note that a packet marked as UNKNOWN
may well be a valid DHCP packet, just a type not expected by the server
(e.g. it will report a received OFFER packet as UNKNOWN).
% DHCP4_PACKET_SEND_FAIL failed to send DHCPv4 packet: %1
This error is output if the IPv4 DHCP server fails to send an assembled
DHCP message to a client. The reason for the error is included in the
message.
% DHCP4_PACK_FAIL failed to assemble response correctly
This error is output if the server failed to assemble the data to be
returned to the client into a valid packet. The cause is most likely
......
......@@ -73,9 +73,15 @@ Dhcpv4Srv::run() {
int timeout = 1000;
// client's message and server's response
Pkt4Ptr query = IfaceMgr::instance().receive4(timeout);
Pkt4Ptr query;
Pkt4Ptr rsp;
try {
query = IfaceMgr::instance().receive4(timeout);
} catch (const std::exception& e) {
LOG_ERROR(dhcp4_logger, DHCP4_PACKET_RECEIVE_FAIL).arg(e.what());
}
if (query) {
try {
query->unpack();
......@@ -141,7 +147,11 @@ Dhcpv4Srv::run() {
.arg(rsp->getType()).arg(rsp->toText());
if (rsp->pack()) {
IfaceMgr::instance().send(rsp);
try {
IfaceMgr::instance().send(rsp);
} catch (const std::exception& e) {
LOG_ERROR(dhcp4_logger, DHCP4_PACKET_SEND_FAIL).arg(e.what());
}
} else {
LOG_ERROR(dhcp4_logger, DHCP4_PACK_FAIL);
}
......
......@@ -45,12 +45,22 @@ server is about to open sockets on the specified port.
% DHCP6_PACKET_PARSE_FAIL failed to parse incoming packet
The IPv6 DHCP server has received a packet that it is unable to interpret.
% DHCP6_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1
The IPv6 DHCP server tried to receive a packet but an error
occured during this attempt. The reason for the error is included in
the message.
% DHCP6_PACKET_RECEIVED %1 (type %2) packet received
A debug message noting that the server has received the specified type
of packet. Note that a packet marked as UNKNOWN may well be a valid
DHCP packet, just a type not expected by the server (e.g. it will report
a received OFFER packet as UNKNOWN).
% DHCP6_PACKET_SEND_FAIL failed to send DHCPv6 packet: %1
This error is output if the IPv6 DHCP server fails to send an assembled
DHCP message to a client. The reason for the error is included in the
message.
% DHCP6_PACK_FAIL failed to assemble response correctly
This error is output if the server failed to assemble the data to be
returned to the client into a valid packet. The reason is most likely
......
......@@ -84,9 +84,15 @@ bool Dhcpv6Srv::run() {
int timeout = 1000;
// client's message and server's response
Pkt6Ptr query = IfaceMgr::instance().receive6(timeout);
Pkt6Ptr query;
Pkt6Ptr rsp;
try {
query = IfaceMgr::instance().receive6(timeout);
} catch (const std::exception& e) {
LOG_ERROR(dhcp6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
}
if (query) {
if (!query->unpack()) {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
......@@ -154,7 +160,11 @@ bool Dhcpv6Srv::run() {
.arg(rsp->getType()).arg(rsp->toText());
if (rsp->pack()) {
IfaceMgr::instance().send(rsp);
try {
IfaceMgr::instance().send(rsp);
} catch (const std::exception& e) {
LOG_ERROR(dhcp6_logger, DHCP6_PACKET_SEND_FAIL).arg(e.what());
}
} else {
LOG_ERROR(dhcp6_logger, DHCP6_PACK_FAIL);
}
......
This diff is collapsed.
......@@ -28,6 +28,38 @@
namespace isc {
namespace dhcp {
/// @brief IfaceMgr exception thrown thrown when interface detection fails.
class IfaceDetectError : public Exception {
public:
IfaceDetectError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief IfaceMgr exception thrown thrown when socket opening
/// or configuration failed.
class SocketConfigError : public Exception {
public:
SocketConfigError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief IfaceMgr exception thrown thrown when error occured during
/// reading data from socket.
class SocketReadError : public Exception {
public:
SocketReadError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief IfaceMgr exception thrown thrown when error occured during
/// sedning data through socket.
class SocketWriteError : public Exception {
public:
SocketWriteError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief handles network interfaces, transmission and reception
///
/// IfaceMgr is an interface manager class that detects available network
......@@ -340,6 +372,8 @@ public:
///
/// @param pkt packet to be sent
///
/// @throw isc::BadValue if invalid interface specified in the packet.
/// @throw isc::dhcp::SocketWriteError if sendmsg() failed to send packet.
/// @return true if sending was successful
bool send(const Pkt6Ptr& pkt);
......@@ -351,6 +385,8 @@ public:
///
/// @param pkt a packet to be sent
///
/// @throw isc::BadValue if invalid interface specified in the packet.
/// @throw isc::dhcp::SocketWriteError if sendmsg() failed to send packet.
/// @return true if sending was successful
bool send(const Pkt4Ptr& pkt);
......@@ -369,6 +405,7 @@ public:
/// (in microseconds)
///
/// @throw isc::BadValue if timeout_usec is greater than one million
/// @throw isc::dhcp::SocketReadError if error occured when receiving a packet.
/// @return Pkt6 object representing received packet (or NULL)
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
......@@ -383,6 +420,7 @@ public:
/// (in microseconds)
///
/// @throw isc::BadValue if timeout_usec is greater than one million
/// @throw isc::dhcp::SocketReadError if error occured when receiving a packet.
/// @return Pkt4 object representing received packet (or NULL)
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0);
......@@ -460,6 +498,7 @@ public:
///
/// @param port specifies port number (usually DHCP6_SERVER_PORT)
///
/// @throw SocketOpenFailure if tried and failed to open socket.
/// @return true if any sockets were open
bool openSockets6(const uint16_t port = DHCP6_SERVER_PORT);
......@@ -472,6 +511,7 @@ public:
///
/// @param port specifies port number (usually DHCP4_SERVER_PORT)
///
/// @throw SocketOpenFailure if tried and failed to open socket.
/// @return true if any sockets were open
bool openSockets4(const uint16_t port = DHCP4_SERVER_PORT);
......
......@@ -417,8 +417,6 @@ namespace dhcp {
/// Uses the socket-based netlink protocol to retrieve the list of interfaces
/// from the Linux kernel.
void IfaceMgr::detectIfaces() {
cout << "Linux: detecting interfaces." << endl;
// Copies of netlink messages about links will be stored here.
Netlink::NetlinkMessages link_info;
......@@ -495,8 +493,6 @@ void IfaceMgr::detectIfaces() {
nl.release_list(link_info);
nl.release_list(addr_info);
printIfaces();
}
/// @brief sets flag_*_ fields.
......@@ -558,10 +554,7 @@ bool IfaceMgr::os_receive4(struct msghdr& m, Pkt4Ptr& pkt) {
// broadcast. This will return broadcast address, not
// the address we are bound to.
// IOAddress tmp(htonl(pktinfo->ipi_spec_dst.s_addr));
// cout << "The other addr is: " << tmp.toText() << endl;
// Perhaps we should uncomment this:
// XXX: Perhaps we should uncomment this:
// to_addr = pktinfo->ipi_spec_dst;
}
cmsg = CMSG_NXTHDR(&m, cmsg);
......
......@@ -72,26 +72,23 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
offset += 2;
if (offset + opt_len > end) {
cout << "Option " << opt_type << " truncated." << endl;
// @todo: consider throwing exception here.
return (offset);
}
OptionPtr opt;
switch (opt_type) {
case D6O_IA_NA:
case D6O_IA_PD:
// cout << "Creating Option6IA" << endl;
opt = OptionPtr(new Option6IA(opt_type,
buf.begin() + offset,
buf.begin() + offset + opt_len));
break;
case D6O_IAADDR:
// cout << "Creating Option6IAAddr" << endl;
opt = OptionPtr(new Option6IAAddr(opt_type,
buf.begin() + offset,
buf.begin() + offset + opt_len));
break;
default:
// cout << "Creating Option" << endl;
opt = OptionPtr(new Option(Option::V6,
opt_type,
buf.begin() + offset,
......@@ -151,15 +148,9 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
void LibDHCP::packOptions6(isc::util::OutputBuffer &buf,
const isc::dhcp::Option::OptionCollection& options) {
try {
for (Option::OptionCollection::const_iterator it = options.begin();
it != options.end(); ++it) {
it->second->pack(buf);
}
}
catch (const Exception&) {
cout << "Packet build failed (Option build failed)." << endl;
throw;
for (Option::OptionCollection::const_iterator it = options.begin();
it != options.end(); ++it) {
it->second->pack(buf);
}
}
......
......@@ -197,8 +197,6 @@ void Pkt4::check() {
}
void Pkt4::repack() {
cout << "Convering RX packet to TX packet: " << data_.size() << " bytes." << endl;
bufferOut_.writeData(&data_[0], data_.size());
}
......
......@@ -100,7 +100,7 @@ Pkt6::packUDP() {
LibDHCP::packOptions6(bufferOut_, options_);
}
catch (const Exception& e) {
cout << "Packet build failed:" << e.what() << endl;
/// @todo: throw exception here once we turn this function to void.
return (false);
}
return (true);
......@@ -129,8 +129,8 @@ Pkt6::unpack() {
bool
Pkt6::unpackUDP() {
if (data_.size() < 4) {
std::cout << "DHCPv6 packet truncated. Only " << data_.size()
<< " bytes. Need at least 4." << std::endl;
// @todo: throw exception here informing that packet is truncated
// once we turn this function to void.
return (false);
}
msg_type_ = data_[0];
......@@ -143,7 +143,7 @@ Pkt6::unpackUDP() {
LibDHCP::unpackOptions6(opt_buffer, options_);
} catch (const Exception& e) {
cout << "Packet parsing failed:" << e.what() << endl;
// @todo: throw exception here once we turn this function to void.
return (false);
}
return (true);
......@@ -197,8 +197,6 @@ Pkt6::delOption(uint16_t type) {
}
void Pkt6::repack() {
cout << "Convering RX packet to TX packet: " << data_.size() << " bytes." << endl;
bufferOut_.writeData(&data_[0], data_.size());
}
......
......@@ -82,10 +82,8 @@ TEST_F(IfaceMgrTest, loDetect) {
// it will go away as soon as proper interface detection
// is implemented
if (if_nametoindex("lo") > 0) {
cout << "This is Linux, using lo as loopback." << endl;
snprintf(LOOPBACK, BUF_SIZE - 1, "lo");
} else if (if_nametoindex("lo0") > 0) {
cout << "This is BSD, using lo0 as loopback." << endl;
snprintf(LOOPBACK, BUF_SIZE - 1, "lo0");
} else {
cout << "Failed to detect loopback interface. Neither "
......@@ -421,7 +419,7 @@ TEST_F(IfaceMgrTest, sockets6) {
// testing socket operation in a portable way is tricky
// without interface detection implemented
NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
IOAddress loAddr("::1");
......@@ -441,10 +439,25 @@ TEST_F(IfaceMgrTest, sockets6) {
// removed code for binding socket twice to the same address/port
// as it caused problems on some platforms (e.g. Mac OS X)
close(socket1);
close(socket2);
// Close sockets here because the following tests will want to
// open sockets on the same ports.
ifacemgr->closeSockets();
delete ifacemgr;
// Use address that is not assigned to LOOPBACK iface.
IOAddress invalidAddr("::2");
EXPECT_THROW(
ifacemgr->openSocket(LOOPBACK, invalidAddr, 10547),
SocketConfigError
);
// Use non-existing interface name.
EXPECT_THROW(
ifacemgr->openSocket("non_existing_interface", loAddr, 10548),
BadValue
);
// Do not call closeSockets() because it is called by IfaceMgr's
// virtual destructor.
}
TEST_F(IfaceMgrTest, socketsFromIface) {
......@@ -468,6 +481,18 @@ TEST_F(IfaceMgrTest, socketsFromIface) {
EXPECT_GT(socket2, 0);
close(socket2);
// Close sockets here because the following tests will want to
// open sockets on the same ports.
ifacemgr->closeSockets();
// Use invalid interface name.
EXPECT_THROW(
ifacemgr->openSocketFromIface("non_existing_interface", PORT1, AF_INET),
BadValue
);
// Do not call closeSockets() because it is called by IfaceMgr's
// virtual destructor.
}
......@@ -482,7 +507,6 @@ TEST_F(IfaceMgrTest, socketsFromAddress) {
);
// socket descriptor must be positive integer
EXPECT_GT(socket1, 0);
close(socket1);
// Open v4 socket on loopback interface and bind to different port
int socket2 = 0;
......@@ -492,7 +516,19 @@ TEST_F(IfaceMgrTest, socketsFromAddress) {
);
// socket descriptor must be positive integer
EXPECT_GT(socket2, 0);
close(socket2);
// Close sockets here because the following tests will want to
// open sockets on the same ports.
ifacemgr->closeSockets();
// Use non-existing address.
IOAddress invalidAddr("1.2.3.4");
EXPECT_THROW(
ifacemgr->openSocketFromAddress(invalidAddr, PORT1), BadValue
);
// Do not call closeSockets() because it is called by IfaceMgr's
// virtual destructor.
}
TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
......@@ -507,7 +543,6 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
socket1 = ifacemgr->openSocketFromRemoteAddress(loAddr6, PORT1);
);
EXPECT_GT(socket1, 0);
close(socket1);
// Open v4 socket to connect to remote address.
int socket2 = 0;
......@@ -516,7 +551,10 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
socket2 = ifacemgr->openSocketFromRemoteAddress(loAddr, PORT2);
);
EXPECT_GT(socket2, 0);
close(socket2);
// Close sockets here because the following tests will want to
// open sockets on the same ports.
ifacemgr->closeSockets();
// The following test is currently disabled for OSes other than
// Linux because interface detection is not implemented on them.
......@@ -530,8 +568,10 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
socket3 = ifacemgr->openSocketFromRemoteAddress(bcastAddr, PORT2);
);
EXPECT_GT(socket3, 0);
close(socket3);
#endif
// Do not call closeSockets() because it is called by IfaceMgr's
// virtual destructor.
}
// TODO: disabled due to other naming on various systems
......@@ -570,7 +610,7 @@ TEST_F(IfaceMgrTest, sendReceive6) {
// testing socket operation in a portable way is tricky
// without interface detection implemented
NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
// let's assume that every supported OS have lo interface
IOAddress loAddr("::1");
......@@ -619,7 +659,11 @@ TEST_F(IfaceMgrTest, sendReceive6) {
// we should accept both values as source ports.
EXPECT_TRUE((rcvPkt->getRemotePort() == 10546) || (rcvPkt->getRemotePort() == 10547));
delete ifacemgr;
// try to send/receive data over the closed socket. Closed socket's descriptor is
// still being hold by IfaceMgr which will try to use it to receive data.
close(socket1);
EXPECT_THROW(ifacemgr->receive6(10), SocketReadError);
EXPECT_THROW(ifacemgr->send(sendPkt), SocketWriteError);
}
TEST_F(IfaceMgrTest, sendReceive4) {
......@@ -627,7 +671,7 @@ TEST_F(IfaceMgrTest, sendReceive4) {
// testing socket operation in a portable way is tricky
// without interface detection implemented
NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
// let's assume that every supported OS have lo interface
IOAddress loAddr("127.0.0.1");
......@@ -675,8 +719,7 @@ TEST_F(IfaceMgrTest, sendReceive4) {
EXPECT_EQ(true, ifacemgr->send(sendPkt));
rcvPkt = ifacemgr->receive4(10);
ASSERT_NO_THROW(rcvPkt = ifacemgr->receive4(10));
ASSERT_TRUE(rcvPkt); // received our own packet
ASSERT_NO_THROW(
......@@ -710,7 +753,11 @@ TEST_F(IfaceMgrTest, sendReceive4) {
// assume the one or the other will always be choosen for sending data. We should
// skip checking source port of sent address.
delete ifacemgr;
// try to receive data over the closed socket. Closed socket's descriptor is
// still being hold by IfaceMgr which will try to use it to receive data.
close(socket1);
EXPECT_THROW(ifacemgr->receive4(10), SocketReadError);
EXPECT_THROW(ifacemgr->send(sendPkt), SocketWriteError);
}
......@@ -1214,7 +1261,7 @@ TEST_F(IfaceMgrTest, controlSession) {
EXPECT_NO_THROW(ifacemgr->set_session_socket(pipefd[0], my_callback));
Pkt4Ptr pkt4;
pkt4 = ifacemgr->receive4(1);
ASSERT_NO_THROW(pkt4 = ifacemgr->receive4(1));
// Our callback should not be called this time (there was no data)
EXPECT_FALSE(callback_ok);
......@@ -1226,7 +1273,7 @@ TEST_F(IfaceMgrTest, controlSession) {
EXPECT_EQ(38, write(pipefd[1], "Hi, this is a message sent over a pipe", 38));
// ... and repeat
pkt4 = ifacemgr->receive4(1);
ASSERT_NO_THROW(pkt4 = ifacemgr->receive4(1));
// IfaceMgr should not process control socket data as incoming packets
EXPECT_FALSE(pkt4);
......
......@@ -980,7 +980,13 @@ TestControl::receivePackets(const TestControlSocket& socket) {
uint64_t received = 0;
while (receiving) {
if (CommandOptions::instance().getIpVersion() == 4) {
Pkt4Ptr pkt4 = IfaceMgr::instance().receive4(timeout);
Pkt4Ptr pkt4;
try {
pkt4 = IfaceMgr::instance().receive4(timeout);
} catch (const Exception& e) {
std::cerr << "Failed to receive DHCPv4 packet: "
<< e.what() << std::endl;
}
if (!pkt4) {
receiving = false;
} else {
......@@ -992,7 +998,13 @@ TestControl::receivePackets(const TestControlSocket& socket) {
processReceivedPacket4(socket, pkt4);
}
} else if (CommandOptions::instance().getIpVersion() == 6) {
Pkt6Ptr pkt6 = IfaceMgr::instance().receive6(timeout);
Pkt6Ptr pkt6;
try {
pkt6 = IfaceMgr::instance().receive6(timeout);
} catch (const Exception& e) {
std::cerr << "Failed to receive DHCPv6 packet: "
<< e.what() << std::endl;
}
if (!pkt6) {
receiving = false;
} else {
......
......@@ -633,8 +633,10 @@ protected:
///
/// \param socket socket to be used to send the message.
/// \param preload preload mode, packets not included in statistics.
///
/// \throw isc::Unexpected if failed to create new packet instance.
/// \throw isc::BadValue if MAC address has invalid length.
/// \throw isc::dhcp::SocketWriteError if failed to send the packet.
void sendDiscover4(const TestControlSocket& socket,
const bool preload = false);
......@@ -650,7 +652,9 @@ protected:
/// \param socket socket to be used to send the message.
/// \param template_buf buffer holding template packet.
/// \param preload preload mode, packets not included in statistics.
///
/// \throw isc::OutOfRange if randomization offset is out of bounds.
/// \throw isc::dhcp::SocketWriteError if failed to send the packet.
void sendDiscover4(const TestControlSocket& socket,
const std::vector<uint8_t>& template_buf,
const bool preload = false);
......@@ -689,9 +693,11 @@ protected:
/// \param socket socket to be used to send message.
/// \param discover_pkt4 DISCOVER packet sent.
/// \param offer_pkt4 OFFER packet object.
///
/// \throw isc::Unexpected if unexpected error occured.
/// \throw isc::InvalidOperation if Statistics Manager has not been
/// initialized.
/// \throw isc::dhcp::SocketWriteError if failed to send the packet.
void sendRequest4(const TestControlSocket& socket,
const dhcp::Pkt4Ptr& discover_pkt4,
const dhcp::Pkt4Ptr& offer_pkt4);
......@@ -706,6 +712,8 @@ protected:
/// \param template_buf buffer holding template packet.
/// \param discover_pkt4 DISCOVER packet sent.
/// \param offer_pkt4 OFFER packet received.
///
/// \throw isc::dhcp::SocketWriteError if failed to send the packet.
void sendRequest4(const TestControlSocket& socket,
const std::vector<uint8_t>& template_buf,
const dhcp::Pkt4Ptr& discover_pkt4,
......@@ -726,6 +734,8 @@ protected:
/// \throw isc::Unexpected if unexpected error occured.
/// \throw isc::InvalidOperation if Statistics Manager has not been
/// initialized.
///
/// \throw isc::dhcp::SocketWriteError if failed to send the packet.
void sendRequest6(const TestControlSocket& socket,
const dhcp::Pkt6Ptr& advertise_pkt6);
......@@ -738,6 +748,8 @@ protected:
/// \param socket socket to be used to send message.
/// \param template_buf packet template buffer.
/// \param advertise_pkt6 ADVERTISE packet object.
///
/// \throw isc::dhcp::SocketWriteError if failed to send the packet.
void sendRequest6(const TestControlSocket& socket,
const std::vector<uint8_t>& template_buf,
const dhcp::Pkt6Ptr& advertise_pkt6);
......@@ -756,7 +768,9 @@ protected:
///
/// \param socket socket to be used to send the message.
/// \param preload mode, packets not included in statistics.
///
/// \throw isc::Unexpected if failed to create new packet instance.
/// \throw isc::dhcp::SocketWriteError if failed to send the packet.
void sendSolicit6(const TestControlSocket& socket,
const bool preload = false);
......@@ -769,6 +783,8 @@ protected:
/// \param socket socket to be used to send the message.
/// \param template_buf packet template buffer.
/// \param preload mode, packets not included in statistics.
///
/// \throw isc::dhcp::SocketWriteError if failed to send the packet.
void sendSolicit6(const TestControlSocket& socket,
const std::vector<uint8_t>& template_buf,
const bool preload = false);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. P