ncr_udp.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. // Copyright (C) 2013-2016 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. #ifndef NCR_UDP_LISTENER_H
  7. #define NCR_UDP_LISTENER_H
  8. /// @file ncr_udp.h
  9. /// @brief This file provides UDP socket based implementation for sending and
  10. /// receiving NameChangeRequests
  11. ///
  12. /// These classes are derived from the abstract classes, NameChangeListener
  13. /// and NameChangeSender (see ncr_io.h).
  14. ///
  15. /// The following discussion will refer to three layers of communications:
  16. ///
  17. /// * Application layer - This is the business layer which needs to
  18. /// transport NameChangeRequests, and is unaware of the means by which
  19. /// they are transported.
  20. ///
  21. /// * IO layer - This is the low-level layer that is directly responsible
  22. /// for sending and receiving data asynchronously and is supplied through
  23. /// other libraries. This layer is largely unaware of the nature of the
  24. /// data being transmitted. In other words, it doesn't know beans about
  25. /// NCRs.
  26. ///
  27. /// * NameChangeRequest layer - This is the layer which acts as the
  28. /// intermediary between the Application layer and the IO layer. It must
  29. /// be able to move NameChangeRequests to the IO layer as raw data and move
  30. /// raw data from the IO layer in the Application layer as
  31. /// NameChangeRequests.
  32. ///
  33. /// This file defines NameChangeUDPListener class for receiving NCRs, and
  34. /// NameChangeUDPSender for sending NCRs.
  35. ///
  36. /// Both the listener and sender implementations utilize the same underlying
  37. /// construct to move NCRs to and from a UDP socket. This construct consists
  38. /// of a set of classes centered around isc::asiolink::UDPSocket. UDPSocket
  39. /// is a templated class that supports asio asynchronous event processing; and
  40. /// which accepts as its parameter, the name of a callback class.
  41. ///
  42. /// The asynchronous services provided by UDPSocket typically accept a buffer
  43. /// for transferring data (either in or out depending on the service direction)
  44. /// and an object which supplies a callback to invoke upon completion of the
  45. /// service.
  46. ///
  47. /// The callback class must provide an operator() with the following signature:
  48. /// @code
  49. /// void operator ()(const boost::system::error_code error_code,
  50. /// const size_t bytes_transferred);
  51. /// @endcode
  52. ///
  53. /// Upon completion of the service, the callback instance's operator() is
  54. /// invoked by the asio layer. It is given both a outcome result and the
  55. /// number of bytes either read or written, to or from the buffer supplied
  56. /// to the service.
  57. ///
  58. /// Typically, an asiolink based implementation would simply implement the
  59. /// callback operator directly. However, the nature of the asiolink library
  60. /// is such that the callback object may be copied several times during course
  61. /// of a service invocation. This implies that any class being used as a
  62. /// callback class must be copyable. This is not always desirable. In order
  63. /// to separate the callback class from the NameChangeRequest, the construct
  64. /// defines the UDPCallback class for use as a copyable, callback object.
  65. ///
  66. /// The UDPCallback class provides the asiolink layer callback operator(),
  67. /// which is invoked by the asiolink layer upon service completion. It
  68. /// contains:
  69. /// * a pointer to the transfer buffer
  70. /// * the capacity of the transfer buffer
  71. /// * a IO layer outcome result
  72. /// * the number of bytes transferred
  73. /// * a method pointer to a NameChangeRequest layer completion handler
  74. ///
  75. /// This last item, is critical. It points to an instance method that
  76. /// will be invoked by the UDPCallback operator. This provides access to
  77. /// the outcome of the service call to the NameChangeRequest layer without
  78. /// that layer being used as the actual callback object.
  79. ///
  80. /// The completion handler method signature is codified in the typedef,
  81. /// UDPCompletionHandler, and must be as follows:
  82. ///
  83. /// @code
  84. /// void(const bool, const UDPCallback*)
  85. /// @endcode
  86. ///
  87. /// Note that is accepts two parameters. The first is a boolean indicator
  88. /// which indicates if the service call completed successfully or not. The
  89. /// second is a pointer to the callback object invoked by the IOService upon
  90. /// completion of the service. The callback instance will contain all of the
  91. /// pertinent information about the invocation and outcome of the service.
  92. ///
  93. /// Using the contents of the callback, it is the responsibility of the
  94. /// UDPCompletionHandler to interpret the results of the service invocation and
  95. /// pass the interpretation to the application layer via either
  96. /// NameChangeListener::invokeRecvHandler in the case of the UDP listener, or
  97. /// NameChangeSender::invokeSendHandler in the case of UDP sender.
  98. ///
  99. #include <asiolink/asio_wrapper.h>
  100. #include <asiolink/io_address.h>
  101. #include <asiolink/io_service.h>
  102. #include <asiolink/udp_endpoint.h>
  103. #include <asiolink/udp_socket.h>
  104. #include <dhcp_ddns/ncr_io.h>
  105. #include <util/buffer.h>
  106. #include <util/watch_socket.h>
  107. #include <boost/shared_array.hpp>
  108. /// responsibility of the completion handler to perform the steps necessary
  109. /// to interpret the raw data provided by the service outcome. The
  110. /// UDPCallback operator implementation is mostly a pass through.
  111. ///
  112. namespace isc {
  113. namespace dhcp_ddns {
  114. /// @brief Thrown when a UDP level exception occurs.
  115. class NcrUDPError : public isc::Exception {
  116. public:
  117. NcrUDPError(const char* file, size_t line, const char* what) :
  118. isc::Exception(file, line, what) { };
  119. };
  120. class UDPCallback;
  121. /// @brief Defines a function pointer for NameChangeRequest completion handlers.
  122. typedef boost::function<void(const bool, const UDPCallback*)>
  123. UDPCompletionHandler;
  124. /// @brief Defines a dynamically allocated shared array.
  125. typedef boost::shared_array<uint8_t> RawBufferPtr;
  126. typedef boost::shared_ptr<asiolink::UDPEndpoint> UDPEndpointPtr;
  127. /// @brief Implements the callback class passed into UDPSocket calls.
  128. ///
  129. /// It serves as the link between the asiolink::UDPSocket asynchronous services
  130. /// and the NameChangeRequest layer. The class provides the asiolink layer
  131. /// callback operator(), which is invoked by the asiolink layer upon service
  132. /// completion. It contains all of the data pertinent to both the invocation
  133. /// and completion of a service, as well as a pointer to NameChangeRequest
  134. /// layer completion handler to invoke.
  135. ///
  136. class UDPCallback {
  137. public:
  138. /// @brief Container class which stores service invocation related data.
  139. ///
  140. /// Because the callback object may be copied numerous times during the
  141. /// course of service invocation, it does not directly contain data values.
  142. /// Rather it will retain a shared pointer to an instance of this structure
  143. /// thus ensuring that all copies of the callback object, ultimately refer
  144. /// to the same data values.
  145. struct Data {
  146. /// @brief Constructor
  147. ///
  148. /// @param buffer is a pointer to the data transfer buffer. This is
  149. /// the buffer data will be written to on a read, or read from on a
  150. /// send.
  151. /// @param buf_size is the capacity of the buffer
  152. /// @param data_source storage for UDP endpoint which supplied the data
  153. Data(RawBufferPtr& buffer, const size_t buf_size,
  154. UDPEndpointPtr& data_source)
  155. : buffer_(buffer), buf_size_(buf_size), data_source_(data_source),
  156. put_len_(0), error_code_(), bytes_transferred_(0) {
  157. };
  158. /// @brief A pointer to the data transfer buffer.
  159. RawBufferPtr buffer_;
  160. /// @brief Storage capacity of the buffer.
  161. size_t buf_size_;
  162. /// @brief The UDP endpoint that is the origin of the data transferred.
  163. UDPEndpointPtr data_source_;
  164. /// @brief Stores this size of the data within the buffer when written
  165. /// there manually. (See UDPCallback::putData()) .
  166. size_t put_len_;
  167. /// @brief Stores the IO layer result code of the completed IO service.
  168. boost::system::error_code error_code_;
  169. /// @brief Stores the number of bytes transferred by completed IO
  170. /// service.
  171. /// For a read it is the number of bytes written into the
  172. /// buffer. For a write it is the number of bytes read from the
  173. /// buffer.
  174. size_t bytes_transferred_;
  175. };
  176. /// @brief Used as the callback object for UDPSocket services.
  177. ///
  178. /// @param buffer is a pointer to the data transfer buffer. This is
  179. /// the buffer data will be written to on a read, or read from on a
  180. /// send.
  181. /// @param buf_size is the capacity of the buffer
  182. /// @param data_source storage for UDP endpoint which supplied the data
  183. /// @param handler is a method pointer to the completion handler that
  184. /// is to be called by the operator() implementation.
  185. ///
  186. /// @throw NcrUDPError if either the handler or buffer pointers
  187. /// are invalid.
  188. UDPCallback (RawBufferPtr& buffer, const size_t buf_size,
  189. UDPEndpointPtr& data_source,
  190. const UDPCompletionHandler& handler);
  191. /// @brief Operator that will be invoked by the asiolink layer.
  192. ///
  193. /// @param error_code is the IO layer result code of the
  194. /// completed IO service.
  195. /// @param bytes_transferred is the number of bytes transferred by
  196. /// completed IO.
  197. /// For a read it is the number of bytes written into the
  198. /// buffer. For a write it is the number of bytes read from the
  199. /// buffer.
  200. void operator ()(const boost::system::error_code error_code,
  201. const size_t bytes_transferred);
  202. /// @brief Returns the number of bytes transferred by the completed IO
  203. /// service.
  204. ///
  205. /// For a read it is the number of bytes written into the
  206. /// buffer. For a write it is the number of bytes read from the
  207. /// buffer.
  208. size_t getBytesTransferred() const {
  209. return (data_->bytes_transferred_);
  210. }
  211. /// @brief Sets the number of bytes transferred.
  212. ///
  213. /// @param value is the new value to assign to bytes transferred.
  214. void setBytesTransferred(const size_t value) {
  215. data_->bytes_transferred_ = value;
  216. }
  217. /// @brief Returns the completed IO layer service outcome status.
  218. boost::system::error_code getErrorCode() const {
  219. return (data_->error_code_);
  220. }
  221. /// @brief Sets the completed IO layer service outcome status.
  222. ///
  223. /// @param value is the new value to assign to outcome status.
  224. void setErrorCode(const boost::system::error_code value) {
  225. data_->error_code_ = value;
  226. }
  227. /// @brief Returns the data transfer buffer.
  228. RawBufferPtr getBuffer() const {
  229. return (data_->buffer_);
  230. }
  231. /// @brief Returns the data transfer buffer capacity.
  232. size_t getBufferSize() const {
  233. return (data_->buf_size_);
  234. }
  235. /// @brief Returns a pointer the data transfer buffer content.
  236. const uint8_t* getData() const {
  237. return (data_->buffer_.get());
  238. }
  239. /// @brief Copies data into the data transfer buffer.
  240. ///
  241. /// Copies the given number of bytes from the given source buffer
  242. /// into the data transfer buffer, and updates the value of put length.
  243. /// This method may be used when performing sends to make a copy of
  244. /// the "raw data" that was shipped (or attempted) accessible to the
  245. /// upstream callback.
  246. ///
  247. /// @param src is a pointer to the data source from which to copy
  248. /// @param len is the number of bytes to copy
  249. ///
  250. /// @throw NcrUDPError if the number of bytes to copy exceeds
  251. /// the buffer capacity or if the source pointer is invalid.
  252. void putData(const uint8_t* src, size_t len);
  253. /// @brief Returns the number of bytes manually written into the
  254. /// transfer buffer.
  255. size_t getPutLen() const {
  256. return (data_->put_len_);
  257. }
  258. /// @brief Sets the data source to the given endpoint.
  259. ///
  260. /// @param endpoint is the new value to assign to data source.
  261. void setDataSource(UDPEndpointPtr& endpoint) {
  262. data_->data_source_ = endpoint;
  263. }
  264. /// @brief Returns the UDP endpoint that provided the transferred data.
  265. const UDPEndpointPtr& getDataSource() {
  266. return (data_->data_source_);
  267. }
  268. private:
  269. /// @brief NameChangeRequest layer completion handler to invoke.
  270. UDPCompletionHandler handler_;
  271. /// @brief Shared pointer to the service data container.
  272. boost::shared_ptr<Data> data_;
  273. };
  274. /// @brief Convenience type for UDP socket based listener
  275. typedef isc::asiolink::UDPSocket<UDPCallback> NameChangeUDPSocket;
  276. /// @brief Provides the ability to receive NameChangeRequests via UDP socket
  277. ///
  278. /// This class is a derivation of the NameChangeListener which is capable of
  279. /// receiving NameChangeRequests through a UDP socket. The caller need only
  280. /// supply network addressing and a RequestReceiveHandler instance to receive
  281. /// NameChangeRequests asynchronously.
  282. class NameChangeUDPListener : public NameChangeListener {
  283. public:
  284. /// @brief Defines the maximum size packet that can be received.
  285. static const size_t RECV_BUF_MAX = isc::asiolink::
  286. UDPSocket<UDPCallback>::MIN_SIZE;
  287. /// @brief Constructor
  288. ///
  289. /// @param ip_address is the network address on which to listen
  290. /// @param port is the UDP port on which to listen
  291. /// @param format is the wire format of the inbound requests. Currently
  292. /// only JSON is supported
  293. /// @param ncr_recv_handler the receive handler object to notify when
  294. /// a receive completes.
  295. /// @param reuse_address enables IP address sharing when true
  296. /// It defaults to false.
  297. ///
  298. /// @throw base class throws NcrListenerError if handler is invalid.
  299. NameChangeUDPListener(const isc::asiolink::IOAddress& ip_address,
  300. const uint32_t port,
  301. const NameChangeFormat format,
  302. RequestReceiveHandler& ncr_recv_handler,
  303. const bool reuse_address = false);
  304. /// @brief Destructor.
  305. virtual ~NameChangeUDPListener();
  306. /// @brief Opens a UDP socket using the given IOService.
  307. ///
  308. /// Creates a NameChangeUDPSocket bound to the listener's ip address
  309. /// and port, that is monitored by the given IOService instance.
  310. ///
  311. /// @param io_service the IOService which will monitor the socket.
  312. ///
  313. /// @throw NcrUDPError if the open fails.
  314. virtual void open(isc::asiolink::IOService& io_service);
  315. /// @brief Closes the UDPSocket.
  316. ///
  317. /// It first invokes the socket's cancel method which should stop any
  318. /// pending read and remove the socket callback from the IOService. It
  319. /// then calls the socket's close method to actually close the socket.
  320. ///
  321. /// @throw NcrUDPError if the open fails.
  322. virtual void close();
  323. /// @brief Initiates an asynchronous read on the socket.
  324. ///
  325. /// Invokes the asyncReceive() method on the socket passing in the
  326. /// recv_callback_ member's transfer buffer as the receive buffer, and
  327. /// recv_callback_ itself as the callback object.
  328. ///
  329. /// @throw NcrUDPError if the open fails.
  330. void doReceive();
  331. /// @brief Implements the NameChangeRequest level receive completion
  332. /// handler.
  333. ///
  334. /// This method is invoked by the UPDCallback operator() implementation,
  335. /// passing in the boolean success indicator and pointer to itself.
  336. ///
  337. /// If the indicator denotes success, then the method will attempt to
  338. /// to construct a NameChangeRequest from the received data. If the
  339. /// construction was successful, it will send the new NCR to the
  340. /// application layer by calling invokeRecvHandler() with a success
  341. /// status and a pointer to the new NCR.
  342. ///
  343. /// If the buffer contains invalid data such that construction fails,
  344. /// the method will log the failure and then call doReceive() to start a
  345. /// initiate the next receive.
  346. ///
  347. /// If the indicator denotes failure the method will log the failure and
  348. /// notify the application layer by calling invokeRecvHandler() with
  349. /// an error status and an empty pointer.
  350. ///
  351. /// @param successful boolean indicator that should be true if the
  352. /// socket receive completed without error, false otherwise.
  353. /// @param recv_callback pointer to the callback instance which handled
  354. /// the socket receive completion.
  355. void receiveCompletionHandler(const bool successful,
  356. const UDPCallback* recv_callback);
  357. private:
  358. /// @brief IP address on which to listen for requests.
  359. isc::asiolink::IOAddress ip_address_;
  360. /// @brief Port number on which to listen for requests.
  361. uint32_t port_;
  362. /// @brief Wire format of the inbound requests.
  363. NameChangeFormat format_;
  364. /// @brief Low level socket underneath the listening socket
  365. boost::shared_ptr<boost::asio::ip::udp::socket> asio_socket_;
  366. /// @brief NameChangeUDPSocket listening socket
  367. boost::shared_ptr<NameChangeUDPSocket> socket_;
  368. /// @brief Pointer to the receive callback
  369. boost::shared_ptr<UDPCallback> recv_callback_;
  370. /// @brief Flag which enables the reuse address socket option if true.
  371. bool reuse_address_;
  372. ///
  373. /// @name Copy and constructor assignment operator
  374. ///
  375. /// The copy constructor and assignment operator are private to avoid
  376. /// potential issues with multiple listeners attempting to share sockets
  377. /// and callbacks.
  378. private:
  379. NameChangeUDPListener(const NameChangeUDPListener& source);
  380. NameChangeUDPListener& operator=(const NameChangeUDPListener& source);
  381. //@}
  382. };
  383. /// @brief Provides the ability to send NameChangeRequests via UDP socket
  384. ///
  385. /// This class is a derivation of the NameChangeSender which is capable of
  386. /// sending NameChangeRequests through a UDP socket. The caller need only
  387. /// supply network addressing and a RequestSendHandler instance to send
  388. /// NameChangeRequests asynchronously.
  389. class NameChangeUDPSender : public NameChangeSender {
  390. public:
  391. /// @brief Defines the maximum size packet that can be sent.
  392. static const size_t SEND_BUF_MAX = NameChangeUDPListener::RECV_BUF_MAX;
  393. /// @brief Constructor
  394. ///
  395. /// @param ip_address the IP address from which to send
  396. /// @param port the port from which to send
  397. /// @param server_address the IP address of the target listener
  398. /// @param server_port is the IP port of the target listener
  399. /// @param format is the wire format of the outbound requests.
  400. /// @param ncr_send_handler the send handler object to notify when
  401. /// when a send completes.
  402. /// @param send_que_max sets the maximum number of entries allowed in
  403. /// the send queue.
  404. /// It defaults to NameChangeSender::MAX_QUEUE_DEFAULT
  405. /// @param reuse_address enables IP address sharing when true
  406. /// It defaults to false.
  407. ///
  408. NameChangeUDPSender(const isc::asiolink::IOAddress& ip_address,
  409. const uint32_t port, const isc::asiolink::IOAddress& server_address,
  410. const uint32_t server_port, const NameChangeFormat format,
  411. RequestSendHandler& ncr_send_handler,
  412. const size_t send_que_max = NameChangeSender::MAX_QUEUE_DEFAULT,
  413. const bool reuse_address = false);
  414. /// @brief Destructor
  415. virtual ~NameChangeUDPSender();
  416. /// @brief Opens a UDP socket using the given IOService.
  417. ///
  418. /// Creates a NameChangeUDPSocket bound to the sender's IP address
  419. /// and port, that is monitored by the given IOService instance.
  420. ///
  421. /// @param io_service the IOService which will monitor the socket.
  422. ///
  423. /// @throw NcrUDPError if the open fails.
  424. virtual void open(isc::asiolink::IOService& io_service);
  425. /// @brief Closes the UDPSocket.
  426. ///
  427. /// It first invokes the socket's cancel method which should stop any
  428. /// pending send and remove the socket callback from the IOService. It
  429. /// then calls the socket's close method to actually close the socket.
  430. ///
  431. /// @throw NcrUDPError if the open fails.
  432. virtual void close();
  433. /// @brief Sends a given request asynchronously over the socket
  434. ///
  435. /// The given NameChangeRequest is converted to wire format and copied
  436. /// into the send callback's transfer buffer. Then the socket's
  437. /// asyncSend() method is called, passing in send_callback_ member's
  438. /// transfer buffer as the send buffer and the send_callback_ itself
  439. /// as the callback object.
  440. /// @param ncr NameChangeRequest to send.
  441. virtual void doSend(NameChangeRequestPtr& ncr);
  442. /// @brief Implements the NameChangeRequest level send completion handler.
  443. ///
  444. /// This method is invoked by the UDPCallback operator() implementation,
  445. /// passing in the boolean success indicator and pointer to itself.
  446. ///
  447. /// If the indicator denotes success, then the method will notify the
  448. /// application layer by calling invokeSendHandler() with a success
  449. /// status.
  450. ///
  451. /// If the indicator denotes failure the method will log the failure and
  452. /// notify the application layer by calling invokeRecvHandler() with
  453. /// an error status.
  454. ///
  455. /// @param successful boolean indicator that should be true if the
  456. /// socket send completed without error, false otherwise.
  457. /// @param send_callback pointer to the callback instance which handled
  458. /// the socket receive completion.
  459. void sendCompletionHandler(const bool successful,
  460. const UDPCallback* send_callback);
  461. /// @brief Returns a file descriptor suitable for use with select
  462. ///
  463. /// The value returned is an open file descriptor which can be used with
  464. /// select() system call to monitor the sender for IO events. This allows
  465. /// NameChangeUDPSenders to be used in applications which use select,
  466. /// rather than IOService to wait for IO events to occur.
  467. ///
  468. /// @warning Attempting other use of this value may lead to unpredictable
  469. /// behavior in the sender.
  470. ///
  471. /// @return Returns an "open" file descriptor
  472. ///
  473. /// @throw NcrSenderError if the sender is not in send mode,
  474. virtual int getSelectFd();
  475. /// @brief Returns whether or not the sender has IO ready to process.
  476. ///
  477. /// @return true if the sender has at IO ready, false otherwise.
  478. virtual bool ioReady();
  479. private:
  480. /// @brief Closes watch socket if the socket is open.
  481. ///
  482. /// This method closes watch socket if its instance exists and if the
  483. /// socket is open. An error message is logged when this operation fails.
  484. void closeWatchSocket();
  485. /// @brief IP address from which to send.
  486. isc::asiolink::IOAddress ip_address_;
  487. /// @brief Port from which to send.
  488. uint32_t port_;
  489. /// @brief IP address of the target listener.
  490. isc::asiolink::IOAddress server_address_;
  491. /// @brief Port of the target listener.
  492. uint32_t server_port_;
  493. /// @brief Wire format of the outbound requests.
  494. NameChangeFormat format_;
  495. /// @brief Low level socket underneath the sending socket.
  496. boost::shared_ptr<boost::asio::ip::udp::socket> asio_socket_;
  497. /// @brief NameChangeUDPSocket sending socket.
  498. boost::shared_ptr<NameChangeUDPSocket> socket_;
  499. /// @brief Endpoint of the target listener.
  500. boost::shared_ptr<isc::asiolink::UDPEndpoint> server_endpoint_;
  501. /// @brief Pointer to the send callback
  502. boost::shared_ptr<UDPCallback> send_callback_;
  503. /// @brief Flag which enables the reuse address socket option if true.
  504. bool reuse_address_;
  505. /// @brief Pointer to WatchSocket instance supplying the "select-fd".
  506. util::WatchSocketPtr watch_socket_;
  507. };
  508. } // namespace isc::dhcp_ddns
  509. } // namespace isc
  510. #endif