summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/iface_mgr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/iface_mgr.cc')
-rw-r--r--src/lib/dhcp/iface_mgr.cc138
1 files changed, 76 insertions, 62 deletions
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index 896a034e7b..a349e1d01b 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -674,7 +674,7 @@ IfaceMgr::openSockets6(const uint16_t port,
void
IfaceMgr::startDHCPReceiver(const uint16_t family) {
if (receiver_thread_) {
- isc_throw(Unexpected, "a receiver thread already exits");
+ isc_throw(InvalidOperation, "a receiver thread already exists");
}
switch (family) {
@@ -970,7 +970,7 @@ Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
}
}
- // add watch sockets.
+ // Add receiver thread watch and error sockets.
FD_SET(receive_watch_.getSelectFd(), &sockets);
if (maxfd < receive_watch_.getSelectFd()) {
maxfd = receive_watch_.getSelectFd();
@@ -980,6 +980,12 @@ Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
maxfd = error_watch_.getSelectFd();
}
+ // Set timeout for our next select() call. If there are
+ // no DHCP packets to read, then we'll wait for a finite
+ // amount of time for an IO event. Otherwise, we'll
+ // poll (timeout = 0 secs). We need to poll, even if
+ // DHCP packets are waiting so we don't starve external
+ // sockets under heavy DHCP load.
struct timeval select_timeout;
if (getPacketQueue4()->empty()) {
select_timeout.tv_sec = timeout_sec;
@@ -996,8 +1002,7 @@ Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
if ((result == 0) && getPacketQueue4()->empty()) {
// nothing received and timeout has been reached
- return (Pkt4Ptr()); // NULL
-
+ return (Pkt4Ptr());
} else if (result < 0) {
// In most cases we would like to know whether select() returned
// an error because of a signal being received or for some other
@@ -1013,41 +1018,43 @@ Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
}
}
- // Check errors.
- if (FD_ISSET(error_watch_.getSelectFd(), &sockets)) {
- string msg = receiver_error_;
- error_watch_.clearReady();
- isc_throw(SocketReadError, msg);
- }
-
- // Let's find out which socket has the data
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
- if (!FD_ISSET(s.socket_, &sockets)) {
- continue;
+ // We only check external sockets if select detected an event.
+ if (result > 0) {
+ // Check for receiver thread read errors.
+ if (FD_ISSET(error_watch_.getSelectFd(), &sockets)) {
+ string msg = receiver_error_;
+ error_watch_.clearReady();
+ isc_throw(SocketReadError, msg);
}
- // something received over external socket
+ // Let's find out which external socket has the data
+ BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ if (!FD_ISSET(s.socket_, &sockets)) {
+ continue;
+ }
- // Calling the external socket's callback provides its service
- // layer access without integrating any specific features
- // in IfaceMgr
- if (s.callback_) {
- s.callback_();
- }
+ // something received over external socket
- return (Pkt4Ptr());
- }
+ // Calling the external socket's callback provides its service
+ // layer access without integrating any specific features
+ // in IfaceMgr
+ if (s.callback_) {
+ s.callback_();
+ }
- // Protected packet queue access.
- {
- Mutex::Locker lock(receiver_lock_);
- Pkt4Ptr pkt = getPacketQueue4()->dequeuePacket();
- if (!pkt) {
- receive_watch_.clearReady();
+ return (Pkt4Ptr());
}
+ }
- return (pkt);
+ // If we're here it should only be because there are DHCP packets waiting.
+ // Protected packet queue access.
+ Mutex::Locker lock(receiver_lock_);
+ Pkt4Ptr pkt = getPacketQueue4()->dequeuePacket();
+ if (!pkt) {
+ receive_watch_.clearReady();
}
+
+ return (pkt);
}
Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
@@ -1073,7 +1080,7 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
}
}
- // add watch sockets.
+ // Add receiver thread watch and error sockets.
FD_SET(receive_watch_.getSelectFd(), &sockets);
if (maxfd < receive_watch_.getSelectFd()) {
maxfd = receive_watch_.getSelectFd();
@@ -1083,6 +1090,12 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
maxfd = error_watch_.getSelectFd();
}
+ // Set timeout for our next select() call. If there are
+ // no DHCP packets to read, then we'll wait for a finite
+ // amount of time for an IO event. Otherwise, we'll
+ // poll (timeout = 0 secs). We need to poll, even if
+ // DHCP packets are waiting so we don't starve external
+ // sockets under heavy DHCP load.
struct timeval select_timeout;
if (getPacketQueue6()->empty()) {
select_timeout.tv_sec = timeout_sec;
@@ -1099,8 +1112,7 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
if ((result == 0) && getPacketQueue6()->empty()) {
// nothing received and timeout has been reached
- return (Pkt6Ptr()); // NULL
-
+ return (Pkt6Ptr());
} else if (result < 0) {
// In most cases we would like to know whether select() returned
// an error because of a signal being received or for some other
@@ -1116,41 +1128,43 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
}
}
- // Check errors.
- if (FD_ISSET(error_watch_.getSelectFd(), &sockets)) {
- string msg = receiver_error_;
- error_watch_.clearReady();
- isc_throw(SocketReadError, msg);
- }
-
- // Let's find out which socket has the data
- BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
- if (!FD_ISSET(s.socket_, &sockets)) {
- continue;
+ // We only check external sockets if select detected an event.
+ if (result > 0) {
+ // Check for receiver thread read errors.
+ if (FD_ISSET(error_watch_.getSelectFd(), &sockets)) {
+ string msg = receiver_error_;
+ error_watch_.clearReady();
+ isc_throw(SocketReadError, msg);
}
- // something received over external socket
+ // Let's find out which external socket has the data
+ BOOST_FOREACH(SocketCallbackInfo s, callbacks_) {
+ if (!FD_ISSET(s.socket_, &sockets)) {
+ continue;
+ }
- // Calling the external socket's callback provides its service
- // layer access without integrating any specific features
- // in IfaceMgr
- if (s.callback_) {
- s.callback_();
- }
+ // something received over external socket
- return (Pkt6Ptr());
- }
+ // Calling the external socket's callback provides its service
+ // layer access without integrating any specific features
+ // in IfaceMgr
+ if (s.callback_) {
+ s.callback_();
+ }
- // Protected DHCP packet queue access.
- {
- Mutex::Locker lock(receiver_lock_);
- Pkt6Ptr pkt = getPacketQueue6()->dequeuePacket();
- if (!pkt) {
- receive_watch_.clearReady();
+ return (Pkt6Ptr());
}
+ }
- return (pkt);
+ // If we're here it should only be because there are DHCP packets waiting.
+ // Protected packet queue access.
+ Mutex::Locker lock(receiver_lock_);
+ Pkt6Ptr pkt = getPacketQueue6()->dequeuePacket();
+ if (!pkt) {
+ receive_watch_.clearReady();
}
+
+ return (pkt);
}
void IfaceMgr::receiveDHCP4Packets() {
@@ -1194,7 +1208,7 @@ void IfaceMgr::receiveDHCP4Packets() {
// zero out the errno to be safe.
errno = 0;
- // Note we wait until something happen.
+ // Select with null timeouts to wait indefinetly an event
int result = select(maxfd + 1, &rd_set, 0, 0, 0);
// Re-check the watch socket.