Kea 2.0.1
iface_mgr.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
9#include <asiolink/io_error.h>
11#include <dhcp/dhcp4.h>
12#include <dhcp/dhcp6.h>
13#include <dhcp/iface_mgr.h>
20
21#include <boost/scoped_ptr.hpp>
22
23#include <cstring>
24#include <errno.h>
25#include <fstream>
26#include <functional>
27#include <limits>
28#include <sstream>
29
30#include <arpa/inet.h>
31#include <netinet/in.h>
32#include <string.h>
33#include <sys/ioctl.h>
34#include <sys/select.h>
35
36#ifndef FD_COPY
37#define FD_COPY(orig, copy) \
38 do { \
39 memmove(copy, orig, sizeof(fd_set)); \
40 } while (0)
41#endif
42
43using namespace std;
44using namespace isc::asiolink;
45using namespace isc::util;
46using namespace isc::util::io;
47using namespace isc::util::io::internal;
48
49namespace isc {
50namespace dhcp {
51
52IfaceMgr&
54 return (*instancePtr());
55}
56
57const IfaceMgrPtr&
59 static IfaceMgrPtr iface_mgr(new IfaceMgr());
60 return (iface_mgr);
61}
62
63Iface::Iface(const std::string& name, unsigned int ifindex)
64 :name_(name), ifindex_(ifindex), mac_len_(0), hardware_type_(0),
65 flag_loopback_(false), flag_up_(false), flag_running_(false),
66 flag_multicast_(false), flag_broadcast_(false), flags_(0),
67 inactive4_(false), inactive6_(false)
68{
69 // Sanity checks.
70 if (name.empty()) {
71 isc_throw(BadValue, "Interface name must not be empty");
72 }
73 memset(mac_, 0, sizeof(mac_));
74}
75
76void
78 // Close IPv4 sockets.
79 closeSockets(AF_INET);
80 // Close IPv6 sockets.
81 closeSockets(AF_INET6);
82}
83
84void
85Iface::closeSockets(const uint16_t family) {
86 // Check that the correct 'family' value has been specified.
87 // The possible values are AF_INET or AF_INET6. Note that, in
88 // the current code they are used to differentiate that the
89 // socket is used to transmit IPv4 or IPv6 traffic. However,
90 // the actual family types of the sockets may be different,
91 // e.g. for LPF we are using raw sockets of AF_PACKET family.
92 //
93 // @todo Consider replacing the AF_INET and AF_INET6 with some
94 // enum which will not be confused with the actual socket type.
95 if ((family != AF_INET) && (family != AF_INET6)) {
96 isc_throw(BadValue, "Invalid socket family " << family
97 << " specified when requested to close all sockets"
98 << " which belong to this family");
99 }
100
101 // Search for the socket of the specific type.
102 SocketCollection::iterator sock = sockets_.begin();
103 while (sock != sockets_.end()) {
104 if (sock->family_ == family) {
105 // Close and delete the socket and move to the
106 // next one.
107 close(sock->sockfd_);
108 // Close fallback socket if open.
109 if (sock->fallbackfd_ >= 0) {
110 close(sock->fallbackfd_);
111 }
112 sockets_.erase(sock++);
113
114 } else {
115 // Different type of socket. Let's move
116 // to the next one.
117 ++sock;
118
119 }
120 }
121}
122
123std::string
125 ostringstream tmp;
126 tmp << name_ << "/" << ifindex_;
127 return (tmp.str());
128}
129
130std::string
132 ostringstream tmp;
133 tmp.fill('0');
134 tmp << hex;
135 for (int i = 0; i < mac_len_; i++) {
136 tmp.width(2);
137 tmp << static_cast<int>(mac_[i]);
138 if (i < mac_len_-1) {
139 tmp << ":";
140 }
141 }
142 return (tmp.str());
143}
144
145void Iface::setMac(const uint8_t* mac, size_t len) {
146 if (len > MAX_MAC_LEN) {
147 isc_throw(OutOfRange, "Interface " << getFullName()
148 << " was detected to have link address of length "
149 << len << ", but maximum supported length is "
150 << MAX_MAC_LEN);
151 }
152 mac_len_ = len;
153 if (len > 0) {
154 memcpy(mac_, mac, len);
155 }
156}
157
159 for (AddressCollection::iterator a = addrs_.begin();
160 a!=addrs_.end(); ++a) {
161 if (a->get() == addr) {
162 addrs_.erase(a);
163 return (true);
164 }
165 }
166 return (false);
167}
168
169bool Iface::delSocket(const uint16_t sockfd) {
170 list<SocketInfo>::iterator sock = sockets_.begin();
171 while (sock!=sockets_.end()) {
172 if (sock->sockfd_ == sockfd) {
173 close(sockfd);
174 // Close fallback socket if open.
175 if (sock->fallbackfd_ >= 0) {
176 close(sock->fallbackfd_);
177 }
178 sockets_.erase(sock);
179 return (true); //socket found
180 }
181 ++sock;
182 }
183 return (false); // socket not found
184}
185
187 : packet_filter_(new PktFilterInet()),
188 packet_filter6_(new PktFilterInet6()),
189 test_mode_(false),
190 allow_loopback_(false) {
191
192 // Ensure that PQMs have been created to guarantee we have
193 // default packet queues in place.
194 try {
195 packet_queue_mgr4_.reset(new PacketQueueMgr4());
196 packet_queue_mgr6_.reset(new PacketQueueMgr6());
197 } catch (const std::exception& ex) {
198 isc_throw(Unexpected, "Failed to create PacketQueueManagers: " << ex.what());
199 }
200
201 try {
202
203 // required for sending/receiving packets
204 // let's keep it in front, just in case someone
205 // wants to send anything during initialization
206 detectIfaces();
207
208 } catch (const std::exception& ex) {
210 }
211}
212
214 for (Address a : unicasts_) {
215 if (a.get() == addr) {
216 isc_throw(BadValue, "Address " << addr
217 << " already defined on the " << name_ << " interface.");
218 }
219 }
220 unicasts_.push_back(Optional<IOAddress>(addr));
221}
222
223bool
225 // Iterate over existing addresses assigned to the interface.
226 // Try to find the one that is IPv4.
227 for (Address addr : getAddresses()) {
228 // If address is IPv4, we assign it to the function argument
229 // and return true.
230 if (addr.get().isV4()) {
231 address = addr.get();
232 return (true);
233 }
234 }
235 // There is no IPv4 address assigned to this interface.
236 return (false);
237}
238
239bool
241 for (Address addr : getAddresses()) {
242 if (address == addr.get()) {
243 return (true);
244 }
245 }
246 return (false);
247}
248
249void
251 addrs_.push_back(Address(addr));
252}
253
254void
255Iface::setActive(const IOAddress& address, const bool active) {
256 for (AddressCollection::iterator addr_it = addrs_.begin();
257 addr_it != addrs_.end(); ++addr_it) {
258 if (address == addr_it->get()) {
259 addr_it->unspecified(!active);
260 return;
261 }
262 }
263 isc_throw(BadValue, "specified address " << address << " was not"
264 " found on the interface " << getName());
265}
266
267void
268Iface::setActive(const bool active) {
269 for (AddressCollection::iterator addr_it = addrs_.begin();
270 addr_it != addrs_.end(); ++addr_it) {
271 addr_it->unspecified(!active);
272 }
273}
274
275unsigned int
277 uint16_t count = 0;
278 for (Address addr : addrs_) {
279 if (!addr.unspecified() && addr.get().isV4()) {
280 ++count;
281 }
282 }
283 return (count);
284}
285
287 // Clears bound addresses.
289
290 // Stops the receiver thread if there is one.
292
293 for (IfacePtr iface : ifaces_) {
294 iface->closeSockets();
295 }
296}
297
299 if (isDHCPReceiverRunning()) {
300 dhcp_receiver_->stop();
301 }
302
303 dhcp_receiver_.reset();
304
305 if (getPacketQueue4()) {
306 getPacketQueue4()->clear();
307 }
308
309 if (getPacketQueue6()) {
310 getPacketQueue6()->clear();
311 }
312}
313
315 closeSockets();
316}
317
318bool
320 return (packet_filter_->isDirectResponseSupported());
321}
322
323void
325 if (socketfd < 0) {
326 isc_throw(BadValue, "Attempted to install callback for invalid socket "
327 << socketfd);
328 }
329 std::lock_guard<std::mutex> lock(callbacks_mutex_);
330 for (SocketCallbackInfo s : callbacks_) {
331 // There's such a socket description there already.
332 // Update the callback and we're done
333 if (s.socket_ == socketfd) {
334 s.callback_ = callback;
335 return;
336 }
337 }
338
339 // Add a new entry to the callbacks vector
341 x.socket_ = socketfd;
342 x.callback_ = callback;
343 callbacks_.push_back(x);
344}
345
346void
348 std::lock_guard<std::mutex> lock(callbacks_mutex_);
349 deleteExternalSocketInternal(socketfd);
350}
351
352void
353IfaceMgr::deleteExternalSocketInternal(int socketfd) {
354 for (SocketCallbackInfoContainer::iterator s = callbacks_.begin();
355 s != callbacks_.end(); ++s) {
356 if (s->socket_ == socketfd) {
357 callbacks_.erase(s);
358 return;
359 }
360 }
361}
362
363int
365 std::lock_guard<std::mutex> lock(callbacks_mutex_);
366 std::vector<int> bad_fds;
367 for (SocketCallbackInfo s : callbacks_) {
368 errno = 0;
369 if (fcntl(s.socket_, F_GETFD) < 0 && (errno == EBADF)) {
370 bad_fds.push_back(s.socket_);
371 }
372 }
373
374 for (auto bad_fd : bad_fds) {
375 deleteExternalSocketInternal(bad_fd);
376 }
377
378 return (bad_fds.size());
379}
380
381void
383 std::lock_guard<std::mutex> lock(callbacks_mutex_);
384 callbacks_.clear();
385}
386
387void
389 // Do not allow null pointer.
390 if (!packet_filter) {
391 isc_throw(InvalidPacketFilter, "NULL packet filter object specified for"
392 " DHCPv4");
393 }
394 // Different packet filters use different socket types. It does not make
395 // sense to allow the change of packet filter when there are IPv4 sockets
396 // open because they can't be used by the receive/send functions of the
397 // new packet filter. Below, we check that there are no open IPv4 sockets.
398 // If we find at least one, we have to fail. However, caller still has a
399 // chance to replace the packet filter if he closes sockets explicitly.
400 if (hasOpenSocket(AF_INET)) {
401 // There is at least one socket open, so we have to fail.
403 "it is not allowed to set new packet"
404 << " filter when there are open IPv4 sockets - need"
405 << " to close them first");
406 }
407 // Everything is fine, so replace packet filter.
408 packet_filter_ = packet_filter;
409}
410
411void
413 if (!packet_filter) {
414 isc_throw(InvalidPacketFilter, "NULL packet filter object specified for"
415 " DHCPv6");
416 }
417
418 if (hasOpenSocket(AF_INET6)) {
419 // There is at least one socket open, so we have to fail.
421 "it is not allowed to set new packet"
422 << " filter when there are open IPv6 sockets - need"
423 << " to close them first");
424 }
425
426 packet_filter6_ = packet_filter;
427}
428
429bool
430IfaceMgr::hasOpenSocket(const uint16_t family) const {
431 // Iterate over all interfaces and search for open sockets.
432 for (IfacePtr iface : ifaces_) {
433 for (SocketInfo sock : iface->getSockets()) {
434 // Check if the socket matches specified family.
435 if (sock.family_ == family) {
436 // There is at least one socket open, so return.
437 return (true);
438 }
439 }
440 }
441 // There are no open sockets found for the specified family.
442 return (false);
443}
444
445bool
447 // Fast track for IPv4 using bound addresses.
448 if (addr.isV4() && !bound_address_.empty()) {
449 return (bound_address_.count(addr.toUint32()) != 0);
450 }
451 // Iterate over all interfaces and search for open sockets.
452 for (IfacePtr iface : ifaces_) {
453 for (SocketInfo sock : iface->getSockets()) {
454 // Check if the socket address matches the specified address or
455 // if address is unspecified (in6addr_any).
456 if (sock.addr_ == addr) {
457 return (true);
458 } else if (sock.addr_.isV6Zero()) {
459 // Handle the case that the address is unspecified (any).
460 // This happens only with IPv6 so we do not check IPv4.
461 // In this case, we should check if the specified address
462 // belongs to any of the interfaces.
463 for (IfacePtr it : ifaces_) {
464 for (Iface::Address a : it->getAddresses()) {
465 if (addr == a.get()) {
466 return (true);
467 }
468 }
469 }
470 // The address does not belongs to any interface.
471 return (false);
472 }
473 }
474 }
475 // There are no open sockets found for the specified family.
476 return (false);
477}
478
480 string ifaceName;
481 const string v4addr("127.0.0.1"), v6addr("::1");
482
483 // This is a stub implementation for interface detection. Actual detection
484 // is faked by detecting loopback interface (lo or lo0). It will eventually
485 // be removed once we have actual implementations for all supported systems.
486
487 if (if_nametoindex("lo") > 0) {
488 ifaceName = "lo";
489 // this is Linux-like OS
490 } else if (if_nametoindex("lo0") > 0) {
491 ifaceName = "lo0";
492 // this is BSD-like OS
493 } else {
494 // we give up. What OS is this, anyway? Solaris? Hurd?
496 "Interface detection on this OS is not supported.");
497 }
498
499 IfacePtr iface(new Iface(ifaceName, if_nametoindex(ifaceName.c_str())));
500 iface->flag_up_ = true;
501 iface->flag_running_ = true;
502
503 // Note that we claim that this is not a loopback. iface_mgr tries to open a
504 // socket on all interfaces that are up, running and not loopback. As this is
505 // the only interface we were able to detect, let's pretend this is a normal
506 // interface.
507 iface->flag_loopback_ = false;
508 iface->flag_multicast_ = true;
509 iface->flag_broadcast_ = true;
510 iface->setHWType(HWTYPE_ETHERNET);
511
512 iface->addAddress(IOAddress(v4addr));
513 iface->addAddress(IOAddress(v6addr));
514 addInterface(iface);
515}
516
517bool
518IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
519 IfaceMgrErrorMsgCallback error_handler) {
520 int count = 0;
521 int bcast_num = 0;
522
523 for (IfacePtr iface : ifaces_) {
524 // If the interface is inactive, there is nothing to do. Simply
525 // proceed to the next detected interface.
526 if (iface->inactive4_) {
527 continue;
528
529 } else {
530 // If the interface has been specified in the configuration that
531 // it should be used to listen the DHCP traffic we have to check
532 // that the interface configuration is valid and that the interface
533 // is not a loopback interface. In both cases, we want to report
534 // that the socket will not be opened.
535 // Relax the check when the loopback interface was explicitly
536 // allowed
537 if (iface->flag_loopback_ && !allow_loopback_) {
538 IFACEMGR_ERROR(SocketConfigError, error_handler,
539 "must not open socket on the loopback"
540 " interface " << iface->getName());
541 continue;
542
543 }
544
545 if (!iface->flag_up_) {
546 IFACEMGR_ERROR(SocketConfigError, error_handler,
547 "the interface " << iface->getName()
548 << " is down");
549 continue;
550 }
551
552 if (!iface->flag_running_) {
553 IFACEMGR_ERROR(SocketConfigError, error_handler,
554 "the interface " << iface->getName()
555 << " is not running");
556 continue;
557 }
558
559 IOAddress out_address("0.0.0.0");
560 if (!iface->getAddress4(out_address)) {
561 IFACEMGR_ERROR(SocketConfigError, error_handler,
562 "the interface " << iface->getName()
563 << " has no usable IPv4 addresses configured");
564 continue;
565 }
566 }
567
568 for (Iface::Address addr : iface->getAddresses()) {
569 // Skip non-IPv4 addresses and those that weren't selected..
570 if (addr.unspecified() || !addr.get().isV4()) {
571 continue;
572 }
573
574 // If selected interface is broadcast capable set appropriate
575 // options on the socket so as it can receive and send broadcast
576 // messages.
577 if (iface->flag_broadcast_ && use_bcast) {
578 // The DHCP server must have means to determine which interface
579 // the broadcast packets are coming from. This is achieved by
580 // binding a socket to the device (interface) and specialized
581 // packet filters (e.g. BPF and LPF) implement this mechanism.
582 // If the PktFilterInet (generic one) is used, the socket is
583 // bound to INADDR_ANY which effectively binds the socket to
584 // all addresses on all interfaces. So, only one of those can
585 // be opened. Currently, the direct response support is
586 // provided by the PktFilterLPF and PktFilterBPF, so by checking
587 // the support for direct response we actually determine that
588 // one of those objects is in use. For all other objects we
589 // assume that binding to the device is not supported and we
590 // cease opening sockets and display the appropriate message.
591 if (!isDirectResponseSupported() && bcast_num > 0) {
592 IFACEMGR_ERROR(SocketConfigError, error_handler,
593 "Binding socket to an interface is not"
594 " supported on this OS; therefore only"
595 " one socket listening to broadcast traffic"
596 " can be opened. Sockets will not be opened"
597 " on remaining interfaces");
598 continue;
599
600 } else {
601 try {
602 // We haven't open any broadcast sockets yet, so we can
603 // open at least one more.
604 openSocket(iface->getName(), addr.get(), port, true, true);
605 } catch (const Exception& ex) {
606 IFACEMGR_ERROR(SocketConfigError, error_handler,
607 "failed to open socket on interface "
608 << iface->getName() << ", reason: "
609 << ex.what());
610 continue;
611
612 }
613 // Binding socket to an interface is not supported so we
614 // can't open any more broadcast sockets. Increase the
615 // number of open broadcast sockets.
616 ++bcast_num;
617 }
618
619 } else {
620 try {
621 // Not broadcast capable, do not set broadcast flags.
622 openSocket(iface->getName(), addr.get(), port, false, false);
623 } catch (const Exception& ex) {
624 IFACEMGR_ERROR(SocketConfigError, error_handler,
625 "failed to open socket on interface "
626 << iface->getName() << ", reason: "
627 << ex.what());
628 continue;
629 }
630
631 }
632 ++count;
633
634 }
635 }
636
637 // If we have open sockets, start the receiver.
638 if (count > 0) {
639 // Collects bound addresses.
641
642 // Starts the receiver thread (if queueing is enabled).
643 startDHCPReceiver(AF_INET);
644 }
645
646 return (count > 0);
647}
648
649bool
650IfaceMgr::openSockets6(const uint16_t port,
651 IfaceMgrErrorMsgCallback error_handler) {
652 int count = 0;
653
654 for (IfacePtr iface : ifaces_) {
655 if (iface->inactive6_) {
656 continue;
657
658 } else {
659 // If the interface has been specified in the configuration that
660 // it should be used to listen the DHCP traffic we have to check
661 // that the interface configuration is valid and that the interface
662 // is not a loopback interface. In both cases, we want to report
663 // that the socket will not be opened.
664 // Relax the check when the loopback interface was explicitly
665 // allowed
666 if (iface->flag_loopback_ && !allow_loopback_) {
667 IFACEMGR_ERROR(SocketConfigError, error_handler,
668 "must not open socket on the loopback"
669 " interface " << iface->getName());
670 continue;
671
672 } else if (!iface->flag_up_) {
673 IFACEMGR_ERROR(SocketConfigError, error_handler,
674 "the interface " << iface->getName()
675 << " is down");
676 continue;
677 } else if (!iface->flag_running_) {
678 IFACEMGR_ERROR(SocketConfigError, error_handler,
679 "the interface " << iface->getName()
680 << " is not running");
681 continue;
682 }
683
684 }
685
686 // Open unicast sockets if there are any unicast addresses defined
687 for (Iface::Address addr : iface->getUnicasts()) {
688
689 try {
690 openSocket(iface->getName(), addr, port);
691 } catch (const Exception& ex) {
692 IFACEMGR_ERROR(SocketConfigError, error_handler,
693 "Failed to open unicast socket on interface "
694 << iface->getName() << ", reason: "
695 << ex.what());
696 continue;
697 }
698
699 count++;
700
701 }
702
703 for (Iface::Address addr : iface->getAddresses()) {
704
705 // Skip all but V6 addresses.
706 if (!addr.get().isV6()) {
707 continue;
708 }
709
710 // Bind link-local addresses only. Otherwise we bind several sockets
711 // on interfaces that have several global addresses. For examples
712 // with interface with 2 global addresses, we would bind 3 sockets
713 // (one for link-local and two for global). That would result in
714 // getting each message 3 times.
715 if (!addr.get().isV6LinkLocal()){
716 continue;
717 }
718
719 // Run OS-specific function to open a socket capable of receiving
720 // packets sent to All_DHCP_Relay_Agents_and_Servers multicast
721 // address.
722 if (openMulticastSocket(*iface, addr, port, error_handler)) {
723 ++count;
724 }
725
726 }
727 }
728
729 // If we have open sockets, start the receiver.
730 if (count > 0) {
731 // starts the receiver thread (if queueing is enabled).
732 startDHCPReceiver(AF_INET6);
733 }
734 return (count > 0);
735}
736
737void
738IfaceMgr::startDHCPReceiver(const uint16_t family) {
739 if (isDHCPReceiverRunning()) {
740 isc_throw(InvalidOperation, "a receiver thread already exists");
741 }
742
743 switch (family) {
744 case AF_INET:
745 // If the queue doesn't exist, packet queing has been configured
746 // as disabled. If there is no queue, we do not create a receiver.
747 if(!getPacketQueue4()) {
748 return;
749 }
750
751 dhcp_receiver_.reset(new WatchedThread());
752 dhcp_receiver_->start(std::bind(&IfaceMgr::receiveDHCP4Packets, this));
753 break;
754 case AF_INET6:
755 // If the queue doesn't exist, packet queing has been configured
756 // as disabled. If there is no queue, we do not create a receiver.
757 if(!getPacketQueue6()) {
758 return;
759 }
760
761 dhcp_receiver_.reset(new WatchedThread());
762 dhcp_receiver_->start(std::bind(&IfaceMgr::receiveDHCP6Packets, this));
763 break;
764 default:
765 isc_throw (BadValue, "startDHCPReceiver: invalid family: " << family);
766 break;
767 }
768}
769
770void
772 for (const IfacePtr& existing : ifaces_) {
773 if ((existing->getName() == iface->getName()) ||
774 (existing->getIndex() == iface->getIndex())) {
775 isc_throw(Unexpected, "Can't add " << iface->getFullName() <<
776 " when " << existing->getFullName() <<
777 " already exists.");
778 }
779 }
780 ifaces_.push_back(iface);
781}
782
783void
784IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
785 for (IfacePtr iface : ifaces_) {
786 const Iface::AddressCollection& addrs = iface->getAddresses();
787
788 out << "Detected interface " << iface->getFullName()
789 << ", hwtype=" << iface->getHWType()
790 << ", mac=" << iface->getPlainMac();
791 out << ", flags=" << hex << iface->flags_ << dec << "("
792 << (iface->flag_loopback_?"LOOPBACK ":"")
793 << (iface->flag_up_?"UP ":"")
794 << (iface->flag_running_?"RUNNING ":"")
795 << (iface->flag_multicast_?"MULTICAST ":"")
796 << (iface->flag_broadcast_?"BROADCAST ":"")
797 << ")" << endl;
798 out << " " << addrs.size() << " addr(s):";
799
800 for (Iface::Address addr : addrs) {
801 out << " " << addr.get().toText();
802 }
803 out << endl;
804 }
805}
806
808IfaceCollection::getIface(uint32_t ifindex) {
809 return (getIfaceInternal(ifindex, MultiThreadingMgr::instance().getMode()));
810}
811
812
814IfaceCollection::getIface(const std::string& ifname) {
815 return (getIfaceInternal(ifname, MultiThreadingMgr::instance().getMode()));
816}
817
819IfaceCollection::getIfaceInternal(uint32_t ifindex, bool need_lock) {
820 if (need_lock) {
821 lock_guard<mutex> lock(mutex_);
822 if (cache_ && (cache_->getIndex() == ifindex)) {
823 return (cache_);
824 }
825 } else {
826 if (cache_ && (cache_->getIndex() == ifindex)) {
827 return (cache_);
828 }
829 }
830 const auto& idx = ifaces_container_.get<1>();
831 auto it = idx.find(ifindex);
832 if (it == idx.end()) {
833 return (IfacePtr()); // not found
834 }
835 if (need_lock) {
836 lock_guard<mutex> lock(mutex_);
837 cache_ = *it;
838 return (cache_);
839 } else {
840 lock_guard<mutex> lock(mutex_);
841 cache_ = *it;
842 return (cache_);
843 }
844}
845
847IfaceCollection::getIfaceInternal(const std::string& ifname, bool need_lock) {
848 if (need_lock) {
849 lock_guard<mutex> lock(mutex_);
850 if (cache_ && (cache_->getName() == ifname)) {
851 return (cache_);
852 }
853 } else {
854 if (cache_ && (cache_->getName() == ifname)) {
855 return (cache_);
856 }
857 }
858 const auto& idx = ifaces_container_.get<2>();
859 auto it = idx.find(ifname);
860 if (it == idx.end()) {
861 return (IfacePtr()); // not found
862 }
863 if (need_lock) {
864 lock_guard<mutex> lock(mutex_);
865 cache_ = *it;
866 return (cache_);
867 } else {
868 lock_guard<mutex> lock(mutex_);
869 cache_ = *it;
870 return (cache_);
871 }
872}
873
875IfaceMgr::getIface(int ifindex) {
876 if ((ifindex < 0) || (ifindex > std::numeric_limits<int32_t>::max())) {
877 return (IfacePtr()); // out of range
878 }
879 return (ifaces_.getIface(ifindex));
880}
881
883IfaceMgr::getIface(const std::string& ifname) {
884 if (ifname.empty()) {
885 return (IfacePtr()); // empty
886 }
887 return (ifaces_.getIface(ifname));
888}
889
892 if (pkt->indexSet()) {
893 return (getIface(pkt->getIndex()));
894 } else {
895 return (getIface(pkt->getIface()));
896 }
897}
898
899void
901 ifaces_.clear();
902}
903
904void
906 bound_address_.clear();
907}
908
909void
911 for (IfacePtr iface : ifaces_) {
912 for (SocketInfo sock : iface->getSockets()) {
913 const IOAddress& addr = sock.addr_;
914 if (!addr.isV4()) {
915 continue;
916 }
917 if (bound_address_.count(addr.toUint32()) == 0) {
918 bound_address_.insert(addr);
919 }
920 }
921 }
922}
923
924void
926 for (IfacePtr iface : ifaces_) {
927 iface->clearUnicasts();
928 }
929}
930
931int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
932 const uint16_t port, const bool receive_bcast,
933 const bool send_bcast) {
934 IfacePtr iface = getIface(ifname);
935 if (!iface) {
936 isc_throw(BadValue, "There is no " << ifname << " interface present.");
937 }
938 if (addr.isV4()) {
939 return openSocket4(*iface, addr, port, receive_bcast, send_bcast);
940
941 } else if (addr.isV6()) {
942 return openSocket6(*iface, addr, port, receive_bcast);
943
944 } else {
945 isc_throw(BadValue, "Failed to detect family of address: "
946 << addr);
947 }
948}
949
950int IfaceMgr::openSocketFromIface(const std::string& ifname,
951 const uint16_t port,
952 const uint8_t family) {
953 // Search for specified interface among detected interfaces.
954 for (IfacePtr iface : ifaces_) {
955 if ((iface->getFullName() != ifname) &&
956 (iface->getName() != ifname)) {
957 continue;
958 }
959
960 // Interface is now detected. Search for address on interface
961 // that matches address family (v6 or v4).
962 Iface::AddressCollection addrs = iface->getAddresses();
963 Iface::AddressCollection::iterator addr_it = addrs.begin();
964 while (addr_it != addrs.end()) {
965 if (addr_it->get().getFamily() == family) {
966 // We have interface and address so let's open socket.
967 // This may cause isc::Unexpected exception.
968 return (openSocket(iface->getName(), *addr_it, port, false));
969 }
970 ++addr_it;
971 }
972 // If we are at the end of address collection it means that we found
973 // interface but there is no address for family specified.
974 if (addr_it == addrs.end()) {
975 // Stringify the family value to append it to exception string.
976 std::string family_name("AF_INET");
977 if (family == AF_INET6) {
978 family_name = "AF_INET6";
979 }
980 // We did not find address on the interface.
981 isc_throw(SocketConfigError, "There is no address for interface: "
982 << ifname << ", port: " << port << ", address "
983 " family: " << family_name);
984 }
985 }
986 // If we got here it means that we had not found the specified interface.
987 // Otherwise we would have returned from previous exist points.
988 isc_throw(BadValue, "There is no " << ifname << " interface present.");
989}
990
992 const uint16_t port) {
993 // Search through detected interfaces and addresses to match
994 // local address we got.
995 for (IfacePtr iface : ifaces_) {
996 for (Iface::Address a : iface->getAddresses()) {
997
998 // Local address must match one of the addresses
999 // on detected interfaces. If it does, we have
1000 // address and interface detected so we can open
1001 // socket.
1002 if (a.get() == addr) {
1003 // Open socket using local interface, address and port.
1004 // This may cause isc::Unexpected exception.
1005 return (openSocket(iface->getName(), a, port, false));
1006 }
1007 }
1008 }
1009 // If we got here it means that we did not find specified address
1010 // on any available interface.
1011 isc_throw(BadValue, "There is no such address " << addr);
1012}
1013
1015 const uint16_t port) {
1016 try {
1017 // Get local address to be used to connect to remote location.
1018 IOAddress local_address(getLocalAddress(remote_addr, port));
1019 return openSocketFromAddress(local_address, port);
1020 } catch (const Exception& e) {
1022 }
1023}
1024
1026IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
1027 // Create remote endpoint, we will be connecting to it.
1028 boost::scoped_ptr<const UDPEndpoint>
1029 remote_endpoint(static_cast<const UDPEndpoint*>
1030 (UDPEndpoint::create(IPPROTO_UDP, remote_addr, port)));
1031 if (!remote_endpoint) {
1032 isc_throw(Unexpected, "Unable to create remote endpoint");
1033 }
1034
1035 // Create socket that will be used to connect to remote endpoint.
1036 boost::asio::io_service io_service;
1037 boost::asio::ip::udp::socket sock(io_service);
1038
1039 boost::system::error_code err_code;
1040 // If remote address is broadcast address we have to
1041 // allow this on the socket.
1042 if (remote_addr.isV4() &&
1043 (remote_addr == IOAddress(DHCP_IPV4_BROADCAST_ADDRESS))) {
1044 // Socket has to be open prior to setting the broadcast
1045 // option. Otherwise set_option will complain about
1046 // bad file descriptor.
1047
1048 // @todo: We don't specify interface in any way here. 255.255.255.255
1049 // We can very easily end up with a socket working on a different
1050 // interface.
1051
1052 // zero out the errno to be safe
1053 errno = 0;
1054
1055 sock.open(boost::asio::ip::udp::v4(), err_code);
1056 if (err_code) {
1057 const char* errstr = strerror(errno);
1058 isc_throw(Unexpected, "failed to open UDPv4 socket, reason:"
1059 << errstr);
1060 }
1061 sock.set_option(boost::asio::socket_base::broadcast(true), err_code);
1062 if (err_code) {
1063 sock.close();
1064 isc_throw(Unexpected, "failed to enable broadcast on the socket");
1065 }
1066 }
1067
1068 // Try to connect to remote endpoint and check if attempt is successful.
1069 sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
1070 if (err_code) {
1071 sock.close();
1072 isc_throw(Unexpected, "failed to connect to remote endpoint.");
1073 }
1074
1075 // Once we are connected socket object holds local endpoint.
1076 boost::asio::ip::udp::socket::endpoint_type local_endpoint =
1077 sock.local_endpoint();
1078 boost::asio::ip::address local_address(local_endpoint.address());
1079
1080 // Close the socket.
1081 sock.close();
1082
1083 // Return address of local endpoint.
1084 return IOAddress(local_address);
1085}
1086
1087int
1089 const uint16_t port, const bool receive_bcast,
1090 const bool send_bcast) {
1091
1092 // Assuming that packet filter is not null, because its modifier checks it.
1093 SocketInfo info = packet_filter_->openSocket(iface, addr, port,
1094 receive_bcast, send_bcast);
1095 iface.addSocket(info);
1096
1097 return (info.sockfd_);
1098}
1099
1100bool
1102 IfacePtr iface = getIface(pkt);
1103 if (!iface) {
1104 isc_throw(BadValue, "Unable to send DHCPv6 message. Invalid interface ("
1105 << pkt->getIface() << ") specified.");
1106 }
1107
1108 // Assuming that packet filter is not null, because its modifier checks it.
1109 // The packet filter returns an int but in fact it either returns 0 or throws.
1110 return (packet_filter6_->send(*iface, getSocket(pkt), pkt) == 0);
1111}
1112
1113bool
1115 IfacePtr iface = getIface(pkt);
1116 if (!iface) {
1117 isc_throw(BadValue, "Unable to send DHCPv4 message. Invalid interface ("
1118 << pkt->getIface() << ") specified.");
1119 }
1120
1121 // Assuming that packet filter is not null, because its modifier checks it.
1122 // The packet filter returns an int but in fact it either returns 0 or throws.
1123 return (packet_filter_->send(*iface, getSocket(pkt).sockfd_, pkt) == 0);
1124}
1125
1126Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
1127 if (isDHCPReceiverRunning()) {
1128 return (receive4Indirect(timeout_sec, timeout_usec));
1129 }
1130
1131 return (receive4Direct(timeout_sec, timeout_usec));
1132}
1133
1134Pkt4Ptr IfaceMgr::receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
1135 // Sanity check for microsecond timeout.
1136 if (timeout_usec >= 1000000) {
1137 isc_throw(BadValue, "fractional timeout must be shorter than"
1138 " one million microseconds");
1139 }
1140
1141 fd_set sockets;
1142 int maxfd = 0;
1143
1144 FD_ZERO(&sockets);
1145
1146 // if there are any callbacks for external sockets registered...
1147 {
1148 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1149 if (!callbacks_.empty()) {
1150 for (SocketCallbackInfo s : callbacks_) {
1151 // Add this socket to listening set
1152 addFDtoSet(s.socket_, maxfd, &sockets);
1153 }
1154 }
1155 }
1156
1157 // Add Receiver ready watch socket
1158 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::READY), maxfd, &sockets);
1159
1160 // Add Receiver error watch socket
1161 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::ERROR), maxfd, &sockets);
1162
1163 // Set timeout for our next select() call. If there are
1164 // no DHCP packets to read, then we'll wait for a finite
1165 // amount of time for an IO event. Otherwise, we'll
1166 // poll (timeout = 0 secs). We need to poll, even if
1167 // DHCP packets are waiting so we don't starve external
1168 // sockets under heavy DHCP load.
1169 struct timeval select_timeout;
1170 if (getPacketQueue4()->empty()) {
1171 select_timeout.tv_sec = timeout_sec;
1172 select_timeout.tv_usec = timeout_usec;
1173 } else {
1174 select_timeout.tv_sec = 0;
1175 select_timeout.tv_usec = 0;
1176 }
1177
1178 // zero out the errno to be safe
1179 errno = 0;
1180
1181 int result = select(maxfd + 1, &sockets, 0, 0, &select_timeout);
1182
1183 if ((result == 0) && getPacketQueue4()->empty()) {
1184 // nothing received and timeout has been reached
1185 return (Pkt4Ptr());
1186 } else if (result < 0) {
1187 // In most cases we would like to know whether select() returned
1188 // an error because of a signal being received or for some other
1189 // reason. This is because DHCP servers use signals to trigger
1190 // certain actions, like reconfiguration or graceful shutdown.
1191 // By catching a dedicated exception the caller will know if the
1192 // error returned by the function is due to the reception of the
1193 // signal or for some other reason.
1194 if (errno == EINTR) {
1195 isc_throw(SignalInterruptOnSelect, strerror(errno));
1196 } else if (errno == EBADF) {
1197 int cnt = purgeBadSockets();
1199 "SELECT interrupted by one invalid sockets, purged "
1200 << cnt << " socket descriptors");
1201 } else {
1202 isc_throw(SocketReadError, strerror(errno));
1203 }
1204 }
1205
1206 // We only check external sockets if select detected an event.
1207 if (result > 0) {
1208 // Check for receiver thread read errors.
1209 if (dhcp_receiver_->isReady(WatchedThread::ERROR)) {
1210 string msg = dhcp_receiver_->getLastError();
1211 dhcp_receiver_->clearReady(WatchedThread::ERROR);
1213 }
1214
1215 // Let's find out which external socket has the data
1216 SocketCallbackInfo ex_sock;
1217 bool found = false;
1218 {
1219 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1220 for (SocketCallbackInfo s : callbacks_) {
1221 if (!FD_ISSET(s.socket_, &sockets)) {
1222 continue;
1223 }
1224 found = true;
1225
1226 // something received over external socket
1227 if (s.callback_) {
1228 // Note the external socket to call its callback without
1229 // the lock taken so it can be deleted.
1230 ex_sock = s;
1231 break;
1232 }
1233 }
1234 }
1235
1236 if (ex_sock.callback_) {
1237 // Calling the external socket's callback provides its service
1238 // layer access without integrating any specific features
1239 // in IfaceMgr
1240 ex_sock.callback_(ex_sock.socket_);
1241 }
1242 if (found) {
1243 return (Pkt4Ptr());
1244 }
1245 }
1246
1247 // If we're here it should only be because there are DHCP packets waiting.
1248 Pkt4Ptr pkt = getPacketQueue4()->dequeuePacket();
1249 if (!pkt) {
1250 dhcp_receiver_->clearReady(WatchedThread::READY);
1251 }
1252
1253 return (pkt);
1254}
1255
1256Pkt4Ptr IfaceMgr::receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
1257 // Sanity check for microsecond timeout.
1258 if (timeout_usec >= 1000000) {
1259 isc_throw(BadValue, "fractional timeout must be shorter than"
1260 " one million microseconds");
1261 }
1262 boost::scoped_ptr<SocketInfo> candidate;
1263 fd_set sockets;
1264 int maxfd = 0;
1265
1266 FD_ZERO(&sockets);
1267
1271 for (IfacePtr iface : ifaces_) {
1272 for (SocketInfo s : iface->getSockets()) {
1273 // Only deal with IPv4 addresses.
1274 if (s.addr_.isV4()) {
1275 // Add this socket to listening set
1276 addFDtoSet(s.sockfd_, maxfd, &sockets);
1277 }
1278 }
1279 }
1280
1281 // if there are any callbacks for external sockets registered...
1282 {
1283 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1284 if (!callbacks_.empty()) {
1285 for (SocketCallbackInfo s : callbacks_) {
1286 // Add this socket to listening set
1287 addFDtoSet(s.socket_, maxfd, &sockets);
1288 }
1289 }
1290 }
1291
1292 struct timeval select_timeout;
1293 select_timeout.tv_sec = timeout_sec;
1294 select_timeout.tv_usec = timeout_usec;
1295
1296 // zero out the errno to be safe
1297 errno = 0;
1298
1299 int result = select(maxfd + 1, &sockets, 0, 0, &select_timeout);
1300
1301 if (result == 0) {
1302 // nothing received and timeout has been reached
1303 return (Pkt4Ptr()); // null
1304
1305 } else if (result < 0) {
1306 // In most cases we would like to know whether select() returned
1307 // an error because of a signal being received or for some other
1308 // reason. This is because DHCP servers use signals to trigger
1309 // certain actions, like reconfiguration or graceful shutdown.
1310 // By catching a dedicated exception the caller will know if the
1311 // error returned by the function is due to the reception of the
1312 // signal or for some other reason.
1313 if (errno == EINTR) {
1314 isc_throw(SignalInterruptOnSelect, strerror(errno));
1315 } else if (errno == EBADF) {
1316 int cnt = purgeBadSockets();
1318 "SELECT interrupted by one invalid sockets, purged "
1319 << cnt << " socket descriptors");
1320 } else {
1321 isc_throw(SocketReadError, strerror(errno));
1322 }
1323 }
1324
1325 // Let's find out which socket has the data
1326 SocketCallbackInfo ex_sock;
1327 bool found = false;
1328 {
1329 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1330 for (SocketCallbackInfo s : callbacks_) {
1331 if (!FD_ISSET(s.socket_, &sockets)) {
1332 continue;
1333 }
1334 found = true;
1335
1336 // something received over external socket
1337 if (s.callback_) {
1338 // Note the external socket to call its callback without
1339 // the lock taken so it can be deleted.
1340 ex_sock = s;
1341 break;
1342 }
1343 }
1344 }
1345
1346 if (ex_sock.callback_) {
1347 // Calling the external socket's callback provides its service
1348 // layer access without integrating any specific features
1349 // in IfaceMgr
1350 ex_sock.callback_(ex_sock.socket_);
1351 }
1352 if (found) {
1353 return (Pkt4Ptr());
1354 }
1355
1356 // Let's find out which interface/socket has the data
1357 IfacePtr recv_if;
1358 for (IfacePtr iface : ifaces_) {
1359 for (SocketInfo s : iface->getSockets()) {
1360 if (FD_ISSET(s.sockfd_, &sockets)) {
1361 candidate.reset(new SocketInfo(s));
1362 break;
1363 }
1364 }
1365 if (candidate) {
1366 recv_if = iface;
1367 break;
1368 }
1369 }
1370
1371 if (!candidate || !recv_if) {
1372 isc_throw(SocketReadError, "received data over unknown socket");
1373 }
1374
1375 // Now we have a socket, let's get some data from it!
1376 // Assuming that packet filter is not null, because its modifier checks it.
1377 return (packet_filter_->receive(*recv_if, *candidate));
1378}
1379
1380Pkt6Ptr
1381IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
1382 if (isDHCPReceiverRunning()) {
1383 return (receive6Indirect(timeout_sec, timeout_usec));
1384 }
1385
1386 return (receive6Direct(timeout_sec, timeout_usec));
1387}
1388
1389void
1390IfaceMgr::addFDtoSet(int fd, int& maxfd, fd_set* sockets) {
1391 if (!sockets) {
1392 isc_throw(BadValue, "addFDtoSet: sockets can't be null");
1393 }
1394
1395 FD_SET(fd, sockets);
1396 if (maxfd < fd) {
1397 maxfd = fd;
1398 }
1399}
1400
1401Pkt6Ptr
1402IfaceMgr::receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
1403 // Sanity check for microsecond timeout.
1404 if (timeout_usec >= 1000000) {
1405 isc_throw(BadValue, "fractional timeout must be shorter than"
1406 " one million microseconds");
1407 }
1408
1409 boost::scoped_ptr<SocketInfo> candidate;
1410 fd_set sockets;
1411 int maxfd = 0;
1412
1413 FD_ZERO(&sockets);
1414
1418 for (IfacePtr iface : ifaces_) {
1419 for (SocketInfo s : iface->getSockets()) {
1420 // Only deal with IPv6 addresses.
1421 if (s.addr_.isV6()) {
1422 // Add this socket to listening set
1423 addFDtoSet(s.sockfd_, maxfd, &sockets);
1424 }
1425 }
1426 }
1427
1428 // if there are any callbacks for external sockets registered...
1429 {
1430 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1431 if (!callbacks_.empty()) {
1432 for (SocketCallbackInfo s : callbacks_) {
1433 // Add this socket to listening set
1434 addFDtoSet(s.socket_, maxfd, &sockets);
1435 }
1436 }
1437 }
1438
1439 struct timeval select_timeout;
1440 select_timeout.tv_sec = timeout_sec;
1441 select_timeout.tv_usec = timeout_usec;
1442
1443 // zero out the errno to be safe
1444 errno = 0;
1445
1446 int result = select(maxfd + 1, &sockets, 0, 0, &select_timeout);
1447
1448 if (result == 0) {
1449 // nothing received and timeout has been reached
1450 return (Pkt6Ptr()); // null
1451
1452 } else if (result < 0) {
1453 // In most cases we would like to know whether select() returned
1454 // an error because of a signal being received or for some other
1455 // reason. This is because DHCP servers use signals to trigger
1456 // certain actions, like reconfiguration or graceful shutdown.
1457 // By catching a dedicated exception the caller will know if the
1458 // error returned by the function is due to the reception of the
1459 // signal or for some other reason.
1460 if (errno == EINTR) {
1461 isc_throw(SignalInterruptOnSelect, strerror(errno));
1462 } else if (errno == EBADF) {
1463 int cnt = purgeBadSockets();
1465 "SELECT interrupted by one invalid sockets, purged "
1466 << cnt << " socket descriptors");
1467 } else {
1468 isc_throw(SocketReadError, strerror(errno));
1469 }
1470 }
1471
1472 // Let's find out which socket has the data
1473 SocketCallbackInfo ex_sock;
1474 bool found = false;
1475 {
1476 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1477 for (SocketCallbackInfo s : callbacks_) {
1478 if (!FD_ISSET(s.socket_, &sockets)) {
1479 continue;
1480 }
1481 found = true;
1482
1483 // something received over external socket
1484 if (s.callback_) {
1485 // Note the external socket to call its callback without
1486 // the lock taken so it can be deleted.
1487 ex_sock = s;
1488 break;
1489 }
1490 }
1491 }
1492
1493 if (ex_sock.callback_) {
1494 // Calling the external socket's callback provides its service
1495 // layer access without integrating any specific features
1496 // in IfaceMgr
1497 ex_sock.callback_(ex_sock.socket_);
1498 }
1499 if (found) {
1500 return (Pkt6Ptr());
1501 }
1502
1503 // Let's find out which interface/socket has the data
1504 for (IfacePtr iface : ifaces_) {
1505 for (SocketInfo s : iface->getSockets()) {
1506 if (FD_ISSET(s.sockfd_, &sockets)) {
1507 candidate.reset(new SocketInfo(s));
1508 break;
1509 }
1510 }
1511 if (candidate) {
1512 break;
1513 }
1514 }
1515
1516 if (!candidate) {
1517 isc_throw(SocketReadError, "received data over unknown socket");
1518 }
1519 // Assuming that packet filter is not null, because its modifier checks it.
1520 return (packet_filter6_->receive(*candidate));
1521}
1522
1523Pkt6Ptr
1524IfaceMgr::receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
1525 // Sanity check for microsecond timeout.
1526 if (timeout_usec >= 1000000) {
1527 isc_throw(BadValue, "fractional timeout must be shorter than"
1528 " one million microseconds");
1529 }
1530
1531 fd_set sockets;
1532 int maxfd = 0;
1533
1534 FD_ZERO(&sockets);
1535
1536 // if there are any callbacks for external sockets registered...
1537 {
1538 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1539 if (!callbacks_.empty()) {
1540 for (SocketCallbackInfo s : callbacks_) {
1541 // Add this socket to listening set
1542 addFDtoSet(s.socket_, maxfd, &sockets);
1543 }
1544 }
1545 }
1546
1547 // Add Receiver ready watch socket
1548 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::READY), maxfd, &sockets);
1549
1550 // Add Receiver error watch socket
1551 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::ERROR), maxfd, &sockets);
1552
1553 // Set timeout for our next select() call. If there are
1554 // no DHCP packets to read, then we'll wait for a finite
1555 // amount of time for an IO event. Otherwise, we'll
1556 // poll (timeout = 0 secs). We need to poll, even if
1557 // DHCP packets are waiting so we don't starve external
1558 // sockets under heavy DHCP load.
1559 struct timeval select_timeout;
1560 if (getPacketQueue6()->empty()) {
1561 select_timeout.tv_sec = timeout_sec;
1562 select_timeout.tv_usec = timeout_usec;
1563 } else {
1564 select_timeout.tv_sec = 0;
1565 select_timeout.tv_usec = 0;
1566 }
1567
1568 // zero out the errno to be safe
1569 errno = 0;
1570
1571 int result = select(maxfd + 1, &sockets, 0, 0, &select_timeout);
1572
1573 if ((result == 0) && getPacketQueue6()->empty()) {
1574 // nothing received and timeout has been reached
1575 return (Pkt6Ptr());
1576 } else if (result < 0) {
1577 // In most cases we would like to know whether select() returned
1578 // an error because of a signal being received or for some other
1579 // reason. This is because DHCP servers use signals to trigger
1580 // certain actions, like reconfiguration or graceful shutdown.
1581 // By catching a dedicated exception the caller will know if the
1582 // error returned by the function is due to the reception of the
1583 // signal or for some other reason.
1584 if (errno == EINTR) {
1585 isc_throw(SignalInterruptOnSelect, strerror(errno));
1586 } else if (errno == EBADF) {
1587 int cnt = purgeBadSockets();
1589 "SELECT interrupted by one invalid sockets, purged "
1590 << cnt << " socket descriptors");
1591 } else {
1592 isc_throw(SocketReadError, strerror(errno));
1593 }
1594 }
1595
1596 // We only check external sockets if select detected an event.
1597 if (result > 0) {
1598 // Check for receiver thread read errors.
1599 if (dhcp_receiver_->isReady(WatchedThread::ERROR)) {
1600 string msg = dhcp_receiver_->getLastError();
1601 dhcp_receiver_->clearReady(WatchedThread::ERROR);
1603 }
1604
1605 // Let's find out which external socket has the data
1606 SocketCallbackInfo ex_sock;
1607 bool found = false;
1608 {
1609 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1610 for (SocketCallbackInfo s : callbacks_) {
1611 if (!FD_ISSET(s.socket_, &sockets)) {
1612 continue;
1613 }
1614 found = true;
1615
1616 // something received over external socket
1617 if (s.callback_) {
1618 // Note the external socket to call its callback without
1619 // the lock taken so it can be deleted.
1620 ex_sock = s;
1621 break;
1622 }
1623 }
1624 }
1625
1626 if (ex_sock.callback_) {
1627 // Calling the external socket's callback provides its service
1628 // layer access without integrating any specific features
1629 // in IfaceMgr
1630 ex_sock.callback_(ex_sock.socket_);
1631 }
1632 if (found) {
1633 return (Pkt6Ptr());
1634 }
1635 }
1636
1637 // If we're here it should only be because there are DHCP packets waiting.
1638 Pkt6Ptr pkt = getPacketQueue6()->dequeuePacket();
1639 if (!pkt) {
1640 dhcp_receiver_->clearReady(WatchedThread::READY);
1641 }
1642
1643 return (pkt);
1644}
1645
1646void
1647IfaceMgr::receiveDHCP4Packets() {
1648 fd_set sockets;
1649 int maxfd = 0;
1650
1651 FD_ZERO(&sockets);
1652
1653 // Add terminate watch socket.
1654 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE), maxfd, &sockets);
1655
1656 // Add Interface sockets.
1657 for (IfacePtr iface : ifaces_) {
1658 for (SocketInfo s : iface->getSockets()) {
1659 // Only deal with IPv4 addresses.
1660 if (s.addr_.isV4()) {
1661 // Add this socket to listening set.
1662 addFDtoSet(s.sockfd_, maxfd, &sockets);
1663 }
1664 }
1665 }
1666
1667 for (;;) {
1668 // Check the watch socket.
1669 if (dhcp_receiver_->shouldTerminate()) {
1670 return;
1671 }
1672
1673 fd_set rd_set;
1674 FD_COPY(&sockets, &rd_set);
1675
1676 // zero out the errno to be safe.
1677 errno = 0;
1678
1679 // Select with null timeouts to wait indefinitely an event
1680 int result = select(maxfd + 1, &rd_set, 0, 0, 0);
1681
1682 // Re-check the watch socket.
1683 if (dhcp_receiver_->shouldTerminate()) {
1684 return;
1685 }
1686
1687 if (result == 0) {
1688 // nothing received?
1689 continue;
1690
1691 } else if (result < 0) {
1692 // This thread should not get signals?
1693 if (errno != EINTR) {
1694 // Signal the error to receive4.
1695 dhcp_receiver_->setError(strerror(errno));
1696 // We need to sleep in case of the error condition to
1697 // prevent the thread from tight looping when result
1698 // gets negative.
1699 sleep(1);
1700 }
1701 continue;
1702 }
1703
1704 // Let's find out which interface/socket has data.
1705 for (IfacePtr iface : ifaces_) {
1706 for (SocketInfo s : iface->getSockets()) {
1707 if (FD_ISSET(s.sockfd_, &sockets)) {
1708 receiveDHCP4Packet(*iface, s);
1709 // Can take time so check one more time the watch socket.
1710 if (dhcp_receiver_->shouldTerminate()) {
1711 return;
1712 }
1713 }
1714 }
1715 }
1716 }
1717
1718}
1719
1720void
1721IfaceMgr::receiveDHCP6Packets() {
1722 fd_set sockets;
1723 int maxfd = 0;
1724
1725 FD_ZERO(&sockets);
1726
1727 // Add terminate watch socket.
1728 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE), maxfd, &sockets);
1729
1730 // Add Interface sockets.
1731 for (IfacePtr iface : ifaces_) {
1732 for (SocketInfo s : iface->getSockets()) {
1733 // Only deal with IPv6 addresses.
1734 if (s.addr_.isV6()) {
1735 // Add this socket to listening set.
1736 addFDtoSet(s.sockfd_ , maxfd, &sockets);
1737 }
1738 }
1739 }
1740
1741 for (;;) {
1742 // Check the watch socket.
1743 if (dhcp_receiver_->shouldTerminate()) {
1744 return;
1745 }
1746
1747 fd_set rd_set;
1748 FD_COPY(&sockets, &rd_set);
1749
1750 // zero out the errno to be safe.
1751 errno = 0;
1752
1753 // Note we wait until something happen.
1754 int result = select(maxfd + 1, &rd_set, 0, 0, 0);
1755
1756 // Re-check the watch socket.
1757 if (dhcp_receiver_->shouldTerminate()) {
1758 return;
1759 }
1760
1761 if (result == 0) {
1762 // nothing received?
1763 continue;
1764 } else if (result < 0) {
1765 // This thread should not get signals?
1766 if (errno != EINTR) {
1767 // Signal the error to receive6.
1768 dhcp_receiver_->setError(strerror(errno));
1769 // We need to sleep in case of the error condition to
1770 // prevent the thread from tight looping when result
1771 // gets negative.
1772 sleep(1);
1773 }
1774 continue;
1775 }
1776
1777 // Let's find out which interface/socket has data.
1778 for (IfacePtr iface : ifaces_) {
1779 for (SocketInfo s : iface->getSockets()) {
1780 if (FD_ISSET(s.sockfd_, &sockets)) {
1781 receiveDHCP6Packet(s);
1782 // Can take time so check one more time the watch socket.
1783 if (dhcp_receiver_->shouldTerminate()) {
1784 return;
1785 }
1786 }
1787 }
1788 }
1789 }
1790}
1791
1792void
1793IfaceMgr::receiveDHCP4Packet(Iface& iface, const SocketInfo& socket_info) {
1794 int len;
1795
1796 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
1797 if (result < 0) {
1798 // Signal the error to receive4.
1799 dhcp_receiver_->setError(strerror(errno));
1800 return;
1801 }
1802 if (len == 0) {
1803 // Nothing to read.
1804 return;
1805 }
1806
1807 Pkt4Ptr pkt;
1808
1809 try {
1810 pkt = packet_filter_->receive(iface, socket_info);
1811 } catch (const std::exception& ex) {
1812 dhcp_receiver_->setError(strerror(errno));
1813 } catch (...) {
1814 dhcp_receiver_->setError("packet filter receive() failed");
1815 }
1816
1817 if (pkt) {
1818 getPacketQueue4()->enqueuePacket(pkt, socket_info);
1819 dhcp_receiver_->markReady(WatchedThread::READY);
1820 }
1821}
1822
1823void
1824IfaceMgr::receiveDHCP6Packet(const SocketInfo& socket_info) {
1825 int len;
1826
1827 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
1828 if (result < 0) {
1829 // Signal the error to receive6.
1830 dhcp_receiver_->setError(strerror(errno));
1831 return;
1832 }
1833 if (len == 0) {
1834 // Nothing to read.
1835 return;
1836 }
1837
1838 Pkt6Ptr pkt;
1839
1840 try {
1841 pkt = packet_filter6_->receive(socket_info);
1842 } catch (const std::exception& ex) {
1843 dhcp_receiver_->setError(ex.what());
1844 } catch (...) {
1845 dhcp_receiver_->setError("packet filter receive() failed");
1846 }
1847
1848 if (pkt) {
1849 getPacketQueue6()->enqueuePacket(pkt, socket_info);
1850 dhcp_receiver_->markReady(WatchedThread::READY);
1851 }
1852}
1853
1854uint16_t
1856 IfacePtr iface = getIface(pkt);
1857 if (!iface) {
1858 isc_throw(IfaceNotFound, "Tried to find socket for non-existent interface");
1859 }
1860
1861
1862 const Iface::SocketCollection& socket_collection = iface->getSockets();
1863
1864 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
1865
1866 Iface::SocketCollection::const_iterator s;
1867 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
1868
1869 // We should not merge those conditions for debugging reasons.
1870
1871 // V4 sockets are useless for sending v6 packets.
1872 if (s->family_ != AF_INET6) {
1873 continue;
1874 }
1875
1876 // Sockets bound to multicast address are useless for sending anything.
1877 if (s->addr_.isV6Multicast()) {
1878 continue;
1879 }
1880
1881 if (s->addr_ == pkt->getLocalAddr()) {
1882 // This socket is bound to the source address. This is perfect
1883 // match, no need to look any further.
1884 return (s->sockfd_);
1885 }
1886
1887 // If we don't have any other candidate, this one will do
1888 if (candidate == socket_collection.end()) {
1889 candidate = s;
1890 } else {
1891 // If we want to send something to link-local and the socket is
1892 // bound to link-local or we want to send to global and the socket
1893 // is bound to global, then use it as candidate
1894 if ( (pkt->getRemoteAddr().isV6LinkLocal() &&
1895 s->addr_.isV6LinkLocal()) ||
1896 (!pkt->getRemoteAddr().isV6LinkLocal() &&
1897 !s->addr_.isV6LinkLocal()) ) {
1898 candidate = s;
1899 }
1900 }
1901 }
1902
1903 if (candidate != socket_collection.end()) {
1904 return (candidate->sockfd_);
1905 }
1906
1907 isc_throw(SocketNotFound, "Interface " << iface->getFullName()
1908 << " does not have any suitable IPv6 sockets open.");
1909}
1910
1913 IfacePtr iface = getIface(pkt);
1914 if (!iface) {
1915 isc_throw(IfaceNotFound, "Tried to find socket for non-existent interface");
1916 }
1917
1918 const Iface::SocketCollection& socket_collection = iface->getSockets();
1919 // A candidate being an end of the iterator marks that it is a beginning of
1920 // the socket search and that the candidate needs to be set to the first
1921 // socket found.
1922 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
1923 Iface::SocketCollection::const_iterator s;
1924 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
1925 if (s->family_ == AF_INET) {
1926 if (s->addr_ == pkt->getLocalAddr()) {
1927 return (*s);
1928 }
1929
1930 if (candidate == socket_collection.end()) {
1931 candidate = s;
1932 }
1933 }
1934 }
1935
1936 if (candidate == socket_collection.end()) {
1937 isc_throw(SocketNotFound, "Interface " << iface->getFullName()
1938 << " does not have any suitable IPv4 sockets open.");
1939 }
1940
1941 return (*candidate);
1942}
1943
1944bool
1946 if (isDHCPReceiverRunning()) {
1947 isc_throw(InvalidOperation, "Cannot reconfigure queueing"
1948 " while DHCP receiver thread is running");
1949 }
1950
1951 bool enable_queue = false;
1952 if (queue_control) {
1953 try {
1954 enable_queue = data::SimpleParser::getBoolean(queue_control, "enable-queue");
1955 } catch (...) {
1956 // @todo - for now swallow not found errors.
1957 // if not present we assume default
1958 }
1959 }
1960
1961 if (enable_queue) {
1962 // Try to create the queue as configured.
1963 if (family == AF_INET) {
1964 packet_queue_mgr4_->createPacketQueue(queue_control);
1965 } else {
1966 packet_queue_mgr6_->createPacketQueue(queue_control);
1967 }
1968 } else {
1969 // Destroy the current queue (if one), this inherently disables threading.
1970 if (family == AF_INET) {
1971 packet_queue_mgr4_->destroyPacketQueue();
1972 } else {
1973 packet_queue_mgr6_->destroyPacketQueue();
1974 }
1975 }
1976
1977 return(enable_queue);
1978}
1979
1980} // end of namespace isc::dhcp
1981} // end of namespace isc
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 when a function is not implemented.
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.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
void clear()
Clear the collection.
Definition: iface_mgr.h:532
void push_back(const IfacePtr &iface)
Adds an interface to the collection.
Definition: iface_mgr.h:542
IfacePtr getIface(uint32_t ifindex)
Lookup by interface index.
Definition: iface_mgr.cc:808
IfaceMgr exception thrown thrown when interface detection fails.
Definition: iface_mgr.h:41
void clearIfaces()
Removes detected interfaces.
Definition: iface_mgr.cc:900
static void addFDtoSet(int fd, int &maxfd, fd_set *sockets)
Convenience method for adding an descriptor to a set.
Definition: iface_mgr.cc:1390
int purgeBadSockets()
Scans registered socket set and removes any that are invalid.
Definition: iface_mgr.cc:364
void deleteExternalSocket(int socketfd)
Deletes external socket.
Definition: iface_mgr.cc:347
Pkt6Ptr receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets indirectly or data from external sockets.
Definition: iface_mgr.cc:1524
bool openSockets6(const uint16_t port=DHCP6_SERVER_PORT, IfaceMgrErrorMsgCallback error_handler=0)
Opens IPv6 sockets on detected interfaces.
Definition: iface_mgr.cc:650
std::function< void(int fd)> SocketCallback
Defines callback used when data is received over external sockets.
Definition: iface_mgr.h:636
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.
Definition: iface_mgr.cc:931
int openSocketFromAddress(const isc::asiolink::IOAddress &addr, const uint16_t port)
Opens UDP/IP socket and binds to address specified.
Definition: iface_mgr.cc:991
void printIfaces(std::ostream &out=std::cout)
Debugging method that prints out all available interfaces.
Definition: iface_mgr.cc:784
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.
Definition: iface_mgr.cc:1088
BoundAddresses bound_address_
Unordered set of IPv4 bound addresses.
Definition: iface_mgr.h:1424
void setPacketFilter(const PktFilterPtr &packet_filter)
Set packet filter object to handle sending and receiving DHCPv4 messages.
Definition: iface_mgr.cc:388
int openSocketFromIface(const std::string &ifname, const uint16_t port, const uint8_t family)
Opens UDP/IP socket and binds it to interface specified.
Definition: iface_mgr.cc:950
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
Definition: iface_mgr.cc:1381
IfaceCollection ifaces_
List of available interfaces.
Definition: iface_mgr.h:1421
void startDHCPReceiver(const uint16_t family)
Starts DHCP packet receiver.
Definition: iface_mgr.cc:738
void clearUnicasts()
Clears unicast addresses on all interfaces.
Definition: iface_mgr.cc:925
void detectIfaces()
Detects network interfaces.
bool openSockets4(const uint16_t port=DHCP4_SERVER_PORT, const bool use_bcast=true, IfaceMgrErrorMsgCallback error_handler=0)
Opens IPv4 sockets on detected interfaces.
Definition: iface_mgr.cc:518
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
bool isDHCPReceiverRunning() const
Returns true if there is a receiver exists and its thread is currently running.
Definition: iface_mgr.h:1251
bool hasOpenSocket(const uint16_t family) const
Checks if there is at least one socket of the specified family open.
Definition: iface_mgr.cc:430
virtual ~IfaceMgr()
Destructor.
Definition: iface_mgr.cc:314
void collectBoundAddresses()
Collect the addresses all sockets are bound to.
Definition: iface_mgr.cc:910
int openSocket6(Iface &iface, const isc::asiolink::IOAddress &addr, uint16_t port, const bool join_multicast)
Opens IPv6 socket.
bool configureDHCPPacketQueue(const uint16_t family, data::ConstElementPtr queue_control)
Configures DHCP packet queue.
Definition: iface_mgr.cc:1945
void stubDetectIfaces()
Stub implementation of network interface detection.
Definition: iface_mgr.cc:479
int openSocketFromRemoteAddress(const isc::asiolink::IOAddress &remote_addr, const uint16_t port)
Opens UDP/IP socket to be used to connect to remote address.
Definition: iface_mgr.cc:1014
Pkt6Ptr receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets directly or data from external sockets.
Definition: iface_mgr.cc:1402
bool isDirectResponseSupported() const
Check if packet be sent directly to the client having no address.
Definition: iface_mgr.cc:319
void clearBoundAddresses()
Clears the addresses all sockets are bound to.
Definition: iface_mgr.cc:905
void addExternalSocket(int socketfd, SocketCallback callback)
Adds external socket and a callback.
Definition: iface_mgr.cc:324
void addInterface(const IfacePtr &iface)
Adds an interface to list of known interfaces.
Definition: iface_mgr.cc:771
IfaceMgr()
Protected constructor.
Definition: iface_mgr.cc:186
IfacePtr getIface(int ifindex)
Returns interface specified interface index.
Definition: iface_mgr.cc:875
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
Definition: iface_mgr.cc:1101
Pkt4Ptr receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets indirectly or data from external sockets.
Definition: iface_mgr.cc:1134
void closeSockets()
Closes all open sockets.
Definition: iface_mgr.cc:286
PacketQueue6Ptr getPacketQueue6()
Fetches the DHCPv6 receiver packet queue.
Definition: iface_mgr.h:1227
static const IfaceMgrPtr & instancePtr()
Returns pointer to the sole instance of the interface manager.
Definition: iface_mgr.cc:58
void deleteAllExternalSockets()
Deletes all external sockets.
Definition: iface_mgr.cc:382
void stopDHCPReceiver()
Stops the DHCP packet receiver.
Definition: iface_mgr.cc:298
Pkt4Ptr receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets directly or data from external sockets.
Definition: iface_mgr.cc:1256
PacketQueue4Ptr getPacketQueue4()
Fetches the DHCPv4 receiver packet queue.
Definition: iface_mgr.h:1210
uint16_t getSocket(const isc::dhcp::Pkt6Ptr &pkt)
Return most suitable socket for transmitting specified IPv6 packet.
Definition: iface_mgr.cc:1855
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
Definition: iface_mgr.cc:1126
IfaceMgr exception thrown when there is no suitable interface.
Definition: iface_mgr.h:86
Represents a single network interface.
Definition: iface_mgr.h:118
std::string getPlainMac() const
Returns link-layer address a plain text.
Definition: iface_mgr.cc:131
size_t mac_len_
Length of link-layer address (usually 6).
Definition: iface_mgr.h:415
AddressCollection addrs_
List of assigned addresses.
Definition: iface_mgr.h:406
std::string getFullName() const
Returns full interface name as "ifname/ifindex" string.
Definition: iface_mgr.cc:124
std::string name_
Network interface name.
Definition: iface_mgr.h:400
SocketCollection sockets_
Socket used to send data.
Definition: iface_mgr.h:397
const AddressCollection & getAddresses() const
Returns all addresses available on an interface.
Definition: iface_mgr.h:251
void setActive(const isc::asiolink::IOAddress &address, const bool active)
Activates or deactivates address for the interface.
Definition: iface_mgr.cc:255
std::string getName() const
Returns interface name.
Definition: iface_mgr.h:221
Iface(const std::string &name, unsigned int ifindex)
Iface constructor.
Definition: iface_mgr.cc:63
bool delAddress(const isc::asiolink::IOAddress &addr)
Deletes an address from an interface.
Definition: iface_mgr.cc:158
bool hasAddress(const isc::asiolink::IOAddress &address) const
Check if the interface has the specified address assigned.
Definition: iface_mgr.cc:240
void setMac(const uint8_t *mac, size_t macLen)
Sets MAC address of the interface.
Definition: iface_mgr.cc:145
bool delSocket(uint16_t sockfd)
Closes socket.
Definition: iface_mgr.cc:169
std::list< Address > AddressCollection
Type that defines list of addresses.
Definition: iface_mgr.h:128
std::list< SocketInfo > SocketCollection
Type that holds a list of socket information.
Definition: iface_mgr.h:139
static const unsigned int MAX_MAC_LEN
Maximum MAC address length (Infiniband uses 20 bytes)
Definition: iface_mgr.h:122
void addUnicast(const isc::asiolink::IOAddress &addr)
Adds unicast the server should listen on.
Definition: iface_mgr.cc:213
unsigned int countActive4() const
Returns a number of activated IPv4 addresses on the interface.
Definition: iface_mgr.cc:276
uint8_t mac_[MAX_MAC_LEN]
Link-layer address.
Definition: iface_mgr.h:412
util::Optional< asiolink::IOAddress > Address
Address type.
Definition: iface_mgr.h:125
void addAddress(const isc::asiolink::IOAddress &addr)
Adds an address to an interface.
Definition: iface_mgr.cc:250
void closeSockets()
Closes all open sockets on interface.
Definition: iface_mgr.cc:77
void addSocket(const SocketInfo &sock)
Adds socket descriptor to an interface.
Definition: iface_mgr.h:318
int ifindex_
Interface index (a value that uniquely identifies an interface).
Definition: iface_mgr.h:403
AddressCollection unicasts_
List of unicast addresses the server should listen on.
Definition: iface_mgr.h:409
bool getAddress4(isc::asiolink::IOAddress &address) const
Returns IPv4 address assigned to the interface.
Definition: iface_mgr.cc:224
Exception thrown when invalid packet filter object specified.
Definition: pkt_filter.h:18
Exception thrown when it is not allowed to set new Packet Filter.
Definition: iface_mgr.h:48
Packet Queue Manager for DHPCv4 servers.
Packet Queue Manager for DHPCv6 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.
Definition: iface_mgr.h:55
IfaceMgr exception thrown thrown when socket opening or configuration failed.
Definition: iface_mgr.h:63
IfaceMgr exception thrown when there is no suitable socket found.
Definition: iface_mgr.h:93
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
Definition: iface_mgr.h:71
A template representing an optional value.
Definition: optional.h:36
Provides a thread and controls for monitoring its activities.
#define DHCP_IPV4_BROADCAST_ADDRESS
Definition: dhcp4.h:42
const Name & name_
Definition: dns/message.cc:693
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define FD_COPY(orig, copy)
Definition: iface_mgr.cc:37
#define IFACEMGR_ERROR(ex_type, handler, stream)
A macro which handles an error in IfaceMgr.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
@ info
Definition: db_log.h:120
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition: pkt.h:797
boost::shared_ptr< IfaceMgr > IfaceMgrPtr
Type definition for the pointer to the IfaceMgr.
Definition: iface_mgr.h:614
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:544
boost::shared_ptr< PktFilter > PktFilterPtr
Pointer to a PktFilter object.
Definition: pkt_filter.h:134
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition: iface_mgr.h:463
std::function< void(const std::string &errmsg)> IfaceMgrErrorMsgCallback
This type describes the callback function invoked when error occurs in the IfaceMgr.
Definition: iface_mgr.h:624
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
boost::shared_ptr< PktFilter6 > PktFilter6Ptr
Pointer to a PktFilter object.
Definition: pkt_filter6.h:136
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
Keeps callback information for external sockets.
Definition: iface_mgr.h:639
SocketCallback callback_
A callback that will be called when data arrives over socket_.
Definition: iface_mgr.h:644
int socket_
Socket descriptor of the external socket.
Definition: iface_mgr.h:641
Holds information about socket.
Definition: socket_info.h:19