26#include <boost/scoped_ptr.hpp>
36#include <netinet/in.h>
46namespace ph = std::placeholders;
69 isc_throw(BadValue,
"Interface name must not be empty");
93 if ((family != AF_INET) && (family != AF_INET6)) {
95 <<
" specified when requested to close all sockets"
96 <<
" which belong to this family");
100 SocketCollection::iterator sock =
sockets_.begin();
102 if (sock->family_ == family) {
105 close(sock->sockfd_);
107 if (sock->fallbackfd_ >= 0) {
108 close(sock->fallbackfd_);
131 for (
unsigned i = 0; i <
mac_len_; i++) {
133 tmp << static_cast<int>(
mac_[i]);
144 <<
" was detected to have link address of length "
145 << len <<
", but maximum supported length is "
150 memcpy(
mac_, mac, len);
155 for (AddressCollection::iterator a =
addrs_.begin(); a !=
addrs_.end(); ++a) {
156 if (a->get() == addr) {
165 SocketCollection::iterator sock =
sockets_.begin();
167 if (sock->sockfd_ == sockfd) {
170 if (sock->fallbackfd_ >= 0) {
171 close(sock->fallbackfd_);
184 test_mode_(false), check_thread_id_(true),
185 allow_loopback_(false), family_(AF_INET) {
186 id_ = std::this_thread::get_id();
193 }
catch (
const std::exception& ex) {
206 }
catch (
const std::exception& ex) {
220 if (a.get() == addr) {
222 <<
" already defined on the " <<
name_ <<
" interface.");
235 if (addr.get().isV4()) {
236 address = addr.get();
247 if (address == addr.get()) {
263 for (
auto& addr :
addrs_) {
264 if (address == addr.get()) {
265 addr.unspecified(!active);
270 " found on the interface " <<
getName());
275 for (
auto& addr :
addrs_) {
276 addr.unspecified(!active);
284 if (!addr.unspecified() && addr.get().isV4()) {
306 for (
auto const& addr :
addrs_) {
309 result->set(
"addresses", addrs);
321 iface->closeSockets();
327 dhcp_receiver_->stop();
330 dhcp_receiver_.reset();
350 for (
auto const& iface:
ifaces_) {
351 result->add(iface->toElement());
358 return (packet_filter_->isDirectResponseSupported());
363 return (packet_filter_->isSocketReceivedTimeSupported());
372 if (check_thread_id_ && std::this_thread::get_id() !=
id_) {
375 .arg(std::this_thread::get_id())
381 std::lock_guard<std::mutex> lock(callbacks_mutex_);
382 auto& idx = callbacks_.get<1>();
383 auto it = idx.find(socketfd);
384 if (it != idx.end()) {
394 callbacks_.push_back(x);
399 std::lock_guard<std::mutex> lock(callbacks_mutex_);
400 deleteExternalSocketInternal(socketfd);
404IfaceMgr::deleteExternalSocketInternal(
int socketfd) {
405 if (check_thread_id_ && std::this_thread::get_id() !=
id_) {
408 .arg(std::this_thread::get_id())
411 auto& idx = callbacks_.get<1>();
412 auto it = idx.find(socketfd);
413 if (it == idx.end()) {
423 std::lock_guard<std::mutex> lock(callbacks_mutex_);
424 auto const& idx = callbacks_.get<1>();
425 auto const it = idx.find(fd);
426 return (it != idx.end());
431 std::lock_guard<std::mutex> lock(callbacks_mutex_);
432 auto const& idx = callbacks_.get<1>();
433 auto const it = idx.find(fd);
434 if (it != idx.end()) {
435 return (it->unusable_);
443 if (check_thread_id_ && std::this_thread::get_id() !=
id_) {
445 .arg(std::this_thread::get_id())
448 std::lock_guard<std::mutex> lock(callbacks_mutex_);
454 std::list<int> result;
455 std::lock_guard<std::mutex> lock(callbacks_mutex_);
457 result.push_back(s.socket_);
465 if (!packet_filter) {
478 "it is not allowed to set new packet"
479 <<
" filter when there are open IPv4 sockets - need"
480 <<
" to close them first");
483 packet_filter_ = packet_filter;
488 if (!packet_filter) {
496 "it is not allowed to set new packet"
497 <<
" filter when there are open IPv6 sockets - need"
498 <<
" to close them first");
501 packet_filter6_ = packet_filter;
508 for (
const SocketInfo& sock : iface->getSockets()) {
510 if (sock.family_ == family) {
528 for (
const SocketInfo& sock : iface->getSockets()) {
531 if (sock.addr_ == addr) {
533 }
else if (sock.addr_.isV6Zero() && !unicast) {
540 if (addr == a.get()) {
557 const bool skip_opened) {
563 iface->clearErrors();
567 if (iface->inactive4_) {
578 if (iface->flag_loopback_ && !allow_loopback_) {
580 "must not open socket on the loopback"
581 " interface " << iface->getName());
585 if (!iface->flag_up_) {
587 "the interface " << iface->getName()
592 if (!iface->flag_running_) {
594 "the interface " << iface->getName()
595 <<
" is not running");
600 if (!iface->getAddress4(out_address)) {
602 "the interface " << iface->getName()
603 <<
" has no usable IPv4 addresses configured");
609 if (addr.unspecified() || !addr.get().isV4()) {
616 bool is_open_as_broadcast = iface->flag_broadcast_ && use_bcast;
633 "Binding socket to an interface is not"
634 " supported on this OS; therefore only"
635 " one socket listening to broadcast traffic"
636 " can be opened. Sockets will not be opened"
637 " on remaining interfaces");
649 is_open_as_broadcast,
650 is_open_as_broadcast);
653 "Failed to open socket on interface "
661 if (is_open_as_broadcast) {
687 const bool skip_opened) {
692 iface->clearErrors();
696 if (iface->inactive6_) {
707 if (iface->flag_loopback_ && !allow_loopback_) {
709 "must not open socket on the loopback"
710 " interface " << iface->getName());
712 }
else if (!iface->flag_up_) {
714 "the interface " << iface->getName()
717 }
else if (!iface->flag_running_) {
719 "the interface " << iface->getName()
720 <<
" is not running");
733 !iface->getSockets().size()) {
738 "Failed to open unicast socket on interface "
740 <<
", reason: " << ex.
what());
750 if (!addr.get().isV6()) {
759 if (!addr.get().isV6LinkLocal()) {
774 iface->getSockets().size() <= iface->getUnicasts().size()) {
778 IfaceMgr::openMulticastSocket(*iface, addr, port);
781 "Failed to open multicast socket on interface "
782 << iface->getName() <<
", reason: " << ex.
what());
814 dhcp_receiver_->start(std::bind(&IfaceMgr::receiveDHCP4Packets,
this));
824 dhcp_receiver_->start(std::bind(&IfaceMgr::receiveDHCP6Packets,
this));
835 if ((existing->getName() == iface->getName()) ||
836 (existing->getIndex() == iface->getIndex())) {
838 " when " << existing->getFullName() <<
850 out <<
"Detected interface " << iface->getFullName()
851 <<
", hwtype=" << iface->getHWType()
852 <<
", mac=" << iface->getPlainMac();
853 out <<
", flags=" << hex << iface->flags_ << dec <<
"("
854 << (iface->flag_loopback_?
"LOOPBACK ":
"")
855 << (iface->flag_up_?
"UP ":
"")
856 << (iface->flag_running_?
"RUNNING ":
"")
857 << (iface->flag_multicast_?
"MULTICAST ":
"")
858 << (iface->flag_broadcast_?
"BROADCAST ":
"")
860 out <<
" " << addrs.size() <<
" addr(s):";
863 out <<
" " << addr.get().toText();
880IfaceCollection::getIfaceInternal(
const unsigned int ifindex,
const bool need_lock) {
885 lock_guard<mutex> lock(mutex_);
886 if (cache_ && (cache_->getIndex() == ifindex)) {
890 if (cache_ && (cache_->getIndex() == ifindex)) {
894 auto const& idx = ifaces_container_.get<1>();
895 auto it = idx.find(ifindex);
896 if (it == idx.end()) {
900 lock_guard<mutex> lock(mutex_);
910IfaceCollection::getIfaceInternal(
const std::string& ifname,
const bool need_lock) {
912 lock_guard<mutex> lock(mutex_);
913 if (cache_ && (cache_->getName() == ifname)) {
917 if (cache_ && (cache_->getName() == ifname)) {
921 auto const& idx = ifaces_container_.get<2>();
922 auto it = idx.find(ifname);
923 if (it == idx.end()) {
927 lock_guard<mutex> lock(mutex_);
938 return (
ifaces_.getIface(ifindex));
943 if (ifname.empty()) {
946 return (
ifaces_.getIface(ifname));
951 if (pkt->indexSet()) {
969IfaceMgr::handleClosedExternalSocket(SocketCallbackInfoIterator it) {
971 if (fcntl(it->socket_, F_GETFD) < 0 && (errno == EBADF)) {
972 SocketCallbackInfo x(*it);
974 callbacks_.replace(it, x);
980IfaceMgr::handleClosedExternalSockets() {
981 std::lock_guard<std::mutex> lock(callbacks_mutex_);
982 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
986 handleClosedExternalSocket(it);
993 socklen_t opt_size =
sizeof(
error);
995 if (getsockopt(s.sockfd_, SOL_SOCKET, SO_ERROR,
996 reinterpret_cast<char*
>(&
error), &opt_size) < 0) {
997 if ((errno == ENOTSOCK) || (errno == ENOPROTOOPT)) {
1001 isc_throw(BadValue,
"Can't get socket error fd: "
1002 << s.sockfd_ <<
" - error: " << strerror(errno));
1007 .arg(iface->getFullName())
1008 .arg(strerror(
error));
1015 for (
const SocketInfo& sock : iface->getSockets()) {
1030 iface->clearUnicasts();
1035 const uint16_t port,
const bool receive_bcast,
1036 const bool send_bcast) {
1043 status =
openSocket4(*iface, addr, port, receive_bcast, send_bcast);
1045 }
else if (addr.
isV6()) {
1046 status =
openSocket6(*iface, addr, port, receive_bcast);
1060 const uint16_t port,
1061 const uint8_t family) {
1064 if ((iface->getFullName() != ifname) &&
1065 (iface->getName() != ifname)) {
1072 Iface::AddressCollection::iterator addr_it = addrs.begin();
1073 while (addr_it != addrs.end()) {
1074 if (addr_it->get().getFamily() == family) {
1077 return (
openSocket(iface->getName(), *addr_it, port,
false));
1083 if (addr_it == addrs.end()) {
1085 std::string family_name(
"AF_INET");
1086 if (family == AF_INET6) {
1087 family_name =
"AF_INET6";
1091 << ifname <<
", port: " << port <<
", address "
1092 " family: " << family_name);
1101 const uint16_t port) {
1111 if (a.get() == addr) {
1114 return (
openSocket(iface->getName(), a, port,
false));
1124 const uint16_t port) {
1127 IOAddress local_address(getLocalAddress(remote_addr, port));
1135IfaceMgr::getLocalAddress(
const IOAddress& remote_addr,
const uint16_t port) {
1137 boost::scoped_ptr<const UDPEndpoint>
1140 if (!remote_endpoint) {
1145 boost::asio::io_context io_service;
1146 boost::asio::ip::udp::socket sock(io_service);
1148 boost::system::error_code err_code;
1151 if (remote_addr.
isV4() &&
1164 sock.open(boost::asio::ip::udp::v4(), err_code);
1166 const char* errstr = strerror(errno);
1170 sock.set_option(boost::asio::socket_base::broadcast(
true), err_code);
1178 sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
1181 isc_throw(Unexpected,
"failed to connect to remote endpoint.");
1185 boost::asio::ip::udp::socket::endpoint_type local_endpoint =
1186 sock.local_endpoint();
1187 boost::asio::ip::address local_address(local_endpoint.address());
1193 return IOAddress(local_address);
1198 const bool receive_bcast,
const bool send_bcast) {
1201 receive_bcast, send_bcast);
1204 return (
info.sockfd_);
1212 << pkt->getIface() <<
") specified.");
1217 return (packet_filter6_->send(*iface,
getSocket(pkt), pkt) == 0);
1225 << pkt->getIface() <<
") specified.");
1230 return (packet_filter_->send(*iface,
getSocket(pkt).sockfd_, pkt) == 0);
1243 if (timeout_usec >= 1000000) {
1245 " one million microseconds");
1248 fd_event_handler_->clear();
1252 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1253 if (!callbacks_.empty()) {
1254 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1255 if (it->unusable_) {
1258 handleClosedExternalSocket(it);
1260 fd_event_handler_->add(it->socket_);
1285 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1290 }
else if (result < 0) {
1298 if (errno == EINTR) {
1300 }
else if (errno == EBADF) {
1301 handleClosedExternalSockets();
1310 std::lock_guard<std::mutex> lk(receiver_mutex_);
1313 string msg = dhcp_receiver_->getLastError();
1320 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1323 std::list<SocketCallbackInfoIterator> to_reloc;
1324 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1325 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1326 if (it->unusable_) {
1329 handleClosedExternalSocket(it);
1330 if (fd_event_handler_->readReady(it->socket_) ||
1331 fd_event_handler_->hasError(it->socket_)) {
1333 to_reloc.push_back(it);
1336 if (it->callback_) {
1345 for (
auto it : to_reloc) {
1346 callbacks_.relocate(callbacks_.end(), it);
1351 if (ex_sock && ex_sock->callback_) {
1355 ex_sock->callback_(ex_sock->socket_);
1360 std::lock_guard<std::mutex> lk(receiver_mutex_);
1371 if (timeout_usec >= 1000000) {
1373 " one million microseconds");
1376 fd_event_handler_->clear();
1384 for (
const SocketInfo& s : iface->getSockets()) {
1386 if (s.addr_.isV4()) {
1388 fd_event_handler_->add(s.sockfd_);
1395 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1396 if (!callbacks_.empty()) {
1397 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1398 if (it->unusable_) {
1401 handleClosedExternalSocket(it);
1403 fd_event_handler_->add(it->socket_);
1411 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1416 }
else if (result < 0) {
1424 if (errno == EINTR) {
1426 }
else if (errno == EBADF) {
1427 handleClosedExternalSockets();
1434 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1437 std::list<SocketCallbackInfoIterator> to_reloc;
1438 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1439 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1440 if (it->unusable_) {
1443 handleClosedExternalSocket(it);
1444 if (fd_event_handler_->readReady(it->socket_) ||
1445 fd_event_handler_->hasError(it->socket_)) {
1447 to_reloc.push_back(it);
1450 if (it->callback_) {
1459 for (
auto it : to_reloc) {
1460 callbacks_.relocate(callbacks_.end(), it);
1465 if (ex_sock && ex_sock->callback_) {
1469 ex_sock->callback_(ex_sock->socket_);
1473 boost::scoped_ptr<SocketInfo> candidate;
1475 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1477 for (
auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1478 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1481 for (
auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1482 if (!fd_event_handler_->readReady(sit->sockfd_) &&
1483 !fd_event_handler_->hasError(sit->sockfd_)) {
1486 ifaces_to_reloc.push_back(iit);
1487 sockets_to_reloc.push_back(sit);
1488 if (fd_event_handler_->hasError(sit->sockfd_)) {
1489 handleIfaceSocketError(*iit, *sit);
1494 if (!sockets_to_reloc.empty()) {
1495 for (
auto it : sockets_to_reloc) {
1496 sidx.relocate(sidx.end(), it);
1504 if (!ifaces_to_reloc.empty()) {
1505 for (
auto it : ifaces_to_reloc) {
1506 iidx.relocate(iidx.end(), it);
1510 if (!candidate || !recv_if) {
1517 if (ioctl(candidate->sockfd_, FIONREAD, &len) < 0) {
1526 return (packet_filter_->receive(*recv_if, *candidate));
1541 if (timeout_usec >= 1000000) {
1543 " one million microseconds");
1546 fd_event_handler_->clear();
1554 for (
const SocketInfo& s : iface->getSockets()) {
1556 if (s.addr_.isV6()) {
1558 fd_event_handler_->add(s.sockfd_);
1565 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1566 if (!callbacks_.empty()) {
1567 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1568 if (it->unusable_) {
1571 handleClosedExternalSocket(it);
1573 fd_event_handler_->add(it->socket_);
1581 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1586 }
else if (result < 0) {
1594 if (errno == EINTR) {
1596 }
else if (errno == EBADF) {
1597 handleClosedExternalSockets();
1604 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1607 std::list<SocketCallbackInfoIterator> to_reloc;
1608 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1609 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1610 if (it->unusable_) {
1613 handleClosedExternalSocket(it);
1614 if (fd_event_handler_->readReady(it->socket_) ||
1615 fd_event_handler_->hasError(it->socket_)) {
1617 to_reloc.push_back(it);
1620 if (it->callback_) {
1629 for (
auto it : to_reloc) {
1630 callbacks_.relocate(callbacks_.end(), it);
1635 if (ex_sock && ex_sock->callback_) {
1639 ex_sock->callback_(ex_sock->socket_);
1643 boost::scoped_ptr<SocketInfo> candidate;
1645 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1647 for (
auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1648 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1651 for (
auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1652 if (!fd_event_handler_->readReady(sit->sockfd_) &&
1653 !fd_event_handler_->hasError(sit->sockfd_)) {
1656 ifaces_to_reloc.push_back(iit);
1657 sockets_to_reloc.push_back(sit);
1658 if (fd_event_handler_->hasError(sit->sockfd_)) {
1659 handleIfaceSocketError(*iit, *sit);
1664 if (!sockets_to_reloc.empty()) {
1665 for (
auto it : sockets_to_reloc) {
1666 sidx.relocate(sidx.end(), it);
1674 if (!ifaces_to_reloc.empty()) {
1675 for (
auto it : ifaces_to_reloc) {
1676 iidx.relocate(iidx.end(), it);
1687 if (ioctl(candidate->sockfd_, FIONREAD, &len) < 0) {
1696 return (packet_filter6_->receive(*candidate));
1702 if (timeout_usec >= 1000000) {
1704 " one million microseconds");
1707 fd_event_handler_->clear();
1711 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1712 if (!callbacks_.empty()) {
1713 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1714 if (it->unusable_) {
1717 handleClosedExternalSocket(it);
1719 fd_event_handler_->add(it->socket_);
1744 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1749 }
else if (result < 0) {
1757 if (errno == EINTR) {
1759 }
else if (errno == EBADF) {
1760 handleClosedExternalSockets();
1769 std::lock_guard<std::mutex> lk(receiver_mutex_);
1772 string msg = dhcp_receiver_->getLastError();
1779 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1782 std::list<SocketCallbackInfoIterator> to_reloc;
1783 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1784 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1785 if (it->unusable_) {
1788 handleClosedExternalSocket(it);
1789 if (fd_event_handler_->readReady(it->socket_) ||
1790 fd_event_handler_->hasError(it->socket_)) {
1792 to_reloc.push_back(it);
1795 if (it->callback_) {
1804 for (
auto it : to_reloc) {
1805 callbacks_.relocate(callbacks_.end(), it);
1810 if (ex_sock && ex_sock->callback_) {
1814 ex_sock->callback_(ex_sock->socket_);
1819 std::lock_guard<std::mutex> lk(receiver_mutex_);
1829IfaceMgr::scanReceiveDHCP4Packets() {
1831 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1834 for (
auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1835 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1838 bool to_reloc =
false;
1840 for (
auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1841 if (!receiver_fd_event_handler_->readReady(sit->sockfd_) &&
1842 !receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1846 ifaces_to_reloc.push_back(iit);
1849 sockets_to_reloc.push_back(sit);
1850 if (receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1851 handleIfaceSocketError(*iit, *sit);
1853 receiveDHCP4Packet(**iit, *sit);
1855 if (dhcp_receiver_->shouldTerminate()) {
1856 isc_throw(ReceiveTerminate,
"receiveDHCP4Packet");
1859 if (!sockets_to_reloc.empty()) {
1860 for (
auto it : sockets_to_reloc) {
1861 sidx.relocate(sidx.end(), it);
1865 if (!sockets_to_reloc.empty()) {
1866 for (
auto it : sockets_to_reloc) {
1867 sidx.relocate(sidx.end(), it);
1873 if (!ifaces_to_reloc.empty()) {
1874 for (
auto it : ifaces_to_reloc) {
1875 iidx.relocate(iidx.end(), it);
1879 if (!ifaces_to_reloc.empty()) {
1880 for (
auto it : ifaces_to_reloc) {
1881 iidx.relocate(iidx.end(), it);
1889IfaceMgr::receiveDHCP4Packets() {
1890 receiver_fd_event_handler_->clear();
1897 for (
const SocketInfo& s : iface->getSockets()) {
1899 if (s.addr_.isV4()) {
1901 receiver_fd_event_handler_->add(s.sockfd_);
1909 if (dhcp_receiver_->shouldTerminate()) {
1917 int result = receiver_fd_event_handler_->waitEvent(0, 0,
false);
1920 if (dhcp_receiver_->shouldTerminate()) {
1921 isc_throw(ReceiveTerminate,
"waitEvent");
1927 }
else if (result < 0) {
1929 if (errno != EINTR) {
1931 std::lock_guard<std::mutex> lk(receiver_mutex_);
1933 dhcp_receiver_->setError(strerror(errno));
1944 scanReceiveDHCP4Packets();
1946 }
catch (
const ReceiveTerminate&) {
1948 }
catch (
const std::exception& ex) {
1949 std::lock_guard<std::mutex> lk(receiver_mutex_);
1950 dhcp_receiver_->setError(
string(ex.what()) +
" error: " + strerror(errno));
1952 std::lock_guard<std::mutex> lk(receiver_mutex_);
1953 dhcp_receiver_->setError(
"receive failed");
1959IfaceMgr::scanReceiveDHCP6Packets() {
1961 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1964 for (
auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1965 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1968 bool to_reloc =
false;
1970 for (
auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1971 if (!receiver_fd_event_handler_->readReady(sit->sockfd_) &&
1972 !receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1976 ifaces_to_reloc.push_back(iit);
1979 sockets_to_reloc.push_back(sit);
1980 if (receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1981 handleIfaceSocketError(*iit, *sit);
1983 receiveDHCP6Packet(*sit);
1985 if (dhcp_receiver_->shouldTerminate()) {
1986 isc_throw(ReceiveTerminate,
"receiveDHCP6Packet");
1989 if (!sockets_to_reloc.empty()) {
1990 for (
auto it : sockets_to_reloc) {
1991 sidx.relocate(sidx.end(), it);
1995 if (!sockets_to_reloc.empty()) {
1996 for (
auto it : sockets_to_reloc) {
1997 sidx.relocate(sidx.end(), it);
2003 if (!ifaces_to_reloc.empty()) {
2004 for (
auto it : ifaces_to_reloc) {
2005 iidx.relocate(iidx.end(), it);
2009 if (!ifaces_to_reloc.empty()) {
2010 for (
auto it : ifaces_to_reloc) {
2011 iidx.relocate(iidx.end(), it);
2019IfaceMgr::receiveDHCP6Packets() {
2020 receiver_fd_event_handler_->clear();
2027 for (
const SocketInfo& s : iface->getSockets()) {
2029 if (s.addr_.isV6()) {
2031 receiver_fd_event_handler_->add(s.sockfd_);
2039 if (dhcp_receiver_->shouldTerminate()) {
2047 int result = receiver_fd_event_handler_->waitEvent(0, 0,
false);
2050 if (dhcp_receiver_->shouldTerminate()) {
2051 isc_throw(ReceiveTerminate,
"waitEvent");
2057 }
else if (result < 0) {
2059 if (errno != EINTR) {
2061 std::lock_guard<std::mutex> lk(receiver_mutex_);
2063 dhcp_receiver_->setError(strerror(errno));
2074 scanReceiveDHCP6Packets();
2076 }
catch (
const ReceiveTerminate&) {
2078 }
catch (
const std::exception& ex) {
2079 std::lock_guard<std::mutex> lk(receiver_mutex_);
2080 dhcp_receiver_->setError(
string(ex.what()) +
" error: " + strerror(errno));
2082 std::lock_guard<std::mutex> lk(receiver_mutex_);
2083 dhcp_receiver_->setError(
"receive failed");
2089IfaceMgr::receiveDHCP4Packet(
Iface& iface,
const SocketInfo& socket_info) {
2092 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
2094 std::lock_guard<std::mutex> lk(receiver_mutex_);
2096 dhcp_receiver_->setError(strerror(errno));
2107 pkt = packet_filter_->receive(iface, socket_info);
2108 }
catch (
const std::exception& ex) {
2109 std::lock_guard<std::mutex> lk(receiver_mutex_);
2110 dhcp_receiver_->setError(ex.what());
2112 std::lock_guard<std::mutex> lk(receiver_mutex_);
2113 dhcp_receiver_->setError(
"packet filter receive() failed");
2117 std::lock_guard<std::mutex> lk(receiver_mutex_);
2124IfaceMgr::receiveDHCP6Packet(
const SocketInfo& socket_info) {
2127 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
2129 std::lock_guard<std::mutex> lk(receiver_mutex_);
2131 dhcp_receiver_->setError(strerror(errno));
2142 pkt = packet_filter6_->receive(socket_info);
2143 }
catch (
const std::exception& ex) {
2144 std::lock_guard<std::mutex> lk(receiver_mutex_);
2145 dhcp_receiver_->setError(ex.what());
2147 std::lock_guard<std::mutex> lk(receiver_mutex_);
2148 dhcp_receiver_->setError(
"packet filter receive() failed");
2152 std::lock_guard<std::mutex> lk(receiver_mutex_);
2167 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
2169 Iface::SocketCollection::const_iterator s;
2170 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
2175 if (s->family_ != AF_INET6) {
2180 if (s->addr_.isV6Multicast()) {
2184 if (s->addr_ == pkt->getLocalAddr()) {
2187 return (s->sockfd_);
2191 if (candidate == socket_collection.end()) {
2197 if ((pkt->getRemoteAddr().isV6LinkLocal() &&
2198 s->addr_.isV6LinkLocal()) ||
2199 (!pkt->getRemoteAddr().isV6LinkLocal() &&
2200 !s->addr_.isV6LinkLocal())) {
2206 if (candidate != socket_collection.end()) {
2207 return (candidate->sockfd_);
2211 <<
" does not have any suitable IPv6 sockets open.");
2225 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
2226 Iface::SocketCollection::const_iterator s;
2227 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
2228 if (s->family_ == AF_INET) {
2229 if (s->addr_ == pkt->getLocalAddr()) {
2233 if (candidate == socket_collection.end()) {
2239 if (candidate == socket_collection.end()) {
2241 <<
" does not have any suitable IPv4 sockets open.");
2244 return (*candidate);
2251 " while DHCP receiver thread is running");
2254 bool enable_queue =
false;
2255 if (queue_control) {
2266 if (family == AF_INET) {
2267 packet_queue_mgr4_->createPacketQueue(queue_control);
2269 packet_queue_mgr6_->createPacketQueue(queue_control);
2273 if (family == AF_INET) {
2274 packet_queue_mgr4_->destroyPacketQueue();
2276 packet_queue_mgr6_->destroyPacketQueue();
2280 return (enable_queue);
2285 errors_.push_back(message);
2300 if (test_mode_ && update_only) {
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
The IOAddress class represents an IP addresses (version agnostic).
std::string toText() const
Convert the address to a string.
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
bool isV6() const
Convenience function to check for an IPv6 address.
bool isV4() const
Convenience function to check for an IPv4 address.
static const IOEndpoint * create(const int protocol, const IOAddress &address, const unsigned short port)
A polymorphic factory of endpoint from address and port.
The UDPEndpoint class is a concrete derived class of IOEndpoint that represents an endpoint of a UDP ...
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
IfacePtr getIface(const unsigned int ifindex)
Lookup by interface index.
LruIndex & getLru()
LRU index.
IfaceContainer::nth_index< 3 >::type LruIndex
Type of LRU index.
IfaceMgr exception thrown thrown when interface detection fails.
Handles network interfaces, transmission and reception.
void clearIfaces()
Removes detected interfaces.
bool isExternalSocket(int fd)
Checks if socket's file description is registered.
void deleteExternalSocket(int socketfd)
Deletes external socket.
Pkt6Ptr receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets indirectly or data from external sockets.
bool openSockets4(const uint16_t port=DHCP4_SERVER_PORT, const bool use_bcast=true, IfaceMgrErrorMsgCallback error_handler=0, const bool skip_opened=false)
Opens IPv4 sockets on detected interfaces.
void stopDHCPReceiver(bool clear_queue=true)
Stops the DHCP packet receiver.
std::function< void(int fd)> SocketCallback
Defines callback used when data is received over external sockets.
int openSocket(const std::string &ifname, const isc::asiolink::IOAddress &addr, const uint16_t port, const bool receive_bcast=false, const bool send_bcast=false)
Opens UDP/IP socket and binds it to address, interface and port.
int openSocketFromAddress(const isc::asiolink::IOAddress &addr, const uint16_t port)
Opens UDP/IP socket and binds to address specified.
void printIfaces(std::ostream &out=std::cout)
Debugging method that prints out all available interfaces.
IfacePtr getIface(const unsigned int ifindex)
Returns interface specified interface index.
int openSocket4(Iface &iface, const isc::asiolink::IOAddress &addr, const uint16_t port, const bool receive_bcast=false, const bool send_bcast=false)
Opens IPv4 socket.
bool openSockets6(const uint16_t port=DHCP6_SERVER_PORT, IfaceMgrErrorMsgCallback error_handler=0, const bool skip_opened=false)
Opens IPv6 sockets on detected interfaces.
BoundAddresses bound_address_
Unordered set of IPv4 bound addresses.
void setPacketFilter(const PktFilterPtr &packet_filter)
Set packet filter object to handle sending and receiving DHCPv4 messages.
int openSocketFromIface(const std::string &ifname, const uint16_t port, const uint8_t family)
Opens UDP/IP socket and binds it to interface specified.
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
void detectIfaces(bool update_only=false)
Detects network interfaces.
IfaceCollection ifaces_
List of available interfaces.
void startDHCPReceiver(const uint16_t family)
Starts DHCP packet receiver.
void clearUnicasts()
Clears unicast addresses on all interfaces.
virtual bool isSocketReceivedTimeSupported() const
Check if the socket received time is supported.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
void initializeFDEventHandler()
Initialize the FD event handler;.
bool isDHCPReceiverRunning() const
Returns true if there is a receiver exists and its thread is currently running.
bool hasOpenSocket(const uint16_t family) const
Checks if there is at least one socket of the specified family open.
virtual ~IfaceMgr()
Destructor.
void collectBoundAddresses()
Collect the addresses all sockets are bound to.
isc::data::ElementPtr ifacesToElement() const
Unparses detected interface list.
int openSocket6(Iface &iface, const isc::asiolink::IOAddress &addr, uint16_t port, const bool join_multicast)
Opens IPv6 socket.
uint16_t getFamily() const
Returns address family.
bool configureDHCPPacketQueue(const uint16_t family, data::ConstElementPtr queue_control)
Configures DHCP packet queue.
int openSocketFromRemoteAddress(const isc::asiolink::IOAddress &remote_addr, const uint16_t port)
Opens UDP/IP socket to be used to connect to remote address.
std::list< int > getAllExternalSockets()
Get the list of external sockets.
Pkt6Ptr receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets directly or data from external sockets.
bool checkDetectIfaces(bool update_only)
Check if the specific system calls used to detect interfaces should be executed.
bool isDirectResponseSupported() const
Check if packet be sent directly to the client having no address.
void clearBoundAddresses()
Clears the addresses all sockets are bound to.
void addExternalSocket(int socketfd, SocketCallback callback)
Adds external socket and a callback.
void addInterface(const IfacePtr &iface)
Adds an interface to list of known interfaces.
IfaceMgr()
Protected constructor.
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
Pkt4Ptr receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets indirectly or data from external sockets.
void closeSockets()
Closes all open sockets.
PacketQueue6Ptr getPacketQueue6()
Fetches the DHCPv6 receiver packet queue.
bool isExternalSocketUnusable(int fd)
Checks if socket's file description is registered.
static const IfaceMgrPtr & instancePtr()
Returns pointer to the sole instance of the interface manager.
void deleteAllExternalSockets()
Deletes all external sockets.
std::thread::id id_
Main thread ID.
Pkt4Ptr receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets directly or data from external sockets.
PacketQueue4Ptr getPacketQueue4()
Fetches the DHCPv4 receiver packet queue.
uint16_t getSocket(const isc::dhcp::Pkt6Ptr &pkt)
Return most suitable socket for transmitting specified IPv6 packet.
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
IfaceMgr exception thrown when there is no suitable interface.
Represents a single network interface.
std::string getPlainMac() const
Returns link-layer address a plain text.
uint64_t flags_
Interface flags (this value is as is returned by OS, it may mean different things on different OSes).
bool inactive4_
Indicates that IPv4 sockets should (true) or should not (false) be opened on this interface.
size_t mac_len_
Length of link-layer address (usually 6).
void clearErrors()
Clears all errors.
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
AddressCollection addrs_
List of assigned addresses.
ErrorBuffer const & getErrors() const
Get the consistent list of error messages.
std::vector< std::string > ErrorBuffer
Type definition for a list of error messages.
std::string getFullName() const
Returns full interface name as "ifname/ifindex" string.
unsigned int ifindex_
Interface index (a value that uniquely identifies an interface).
std::string name_
Network interface name.
boost::multi_index_container< SocketInfo, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::sequenced<> > > SocketCollection
Type that holds a list of socket information.
uint16_t hardware_type_
Hardware type.
SocketCollection sockets_
Socket used to send data.
const AddressCollection & getAddresses() const
Returns all addresses available on an interface.
bool flag_multicast_
Flag specifies if selected interface is multicast capable.
void setActive(const isc::asiolink::IOAddress &address, const bool active)
Activates or deactivates address for the interface.
void addError(std::string const &message)
Add an error to the list of messages.
std::string getName() const
Returns interface name.
Iface(const std::string &name, unsigned int ifindex)
Iface constructor.
bool delAddress(const isc::asiolink::IOAddress &addr)
Deletes an address from an interface.
bool hasAddress(const isc::asiolink::IOAddress &address) const
Check if the interface has the specified address assigned.
SocketCollection::nth_index< 1 >::type SocketLruIndex
SocketInfo LRU index type.
void setMac(const uint8_t *mac, size_t macLen)
Sets MAC address of the interface.
bool flag_running_
Flag specifies if selected interface is running (e.g.
bool delSocket(uint16_t sockfd)
Closes socket.
std::list< Address > AddressCollection
Type that defines list of addresses.
bool inactive6_
Indicates that IPv6 sockets should (true) or should not (false) be opened on this interface.
static const unsigned int MAX_MAC_LEN
Maximum MAC address length (Infiniband uses 20 bytes).
bool flag_loopback_
Specifies if selected interface is loopback.
void addUnicast(const isc::asiolink::IOAddress &addr)
Adds unicast the server should listen on.
unsigned int countActive4() const
Returns a number of activated IPv4 addresses on the interface.
uint8_t mac_[MAX_MAC_LEN]
Link-layer address.
util::Optional< asiolink::IOAddress > Address
Address type.
void addAddress(const isc::asiolink::IOAddress &addr)
Adds an address to an interface.
void closeSockets()
Closes all open sockets on interface.
void addSocket(const SocketInfo &sock)
Adds socket descriptor to an interface.
bool flag_up_
Specifies if selected interface is up.
bool flag_broadcast_
Flag specifies if selected interface is broadcast capable.
AddressCollection unicasts_
List of unicast addresses the server should listen on.
bool getAddress4(isc::asiolink::IOAddress &address) const
Returns IPv4 address assigned to the interface.
Exception thrown when invalid packet filter object specified.
Exception thrown when it is not allowed to set new Packet Filter.
Packet Queue Manager for DHCPv4 servers.
Packet Queue Manager for DHCPv6 servers.
A DHCPv6 packet handling class using datagram sockets.
Packet handling class using AF_INET socket family.
Exception thrown when a call to select is interrupted by a signal.
IfaceMgr exception thrown thrown when socket opening or configuration failed.
IfaceMgr exception thrown when there is an error detected for the respective socket file descriptor.
IfaceMgr exception thrown when there is no suitable socket found.
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
static FDEventHandlerPtr factoryFDEventHandler()
Return an FDEventhandler.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
A template representing an optional value.
Provides a thread and controls for monitoring its activities.
#define DHCP_IPV4_BROADCAST_ADDRESS
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define IFACEMGR_ERROR(ex_type, handler, iface, stream)
A macro which handles an error in IfaceMgr.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
boost::shared_ptr< const Element > ConstElementPtr
boost::shared_ptr< Element > ElementPtr
const isc::log::MessageID DHCP_RECEIVE4_UNKNOWN
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
const isc::log::MessageID DHCP_RECEIVE6_UNKNOWN
boost::shared_ptr< IfaceMgr > IfaceMgrPtr
Type definition for the pointer to the IfaceMgr.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
boost::shared_ptr< PktFilter > PktFilterPtr
Pointer to a PktFilter object.
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
const isc::log::MessageID DHCP_DELETE_EXTERNAL_SOCKET_NOT_FOUND
std::function< void(const std::string &errmsg)> IfaceMgrErrorMsgCallback
This type describes the callback function invoked when error occurs in the IfaceMgr.
const isc::log::MessageID DHCP_ADD_EXTERNAL_SOCKET_ALREADY_EXISTS
const isc::log::MessageID DHCP_ADD_EXTERNAL_SOCKET_BAD_THREAD
const isc::log::MessageID DHCP_IFACE_OPEN_SOCKET
constexpr unsigned int UNSET_IFINDEX
A value used to signal that the interface index was not set.
const isc::log::MessageID DHCP_DELETE_EXTERNAL_SOCKET_BAD_THREAD
const isc::log::MessageID DHCP_DELETE_ALL_EXTERNAL_SOCKETS_BAD_THREAD
isc::log::Logger dhcp_logger("dhcp")
DHCP library Logger.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
boost::shared_ptr< PktFilter6 > PktFilter6Ptr
Pointer to a PktFilter object.
const isc::log::MessageID DHCP_IFACE_SOCKET_ERROR
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Defines the logger used by the top-level component of kea-lfc.
Keeps callback information for external sockets.
SocketCallback callback_
A callback that will be called when data arrives over socket_.
Holds information about socket.