ncr_udp.h 23 KB

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