1 | // |
2 | // impl/connect.hpp |
3 | // ~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2015 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 | |
11 | #ifndef BOOST_ASIO_IMPL_CONNECT_HPP |
12 | #define BOOST_ASIO_IMPL_CONNECT_HPP |
13 | |
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
15 | # pragma once |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
17 | |
18 | #include <boost/asio/detail/bind_handler.hpp> |
19 | #include <boost/asio/detail/consuming_buffers.hpp> |
20 | #include <boost/asio/detail/handler_alloc_helpers.hpp> |
21 | #include <boost/asio/detail/handler_cont_helpers.hpp> |
22 | #include <boost/asio/detail/handler_invoke_helpers.hpp> |
23 | #include <boost/asio/detail/handler_type_requirements.hpp> |
24 | #include <boost/asio/detail/throw_error.hpp> |
25 | #include <boost/asio/error.hpp> |
26 | |
27 | #include <boost/asio/detail/push_options.hpp> |
28 | |
29 | namespace boost { |
30 | namespace asio { |
31 | |
32 | namespace detail |
33 | { |
34 | struct default_connect_condition |
35 | { |
36 | template <typename Iterator> |
37 | Iterator operator()(const boost::system::error_code&, Iterator next) |
38 | { |
39 | return next; |
40 | } |
41 | }; |
42 | } |
43 | |
44 | template <typename Protocol, typename SocketService, typename Iterator> |
45 | Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin) |
46 | { |
47 | boost::system::error_code ec; |
48 | Iterator result = connect(s, begin, ec); |
49 | boost::asio::detail::throw_error(ec, "connect" ); |
50 | return result; |
51 | } |
52 | |
53 | template <typename Protocol, typename SocketService, typename Iterator> |
54 | inline Iterator connect(basic_socket<Protocol, SocketService>& s, |
55 | Iterator begin, boost::system::error_code& ec) |
56 | { |
57 | return connect(s, begin, Iterator(), detail::default_connect_condition(), ec); |
58 | } |
59 | |
60 | template <typename Protocol, typename SocketService, typename Iterator> |
61 | Iterator connect(basic_socket<Protocol, SocketService>& s, |
62 | Iterator begin, Iterator end) |
63 | { |
64 | boost::system::error_code ec; |
65 | Iterator result = connect(s, begin, end, ec); |
66 | boost::asio::detail::throw_error(ec, "connect" ); |
67 | return result; |
68 | } |
69 | |
70 | template <typename Protocol, typename SocketService, typename Iterator> |
71 | inline Iterator connect(basic_socket<Protocol, SocketService>& s, |
72 | Iterator begin, Iterator end, boost::system::error_code& ec) |
73 | { |
74 | return connect(s, begin, end, detail::default_connect_condition(), ec); |
75 | } |
76 | |
77 | template <typename Protocol, typename SocketService, |
78 | typename Iterator, typename ConnectCondition> |
79 | Iterator connect(basic_socket<Protocol, SocketService>& s, |
80 | Iterator begin, ConnectCondition connect_condition) |
81 | { |
82 | boost::system::error_code ec; |
83 | Iterator result = connect(s, begin, connect_condition, ec); |
84 | boost::asio::detail::throw_error(ec, "connect" ); |
85 | return result; |
86 | } |
87 | |
88 | template <typename Protocol, typename SocketService, |
89 | typename Iterator, typename ConnectCondition> |
90 | inline Iterator connect(basic_socket<Protocol, SocketService>& s, |
91 | Iterator begin, ConnectCondition connect_condition, |
92 | boost::system::error_code& ec) |
93 | { |
94 | return connect(s, begin, Iterator(), connect_condition, ec); |
95 | } |
96 | |
97 | template <typename Protocol, typename SocketService, |
98 | typename Iterator, typename ConnectCondition> |
99 | Iterator connect(basic_socket<Protocol, SocketService>& s, |
100 | Iterator begin, Iterator end, ConnectCondition connect_condition) |
101 | { |
102 | boost::system::error_code ec; |
103 | Iterator result = connect(s, begin, end, connect_condition, ec); |
104 | boost::asio::detail::throw_error(ec, "connect" ); |
105 | return result; |
106 | } |
107 | |
108 | template <typename Protocol, typename SocketService, |
109 | typename Iterator, typename ConnectCondition> |
110 | Iterator connect(basic_socket<Protocol, SocketService>& s, |
111 | Iterator begin, Iterator end, ConnectCondition connect_condition, |
112 | boost::system::error_code& ec) |
113 | { |
114 | ec = boost::system::error_code(); |
115 | |
116 | for (Iterator iter = begin; iter != end; ++iter) |
117 | { |
118 | iter = connect_condition(ec, iter); |
119 | if (iter != end) |
120 | { |
121 | s.close(ec); |
122 | s.connect(*iter, ec); |
123 | if (!ec) |
124 | return iter; |
125 | } |
126 | } |
127 | |
128 | if (!ec) |
129 | ec = boost::asio::error::not_found; |
130 | |
131 | return end; |
132 | } |
133 | |
134 | namespace detail |
135 | { |
136 | // Enable the empty base class optimisation for the connect condition. |
137 | template <typename ConnectCondition> |
138 | class base_from_connect_condition |
139 | { |
140 | protected: |
141 | explicit base_from_connect_condition( |
142 | const ConnectCondition& connect_condition) |
143 | : connect_condition_(connect_condition) |
144 | { |
145 | } |
146 | |
147 | template <typename Iterator> |
148 | void check_condition(const boost::system::error_code& ec, |
149 | Iterator& iter, Iterator& end) |
150 | { |
151 | if (iter != end) |
152 | iter = connect_condition_(ec, static_cast<const Iterator&>(iter)); |
153 | } |
154 | |
155 | private: |
156 | ConnectCondition connect_condition_; |
157 | }; |
158 | |
159 | // The default_connect_condition implementation is essentially a no-op. This |
160 | // template specialisation lets us eliminate all costs associated with it. |
161 | template <> |
162 | class base_from_connect_condition<default_connect_condition> |
163 | { |
164 | protected: |
165 | explicit base_from_connect_condition(const default_connect_condition&) |
166 | { |
167 | } |
168 | |
169 | template <typename Iterator> |
170 | void check_condition(const boost::system::error_code&, Iterator&, Iterator&) |
171 | { |
172 | } |
173 | }; |
174 | |
175 | template <typename Protocol, typename SocketService, typename Iterator, |
176 | typename ConnectCondition, typename ComposedConnectHandler> |
177 | class connect_op : base_from_connect_condition<ConnectCondition> |
178 | { |
179 | public: |
180 | connect_op(basic_socket<Protocol, SocketService>& sock, |
181 | const Iterator& begin, const Iterator& end, |
182 | const ConnectCondition& connect_condition, |
183 | ComposedConnectHandler& handler) |
184 | : base_from_connect_condition<ConnectCondition>(connect_condition), |
185 | socket_(sock), |
186 | iter_(begin), |
187 | end_(end), |
188 | start_(0), |
189 | handler_(BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)) |
190 | { |
191 | } |
192 | |
193 | #if defined(BOOST_ASIO_HAS_MOVE) |
194 | connect_op(const connect_op& other) |
195 | : base_from_connect_condition<ConnectCondition>(other), |
196 | socket_(other.socket_), |
197 | iter_(other.iter_), |
198 | end_(other.end_), |
199 | start_(other.start_), |
200 | handler_(other.handler_) |
201 | { |
202 | } |
203 | |
204 | connect_op(connect_op&& other) |
205 | : base_from_connect_condition<ConnectCondition>(other), |
206 | socket_(other.socket_), |
207 | iter_(other.iter_), |
208 | end_(other.end_), |
209 | start_(other.start_), |
210 | handler_(BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(other.handler_)) |
211 | { |
212 | } |
213 | #endif // defined(BOOST_ASIO_HAS_MOVE) |
214 | |
215 | void operator()(boost::system::error_code ec, int start = 0) |
216 | { |
217 | switch (start_ = start) |
218 | { |
219 | case 1: |
220 | for (;;) |
221 | { |
222 | this->check_condition(ec, iter_, end_); |
223 | |
224 | if (iter_ != end_) |
225 | { |
226 | socket_.close(ec); |
227 | socket_.async_connect(*iter_, |
228 | BOOST_ASIO_MOVE_CAST(connect_op)(*this)); |
229 | return; |
230 | } |
231 | |
232 | if (start) |
233 | { |
234 | ec = boost::asio::error::not_found; |
235 | socket_.get_io_service().post(detail::bind_handler(*this, ec)); |
236 | return; |
237 | } |
238 | |
239 | default: |
240 | |
241 | if (iter_ == end_) |
242 | break; |
243 | |
244 | if (!socket_.is_open()) |
245 | { |
246 | ec = boost::asio::error::operation_aborted; |
247 | break; |
248 | } |
249 | |
250 | if (!ec) |
251 | break; |
252 | |
253 | ++iter_; |
254 | } |
255 | |
256 | handler_(static_cast<const boost::system::error_code&>(ec), |
257 | static_cast<const Iterator&>(iter_)); |
258 | } |
259 | } |
260 | |
261 | //private: |
262 | basic_socket<Protocol, SocketService>& socket_; |
263 | Iterator iter_; |
264 | Iterator end_; |
265 | int start_; |
266 | ComposedConnectHandler handler_; |
267 | }; |
268 | |
269 | template <typename Protocol, typename SocketService, typename Iterator, |
270 | typename ConnectCondition, typename ComposedConnectHandler> |
271 | inline void* asio_handler_allocate(std::size_t size, |
272 | connect_op<Protocol, SocketService, Iterator, |
273 | ConnectCondition, ComposedConnectHandler>* this_handler) |
274 | { |
275 | return boost_asio_handler_alloc_helpers::allocate( |
276 | size, this_handler->handler_); |
277 | } |
278 | |
279 | template <typename Protocol, typename SocketService, typename Iterator, |
280 | typename ConnectCondition, typename ComposedConnectHandler> |
281 | inline void asio_handler_deallocate(void* pointer, std::size_t size, |
282 | connect_op<Protocol, SocketService, Iterator, |
283 | ConnectCondition, ComposedConnectHandler>* this_handler) |
284 | { |
285 | boost_asio_handler_alloc_helpers::deallocate( |
286 | pointer, size, this_handler->handler_); |
287 | } |
288 | |
289 | template <typename Protocol, typename SocketService, typename Iterator, |
290 | typename ConnectCondition, typename ComposedConnectHandler> |
291 | inline bool asio_handler_is_continuation( |
292 | connect_op<Protocol, SocketService, Iterator, |
293 | ConnectCondition, ComposedConnectHandler>* this_handler) |
294 | { |
295 | return boost_asio_handler_cont_helpers::is_continuation( |
296 | this_handler->handler_); |
297 | } |
298 | |
299 | template <typename Function, typename Protocol, |
300 | typename SocketService, typename Iterator, |
301 | typename ConnectCondition, typename ComposedConnectHandler> |
302 | inline void asio_handler_invoke(Function& function, |
303 | connect_op<Protocol, SocketService, Iterator, |
304 | ConnectCondition, ComposedConnectHandler>* this_handler) |
305 | { |
306 | boost_asio_handler_invoke_helpers::invoke( |
307 | function, this_handler->handler_); |
308 | } |
309 | |
310 | template <typename Function, typename Protocol, |
311 | typename SocketService, typename Iterator, |
312 | typename ConnectCondition, typename ComposedConnectHandler> |
313 | inline void asio_handler_invoke(const Function& function, |
314 | connect_op<Protocol, SocketService, Iterator, |
315 | ConnectCondition, ComposedConnectHandler>* this_handler) |
316 | { |
317 | boost_asio_handler_invoke_helpers::invoke( |
318 | function, this_handler->handler_); |
319 | } |
320 | } // namespace detail |
321 | |
322 | template <typename Protocol, typename SocketService, |
323 | typename Iterator, typename ComposedConnectHandler> |
324 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, |
325 | void (boost::system::error_code, Iterator)) |
326 | async_connect(basic_socket<Protocol, SocketService>& s, |
327 | Iterator begin, BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler) |
328 | { |
329 | // If you get an error on the following line it means that your handler does |
330 | // not meet the documented type requirements for a ComposedConnectHandler. |
331 | BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( |
332 | ComposedConnectHandler, handler, Iterator) type_check; |
333 | |
334 | detail::async_result_init<ComposedConnectHandler, |
335 | void (boost::system::error_code, Iterator)> init( |
336 | BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)); |
337 | |
338 | detail::connect_op<Protocol, SocketService, Iterator, |
339 | detail::default_connect_condition, BOOST_ASIO_HANDLER_TYPE( |
340 | ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s, |
341 | begin, Iterator(), detail::default_connect_condition(), init.handler)( |
342 | boost::system::error_code(), 1); |
343 | |
344 | return init.result.get(); |
345 | } |
346 | |
347 | template <typename Protocol, typename SocketService, |
348 | typename Iterator, typename ComposedConnectHandler> |
349 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, |
350 | void (boost::system::error_code, Iterator)) |
351 | async_connect(basic_socket<Protocol, SocketService>& s, |
352 | Iterator begin, Iterator end, |
353 | BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler) |
354 | { |
355 | // If you get an error on the following line it means that your handler does |
356 | // not meet the documented type requirements for a ComposedConnectHandler. |
357 | BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( |
358 | ComposedConnectHandler, handler, Iterator) type_check; |
359 | |
360 | detail::async_result_init<ComposedConnectHandler, |
361 | void (boost::system::error_code, Iterator)> init( |
362 | BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)); |
363 | |
364 | detail::connect_op<Protocol, SocketService, Iterator, |
365 | detail::default_connect_condition, BOOST_ASIO_HANDLER_TYPE( |
366 | ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s, |
367 | begin, end, detail::default_connect_condition(), init.handler)( |
368 | boost::system::error_code(), 1); |
369 | |
370 | return init.result.get(); |
371 | } |
372 | |
373 | template <typename Protocol, typename SocketService, typename Iterator, |
374 | typename ConnectCondition, typename ComposedConnectHandler> |
375 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, |
376 | void (boost::system::error_code, Iterator)) |
377 | async_connect(basic_socket<Protocol, SocketService>& s, |
378 | Iterator begin, ConnectCondition connect_condition, |
379 | BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler) |
380 | { |
381 | // If you get an error on the following line it means that your handler does |
382 | // not meet the documented type requirements for a ComposedConnectHandler. |
383 | BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( |
384 | ComposedConnectHandler, handler, Iterator) type_check; |
385 | |
386 | detail::async_result_init<ComposedConnectHandler, |
387 | void (boost::system::error_code, Iterator)> init( |
388 | BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)); |
389 | |
390 | detail::connect_op<Protocol, SocketService, Iterator, |
391 | ConnectCondition, BOOST_ASIO_HANDLER_TYPE( |
392 | ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s, |
393 | begin, Iterator(), connect_condition, init.handler)( |
394 | boost::system::error_code(), 1); |
395 | |
396 | return init.result.get(); |
397 | } |
398 | |
399 | template <typename Protocol, typename SocketService, typename Iterator, |
400 | typename ConnectCondition, typename ComposedConnectHandler> |
401 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, |
402 | void (boost::system::error_code, Iterator)) |
403 | async_connect(basic_socket<Protocol, SocketService>& s, |
404 | Iterator begin, Iterator end, ConnectCondition connect_condition, |
405 | BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler) |
406 | { |
407 | // If you get an error on the following line it means that your handler does |
408 | // not meet the documented type requirements for a ComposedConnectHandler. |
409 | BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( |
410 | ComposedConnectHandler, handler, Iterator) type_check; |
411 | |
412 | detail::async_result_init<ComposedConnectHandler, |
413 | void (boost::system::error_code, Iterator)> init( |
414 | BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)); |
415 | |
416 | detail::connect_op<Protocol, SocketService, Iterator, |
417 | ConnectCondition, BOOST_ASIO_HANDLER_TYPE( |
418 | ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s, |
419 | begin, end, connect_condition, init.handler)( |
420 | boost::system::error_code(), 1); |
421 | |
422 | return init.result.get(); |
423 | } |
424 | |
425 | } // namespace asio |
426 | } // namespace boost |
427 | |
428 | #include <boost/asio/detail/pop_options.hpp> |
429 | |
430 | #endif // BOOST_ASIO_IMPL_CONNECT_HPP |
431 | |