asio_link.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. // Copyright (C) 2010 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. // $Id$
  15. #include <config.h>
  16. #include <unistd.h> // for some IPC/network system calls
  17. #include <sys/socket.h>
  18. #include <netinet/in.h>
  19. #include <asio.hpp>
  20. #include <boost/lexical_cast.hpp>
  21. #include <boost/bind.hpp>
  22. #include <boost/shared_ptr.hpp>
  23. #include <dns/buffer.h>
  24. #include <dns/message.h>
  25. #include <dns/messagerenderer.h>
  26. #include <asio_link.h>
  27. #include <auth/auth_srv.h>
  28. #include <auth/common.h>
  29. using namespace asio;
  30. using asio::ip::udp;
  31. using asio::ip::tcp;
  32. using namespace std;
  33. using namespace isc::dns;
  34. namespace asio_link {
  35. IOAddress::IOAddress(const string& address_str)
  36. // XXX: we cannot simply construct the address in the initialization list
  37. // because we'd like to throw our own exception on failure.
  38. {
  39. error_code err;
  40. asio_address_ = ip::address::from_string(address_str, err);
  41. if (err) {
  42. isc_throw(IOError, "Failed to convert string to address '"
  43. << address_str << "': " << err.message());
  44. }
  45. }
  46. IOAddress::IOAddress(const ip::address& asio_address) :
  47. asio_address_(asio_address)
  48. {}
  49. string
  50. IOAddress::toText() const {
  51. return (asio_address_.to_string());
  52. }
  53. /// \brief The \c TCPEndpoint class is a concrete derived class of
  54. /// \c IOEndpoint that represents an endpoint of a TCP connection.
  55. ///
  56. /// In the current implementation, an object of this class is always
  57. /// instantiated within the wrapper routines. Applications are expected to
  58. /// get access to the object via the abstract base class, \c IOEndpoint.
  59. /// This design may be changed when we generalize the wrapper interface.
  60. ///
  61. /// Note: this implementation is optimized for the case where this object
  62. /// is created from an ASIO endpoint object in a receiving code path
  63. /// by avoiding to make a copy of the base endpoint. For TCP it may not be
  64. /// a big deal, but when we receive UDP packets at a high rate, the copy
  65. /// overhead might be significant.
  66. class TCPEndpoint : public IOEndpoint {
  67. public:
  68. ///
  69. /// \name Constructors and Destructor
  70. ///
  71. //@{
  72. /// \brief Constructor from a pair of address and port.
  73. ///
  74. /// \param address The IP address of the endpoint.
  75. /// \param port The TCP port number of the endpoint.
  76. TCPEndpoint(const IOAddress& address, const unsigned short port) :
  77. asio_endpoint_placeholder_(
  78. new tcp::endpoint(ip::address::from_string(address.toText()),
  79. port)),
  80. asio_endpoint_(*asio_endpoint_placeholder_)
  81. {}
  82. /// \brief Constructor from an ASIO TCP endpoint.
  83. ///
  84. /// This constructor is designed to be an efficient wrapper for the
  85. /// corresponding ASIO class, \c tcp::endpoint.
  86. ///
  87. /// \param asio_endpoint The ASIO representation of the TCP endpoint.
  88. TCPEndpoint(const tcp::endpoint& asio_endpoint) :
  89. asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint)
  90. {}
  91. /// \brief The destructor.
  92. ~TCPEndpoint() { delete asio_endpoint_placeholder_; }
  93. //@}
  94. virtual IOAddress getAddress() const {
  95. return (asio_endpoint_.address());
  96. }
  97. private:
  98. const tcp::endpoint* asio_endpoint_placeholder_;
  99. const tcp::endpoint& asio_endpoint_;
  100. };
  101. /// \brief The \c UDPEndpoint class is a concrete derived class of
  102. /// \c IOEndpoint that represents an endpoint of a UDP packet.
  103. ///
  104. /// Other notes about \c TCPEndpoint applies to this class, too.
  105. class UDPEndpoint : public IOEndpoint {
  106. public:
  107. ///
  108. /// \name Constructors and Destructor.
  109. ///
  110. //@{
  111. /// \brief Constructor from a pair of address and port.
  112. ///
  113. /// \param address The IP address of the endpoint.
  114. /// \param port The UDP port number of the endpoint.
  115. UDPEndpoint(const IOAddress& address, const unsigned short port) :
  116. asio_endpoint_placeholder_(
  117. new udp::endpoint(ip::address::from_string(address.toText()),
  118. port)),
  119. asio_endpoint_(*asio_endpoint_placeholder_)
  120. {}
  121. /// \brief Constructor from an ASIO UDP endpoint.
  122. ///
  123. /// This constructor is designed to be an efficient wrapper for the
  124. /// corresponding ASIO class, \c udp::endpoint.
  125. ///
  126. /// \param asio_endpoint The ASIO representation of the UDP endpoint.
  127. UDPEndpoint(const udp::endpoint& asio_endpoint) :
  128. asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint)
  129. {}
  130. /// \brief The destructor.
  131. ~UDPEndpoint() { delete asio_endpoint_placeholder_; }
  132. //@}
  133. virtual IOAddress getAddress() const {
  134. return (asio_endpoint_.address());
  135. }
  136. private:
  137. const udp::endpoint* asio_endpoint_placeholder_;
  138. const udp::endpoint& asio_endpoint_;
  139. };
  140. const IOEndpoint*
  141. IOEndpoint::create(const int protocol, const IOAddress& address,
  142. const unsigned short port)
  143. {
  144. if (protocol == IPPROTO_UDP) {
  145. return (new UDPEndpoint(address, port));
  146. } else if (protocol == IPPROTO_TCP) {
  147. return (new TCPEndpoint(address, port));
  148. }
  149. isc_throw(IOError,
  150. "IOEndpoint creation attempt for unsupported protocol: " <<
  151. protocol);
  152. }
  153. /// \brief The \c TCPSocket class is a concrete derived class of
  154. /// \c IOSocket that represents a TCP socket.
  155. ///
  156. /// In the current implementation, an object of this class is always
  157. /// instantiated within the wrapper routines. Applications are expected to
  158. /// get access to the object via the abstract base class, \c IOSocket.
  159. /// This design may be changed when we generalize the wrapper interface.
  160. class TCPSocket : public IOSocket {
  161. private:
  162. TCPSocket(const TCPSocket& source);
  163. TCPSocket& operator=(const TCPSocket& source);
  164. public:
  165. /// \brief Constructor from an ASIO TCP socket.
  166. ///
  167. /// \param socket The ASIO representation of the TCP socket.
  168. TCPSocket(tcp::socket& socket) : socket_(socket) {}
  169. virtual int getNative() const { return (socket_.native()); }
  170. virtual int getProtocol() const { return (IPPROTO_TCP); }
  171. private:
  172. tcp::socket& socket_;
  173. };
  174. /// \brief The \c UDPSocket class is a concrete derived class of
  175. /// \c IOSocket that represents a UDP socket.
  176. ///
  177. /// Other notes about \c TCPSocket applies to this class, too.
  178. class UDPSocket : public IOSocket {
  179. private:
  180. UDPSocket(const UDPSocket& source);
  181. UDPSocket& operator=(const UDPSocket& source);
  182. public:
  183. /// \brief Constructor from an ASIO UDP socket.
  184. ///
  185. /// \param socket The ASIO representation of the UDP socket.
  186. UDPSocket(udp::socket& socket) : socket_(socket) {}
  187. virtual int getNative() const { return (socket_.native()); }
  188. virtual int getProtocol() const { return (IPPROTO_UDP); }
  189. private:
  190. udp::socket& socket_;
  191. };
  192. /// \brief The \c DummySocket class is a concrete derived class of
  193. /// \c IOSocket that is not associated with any real socket.
  194. ///
  195. /// This main purpose of this class is tests, where it may be desirable to
  196. /// instantiate an \c IOSocket object without involving system resource
  197. /// allocation such as real network sockets.
  198. class DummySocket : public IOSocket {
  199. private:
  200. DummySocket(const DummySocket& source);
  201. DummySocket& operator=(const DummySocket& source);
  202. public:
  203. /// \brief Constructor from the protocol number.
  204. ///
  205. /// The protocol must validly identify a standard network protocol.
  206. /// For example, to specify TCP \c protocol must be \c IPPROTO_TCP.
  207. ///
  208. /// \param protocol The network protocol number for the socket.
  209. DummySocket(const int protocol) : protocol_(protocol) {}
  210. /// \brief A dummy derived method of \c IOSocket::getNative().
  211. ///
  212. /// This version of method always returns -1 as the object is not
  213. /// associated with a real (native) socket.
  214. virtual int getNative() const { return (-1); }
  215. virtual int getProtocol() const { return (protocol_); }
  216. private:
  217. const int protocol_;
  218. };
  219. IOSocket&
  220. IOSocket::getDummyUDPSocket() {
  221. static DummySocket socket(IPPROTO_UDP);
  222. return (socket);
  223. }
  224. IOSocket&
  225. IOSocket::getDummyTCPSocket() {
  226. static DummySocket socket(IPPROTO_TCP);
  227. return (socket);
  228. }
  229. IOMessage::IOMessage(const void* data, const size_t data_size,
  230. IOSocket& io_socket, const IOEndpoint& remote_endpoint) :
  231. data_(data), data_size_(data_size), io_socket_(io_socket),
  232. remote_endpoint_(remote_endpoint)
  233. {}
  234. //
  235. // Helper classes for asynchronous I/O using asio
  236. //
  237. class TCPClient {
  238. public:
  239. TCPClient(AuthSrv* auth_server, io_service& io_service) :
  240. auth_server_(auth_server),
  241. socket_(io_service),
  242. io_socket_(socket_),
  243. response_buffer_(0),
  244. responselen_buffer_(TCP_MESSAGE_LENGTHSIZE),
  245. response_renderer_(response_buffer_),
  246. dns_message_(Message::PARSE),
  247. custom_callback_(NULL)
  248. {}
  249. void start() {
  250. // Check for queued configuration commands
  251. if (auth_server_ != NULL &&
  252. auth_server_->getConfigSession()->hasQueuedMsgs()) {
  253. auth_server_->getConfigSession()->checkCommand();
  254. }
  255. async_read(socket_, asio::buffer(data_, TCP_MESSAGE_LENGTHSIZE),
  256. boost::bind(&TCPClient::headerRead, this,
  257. placeholders::error,
  258. placeholders::bytes_transferred));
  259. }
  260. tcp::socket& getSocket() { return (socket_); }
  261. void headerRead(const asio::error_code& error,
  262. size_t bytes_transferred)
  263. {
  264. if (!error) {
  265. InputBuffer dnsbuffer(data_, bytes_transferred);
  266. uint16_t msglen = dnsbuffer.readUint16();
  267. async_read(socket_, asio::buffer(data_, msglen),
  268. boost::bind(&TCPClient::requestRead, this,
  269. placeholders::error,
  270. placeholders::bytes_transferred));
  271. } else {
  272. delete this;
  273. }
  274. }
  275. void requestRead(const asio::error_code& error,
  276. size_t bytes_transferred)
  277. {
  278. if (!error) {
  279. const TCPEndpoint remote_endpoint(socket_.remote_endpoint());
  280. const IOMessage io_message(data_, bytes_transferred, io_socket_,
  281. remote_endpoint);
  282. // currently, for testing purpose only
  283. if (custom_callback_ != NULL) {
  284. (*custom_callback_)(io_message);
  285. start();
  286. return;
  287. }
  288. if (auth_server_->processMessage(io_message, dns_message_,
  289. response_renderer_)) {
  290. responselen_buffer_.writeUint16(
  291. response_buffer_.getLength());
  292. async_write(socket_,
  293. asio::buffer(
  294. responselen_buffer_.getData(),
  295. responselen_buffer_.getLength()),
  296. boost::bind(&TCPClient::responseWrite, this,
  297. placeholders::error));
  298. } else {
  299. delete this;
  300. }
  301. } else {
  302. delete this;
  303. }
  304. }
  305. void responseWrite(const asio::error_code& error) {
  306. if (!error) {
  307. async_write(socket_,
  308. asio::buffer(response_buffer_.getData(),
  309. response_buffer_.getLength()),
  310. boost::bind(&TCPClient::handleWrite, this,
  311. placeholders::error));
  312. } else {
  313. delete this;
  314. }
  315. }
  316. void handleWrite(const asio::error_code& error) {
  317. if (!error) {
  318. start(); // handle next request, if any.
  319. } else {
  320. delete this;
  321. }
  322. }
  323. // Currently this is for tests only
  324. void setCallBack(const IOService::IOCallBack* callback) {
  325. custom_callback_ = callback;
  326. }
  327. private:
  328. AuthSrv* auth_server_;
  329. tcp::socket socket_;
  330. TCPSocket io_socket_;
  331. OutputBuffer response_buffer_;
  332. OutputBuffer responselen_buffer_;
  333. MessageRenderer response_renderer_;
  334. Message dns_message_;
  335. enum { MAX_LENGTH = 65535 };
  336. static const size_t TCP_MESSAGE_LENGTHSIZE = 2;
  337. char data_[MAX_LENGTH];
  338. // currently, for testing purpose only.
  339. const IOService::IOCallBack* custom_callback_;
  340. };
  341. class TCPServer {
  342. public:
  343. TCPServer(AuthSrv* auth_server, io_service& io_service,
  344. const ip::address& addr, const uint16_t port) :
  345. auth_server_(auth_server), io_service_(io_service),
  346. acceptor_(io_service_), listening_(new TCPClient(auth_server_,
  347. io_service_)),
  348. custom_callback_(NULL)
  349. {
  350. tcp::endpoint endpoint(addr, port);
  351. acceptor_.open(endpoint.protocol());
  352. // Set v6-only (we use a different instantiation for v4,
  353. // otherwise asio will bind to both v4 and v6
  354. if (addr.is_v6()) {
  355. acceptor_.set_option(ip::v6_only(true));
  356. }
  357. acceptor_.set_option(tcp::acceptor::reuse_address(true));
  358. acceptor_.bind(endpoint);
  359. acceptor_.listen();
  360. acceptor_.async_accept(listening_->getSocket(),
  361. boost::bind(&TCPServer::handleAccept, this,
  362. listening_, placeholders::error));
  363. }
  364. ~TCPServer() { delete listening_; }
  365. void handleAccept(TCPClient* new_client,
  366. const asio::error_code& error)
  367. {
  368. if (!error) {
  369. assert(new_client == listening_);
  370. new_client->setCallBack(custom_callback_);
  371. new_client->start();
  372. listening_ = new TCPClient(auth_server_, io_service_);
  373. acceptor_.async_accept(listening_->getSocket(),
  374. boost::bind(&TCPServer::handleAccept,
  375. this, listening_,
  376. placeholders::error));
  377. } else {
  378. delete new_client;
  379. }
  380. }
  381. // Currently this is for tests only
  382. void setCallBack(const IOService::IOCallBack* callback) {
  383. custom_callback_ = callback;
  384. }
  385. private:
  386. AuthSrv* auth_server_;
  387. io_service& io_service_;
  388. tcp::acceptor acceptor_;
  389. TCPClient* listening_;
  390. // currently, for testing purpose only.
  391. const IOService::IOCallBack* custom_callback_;
  392. };
  393. class UDPServer {
  394. public:
  395. UDPServer(AuthSrv* auth_server, io_service& io_service,
  396. const ip::address& addr, const uint16_t port) :
  397. auth_server_(auth_server),
  398. io_service_(io_service),
  399. socket_(io_service, addr.is_v6() ? udp::v6() : udp::v4()),
  400. io_socket_(socket_),
  401. response_buffer_(0),
  402. response_renderer_(response_buffer_),
  403. dns_message_(Message::PARSE),
  404. custom_callback_(NULL)
  405. {
  406. socket_.set_option(socket_base::reuse_address(true));
  407. // Set v6-only (we use a different instantiation for v4,
  408. // otherwise asio will bind to both v4 and v6
  409. if (addr.is_v6()) {
  410. socket_.set_option(asio::ip::v6_only(true));
  411. socket_.bind(udp::endpoint(addr, port));
  412. } else {
  413. socket_.bind(udp::endpoint(addr, port));
  414. }
  415. startReceive();
  416. }
  417. void handleRequest(const asio::error_code& error,
  418. size_t bytes_recvd)
  419. {
  420. // Check for queued configuration commands
  421. if (auth_server_ != NULL &&
  422. auth_server_->getConfigSession()->hasQueuedMsgs()) {
  423. auth_server_->getConfigSession()->checkCommand();
  424. }
  425. if (!error && bytes_recvd > 0) {
  426. const UDPEndpoint remote_endpoint(sender_endpoint_);
  427. const IOMessage io_message(data_, bytes_recvd, io_socket_,
  428. remote_endpoint);
  429. // currently, for testing purpose only
  430. if (custom_callback_ != NULL) {
  431. (*custom_callback_)(io_message);
  432. startReceive();
  433. return;
  434. }
  435. dns_message_.clear(Message::PARSE);
  436. response_renderer_.clear();
  437. if (auth_server_->processMessage(io_message, dns_message_,
  438. response_renderer_)) {
  439. socket_.async_send_to(
  440. asio::buffer(response_buffer_.getData(),
  441. response_buffer_.getLength()),
  442. sender_endpoint_,
  443. boost::bind(&UDPServer::sendCompleted,
  444. this,
  445. placeholders::error,
  446. placeholders::bytes_transferred));
  447. } else {
  448. startReceive();
  449. }
  450. } else {
  451. startReceive();
  452. }
  453. }
  454. void sendCompleted(const asio::error_code&, size_t) {
  455. // Even if error occurred there's nothing to do. Simply handle
  456. // the next request.
  457. startReceive();
  458. }
  459. // Currently this is for tests only
  460. void setCallBack(const IOService::IOCallBack* callback) {
  461. custom_callback_ = callback;
  462. }
  463. private:
  464. void startReceive() {
  465. socket_.async_receive_from(
  466. asio::buffer(data_, MAX_LENGTH), sender_endpoint_,
  467. boost::bind(&UDPServer::handleRequest, this,
  468. placeholders::error,
  469. placeholders::bytes_transferred));
  470. }
  471. private:
  472. AuthSrv* auth_server_;
  473. io_service& io_service_;
  474. udp::socket socket_;
  475. UDPSocket io_socket_;
  476. OutputBuffer response_buffer_;
  477. MessageRenderer response_renderer_;
  478. Message dns_message_;
  479. udp::endpoint sender_endpoint_;
  480. enum { MAX_LENGTH = 4096 };
  481. char data_[MAX_LENGTH];
  482. // currently, for testing purpose only.
  483. const IOService::IOCallBack* custom_callback_;
  484. };
  485. class IOServiceImpl {
  486. public:
  487. IOServiceImpl(AuthSrv* auth_server, const char& port,
  488. const ip::address* v4addr, const ip::address* v6addr);
  489. asio::io_service io_service_;
  490. AuthSrv* auth_server_;
  491. typedef boost::shared_ptr<UDPServer> UDPServerPtr;
  492. typedef boost::shared_ptr<TCPServer> TCPServerPtr;
  493. UDPServerPtr udp4_server_;
  494. UDPServerPtr udp6_server_;
  495. TCPServerPtr tcp4_server_;
  496. TCPServerPtr tcp6_server_;
  497. // This member is used only for testing at the moment.
  498. IOService::IOCallBack callback_;
  499. };
  500. IOServiceImpl::IOServiceImpl(AuthSrv* auth_server, const char& port,
  501. const ip::address* const v4addr,
  502. const ip::address* const v6addr) :
  503. auth_server_(auth_server),
  504. udp4_server_(UDPServerPtr()), udp6_server_(UDPServerPtr()),
  505. tcp4_server_(TCPServerPtr()), tcp6_server_(TCPServerPtr())
  506. {
  507. uint16_t portnum;
  508. try {
  509. // XXX: SunStudio with stlport4 doesn't reject some invalid
  510. // representation such as "-1" by lexical_cast<uint16_t>, so
  511. // we convert it into a signed integer of a larger size and perform
  512. // range check ourselves.
  513. const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
  514. if (portnum32 < 0 || portnum32 > 65535) {
  515. isc_throw(IOError, "Invalid port number '" << &port);
  516. }
  517. portnum = portnum32;
  518. } catch (const boost::bad_lexical_cast& ex) {
  519. isc_throw(IOError, "Invalid port number '" << &port << "': " <<
  520. ex.what());
  521. }
  522. try {
  523. if (v4addr != NULL) {
  524. udp4_server_ = UDPServerPtr(new UDPServer(auth_server, io_service_,
  525. *v4addr, portnum));
  526. tcp4_server_ = TCPServerPtr(new TCPServer(auth_server, io_service_,
  527. *v4addr, portnum));
  528. }
  529. if (v6addr != NULL) {
  530. udp6_server_ = UDPServerPtr(new UDPServer(auth_server, io_service_,
  531. *v6addr, portnum));
  532. tcp6_server_ = TCPServerPtr(new TCPServer(auth_server, io_service_,
  533. *v6addr, portnum));
  534. }
  535. } catch (const asio::system_error& err) {
  536. // We need to catch and convert any ASIO level exceptions.
  537. // This can happen for unavailable address, binding a privilege port
  538. // without the privilege, etc.
  539. isc_throw(IOError, "Failed to initialize network servers: " <<
  540. err.what());
  541. }
  542. }
  543. IOService::IOService(AuthSrv* auth_server, const char& port,
  544. const char& address) :
  545. impl_(NULL)
  546. {
  547. error_code err;
  548. const ip::address addr = ip::address::from_string(&address, err);
  549. if (err) {
  550. isc_throw(IOError, "Invalid IP address '" << &address << "': "
  551. << err.message());
  552. }
  553. impl_ = new IOServiceImpl(auth_server, port,
  554. addr.is_v4() ? &addr : NULL,
  555. addr.is_v6() ? &addr : NULL);
  556. }
  557. IOService::IOService(AuthSrv* auth_server, const char& port,
  558. const bool use_ipv4, const bool use_ipv6) :
  559. impl_(NULL)
  560. {
  561. const ip::address v4addr_any = ip::address(ip::address_v4::any());
  562. const ip::address* const v4addrp = use_ipv4 ? &v4addr_any : NULL;
  563. const ip::address v6addr_any = ip::address(ip::address_v6::any());
  564. const ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
  565. impl_ = new IOServiceImpl(auth_server, port, v4addrp, v6addrp);
  566. }
  567. IOService::~IOService() {
  568. delete impl_;
  569. }
  570. void
  571. IOService::run() {
  572. impl_->io_service_.run();
  573. }
  574. void
  575. IOService::stop() {
  576. impl_->io_service_.stop();
  577. }
  578. asio::io_service&
  579. IOService::get_io_service() {
  580. return (impl_->io_service_);
  581. }
  582. void
  583. IOService::setCallBack(const IOCallBack callback) {
  584. impl_->callback_ = callback;
  585. if (impl_->udp4_server_ != NULL) {
  586. impl_->udp4_server_->setCallBack(&impl_->callback_);
  587. }
  588. if (impl_->udp6_server_ != NULL) {
  589. impl_->udp6_server_->setCallBack(&impl_->callback_);
  590. }
  591. if (impl_->tcp4_server_ != NULL) {
  592. impl_->tcp4_server_->setCallBack(&impl_->callback_);
  593. }
  594. if (impl_->tcp6_server_ != NULL) {
  595. impl_->tcp6_server_->setCallBack(&impl_->callback_);
  596. }
  597. }
  598. }