/Src/Dependencies/Boost/boost/asio/detail/impl/socket_select_interrupter.ipp

http://hadesmem.googlecode.com/ · C++ Header · 173 lines · 126 code · 33 blank · 14 comment · 25 complexity · dc73f2236e8859891b5f7ef01da4effe MD5 · raw file

  1. //
  2. // detail/impl/socket_select_interrupter.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2011 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_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
  11. #define BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #if defined(BOOST_WINDOWS) \
  17. || defined(__CYGWIN__) \
  18. || defined(__SYMBIAN32__)
  19. #include <cstdlib>
  20. #include <boost/asio/detail/socket_holder.hpp>
  21. #include <boost/asio/detail/socket_ops.hpp>
  22. #include <boost/asio/detail/socket_select_interrupter.hpp>
  23. #include <boost/asio/detail/throw_error.hpp>
  24. #include <boost/asio/error.hpp>
  25. #include <boost/asio/detail/push_options.hpp>
  26. namespace boost {
  27. namespace asio {
  28. namespace detail {
  29. socket_select_interrupter::socket_select_interrupter()
  30. {
  31. open_descriptors();
  32. }
  33. void socket_select_interrupter::open_descriptors()
  34. {
  35. boost::system::error_code ec;
  36. socket_holder acceptor(socket_ops::socket(
  37. AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
  38. if (acceptor.get() == invalid_socket)
  39. boost::asio::detail::throw_error(ec, "socket_select_interrupter");
  40. int opt = 1;
  41. socket_ops::state_type acceptor_state = 0;
  42. socket_ops::setsockopt(acceptor.get(), acceptor_state,
  43. SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
  44. using namespace std; // For memset.
  45. sockaddr_in4_type addr;
  46. std::size_t addr_len = sizeof(addr);
  47. memset(&addr, 0, sizeof(addr));
  48. addr.sin_family = AF_INET;
  49. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  50. addr.sin_port = 0;
  51. if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
  52. addr_len, ec) == socket_error_retval)
  53. boost::asio::detail::throw_error(ec, "socket_select_interrupter");
  54. if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
  55. &addr_len, ec) == socket_error_retval)
  56. boost::asio::detail::throw_error(ec, "socket_select_interrupter");
  57. // Some broken firewalls on Windows will intermittently cause getsockname to
  58. // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
  59. // explicitly specify the target address here to work around this problem.
  60. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  61. if (socket_ops::listen(acceptor.get(),
  62. SOMAXCONN, ec) == socket_error_retval)
  63. boost::asio::detail::throw_error(ec, "socket_select_interrupter");
  64. socket_holder client(socket_ops::socket(
  65. AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
  66. if (client.get() == invalid_socket)
  67. boost::asio::detail::throw_error(ec, "socket_select_interrupter");
  68. if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
  69. addr_len, ec) == socket_error_retval)
  70. boost::asio::detail::throw_error(ec, "socket_select_interrupter");
  71. socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
  72. if (server.get() == invalid_socket)
  73. boost::asio::detail::throw_error(ec, "socket_select_interrupter");
  74. ioctl_arg_type non_blocking = 1;
  75. socket_ops::state_type client_state = 0;
  76. if (socket_ops::ioctl(client.get(), client_state,
  77. FIONBIO, &non_blocking, ec))
  78. boost::asio::detail::throw_error(ec, "socket_select_interrupter");
  79. opt = 1;
  80. socket_ops::setsockopt(client.get(), client_state,
  81. IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
  82. non_blocking = 1;
  83. socket_ops::state_type server_state = 0;
  84. if (socket_ops::ioctl(server.get(), server_state,
  85. FIONBIO, &non_blocking, ec))
  86. boost::asio::detail::throw_error(ec, "socket_select_interrupter");
  87. opt = 1;
  88. socket_ops::setsockopt(server.get(), server_state,
  89. IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
  90. read_descriptor_ = server.release();
  91. write_descriptor_ = client.release();
  92. }
  93. socket_select_interrupter::~socket_select_interrupter()
  94. {
  95. close_descriptors();
  96. }
  97. void socket_select_interrupter::close_descriptors()
  98. {
  99. boost::system::error_code ec;
  100. socket_ops::state_type state = socket_ops::internal_non_blocking;
  101. if (read_descriptor_ != invalid_socket)
  102. socket_ops::close(read_descriptor_, state, true, ec);
  103. if (write_descriptor_ != invalid_socket)
  104. socket_ops::close(write_descriptor_, state, true, ec);
  105. }
  106. void socket_select_interrupter::recreate()
  107. {
  108. close_descriptors();
  109. write_descriptor_ = invalid_socket;
  110. read_descriptor_ = invalid_socket;
  111. open_descriptors();
  112. }
  113. void socket_select_interrupter::interrupt()
  114. {
  115. char byte = 0;
  116. socket_ops::buf b;
  117. socket_ops::init_buf(b, &byte, 1);
  118. boost::system::error_code ec;
  119. socket_ops::send(write_descriptor_, &b, 1, 0, ec);
  120. }
  121. bool socket_select_interrupter::reset()
  122. {
  123. char data[1024];
  124. socket_ops::buf b;
  125. socket_ops::init_buf(b, data, sizeof(data));
  126. boost::system::error_code ec;
  127. int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
  128. bool was_interrupted = (bytes_read > 0);
  129. while (bytes_read == sizeof(data))
  130. bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
  131. return was_interrupted;
  132. }
  133. } // namespace detail
  134. } // namespace asio
  135. } // namespace boost
  136. #include <boost/asio/detail/pop_options.hpp>
  137. #endif // defined(BOOST_WINDOWS)
  138. // || defined(__CYGWIN__)
  139. // || defined(__SYMBIAN32__)
  140. #endif // BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP