ncr_io.h 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef NCR_IO_H
  15. #define NCR_IO_H
  16. /// @file ncr_io.h
  17. /// @brief This file defines abstract classes for exchanging NameChangeRequests.
  18. ///
  19. /// These classes are used for sending and receiving requests to update DNS
  20. /// information for FQDNs embodied as NameChangeRequests (aka NCRs). Ultimately,
  21. /// NCRs must move through the following three layers in order to implement
  22. /// DHCP-DDNS:
  23. ///
  24. /// * Application layer - the business layer which needs to
  25. /// transport NameChangeRequests, and is unaware of the means by which
  26. /// they are transported.
  27. ///
  28. /// * NameChangeRequest layer - This is the layer which acts as the
  29. /// intermediary between the Application layer and the IO layer. It must
  30. /// be able to move NameChangeRequests to the IO layer as raw data and move
  31. /// raw data from the IO layer in the Application layer as
  32. /// NameChangeRequests.
  33. ///
  34. /// * IO layer - the low-level layer that is directly responsible for
  35. /// sending and receiving data asynchronously and is supplied through
  36. /// other libraries. This layer is largely unaware of the nature of the
  37. /// data being transmitted. In other words, it doesn't know beans about
  38. /// NCRs.
  39. ///
  40. /// The abstract classes defined here implement the latter, middle layer,
  41. /// the NameChangeRequest layer. There are two types of participants in this
  42. /// middle ground:
  43. ///
  44. /// * listeners - Receive NCRs from one or more sources. The DHCP-DDNS
  45. /// application, (aka D2), is a listener. Listeners are embodied by the
  46. /// class, NameChangeListener.
  47. ///
  48. /// * senders - sends NCRs to a given target. DHCP servers are senders.
  49. /// Senders are embodied by the class, NameChangeListener.
  50. ///
  51. /// These two classes present a public interface for asynchronous
  52. /// communications that is independent of the IO layer mechanisms. While the
  53. /// type and details of the IO mechanism are not relevant to either class, it
  54. /// is presumed to use isc::asiolink library for asynchronous event processing.
  55. ///
  56. #include <asiolink/io_address.h>
  57. #include <asiolink/io_service.h>
  58. #include <dhcp_ddns/ncr_msg.h>
  59. #include <exceptions/exceptions.h>
  60. #include <deque>
  61. namespace isc {
  62. namespace dhcp_ddns {
  63. /// @brief Exception thrown if an NcrListenerError encounters a general error.
  64. class NcrListenerError : public isc::Exception {
  65. public:
  66. NcrListenerError(const char* file, size_t line, const char* what) :
  67. isc::Exception(file, line, what) { };
  68. };
  69. /// @brief Exception thrown if an error occurs during IO source open.
  70. class NcrListenerOpenError : public isc::Exception {
  71. public:
  72. NcrListenerOpenError(const char* file, size_t line, const char* what) :
  73. isc::Exception(file, line, what) { };
  74. };
  75. /// @brief Exception thrown if an error occurs initiating an IO receive.
  76. class NcrListenerReceiveError : public isc::Exception {
  77. public:
  78. NcrListenerReceiveError(const char* file, size_t line, const char* what) :
  79. isc::Exception(file, line, what) { };
  80. };
  81. /// @brief Abstract interface for receiving NameChangeRequests.
  82. ///
  83. /// NameChangeListener provides the means to:
  84. /// - Supply a callback to invoke upon receipt of an NCR or a listening
  85. /// error
  86. /// - Start listening using a given IOService instance to process events
  87. /// - Stop listening
  88. ///
  89. /// It implements the high level logic flow to listen until a request arrives,
  90. /// invoke the implementation's handler and return to listening for the next
  91. /// request.
  92. ///
  93. /// It provides virtual methods that allow derivations supply implementations
  94. /// to open the appropriate IO source, perform a listen, and close the IO
  95. /// source.
  96. ///
  97. /// The overall design is based on a callback chain. The listener's caller (the
  98. /// application) supplies an "application" layer callback through which it will
  99. /// receive inbound NameChangeRequests. The listener derivation will supply
  100. /// its own callback to the IO layer to process receive events from its IO
  101. /// source. This is referred to as the NameChangeRequest completion handler.
  102. /// It is through this handler that the NameChangeRequest layer gains access
  103. /// to the low level IO read service results. It is expected to assemble
  104. /// NameChangeRequests from the inbound data and forward them to the
  105. /// application layer by invoking the application layer callback registered
  106. /// with the listener.
  107. ///
  108. /// The application layer callback is structured around a nested class,
  109. /// RequestReceiveHandler. It consists of single, abstract operator() which
  110. /// accepts a result code and a pointer to a NameChangeRequest as parameters.
  111. /// In order to receive inbound NCRs, a caller implements a derivation of the
  112. /// RequestReceiveHandler and supplies an instance of this derivation to the
  113. /// NameChangeListener constructor. This "registers" the handler with the
  114. /// listener.
  115. ///
  116. /// To begin listening, the caller invokes the listener's startListener()
  117. /// method, passing in an IOService instance. This in turn will pass the
  118. /// IOService into the virtual method, open(). The open method is where the
  119. /// listener derivation performs the steps necessary to prepare its IO source
  120. /// for reception (e.g. opening a socket, connecting to a database).
  121. ///
  122. /// Assuming the open is successful, startListener will call receiveNext, to
  123. /// initiate an asynchronous receive. This method calls the virtual method,
  124. /// doReceive(). The listener derivation uses doReceive to instigate an IO
  125. /// layer asynchronous receieve passing in its IO layer callback to
  126. /// handle receive events from the IO source.
  127. ///
  128. /// As stated earlier, the derivation's NameChangeRequest completion handler
  129. /// MUST invoke the application layer handler registered with the listener.
  130. /// This is done by passing in either a success status and a populated
  131. /// NameChangeRequest or an error status and an empty request into the
  132. /// listener's invokeRecvHandler method. This is the mechanism by which the
  133. /// listener's caller is handed inbound NCRs.
  134. class NameChangeListener {
  135. public:
  136. /// @brief Defines the outcome of an asynchronous NCR receive
  137. enum Result {
  138. SUCCESS,
  139. TIME_OUT,
  140. STOPPED,
  141. ERROR
  142. };
  143. /// @brief Abstract class for defining application layer receive callbacks.
  144. ///
  145. /// Applications which will receive NameChangeRequests must provide a
  146. /// derivation of this class to the listener constructor in order to
  147. /// receive NameChangeRequests.
  148. class RequestReceiveHandler {
  149. public:
  150. /// @brief Function operator implementing a NCR receive callback.
  151. ///
  152. /// This method allows the application to receive the inbound
  153. /// NameChangeRequests. It is intended to function as a hand off of
  154. /// information and should probably not be time-consuming.
  155. ///
  156. /// @param result contains that receive outcome status.
  157. /// @param ncr is a pointer to the newly received NameChangeRequest if
  158. /// result is NameChangeListener::SUCCESS. It is indeterminate other
  159. /// wise.
  160. /// @throw This method MUST NOT throw.
  161. virtual void operator ()(const Result result,
  162. NameChangeRequestPtr& ncr) = 0;
  163. virtual ~RequestReceiveHandler() {
  164. }
  165. };
  166. /// @brief Constructor
  167. ///
  168. /// @param recv_handler is a pointer the application layer handler to be
  169. /// invoked each time a NCR is received or a receive error occurs.
  170. NameChangeListener(RequestReceiveHandler& recv_handler);
  171. /// @brief Destructor
  172. virtual ~NameChangeListener() {
  173. };
  174. /// @brief Prepares the IO for reception and initiates the first receive.
  175. ///
  176. /// Calls the derivation's open implementation to initialize the IO layer
  177. /// source for receiving inbound requests. If successful, it starts the
  178. /// first asynchronous read by receiveNext.
  179. ///
  180. /// @param io_service is the IOService that will handle IO event processing.
  181. ///
  182. /// @throw NcrListenError if the listener is already "listening" or
  183. /// in the event the open or doReceive methods fail.
  184. void startListening(isc::asiolink::IOService& io_service);
  185. /// @brief Closes the IO source and stops listen logic.
  186. ///
  187. /// Calls the derivation's implementation of close and marks the state
  188. /// as not listening.
  189. void stopListening();
  190. protected:
  191. /// @brief Initiates an asynchronous receive
  192. ///
  193. /// Sets context information to indicate that IO is in progress and invokes
  194. /// the derivation's asynchronous receive method, doReceive. Note doReceive
  195. /// should not be called outside this method to ensure context information
  196. /// integrity.
  197. ///
  198. /// @throw Derivation's doReceive method may throw isc::Exception upon
  199. /// error.
  200. void receiveNext();
  201. /// @brief Calls the NCR receive handler registered with the listener.
  202. ///
  203. /// This is the hook by which the listener's caller's NCR receive handler
  204. /// is called. This method MUST be invoked by the derivation's
  205. /// implementation of doReceive.
  206. ///
  207. /// NOTE:
  208. /// The handler invoked by this method MUST NOT THROW. The handler is
  209. /// at application level and should trap and handle any errors at
  210. /// that level, rather than throw exceptions. If an error has occurred
  211. /// prior to invoking the handler, it will be expressed in terms a failed
  212. /// result being passed to the handler, not a throw. Therefore any
  213. /// exceptions at the handler level are application issues and should be
  214. /// dealt with at that level.
  215. ///
  216. /// This method does wrap the handler invocation within a try-catch
  217. /// block as a fail-safe. The exception will be logged but the
  218. /// receive logic will continue. What this implies is that continued
  219. /// operation may or may not succeed as the application has violated
  220. /// the interface contract.
  221. ///
  222. /// @param result contains that receive outcome status.
  223. /// @param ncr is a pointer to the newly received NameChangeRequest if
  224. /// result is NameChangeListener::SUCCESS. It is indeterminate other
  225. /// wise.
  226. void invokeRecvHandler(const Result result, NameChangeRequestPtr& ncr);
  227. /// @brief Abstract method which opens the IO source for reception.
  228. ///
  229. /// The derivation uses this method to perform the steps needed to
  230. /// prepare the IO source to receive requests.
  231. ///
  232. /// @param io_service is the IOService that process IO events.
  233. ///
  234. /// @throw If the implementation encounters an error it MUST
  235. /// throw it as an isc::Exception or derivative.
  236. virtual void open(isc::asiolink::IOService& io_service) = 0;
  237. /// @brief Abstract method which closes the IO source.
  238. ///
  239. /// The derivation uses this method to perform the steps needed to
  240. /// "close" the IO source.
  241. ///
  242. /// @throw If the implementation encounters an error it MUST
  243. /// throw it as an isc::Exception or derivative.
  244. virtual void close() = 0;
  245. /// @brief Initiates an IO layer asynchronous read.
  246. ///
  247. /// The derivation uses this method to perform the steps needed to
  248. /// initiate an asynchronous read of the IO source with the
  249. /// derivation's IO layer handler as the IO completion callback.
  250. ///
  251. /// @throw If the implementation encounters an error it MUST
  252. /// throw it as an isc::Exception or derivative.
  253. virtual void doReceive() = 0;
  254. public:
  255. /// @brief Returns true if the listener is listening, false otherwise.
  256. ///
  257. /// A true value indicates that the IO source has been opened successfully,
  258. /// and that receive loop logic is active. This implies that closing the
  259. /// IO source will interrupt that operation, resulting in a callback
  260. /// invocation.
  261. bool amListening() const {
  262. return (listening_);
  263. }
  264. /// @brief Returns true if the listener has an IO call in progress.
  265. ///
  266. /// A true value indicates that the listener has an asynchronous IO in
  267. /// progress which will complete at some point in the future. Completion
  268. /// of the call will invoke the registered callback. It is important to
  269. /// understand that the listener and its related objects should not be
  270. /// deleted while there is an IO call pending. This can result in the
  271. /// IO service attempting to invoke methods on objects that are no longer
  272. /// valid.
  273. bool isIoPending() const {
  274. return (io_pending_);
  275. }
  276. private:
  277. /// @brief Sets the listening indicator to the given value.
  278. ///
  279. /// Note, this method is private as it is used the base class is solely
  280. /// responsible for managing the state.
  281. ///
  282. /// @param value is the new value to assign to the indicator.
  283. void setListening(bool value) {
  284. listening_ = value;
  285. }
  286. /// @brief Indicates if the listener is in listening mode.
  287. bool listening_;
  288. /// @brief Indicates that listener has an async IO pending completion.
  289. bool io_pending_;
  290. /// @brief Application level NCR receive completion handler.
  291. RequestReceiveHandler& recv_handler_;
  292. };
  293. /// @brief Defines a smart pointer to an instance of a listener.
  294. typedef boost::shared_ptr<NameChangeListener> NameChangeListenerPtr;
  295. /// @brief Thrown when a NameChangeSender encounters an error.
  296. class NcrSenderError : public isc::Exception {
  297. public:
  298. NcrSenderError(const char* file, size_t line, const char* what) :
  299. isc::Exception(file, line, what) { };
  300. };
  301. /// @brief Exception thrown if an error occurs during IO source open.
  302. class NcrSenderOpenError : public isc::Exception {
  303. public:
  304. NcrSenderOpenError(const char* file, size_t line, const char* what) :
  305. isc::Exception(file, line, what) { };
  306. };
  307. /// @brief Exception thrown if an error occurs initiating an IO send.
  308. class NcrSenderQueueFull : public isc::Exception {
  309. public:
  310. NcrSenderQueueFull(const char* file, size_t line, const char* what) :
  311. isc::Exception(file, line, what) { };
  312. };
  313. /// @brief Exception thrown if an error occurs initiating an IO send.
  314. class NcrSenderSendError : public isc::Exception {
  315. public:
  316. NcrSenderSendError(const char* file, size_t line, const char* what) :
  317. isc::Exception(file, line, what) { };
  318. };
  319. /// @brief Abstract interface for sending NameChangeRequests.
  320. ///
  321. /// NameChangeSender provides the means to:
  322. /// - Supply a callback to invoke upon completing the delivery of an NCR or a
  323. /// send error
  324. /// - Start sending using a given IOService instance to process events
  325. /// - Queue NCRs for delivery
  326. /// - Stop sending
  327. ///
  328. /// It implements the high level logic flow to queue requests for delivery,
  329. /// and ship them one at a time, waiting for the send to complete prior to
  330. /// sending the next request in the queue. If a send fails, the request
  331. /// will remain at the front of queue and will be the send will be retried
  332. /// endlessly unless the caller dequeues the request. Note, it is presumed that
  333. /// a send failure is some form of IO error such as loss of connectivity and
  334. /// not a message content error. It should not be possible to queue an invalid
  335. /// message.
  336. ///
  337. /// It should be noted that once a request is placed onto the send queue it
  338. /// will remain there until one of three things occur:
  339. /// * It is successfully delivered
  340. /// * @c NameChangeSender::skipNext() is called
  341. /// * @c NameChangeSender::clearSendQueue() is called
  342. ///
  343. /// The queue contents are preserved across start and stop listening
  344. /// transitions. This is to provide for error recovery without losing
  345. /// undelivered requests.
  346. /// It provides virtual methods so derivations may supply implementations to
  347. /// open the appropriate IO sink, perform a send, and close the IO sink.
  348. ///
  349. /// The overall design is based on a callback chain. The sender's caller (the
  350. /// application) supplies an "application" layer callback through which it will
  351. /// be given send completion notifications. The sender derivation will employ
  352. /// its own callback at the IO layer to process send events from its IO sink.
  353. /// This callback is expected to forward the outcome of each asynchronous send
  354. /// to the application layer by invoking the application layer callback
  355. /// registered with the sender.
  356. ///
  357. /// The application layer callback is structured around a nested class,
  358. /// RequestSendHandler. It consists of single, abstract operator() which
  359. /// accepts a result code and a pointer to a NameChangeRequest as parameters.
  360. /// In order to receive send completion notifications, a caller implements a
  361. /// derivation of the RequestSendHandler and supplies an instance of this
  362. /// derivation to the NameChangeSender constructor. This "registers" the
  363. /// handler with the sender.
  364. ///
  365. /// To begin sending, the caller invokes the listener's startSending()
  366. /// method, passing in an IOService instance. This in turn will pass the
  367. /// IOService into the virtual method, open(). The open method is where the
  368. /// sender derivation performs the steps necessary to prepare its IO sink for
  369. /// output (e.g. opening a socket, connecting to a database). At this point,
  370. /// the sender is ready to send messages.
  371. ///
  372. /// In order to send a request, the application layer invokes the sender
  373. /// method, sendRequest(), passing in the NameChangeRequest to send. This
  374. /// method places the request onto the back of the send queue, and then invokes
  375. /// the sender method, sendNext().
  376. ///
  377. /// If there is already a send in progress when sendNext() is called, the method
  378. /// will return immediately rather than initiate the next send. This is to
  379. /// ensure that sends are processed sequentially.
  380. ///
  381. /// If there is not a send in progress and the send queue is not empty,
  382. /// the sendNext method will pass the NCR at the front of the send queue into
  383. /// the virtual doSend() method.
  384. ///
  385. /// The sender derivation uses this doSend() method to instigate an IO layer
  386. /// asynchronous send with its IO layer callback to handle send events from its
  387. /// IO sink.
  388. ///
  389. /// As stated earlier, the derivation's IO layer callback MUST invoke the
  390. /// application layer handler registered with the sender. This is done by
  391. /// passing in a status indicating the outcome of the send into the sender's
  392. /// invokeSendHandler method. This is the mechanism by which the sender's
  393. /// caller is handed outbound notifications.
  394. /// After invoking the application layer handler, the invokeSendHandler method
  395. /// will call the sendNext() method to initiate the next send. This ensures
  396. /// that requests continue to dequeue and ship.
  397. ///
  398. class NameChangeSender {
  399. public:
  400. /// @brief Defines the type used for the request send queue.
  401. typedef std::deque<NameChangeRequestPtr> SendQueue;
  402. /// @brief Defines a default maximum number of entries in the send queue.
  403. static const size_t MAX_QUEUE_DEFAULT = 1024;
  404. /// @brief Defines the outcome of an asynchronous NCR send.
  405. enum Result {
  406. SUCCESS,
  407. TIME_OUT,
  408. STOPPED,
  409. ERROR
  410. };
  411. /// @brief Abstract class for defining application layer send callbacks.
  412. ///
  413. /// Applications which will send NameChangeRequests must provide a
  414. /// derivation of this class to the sender constructor in order to
  415. /// receive send outcome notifications.
  416. class RequestSendHandler {
  417. public:
  418. /// @brief Function operator implementing a NCR send callback.
  419. ///
  420. /// This method allows the application to receive the outcome of
  421. /// each send. It is intended to function as a hand off of information
  422. /// and should probably not be time-consuming.
  423. ///
  424. /// @param result contains that send outcome status.
  425. /// @param ncr is a pointer to the NameChangeRequest that was
  426. /// delivered (or attempted).
  427. ///
  428. /// @throw This method MUST NOT throw.
  429. virtual void operator ()(const Result result,
  430. NameChangeRequestPtr& ncr) = 0;
  431. virtual ~RequestSendHandler() {
  432. }
  433. };
  434. /// @brief Constructor
  435. ///
  436. /// @param send_handler is a pointer the application layer handler to be
  437. /// invoked each time a NCR send attempt completes.
  438. /// @param send_queue_max is the maximum number of entries allowed in the
  439. /// send queue. Once the maximum number is reached, all calls to
  440. /// sendRequest will fail with an exception.
  441. NameChangeSender(RequestSendHandler& send_handler,
  442. size_t send_queue_max = MAX_QUEUE_DEFAULT);
  443. /// @brief Destructor
  444. virtual ~NameChangeSender() {
  445. }
  446. /// @brief Prepares the IO for transmission.
  447. ///
  448. /// Calls the derivation's open implementation to initialize the IO layer
  449. /// sink for sending outbound requests.
  450. ///
  451. /// @param io_service is the IOService that will handle IO event processing.
  452. ///
  453. /// @throw NcrSenderError if the sender is already "sending" or
  454. /// NcrSenderOpenError if the open fails.
  455. void startSending(isc::asiolink::IOService & io_service);
  456. /// @brief Closes the IO sink and stops send logic.
  457. ///
  458. /// Calls the derivation's implementation of close and marks the state
  459. /// as not sending.
  460. void stopSending();
  461. /// @brief Queues the given request to be sent.
  462. ///
  463. /// The given request is placed at the back of the send queue and then
  464. /// sendNext is invoked.
  465. ///
  466. /// @param ncr is the NameChangeRequest to send.
  467. ///
  468. /// @throw NcrSenderError if the sender is not in sending state or
  469. /// the request is empty; NcrSenderQueueFull if the send queue has reached
  470. /// capacity.
  471. void sendRequest(NameChangeRequestPtr& ncr);
  472. protected:
  473. /// @brief Dequeues and sends the next request on the send queue.
  474. ///
  475. /// If there is already a send in progress just return. If there is not
  476. /// a send in progress and the send queue is not empty the grab the next
  477. /// message on the front of the queue and call doSend().
  478. ///
  479. void sendNext();
  480. /// @brief Calls the NCR send completion handler registered with the
  481. /// sender.
  482. ///
  483. /// This is the hook by which the sender's caller's NCR send completion
  484. /// handler is called. This method MUST be invoked by the derivation's
  485. /// implementation of doSend. Note that if the send was a success,
  486. /// the entry at the front of the queue is removed from the queue.
  487. /// If not we leave it there so we can retry it. After we invoke the
  488. /// handler we clear the pending ncr value and queue up the next send.
  489. ///
  490. /// NOTE:
  491. /// The handler invoked by this method MUST NOT THROW. The handler is
  492. /// application level logic and should trap and handle any errors at
  493. /// that level, rather than throw exceptions. If IO errors have occurred
  494. /// prior to invoking the handler, they are expressed in terms a failed
  495. /// result being passed to the handler. Therefore any exceptions at the
  496. /// handler level are application issues and should be dealt with at that
  497. /// level.
  498. ///
  499. /// This method does wrap the handler invocation within a try-catch
  500. /// block as a fail-safe. The exception will be logged but the
  501. /// send logic will continue. What this implies is that continued
  502. /// operation may or may not succeed as the application has violated
  503. /// the interface contract.
  504. ///
  505. /// @param result contains that send outcome status.
  506. void invokeSendHandler(const NameChangeSender::Result result);
  507. /// @brief Abstract method which opens the IO sink for transmission.
  508. ///
  509. /// The derivation uses this method to perform the steps needed to
  510. /// prepare the IO sink to send requests.
  511. ///
  512. /// @param io_service is the IOService that process IO events.
  513. ///
  514. /// @throw If the implementation encounters an error it MUST
  515. /// throw it as an isc::Exception or derivative.
  516. virtual void open(isc::asiolink::IOService& io_service) = 0;
  517. /// @brief Abstract method which closes the IO sink.
  518. ///
  519. /// The derivation uses this method to perform the steps needed to
  520. /// "close" the IO sink.
  521. ///
  522. /// @throw If the implementation encounters an error it MUST
  523. /// throw it as an isc::Exception or derivative.
  524. virtual void close() = 0;
  525. /// @brief Initiates an IO layer asynchronous send
  526. ///
  527. /// The derivation uses this method to perform the steps needed to
  528. /// initiate an asynchronous send through the IO sink of the given NCR.
  529. ///
  530. /// @param ncr is a pointer to the NameChangeRequest to send.
  531. /// derivation's IO layer handler as the IO completion callback.
  532. ///
  533. /// @throw If the implementation encounters an error it MUST
  534. /// throw it as an isc::Exception or derivative.
  535. virtual void doSend(NameChangeRequestPtr& ncr) = 0;
  536. public:
  537. /// @brief Removes the request at the front of the send queue
  538. ///
  539. /// This method can be used to avoid further retries of a failed
  540. /// send. It is provided primarily as a just-in-case measure. Since
  541. /// a failed send results in the same request being retried continuously
  542. /// this method makes it possible to remove that entry, causing the
  543. /// subsequent entry in the queue to be attempted on the next send.
  544. /// It is presumed that sends will only fail due to some sort of
  545. /// communications issue. In the unlikely event that a request is
  546. /// somehow tainted and causes an send failure based on its content,
  547. /// this method provides a means to remove th message.
  548. void skipNext();
  549. /// @brief Flushes all entries in the send queue
  550. ///
  551. /// This method can be used to discard all of the NCRs currently in the
  552. /// the send queue. Note it may not be called while the sender is in
  553. /// the sending state.
  554. /// @throw NcrSenderError if called and sender is in sending state.
  555. void clearSendQueue();
  556. /// @brief Returns true if the sender is in send mode, false otherwise.
  557. ///
  558. /// A true value indicates that the IO sink has been opened successfully,
  559. /// and that send loop logic is active.
  560. bool amSending() const {
  561. return (sending_);
  562. }
  563. /// @brief Returns true when a send is in progress.
  564. ///
  565. /// A true value indicates that a request is actively in the process of
  566. /// being delivered.
  567. bool isSendInProgress() const {
  568. return ((ncr_to_send_) ? true : false);
  569. }
  570. /// @brief Returns the maximum number of entries allowed in the send queue.
  571. size_t getQueueMaxSize() const {
  572. return (send_queue_max_);
  573. }
  574. /// @brief Returns the number of entries currently in the send queue.
  575. size_t getQueueSize() const {
  576. return (send_queue_.size());
  577. }
  578. private:
  579. /// @brief Sets the sending indicator to the given value.
  580. ///
  581. /// Note, this method is private as it is used the base class is solely
  582. /// responsible for managing the state.
  583. ///
  584. /// @param value is the new value to assign to the indicator.
  585. void setSending(bool value) {
  586. sending_ = value;
  587. }
  588. /// @brief Boolean indicator which tracks sending status.
  589. bool sending_;
  590. /// @brief A pointer to regisetered send completion handler.
  591. RequestSendHandler& send_handler_;
  592. /// @brief Maximum number of entries permitted in the send queue.
  593. size_t send_queue_max_;
  594. /// @brief Queue of the requests waiting to be sent.
  595. SendQueue send_queue_;
  596. /// @brief Pointer to the request which is in the process of being sent.
  597. NameChangeRequestPtr ncr_to_send_;
  598. };
  599. /// @brief Defines a smart pointer to an instance of a sender.
  600. typedef boost::shared_ptr<NameChangeSender> NameChangeSenderPtr;
  601. } // namespace isc::dhcp_ddns
  602. } // namespace isc
  603. #endif