Chris@16
|
1 //
|
Chris@16
|
2 // detail/impl/socket_select_interrupter.ipp
|
Chris@16
|
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
Chris@16
|
4 //
|
Chris@101
|
5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
Chris@16
|
6 //
|
Chris@16
|
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
|
Chris@16
|
12 #define BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
|
Chris@16
|
13
|
Chris@16
|
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
15 # pragma once
|
Chris@16
|
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/asio/detail/config.hpp>
|
Chris@16
|
19
|
Chris@16
|
20 #if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
21
|
Chris@16
|
22 #if defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
23 || defined(__CYGWIN__) \
|
Chris@16
|
24 || defined(__SYMBIAN32__)
|
Chris@16
|
25
|
Chris@16
|
26 #include <cstdlib>
|
Chris@16
|
27 #include <boost/asio/detail/socket_holder.hpp>
|
Chris@16
|
28 #include <boost/asio/detail/socket_ops.hpp>
|
Chris@16
|
29 #include <boost/asio/detail/socket_select_interrupter.hpp>
|
Chris@16
|
30 #include <boost/asio/detail/throw_error.hpp>
|
Chris@16
|
31 #include <boost/asio/error.hpp>
|
Chris@16
|
32
|
Chris@16
|
33 #include <boost/asio/detail/push_options.hpp>
|
Chris@16
|
34
|
Chris@16
|
35 namespace boost {
|
Chris@16
|
36 namespace asio {
|
Chris@16
|
37 namespace detail {
|
Chris@16
|
38
|
Chris@16
|
39 socket_select_interrupter::socket_select_interrupter()
|
Chris@16
|
40 {
|
Chris@16
|
41 open_descriptors();
|
Chris@16
|
42 }
|
Chris@16
|
43
|
Chris@16
|
44 void socket_select_interrupter::open_descriptors()
|
Chris@16
|
45 {
|
Chris@16
|
46 boost::system::error_code ec;
|
Chris@16
|
47 socket_holder acceptor(socket_ops::socket(
|
Chris@16
|
48 AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
|
Chris@16
|
49 if (acceptor.get() == invalid_socket)
|
Chris@16
|
50 boost::asio::detail::throw_error(ec, "socket_select_interrupter");
|
Chris@16
|
51
|
Chris@16
|
52 int opt = 1;
|
Chris@16
|
53 socket_ops::state_type acceptor_state = 0;
|
Chris@16
|
54 socket_ops::setsockopt(acceptor.get(), acceptor_state,
|
Chris@16
|
55 SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
|
Chris@16
|
56
|
Chris@16
|
57 using namespace std; // For memset.
|
Chris@16
|
58 sockaddr_in4_type addr;
|
Chris@16
|
59 std::size_t addr_len = sizeof(addr);
|
Chris@16
|
60 memset(&addr, 0, sizeof(addr));
|
Chris@16
|
61 addr.sin_family = AF_INET;
|
Chris@101
|
62 addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
|
Chris@16
|
63 addr.sin_port = 0;
|
Chris@16
|
64 if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
|
Chris@16
|
65 addr_len, ec) == socket_error_retval)
|
Chris@16
|
66 boost::asio::detail::throw_error(ec, "socket_select_interrupter");
|
Chris@16
|
67
|
Chris@16
|
68 if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
|
Chris@16
|
69 &addr_len, ec) == socket_error_retval)
|
Chris@16
|
70 boost::asio::detail::throw_error(ec, "socket_select_interrupter");
|
Chris@16
|
71
|
Chris@16
|
72 // Some broken firewalls on Windows will intermittently cause getsockname to
|
Chris@16
|
73 // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
|
Chris@16
|
74 // explicitly specify the target address here to work around this problem.
|
Chris@101
|
75 addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
|
Chris@16
|
76
|
Chris@16
|
77 if (socket_ops::listen(acceptor.get(),
|
Chris@16
|
78 SOMAXCONN, ec) == socket_error_retval)
|
Chris@16
|
79 boost::asio::detail::throw_error(ec, "socket_select_interrupter");
|
Chris@16
|
80
|
Chris@16
|
81 socket_holder client(socket_ops::socket(
|
Chris@16
|
82 AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
|
Chris@16
|
83 if (client.get() == invalid_socket)
|
Chris@16
|
84 boost::asio::detail::throw_error(ec, "socket_select_interrupter");
|
Chris@16
|
85
|
Chris@16
|
86 if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
|
Chris@16
|
87 addr_len, ec) == socket_error_retval)
|
Chris@16
|
88 boost::asio::detail::throw_error(ec, "socket_select_interrupter");
|
Chris@16
|
89
|
Chris@16
|
90 socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
|
Chris@16
|
91 if (server.get() == invalid_socket)
|
Chris@16
|
92 boost::asio::detail::throw_error(ec, "socket_select_interrupter");
|
Chris@16
|
93
|
Chris@16
|
94 ioctl_arg_type non_blocking = 1;
|
Chris@16
|
95 socket_ops::state_type client_state = 0;
|
Chris@16
|
96 if (socket_ops::ioctl(client.get(), client_state,
|
Chris@16
|
97 FIONBIO, &non_blocking, ec))
|
Chris@16
|
98 boost::asio::detail::throw_error(ec, "socket_select_interrupter");
|
Chris@16
|
99
|
Chris@16
|
100 opt = 1;
|
Chris@16
|
101 socket_ops::setsockopt(client.get(), client_state,
|
Chris@16
|
102 IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
|
Chris@16
|
103
|
Chris@16
|
104 non_blocking = 1;
|
Chris@16
|
105 socket_ops::state_type server_state = 0;
|
Chris@16
|
106 if (socket_ops::ioctl(server.get(), server_state,
|
Chris@16
|
107 FIONBIO, &non_blocking, ec))
|
Chris@16
|
108 boost::asio::detail::throw_error(ec, "socket_select_interrupter");
|
Chris@16
|
109
|
Chris@16
|
110 opt = 1;
|
Chris@16
|
111 socket_ops::setsockopt(server.get(), server_state,
|
Chris@16
|
112 IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
|
Chris@16
|
113
|
Chris@16
|
114 read_descriptor_ = server.release();
|
Chris@16
|
115 write_descriptor_ = client.release();
|
Chris@16
|
116 }
|
Chris@16
|
117
|
Chris@16
|
118 socket_select_interrupter::~socket_select_interrupter()
|
Chris@16
|
119 {
|
Chris@16
|
120 close_descriptors();
|
Chris@16
|
121 }
|
Chris@16
|
122
|
Chris@16
|
123 void socket_select_interrupter::close_descriptors()
|
Chris@16
|
124 {
|
Chris@16
|
125 boost::system::error_code ec;
|
Chris@16
|
126 socket_ops::state_type state = socket_ops::internal_non_blocking;
|
Chris@16
|
127 if (read_descriptor_ != invalid_socket)
|
Chris@16
|
128 socket_ops::close(read_descriptor_, state, true, ec);
|
Chris@16
|
129 if (write_descriptor_ != invalid_socket)
|
Chris@16
|
130 socket_ops::close(write_descriptor_, state, true, ec);
|
Chris@16
|
131 }
|
Chris@16
|
132
|
Chris@16
|
133 void socket_select_interrupter::recreate()
|
Chris@16
|
134 {
|
Chris@16
|
135 close_descriptors();
|
Chris@16
|
136
|
Chris@16
|
137 write_descriptor_ = invalid_socket;
|
Chris@16
|
138 read_descriptor_ = invalid_socket;
|
Chris@16
|
139
|
Chris@16
|
140 open_descriptors();
|
Chris@16
|
141 }
|
Chris@16
|
142
|
Chris@16
|
143 void socket_select_interrupter::interrupt()
|
Chris@16
|
144 {
|
Chris@16
|
145 char byte = 0;
|
Chris@16
|
146 socket_ops::buf b;
|
Chris@16
|
147 socket_ops::init_buf(b, &byte, 1);
|
Chris@16
|
148 boost::system::error_code ec;
|
Chris@16
|
149 socket_ops::send(write_descriptor_, &b, 1, 0, ec);
|
Chris@16
|
150 }
|
Chris@16
|
151
|
Chris@16
|
152 bool socket_select_interrupter::reset()
|
Chris@16
|
153 {
|
Chris@16
|
154 char data[1024];
|
Chris@16
|
155 socket_ops::buf b;
|
Chris@16
|
156 socket_ops::init_buf(b, data, sizeof(data));
|
Chris@16
|
157 boost::system::error_code ec;
|
Chris@16
|
158 int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
|
Chris@16
|
159 bool was_interrupted = (bytes_read > 0);
|
Chris@16
|
160 while (bytes_read == sizeof(data))
|
Chris@16
|
161 bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
|
Chris@16
|
162 return was_interrupted;
|
Chris@16
|
163 }
|
Chris@16
|
164
|
Chris@16
|
165 } // namespace detail
|
Chris@16
|
166 } // namespace asio
|
Chris@16
|
167 } // namespace boost
|
Chris@16
|
168
|
Chris@16
|
169 #include <boost/asio/detail/pop_options.hpp>
|
Chris@16
|
170
|
Chris@16
|
171 #endif // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
172 // || defined(__CYGWIN__)
|
Chris@16
|
173 // || defined(__SYMBIAN32__)
|
Chris@16
|
174
|
Chris@16
|
175 #endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
176
|
Chris@16
|
177 #endif // BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
|