/src/contrib/boost/asio/detail/socket_select_interrupter.hpp

http://pythonocc.googlecode.com/ · C++ Header · 194 lines · 141 code · 29 blank · 24 comment · 23 complexity · 8010d075b43080f0f5878517056c33ce MD5 · raw file

  1. //
  2. // socket_select_interrupter.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
  11. #define BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/push_options.hpp>
  16. #include <boost/asio/detail/push_options.hpp>
  17. #include <cstdlib>
  18. #include <boost/throw_exception.hpp>
  19. #include <boost/system/system_error.hpp>
  20. #include <boost/asio/detail/pop_options.hpp>
  21. #include <boost/asio/error.hpp>
  22. #include <boost/asio/detail/socket_holder.hpp>
  23. #include <boost/asio/detail/socket_ops.hpp>
  24. #include <boost/asio/detail/socket_types.hpp>
  25. namespace boost {
  26. namespace asio {
  27. namespace detail {
  28. class socket_select_interrupter
  29. {
  30. public:
  31. // Constructor.
  32. socket_select_interrupter()
  33. {
  34. boost::system::error_code ec;
  35. socket_holder acceptor(socket_ops::socket(
  36. AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
  37. if (acceptor.get() == invalid_socket)
  38. {
  39. boost::system::system_error e(ec, "socket_select_interrupter");
  40. boost::throw_exception(e);
  41. }
  42. int opt = 1;
  43. socket_ops::setsockopt(acceptor.get(),
  44. SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
  45. using namespace std; // For memset.
  46. sockaddr_in4_type addr;
  47. std::size_t addr_len = sizeof(addr);
  48. memset(&addr, 0, sizeof(addr));
  49. addr.sin_family = AF_INET;
  50. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  51. addr.sin_port = 0;
  52. if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
  53. addr_len, ec) == socket_error_retval)
  54. {
  55. boost::system::system_error e(ec, "socket_select_interrupter");
  56. boost::throw_exception(e);
  57. }
  58. if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
  59. &addr_len, ec) == socket_error_retval)
  60. {
  61. boost::system::system_error e(ec, "socket_select_interrupter");
  62. boost::throw_exception(e);
  63. }
  64. // Some broken firewalls on Windows will intermittently cause getsockname to
  65. // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
  66. // explicitly specify the target address here to work around this problem.
  67. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  68. if (socket_ops::listen(acceptor.get(),
  69. SOMAXCONN, ec) == socket_error_retval)
  70. {
  71. boost::system::system_error e(ec, "socket_select_interrupter");
  72. boost::throw_exception(e);
  73. }
  74. socket_holder client(socket_ops::socket(
  75. AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
  76. if (client.get() == invalid_socket)
  77. {
  78. boost::system::system_error e(ec, "socket_select_interrupter");
  79. boost::throw_exception(e);
  80. }
  81. if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
  82. addr_len, ec) == socket_error_retval)
  83. {
  84. boost::system::system_error e(ec, "socket_select_interrupter");
  85. boost::throw_exception(e);
  86. }
  87. socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
  88. if (server.get() == invalid_socket)
  89. {
  90. boost::system::system_error e(ec, "socket_select_interrupter");
  91. boost::throw_exception(e);
  92. }
  93. ioctl_arg_type non_blocking = 1;
  94. if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
  95. {
  96. boost::system::system_error e(ec, "socket_select_interrupter");
  97. boost::throw_exception(e);
  98. }
  99. opt = 1;
  100. socket_ops::setsockopt(client.get(),
  101. IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
  102. non_blocking = 1;
  103. if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
  104. {
  105. boost::system::system_error e(ec, "socket_select_interrupter");
  106. boost::throw_exception(e);
  107. }
  108. opt = 1;
  109. socket_ops::setsockopt(server.get(),
  110. IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
  111. read_descriptor_ = server.release();
  112. write_descriptor_ = client.release();
  113. }
  114. // Destructor.
  115. ~socket_select_interrupter()
  116. {
  117. boost::system::error_code ec;
  118. if (read_descriptor_ != invalid_socket)
  119. socket_ops::close(read_descriptor_, ec);
  120. if (write_descriptor_ != invalid_socket)
  121. socket_ops::close(write_descriptor_, ec);
  122. }
  123. // Interrupt the select call.
  124. void interrupt()
  125. {
  126. char byte = 0;
  127. socket_ops::buf b;
  128. socket_ops::init_buf(b, &byte, 1);
  129. boost::system::error_code ec;
  130. socket_ops::send(write_descriptor_, &b, 1, 0, ec);
  131. }
  132. // Reset the select interrupt. Returns true if the call was interrupted.
  133. bool reset()
  134. {
  135. char data[1024];
  136. socket_ops::buf b;
  137. socket_ops::init_buf(b, data, sizeof(data));
  138. boost::system::error_code ec;
  139. int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
  140. bool was_interrupted = (bytes_read > 0);
  141. while (bytes_read == sizeof(data))
  142. bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
  143. return was_interrupted;
  144. }
  145. // Get the read descriptor to be passed to select.
  146. socket_type read_descriptor() const
  147. {
  148. return read_descriptor_;
  149. }
  150. private:
  151. // The read end of a connection used to interrupt the select call. This file
  152. // descriptor is passed to select such that when it is time to stop, a single
  153. // byte will be written on the other end of the connection and this
  154. // descriptor will become readable.
  155. socket_type read_descriptor_;
  156. // The write end of a connection used to interrupt the select call. A single
  157. // byte may be written to this to wake up the select which is waiting for the
  158. // other end to become readable.
  159. socket_type write_descriptor_;
  160. };
  161. } // namespace detail
  162. } // namespace asio
  163. } // namespace boost
  164. #include <boost/asio/detail/pop_options.hpp>
  165. #endif // BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP