00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
00012 #define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
00013
00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
00015 # pragma once
00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
00017
00018 #include "asio/detail/push_options.hpp"
00019
00020 #include "asio/detail/push_options.hpp"
00021 #include <cstdlib>
00022 #include <boost/throw_exception.hpp>
00023 #include "asio/detail/pop_options.hpp"
00024
00025 #include "asio/error.hpp"
00026 #include "asio/system_error.hpp"
00027 #include "asio/detail/socket_holder.hpp"
00028 #include "asio/detail/socket_ops.hpp"
00029 #include "asio/detail/socket_types.hpp"
00030
00031 namespace asio {
00032 namespace detail {
00033
00034 class socket_select_interrupter
00035 {
00036 public:
00037
00038 socket_select_interrupter()
00039 {
00040 asio::error_code ec;
00041 socket_holder acceptor(socket_ops::socket(
00042 AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
00043 if (acceptor.get() == invalid_socket)
00044 {
00045 asio::system_error e(ec, "socket_select_interrupter");
00046 boost::throw_exception(e);
00047 }
00048
00049 int opt = 1;
00050 socket_ops::setsockopt(acceptor.get(),
00051 SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
00052
00053 using namespace std;
00054 sockaddr_in4_type addr;
00055 std::size_t addr_len = sizeof(addr);
00056 memset(&addr, 0, sizeof(addr));
00057 addr.sin_family = AF_INET;
00058 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
00059 addr.sin_port = 0;
00060 if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
00061 addr_len, ec) == socket_error_retval)
00062 {
00063 asio::system_error e(ec, "socket_select_interrupter");
00064 boost::throw_exception(e);
00065 }
00066
00067 if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
00068 &addr_len, ec) == socket_error_retval)
00069 {
00070 asio::system_error e(ec, "socket_select_interrupter");
00071 boost::throw_exception(e);
00072 }
00073
00074 if (socket_ops::listen(acceptor.get(),
00075 SOMAXCONN, ec) == socket_error_retval)
00076 {
00077 asio::system_error e(ec, "socket_select_interrupter");
00078 boost::throw_exception(e);
00079 }
00080
00081 socket_holder client(socket_ops::socket(
00082 AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
00083 if (client.get() == invalid_socket)
00084 {
00085 asio::system_error e(ec, "socket_select_interrupter");
00086 boost::throw_exception(e);
00087 }
00088
00089 if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
00090 addr_len, ec) == socket_error_retval)
00091 {
00092 asio::system_error e(ec, "socket_select_interrupter");
00093 boost::throw_exception(e);
00094 }
00095
00096 socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
00097 if (server.get() == invalid_socket)
00098 {
00099 asio::system_error e(ec, "socket_select_interrupter");
00100 boost::throw_exception(e);
00101 }
00102
00103 ioctl_arg_type non_blocking = 1;
00104 if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
00105 {
00106 asio::system_error e(ec, "socket_select_interrupter");
00107 boost::throw_exception(e);
00108 }
00109
00110 opt = 1;
00111 socket_ops::setsockopt(client.get(),
00112 IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
00113
00114 non_blocking = 1;
00115 if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
00116 {
00117 asio::system_error e(ec, "socket_select_interrupter");
00118 boost::throw_exception(e);
00119 }
00120
00121 opt = 1;
00122 socket_ops::setsockopt(server.get(),
00123 IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
00124
00125 read_descriptor_ = server.release();
00126 write_descriptor_ = client.release();
00127 }
00128
00129
00130 ~socket_select_interrupter()
00131 {
00132 asio::error_code ec;
00133 if (read_descriptor_ != invalid_socket)
00134 socket_ops::close(read_descriptor_, ec);
00135 if (write_descriptor_ != invalid_socket)
00136 socket_ops::close(write_descriptor_, ec);
00137 }
00138
00139
00140 void interrupt()
00141 {
00142 char byte = 0;
00143 socket_ops::buf b;
00144 socket_ops::init_buf(b, &byte, 1);
00145 asio::error_code ec;
00146 socket_ops::send(write_descriptor_, &b, 1, 0, ec);
00147 }
00148
00149
00150 bool reset()
00151 {
00152 char data[1024];
00153 socket_ops::buf b;
00154 socket_ops::init_buf(b, data, sizeof(data));
00155 asio::error_code ec;
00156 int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
00157 bool was_interrupted = (bytes_read > 0);
00158 while (bytes_read == sizeof(data))
00159 bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
00160 return was_interrupted;
00161 }
00162
00163
00164 socket_type read_descriptor() const
00165 {
00166 return read_descriptor_;
00167 }
00168
00169 private:
00170
00171
00172
00173
00174 socket_type read_descriptor_;
00175
00176
00177
00178
00179 socket_type write_descriptor_;
00180 };
00181
00182 }
00183 }
00184
00185 #include "asio/detail/pop_options.hpp"
00186
00187 #endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP