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