try {
query = receivePacket(timeout);
+
+ } catch (const SignalInterruptOnSelect) {
+ // Packet reception interrupted because a signal has been received.
+ // This is not an error because we might have received a SIGTERM,
+ // SIGINT or SIGHUP which are handled by the server. For signals
+ // that are not handled by the server we rely on the default
+ // behavior of the system, but there is nothing we should log here.
} catch (const std::exception& e) {
+ // Log all other errors.
LOG_ERROR(dhcp4_logger, DHCP4_PACKET_RECEIVE_FAIL).arg(e.what());
}
clean_exit 1
fi
+ # When the server receives a signal the call to select() function is
+ # interrupted. This should not be logged as an error.
+ get_log_messages "DHCP4_PACKET_RECEIVE_FAIL"
+ assert_eq 0 ${_GET_LOG_MESSAGES} \
+ "Expected get_log_messages DHCP4_PACKET_RECEIVE_FAIL return %d, \
+returned %d."
+
# All ok. Shut down Kea and exit.
test_finish 0
}
assert_eq 1 ${_WAIT_FOR_SERVER_DOWN} \
"Expected wait_for_server_down return %d, returned %d"
+ # When the server receives a signal the call to select() function is
+ # interrupted. This should not be logged as an error.
+ get_log_messages "DHCP4_PACKET_RECEIVE_FAIL"
+ assert_eq 0 ${_GET_LOG_MESSAGES} \
+ "Expected get_log_messages return %d, returned %d."
+
test_finish 0
}
if (result == 0) {
// nothing received and timeout has been reached
return (Pkt4Ptr()); // NULL
+
} else if (result < 0) {
- isc_throw(SocketReadError, strerror(errno));
+ // In most cases we would like to know whether select() returned
+ // an error because of a signal being received or for some other
+ // reasaon. This is because DHCP servers use signals to trigger
+ // certain actions, like reconfiguration or graceful shutdown.
+ // By cacthing a dedicated exception the caller will know if the
+ // error returned by the function is due to the reception of the
+ // signal or for some other reason.
+ if (errno == EINTR) {
+ isc_throw(SignalInterruptOnSelect, strerror(errno));
+ } else {
+ isc_throw(SocketReadError, strerror(errno));
+ }
}
// Let's find out which socket has the data
isc::Exception(file, line, what) { };
};
+/// @brief Exception thrown when a call to select is interrupted by a signal.
+class SignalInterruptOnSelect : public Exception {
+public:
+ SignalInterruptOnSelect(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 {
isc::Exception(file, line, what) { };
};
+
/// Holds information about socket.
struct SocketInfo {
/// @return true if sending was successful
bool send(const Pkt4Ptr& pkt);
- /// @brief Tries to receive IPv6 packet over open IPv6 sockets.
- ///
- /// Attempts to receive a single IPv6 packet of any of the open IPv6 sockets.
- /// If reception is successful and all information about its sender
- /// are obtained, Pkt6 object is created and returned.
+ /// @brief Tries to receive DHCPv6 message over open IPv6 sockets.
///
- /// TODO Start using select() and add timeout to be able
- /// to not wait infinitely, but rather do something useful
- /// (e.g. remove expired leases)
+ /// Attempts to receive a single DHCPv6 message over any of the open IPv6
+ /// sockets. If reception is successful and all information about its
+ /// sender is obtained, Pkt6 object is created and returned.
///
/// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds)
///
/// @throw isc::BadValue if timeout_usec is greater than one million
- /// @throw isc::dhcp::SocketReadError if error occured when receiving a packet.
+ /// @throw isc::dhcp::SocketReadError if error occured when receiving a
+ /// packet.
+ /// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
+ /// interrupted by a signal.
+ ///
/// @return Pkt6 object representing received packet (or NULL)
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
/// @brief Tries to receive IPv4 packet over open IPv4 sockets.
///
- /// Attempts to receive a single IPv4 packet of any of the open IPv4 sockets.
- /// If reception is successful and all information about its sender
- /// are obtained, Pkt4 object is created and returned.
+ /// Attempts to receive a single DHCPv4 message over any of the open
+ /// IPv4 sockets. If reception is successful and all information about
+ /// its sender is obtained, Pkt4 object is created and returned.
///
/// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds)
///
/// @throw isc::BadValue if timeout_usec is greater than one million
- /// @throw isc::dhcp::SocketReadError if error occured when receiving a packet.
+ /// @throw isc::dhcp::SocketReadError if error occured when receiving a
+ /// packet.
+ /// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
+ /// interrupted by a signal.
+ ///
/// @return Pkt4 object representing received packet (or NULL)
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0);