|
@@ -18,6 +18,7 @@
|
|
|
#include <string.h>
|
|
|
#include <netinet/in.h>
|
|
|
#include <arpa/inet.h>
|
|
|
+#include <sys/select.h>
|
|
|
|
|
|
#include <dhcp/dhcp4.h>
|
|
|
#include <dhcp/dhcp6.h>
|
|
@@ -121,7 +122,8 @@ bool IfaceMgr::Iface::delSocket(uint16_t sockfd) {
|
|
|
|
|
|
IfaceMgr::IfaceMgr()
|
|
|
:control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
|
|
|
- control_buf_(new char[control_buf_len_])
|
|
|
+ control_buf_(new char[control_buf_len_]),
|
|
|
+ session_socket_(0), session_callback_(NULL)
|
|
|
{
|
|
|
|
|
|
cout << "IfaceMgr initialization." << endl;
|
|
@@ -230,11 +232,13 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
|
|
|
iface!=ifaces_.end();
|
|
|
++iface) {
|
|
|
|
|
|
- cout << "Trying interface " << iface->getFullName() << endl;
|
|
|
+ cout << "Trying opening socket on interface " << iface->getFullName() << endl;
|
|
|
|
|
|
if (iface->flag_loopback_ ||
|
|
|
!iface->flag_up_ ||
|
|
|
!iface->flag_running_) {
|
|
|
+ cout << "Interface " << iface->getFullName()
|
|
|
+ << " not suitable: is loopback, is down or not running" << endl;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
@@ -681,13 +685,19 @@ IfaceMgr::send(const Pkt4Ptr& pkt)
|
|
|
|
|
|
|
|
|
boost::shared_ptr<Pkt4>
|
|
|
-IfaceMgr::receive4() {
|
|
|
+IfaceMgr::receive4(unsigned int timeout) {
|
|
|
|
|
|
const SocketInfo* candidate = 0;
|
|
|
IfaceCollection::const_iterator iface;
|
|
|
+
|
|
|
+ fd_set sockets;
|
|
|
+ FD_ZERO(&sockets);
|
|
|
+ int maxfd = 0;
|
|
|
+
|
|
|
+ stringstream names;
|
|
|
+
|
|
|
for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
|
|
|
|
|
|
- /// @todo: rewrite this as part of #1555
|
|
|
for (SocketCollection::const_iterator s = iface->sockets_.begin();
|
|
|
s != iface->sockets_.end(); ++s) {
|
|
|
|
|
@@ -696,20 +706,82 @@ IfaceMgr::receive4() {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- // This address looks good.
|
|
|
- if (!candidate) {
|
|
|
+ names << s->sockfd_ << "(" << iface->getName() << ") ";
|
|
|
+
|
|
|
+ // add this socket to listening set
|
|
|
+ FD_SET(s->sockfd_, &sockets);
|
|
|
+ if (maxfd < s->sockfd_)
|
|
|
+ maxfd = s->sockfd_;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // if there is session socket registered...
|
|
|
+ if (session_socket_) {
|
|
|
+ // at it to the set as well
|
|
|
+ FD_SET(session_socket_, &sockets);
|
|
|
+ if (maxfd < session_socket_)
|
|
|
+ maxfd = session_socket_;
|
|
|
+ names << session_socket_ << "(session)";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// @todo: implement sub-second precision one day
|
|
|
+ struct timeval select_timeout;
|
|
|
+ select_timeout.tv_sec = timeout;
|
|
|
+ select_timeout.tv_usec = 0;
|
|
|
+
|
|
|
+ cout << "Trying to receive data on sockets: " << names.str()
|
|
|
+ << ". Timeout is " << timeout << " seconds." << endl;
|
|
|
+ int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
|
|
|
+ cout << "select returned " << result << endl;
|
|
|
+
|
|
|
+ if (result == 0) {
|
|
|
+ // nothing received and timeout has been reached
|
|
|
+ return (Pkt4Ptr()); // NULL
|
|
|
+ }
|
|
|
+ if (result < 0) {
|
|
|
+ char buf[512];
|
|
|
+ strncpy(buf, strerror(errno), 512);
|
|
|
+ cout << "Socket read error: " << buf << endl;
|
|
|
+
|
|
|
+ /// @todo: perhaps throw here?
|
|
|
+ return (Pkt4Ptr()); // NULL
|
|
|
+ }
|
|
|
+
|
|
|
+ // Let's find out which socket has the data
|
|
|
+
|
|
|
+ if (session_socket_ && (FD_ISSET(session_socket_, &sockets))) {
|
|
|
+ // something received over session socket
|
|
|
+ cout << "BIND10 command or config available over session socket." << endl;
|
|
|
+
|
|
|
+ if (session_callback_) {
|
|
|
+ // in theory we could call io_service.run_one() here, instead of
|
|
|
+ // implementing callback mechanism, but that would introduce
|
|
|
+ // asiolink dependency to libdhcp++ and that is something we want
|
|
|
+ // to avoid (see CPE market and out long term plans for minimalistic
|
|
|
+ // implementations.
|
|
|
+ session_callback_();
|
|
|
+ }
|
|
|
+
|
|
|
+ return (Pkt4Ptr()); // NULL
|
|
|
+ }
|
|
|
+
|
|
|
+ // Let's find out which interface/socket has the data
|
|
|
+ for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
|
|
|
+ for (SocketCollection::const_iterator s = iface->sockets_.begin();
|
|
|
+ s != iface->sockets_.end(); ++s) {
|
|
|
+ if (FD_ISSET(s->sockfd_, &sockets)) {
|
|
|
candidate = &(*s);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
if (candidate) {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (!candidate) {
|
|
|
- isc_throw(Unexpected, "Failed to find any suitable sockets on all interfaces.");
|
|
|
+ cout << "Received data over unknown socket." << endl;
|
|
|
+ return (Pkt4Ptr()); // NULL
|
|
|
}
|
|
|
|
|
|
cout << "Trying to receive over UDP4 socket " << candidate->sockfd_ << " bound to "
|
|
@@ -746,7 +818,7 @@ IfaceMgr::receive4() {
|
|
|
m.msg_control = &control_buf_[0];
|
|
|
m.msg_controllen = control_buf_len_;
|
|
|
|
|
|
- int result = recvmsg(candidate->sockfd_, &m, 0);
|
|
|
+ result = recvmsg(candidate->sockfd_, &m, 0);
|
|
|
if (result < 0) {
|
|
|
cout << "Failed to receive UDP4 data." << endl;
|
|
|
return (Pkt4Ptr()); // NULL
|