1 //
2 // impl/connect.hpp
3 // ~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2020 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 <algorithm>
19 #include <boost/asio/associated_allocator.hpp>
20 #include <boost/asio/associated_executor.hpp>
21 #include <boost/asio/detail/bind_handler.hpp>
22 #include <boost/asio/detail/handler_alloc_helpers.hpp>
23 #include <boost/asio/detail/handler_cont_helpers.hpp>
24 #include <boost/asio/detail/handler_invoke_helpers.hpp>
25 #include <boost/asio/detail/handler_tracking.hpp>
26 #include <boost/asio/detail/handler_type_requirements.hpp>
27 #include <boost/asio/detail/non_const_lvalue.hpp>
28 #include <boost/asio/detail/throw_error.hpp>
29 #include <boost/asio/error.hpp>
30 #include <boost/asio/post.hpp>
31
32 #include <boost/asio/detail/push_options.hpp>
33
34 namespace boost {
35 namespace asio {
36
37 namespace detail
38 {
39 struct default_connect_condition
40 {
41 template <typename Endpoint>
operator ()boost::asio::detail::default_connect_condition42 bool operator()(const boost::system::error_code&, const Endpoint&)
43 {
44 return true;
45 }
46 };
47
48 template <typename Protocol, typename Iterator>
deref_connect_result(Iterator iter,boost::system::error_code & ec)49 inline typename Protocol::endpoint deref_connect_result(
50 Iterator iter, boost::system::error_code& ec)
51 {
52 return ec ? typename Protocol::endpoint() : *iter;
53 }
54
55 template <typename T, typename Iterator>
56 struct legacy_connect_condition_helper : T
57 {
58 typedef char (*fallback_func_type)(...);
59 operator fallback_func_type() const;
60 };
61
62 template <typename R, typename Arg1, typename Arg2, typename Iterator>
63 struct legacy_connect_condition_helper<R (*)(Arg1, Arg2), Iterator>
64 {
65 R operator()(Arg1, Arg2) const;
66 char operator()(...) const;
67 };
68
69 template <typename T, typename Iterator>
70 struct is_legacy_connect_condition
71 {
72 static char asio_connect_condition_check(char);
73 static char (&asio_connect_condition_check(Iterator))[2];
74
75 static const bool value =
76 sizeof(asio_connect_condition_check(
77 (*static_cast<legacy_connect_condition_helper<T, Iterator>*>(0))(
78 *static_cast<const boost::system::error_code*>(0),
79 *static_cast<const Iterator*>(0)))) != 1;
80 };
81
82 template <typename ConnectCondition, typename Iterator>
call_connect_condition(ConnectCondition & connect_condition,const boost::system::error_code & ec,Iterator next,Iterator end,typename enable_if<is_legacy_connect_condition<ConnectCondition,Iterator>::value>::type * =0)83 inline Iterator call_connect_condition(ConnectCondition& connect_condition,
84 const boost::system::error_code& ec, Iterator next, Iterator end,
85 typename enable_if<is_legacy_connect_condition<
86 ConnectCondition, Iterator>::value>::type* = 0)
87 {
88 if (next != end)
89 return connect_condition(ec, next);
90 return end;
91 }
92
93 template <typename ConnectCondition, typename Iterator>
call_connect_condition(ConnectCondition & connect_condition,const boost::system::error_code & ec,Iterator next,Iterator end,typename enable_if<!is_legacy_connect_condition<ConnectCondition,Iterator>::value>::type * =0)94 inline Iterator call_connect_condition(ConnectCondition& connect_condition,
95 const boost::system::error_code& ec, Iterator next, Iterator end,
96 typename enable_if<!is_legacy_connect_condition<
97 ConnectCondition, Iterator>::value>::type* = 0)
98 {
99 for (;next != end; ++next)
100 if (connect_condition(ec, *next))
101 return next;
102 return end;
103 }
104 }
105
106 template <typename Protocol, typename Executor, typename EndpointSequence>
connect(basic_socket<Protocol,Executor> & s,const EndpointSequence & endpoints,typename enable_if<is_endpoint_sequence<EndpointSequence>::value>::type *)107 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
108 const EndpointSequence& endpoints,
109 typename enable_if<is_endpoint_sequence<
110 EndpointSequence>::value>::type*)
111 {
112 boost::system::error_code ec;
113 typename Protocol::endpoint result = connect(s, endpoints, ec);
114 boost::asio::detail::throw_error(ec, "connect");
115 return result;
116 }
117
118 template <typename Protocol, typename Executor, typename EndpointSequence>
connect(basic_socket<Protocol,Executor> & s,const EndpointSequence & endpoints,boost::system::error_code & ec,typename enable_if<is_endpoint_sequence<EndpointSequence>::value>::type *)119 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
120 const EndpointSequence& endpoints, boost::system::error_code& ec,
121 typename enable_if<is_endpoint_sequence<
122 EndpointSequence>::value>::type*)
123 {
124 return detail::deref_connect_result<Protocol>(
125 connect(s, endpoints.begin(), endpoints.end(),
126 detail::default_connect_condition(), ec), ec);
127 }
128
129 #if !defined(BOOST_ASIO_NO_DEPRECATED)
130 template <typename Protocol, typename Executor, typename Iterator>
connect(basic_socket<Protocol,Executor> & s,Iterator begin,typename enable_if<!is_endpoint_sequence<Iterator>::value>::type *)131 Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
132 typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
133 {
134 boost::system::error_code ec;
135 Iterator result = connect(s, begin, ec);
136 boost::asio::detail::throw_error(ec, "connect");
137 return result;
138 }
139
140 template <typename Protocol, typename Executor, typename Iterator>
connect(basic_socket<Protocol,Executor> & s,Iterator begin,boost::system::error_code & ec,typename enable_if<!is_endpoint_sequence<Iterator>::value>::type *)141 inline Iterator connect(basic_socket<Protocol, Executor>& s,
142 Iterator begin, boost::system::error_code& ec,
143 typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
144 {
145 return connect(s, begin, Iterator(), detail::default_connect_condition(), ec);
146 }
147 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
148
149 template <typename Protocol, typename Executor, typename Iterator>
connect(basic_socket<Protocol,Executor> & s,Iterator begin,Iterator end)150 Iterator connect(basic_socket<Protocol, Executor>& s,
151 Iterator begin, Iterator end)
152 {
153 boost::system::error_code ec;
154 Iterator result = connect(s, begin, end, ec);
155 boost::asio::detail::throw_error(ec, "connect");
156 return result;
157 }
158
159 template <typename Protocol, typename Executor, typename Iterator>
connect(basic_socket<Protocol,Executor> & s,Iterator begin,Iterator end,boost::system::error_code & ec)160 inline Iterator connect(basic_socket<Protocol, Executor>& s,
161 Iterator begin, Iterator end, boost::system::error_code& ec)
162 {
163 return connect(s, begin, end, detail::default_connect_condition(), ec);
164 }
165
166 template <typename Protocol, typename Executor,
167 typename EndpointSequence, typename ConnectCondition>
connect(basic_socket<Protocol,Executor> & s,const EndpointSequence & endpoints,ConnectCondition connect_condition,typename enable_if<is_endpoint_sequence<EndpointSequence>::value>::type *)168 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
169 const EndpointSequence& endpoints, ConnectCondition connect_condition,
170 typename enable_if<is_endpoint_sequence<
171 EndpointSequence>::value>::type*)
172 {
173 boost::system::error_code ec;
174 typename Protocol::endpoint result = connect(
175 s, endpoints, connect_condition, ec);
176 boost::asio::detail::throw_error(ec, "connect");
177 return result;
178 }
179
180 template <typename Protocol, typename Executor,
181 typename EndpointSequence, typename ConnectCondition>
connect(basic_socket<Protocol,Executor> & s,const EndpointSequence & endpoints,ConnectCondition connect_condition,boost::system::error_code & ec,typename enable_if<is_endpoint_sequence<EndpointSequence>::value>::type *)182 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
183 const EndpointSequence& endpoints, ConnectCondition connect_condition,
184 boost::system::error_code& ec,
185 typename enable_if<is_endpoint_sequence<
186 EndpointSequence>::value>::type*)
187 {
188 return detail::deref_connect_result<Protocol>(
189 connect(s, endpoints.begin(), endpoints.end(),
190 connect_condition, ec), ec);
191 }
192
193 #if !defined(BOOST_ASIO_NO_DEPRECATED)
194 template <typename Protocol, typename Executor,
195 typename Iterator, typename ConnectCondition>
196 Iterator connect(basic_socket<Protocol, Executor>& s,
197 Iterator begin, ConnectCondition connect_condition,
198 typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
199 {
200 boost::system::error_code ec;
201 Iterator result = connect(s, begin, connect_condition, ec);
202 boost::asio::detail::throw_error(ec, "connect");
203 return result;
204 }
205
206 template <typename Protocol, typename Executor,
207 typename Iterator, typename ConnectCondition>
connect(basic_socket<Protocol,Executor> & s,Iterator begin,ConnectCondition connect_condition,boost::system::error_code & ec,typename enable_if<!is_endpoint_sequence<Iterator>::value>::type *)208 inline Iterator connect(basic_socket<Protocol, Executor>& s,
209 Iterator begin, ConnectCondition connect_condition,
210 boost::system::error_code& ec,
211 typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
212 {
213 return connect(s, begin, Iterator(), connect_condition, ec);
214 }
215 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
216
217 template <typename Protocol, typename Executor,
218 typename Iterator, typename ConnectCondition>
219 Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
220 Iterator end, ConnectCondition connect_condition)
221 {
222 boost::system::error_code ec;
223 Iterator result = connect(s, begin, end, connect_condition, ec);
224 boost::asio::detail::throw_error(ec, "connect");
225 return result;
226 }
227
228 template <typename Protocol, typename Executor,
229 typename Iterator, typename ConnectCondition>
230 Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
231 Iterator end, ConnectCondition connect_condition,
232 boost::system::error_code& ec)
233 {
234 ec = boost::system::error_code();
235
236 for (Iterator iter = begin; iter != end; ++iter)
237 {
238 iter = (detail::call_connect_condition(connect_condition, ec, iter, end));
239 if (iter != end)
240 {
241 s.close(ec);
242 s.connect(*iter, ec);
243 if (!ec)
244 return iter;
245 }
246 else
247 break;
248 }
249
250 if (!ec)
251 ec = boost::asio::error::not_found;
252
253 return end;
254 }
255
256 namespace detail
257 {
258 // Enable the empty base class optimisation for the connect condition.
259 template <typename ConnectCondition>
260 class base_from_connect_condition
261 {
262 protected:
base_from_connect_condition(const ConnectCondition & connect_condition)263 explicit base_from_connect_condition(
264 const ConnectCondition& connect_condition)
265 : connect_condition_(connect_condition)
266 {
267 }
268
269 template <typename Iterator>
check_condition(const boost::system::error_code & ec,Iterator & iter,Iterator & end)270 void check_condition(const boost::system::error_code& ec,
271 Iterator& iter, Iterator& end)
272 {
273 iter = detail::call_connect_condition(connect_condition_, ec, iter, end);
274 }
275
276 private:
277 ConnectCondition connect_condition_;
278 };
279
280 // The default_connect_condition implementation is essentially a no-op. This
281 // template specialisation lets us eliminate all costs associated with it.
282 template <>
283 class base_from_connect_condition<default_connect_condition>
284 {
285 protected:
base_from_connect_condition(const default_connect_condition &)286 explicit base_from_connect_condition(const default_connect_condition&)
287 {
288 }
289
290 template <typename Iterator>
check_condition(const boost::system::error_code &,Iterator &,Iterator &)291 void check_condition(const boost::system::error_code&, Iterator&, Iterator&)
292 {
293 }
294 };
295
296 template <typename Protocol, typename Executor, typename EndpointSequence,
297 typename ConnectCondition, typename RangeConnectHandler>
298 class range_connect_op : base_from_connect_condition<ConnectCondition>
299 {
300 public:
range_connect_op(basic_socket<Protocol,Executor> & sock,const EndpointSequence & endpoints,const ConnectCondition & connect_condition,RangeConnectHandler & handler)301 range_connect_op(basic_socket<Protocol, Executor>& sock,
302 const EndpointSequence& endpoints,
303 const ConnectCondition& connect_condition,
304 RangeConnectHandler& handler)
305 : base_from_connect_condition<ConnectCondition>(connect_condition),
306 socket_(sock),
307 endpoints_(endpoints),
308 index_(0),
309 start_(0),
310 handler_(BOOST_ASIO_MOVE_CAST(RangeConnectHandler)(handler))
311 {
312 }
313
314 #if defined(BOOST_ASIO_HAS_MOVE)
range_connect_op(const range_connect_op & other)315 range_connect_op(const range_connect_op& other)
316 : base_from_connect_condition<ConnectCondition>(other),
317 socket_(other.socket_),
318 endpoints_(other.endpoints_),
319 index_(other.index_),
320 start_(other.start_),
321 handler_(other.handler_)
322 {
323 }
324
range_connect_op(range_connect_op && other)325 range_connect_op(range_connect_op&& other)
326 : base_from_connect_condition<ConnectCondition>(other),
327 socket_(other.socket_),
328 endpoints_(other.endpoints_),
329 index_(other.index_),
330 start_(other.start_),
331 handler_(BOOST_ASIO_MOVE_CAST(RangeConnectHandler)(other.handler_))
332 {
333 }
334 #endif // defined(BOOST_ASIO_HAS_MOVE)
335
operator ()(boost::system::error_code ec,int start=0)336 void operator()(boost::system::error_code ec, int start = 0)
337 {
338 this->process(ec, start,
339 const_cast<const EndpointSequence&>(endpoints_).begin(),
340 const_cast<const EndpointSequence&>(endpoints_).end());
341 }
342
343 //private:
344 template <typename Iterator>
process(boost::system::error_code ec,int start,Iterator begin,Iterator end)345 void process(boost::system::error_code ec,
346 int start, Iterator begin, Iterator end)
347 {
348 Iterator iter = begin;
349 std::advance(iter, index_);
350
351 switch (start_ = start)
352 {
353 case 1:
354 for (;;)
355 {
356 this->check_condition(ec, iter, end);
357 index_ = std::distance(begin, iter);
358
359 if (iter != end)
360 {
361 socket_.close(ec);
362 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
363 socket_.async_connect(*iter,
364 BOOST_ASIO_MOVE_CAST(range_connect_op)(*this));
365 return;
366 }
367
368 if (start)
369 {
370 ec = boost::asio::error::not_found;
371 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
372 boost::asio::post(socket_.get_executor(),
373 detail::bind_handler(
374 BOOST_ASIO_MOVE_CAST(range_connect_op)(*this), ec));
375 return;
376 }
377
378 /* fall-through */ default:
379
380 if (iter == end)
381 break;
382
383 if (!socket_.is_open())
384 {
385 ec = boost::asio::error::operation_aborted;
386 break;
387 }
388
389 if (!ec)
390 break;
391
392 ++iter;
393 ++index_;
394 }
395
396 handler_(static_cast<const boost::system::error_code&>(ec),
397 static_cast<const typename Protocol::endpoint&>(
398 ec || iter == end ? typename Protocol::endpoint() : *iter));
399 }
400 }
401
402 basic_socket<Protocol, Executor>& socket_;
403 EndpointSequence endpoints_;
404 std::size_t index_;
405 int start_;
406 RangeConnectHandler handler_;
407 };
408
409 template <typename Protocol, typename Executor, typename EndpointSequence,
410 typename ConnectCondition, typename RangeConnectHandler>
411 inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,range_connect_op<Protocol,Executor,EndpointSequence,ConnectCondition,RangeConnectHandler> * this_handler)412 asio_handler_allocate(std::size_t size,
413 range_connect_op<Protocol, Executor, EndpointSequence,
414 ConnectCondition, RangeConnectHandler>* this_handler)
415 {
416 #if defined(BOOST_ASIO_NO_DEPRECATED)
417 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
418 return asio_handler_allocate_is_no_longer_used();
419 #else // defined(BOOST_ASIO_NO_DEPRECATED)
420 return boost_asio_handler_alloc_helpers::allocate(
421 size, this_handler->handler_);
422 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
423 }
424
425 template <typename Protocol, typename Executor, typename EndpointSequence,
426 typename ConnectCondition, typename RangeConnectHandler>
427 inline asio_handler_deallocate_is_deprecated
asio_handler_deallocate(void * pointer,std::size_t size,range_connect_op<Protocol,Executor,EndpointSequence,ConnectCondition,RangeConnectHandler> * this_handler)428 asio_handler_deallocate(void* pointer, std::size_t size,
429 range_connect_op<Protocol, Executor, EndpointSequence,
430 ConnectCondition, RangeConnectHandler>* this_handler)
431 {
432 boost_asio_handler_alloc_helpers::deallocate(
433 pointer, size, this_handler->handler_);
434 #if defined(BOOST_ASIO_NO_DEPRECATED)
435 return asio_handler_deallocate_is_no_longer_used();
436 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
437 }
438
439 template <typename Protocol, typename Executor, typename EndpointSequence,
440 typename ConnectCondition, typename RangeConnectHandler>
asio_handler_is_continuation(range_connect_op<Protocol,Executor,EndpointSequence,ConnectCondition,RangeConnectHandler> * this_handler)441 inline bool asio_handler_is_continuation(
442 range_connect_op<Protocol, Executor, EndpointSequence,
443 ConnectCondition, RangeConnectHandler>* this_handler)
444 {
445 return boost_asio_handler_cont_helpers::is_continuation(
446 this_handler->handler_);
447 }
448
449 template <typename Function, typename Executor, typename Protocol,
450 typename EndpointSequence, typename ConnectCondition,
451 typename RangeConnectHandler>
452 inline asio_handler_invoke_is_deprecated
asio_handler_invoke(Function & function,range_connect_op<Protocol,Executor,EndpointSequence,ConnectCondition,RangeConnectHandler> * this_handler)453 asio_handler_invoke(Function& function,
454 range_connect_op<Protocol, Executor, EndpointSequence,
455 ConnectCondition, RangeConnectHandler>* this_handler)
456 {
457 boost_asio_handler_invoke_helpers::invoke(
458 function, this_handler->handler_);
459 #if defined(BOOST_ASIO_NO_DEPRECATED)
460 return asio_handler_invoke_is_no_longer_used();
461 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
462 }
463
464 template <typename Function, typename Executor, typename Protocol,
465 typename EndpointSequence, typename ConnectCondition,
466 typename RangeConnectHandler>
467 inline asio_handler_invoke_is_deprecated
asio_handler_invoke(const Function & function,range_connect_op<Protocol,Executor,EndpointSequence,ConnectCondition,RangeConnectHandler> * this_handler)468 asio_handler_invoke(const Function& function,
469 range_connect_op<Protocol, Executor, EndpointSequence,
470 ConnectCondition, RangeConnectHandler>* this_handler)
471 {
472 boost_asio_handler_invoke_helpers::invoke(
473 function, this_handler->handler_);
474 #if defined(BOOST_ASIO_NO_DEPRECATED)
475 return asio_handler_invoke_is_no_longer_used();
476 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
477 }
478
479 template <typename Protocol, typename Executor>
480 class initiate_async_range_connect
481 {
482 public:
483 typedef Executor executor_type;
484
initiate_async_range_connect(basic_socket<Protocol,Executor> & s)485 explicit initiate_async_range_connect(basic_socket<Protocol, Executor>& s)
486 : socket_(s)
487 {
488 }
489
get_executor() const490 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
491 {
492 return socket_.get_executor();
493 }
494
495 template <typename RangeConnectHandler,
496 typename EndpointSequence, typename ConnectCondition>
operator ()(BOOST_ASIO_MOVE_ARG (RangeConnectHandler)handler,const EndpointSequence & endpoints,const ConnectCondition & connect_condition) const497 void operator()(BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler,
498 const EndpointSequence& endpoints,
499 const ConnectCondition& connect_condition) const
500 {
501 // If you get an error on the following line it means that your
502 // handler does not meet the documented type requirements for an
503 // RangeConnectHandler.
504 BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK(RangeConnectHandler,
505 handler, typename Protocol::endpoint) type_check;
506
507 non_const_lvalue<RangeConnectHandler> handler2(handler);
508 range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition,
509 typename decay<RangeConnectHandler>::type>(socket_, endpoints,
510 connect_condition, handler2.value)(boost::system::error_code(), 1);
511 }
512
513 private:
514 basic_socket<Protocol, Executor>& socket_;
515 };
516
517 template <typename Protocol, typename Executor, typename Iterator,
518 typename ConnectCondition, typename IteratorConnectHandler>
519 class iterator_connect_op : base_from_connect_condition<ConnectCondition>
520 {
521 public:
iterator_connect_op(basic_socket<Protocol,Executor> & sock,const Iterator & begin,const Iterator & end,const ConnectCondition & connect_condition,IteratorConnectHandler & handler)522 iterator_connect_op(basic_socket<Protocol, Executor>& sock,
523 const Iterator& begin, const Iterator& end,
524 const ConnectCondition& connect_condition,
525 IteratorConnectHandler& handler)
526 : base_from_connect_condition<ConnectCondition>(connect_condition),
527 socket_(sock),
528 iter_(begin),
529 end_(end),
530 start_(0),
531 handler_(BOOST_ASIO_MOVE_CAST(IteratorConnectHandler)(handler))
532 {
533 }
534
535 #if defined(BOOST_ASIO_HAS_MOVE)
iterator_connect_op(const iterator_connect_op & other)536 iterator_connect_op(const iterator_connect_op& other)
537 : base_from_connect_condition<ConnectCondition>(other),
538 socket_(other.socket_),
539 iter_(other.iter_),
540 end_(other.end_),
541 start_(other.start_),
542 handler_(other.handler_)
543 {
544 }
545
iterator_connect_op(iterator_connect_op && other)546 iterator_connect_op(iterator_connect_op&& other)
547 : base_from_connect_condition<ConnectCondition>(other),
548 socket_(other.socket_),
549 iter_(other.iter_),
550 end_(other.end_),
551 start_(other.start_),
552 handler_(BOOST_ASIO_MOVE_CAST(IteratorConnectHandler)(other.handler_))
553 {
554 }
555 #endif // defined(BOOST_ASIO_HAS_MOVE)
556
operator ()(boost::system::error_code ec,int start=0)557 void operator()(boost::system::error_code ec, int start = 0)
558 {
559 switch (start_ = start)
560 {
561 case 1:
562 for (;;)
563 {
564 this->check_condition(ec, iter_, end_);
565
566 if (iter_ != end_)
567 {
568 socket_.close(ec);
569 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
570 socket_.async_connect(*iter_,
571 BOOST_ASIO_MOVE_CAST(iterator_connect_op)(*this));
572 return;
573 }
574
575 if (start)
576 {
577 ec = boost::asio::error::not_found;
578 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
579 boost::asio::post(socket_.get_executor(),
580 detail::bind_handler(
581 BOOST_ASIO_MOVE_CAST(iterator_connect_op)(*this), ec));
582 return;
583 }
584
585 /* fall-through */ default:
586
587 if (iter_ == end_)
588 break;
589
590 if (!socket_.is_open())
591 {
592 ec = boost::asio::error::operation_aborted;
593 break;
594 }
595
596 if (!ec)
597 break;
598
599 ++iter_;
600 }
601
602 handler_(static_cast<const boost::system::error_code&>(ec),
603 static_cast<const Iterator&>(iter_));
604 }
605 }
606
607 //private:
608 basic_socket<Protocol, Executor>& socket_;
609 Iterator iter_;
610 Iterator end_;
611 int start_;
612 IteratorConnectHandler handler_;
613 };
614
615 template <typename Protocol, typename Executor, typename Iterator,
616 typename ConnectCondition, typename IteratorConnectHandler>
617 inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,iterator_connect_op<Protocol,Executor,Iterator,ConnectCondition,IteratorConnectHandler> * this_handler)618 asio_handler_allocate(std::size_t size,
619 iterator_connect_op<Protocol, Executor, Iterator,
620 ConnectCondition, IteratorConnectHandler>* this_handler)
621 {
622 #if defined(BOOST_ASIO_NO_DEPRECATED)
623 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
624 return asio_handler_allocate_is_no_longer_used();
625 #else // defined(BOOST_ASIO_NO_DEPRECATED)
626 return boost_asio_handler_alloc_helpers::allocate(
627 size, this_handler->handler_);
628 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
629 }
630
631 template <typename Protocol, typename Executor, typename Iterator,
632 typename ConnectCondition, typename IteratorConnectHandler>
633 inline asio_handler_deallocate_is_deprecated
asio_handler_deallocate(void * pointer,std::size_t size,iterator_connect_op<Protocol,Executor,Iterator,ConnectCondition,IteratorConnectHandler> * this_handler)634 asio_handler_deallocate(void* pointer, std::size_t size,
635 iterator_connect_op<Protocol, Executor, Iterator,
636 ConnectCondition, IteratorConnectHandler>* this_handler)
637 {
638 boost_asio_handler_alloc_helpers::deallocate(
639 pointer, size, this_handler->handler_);
640 #if defined(BOOST_ASIO_NO_DEPRECATED)
641 return asio_handler_deallocate_is_no_longer_used();
642 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
643 }
644
645 template <typename Protocol, typename Executor, typename Iterator,
646 typename ConnectCondition, typename IteratorConnectHandler>
asio_handler_is_continuation(iterator_connect_op<Protocol,Executor,Iterator,ConnectCondition,IteratorConnectHandler> * this_handler)647 inline bool asio_handler_is_continuation(
648 iterator_connect_op<Protocol, Executor, Iterator,
649 ConnectCondition, IteratorConnectHandler>* this_handler)
650 {
651 return boost_asio_handler_cont_helpers::is_continuation(
652 this_handler->handler_);
653 }
654
655 template <typename Function, typename Executor, typename Protocol,
656 typename Iterator, typename ConnectCondition,
657 typename IteratorConnectHandler>
658 inline asio_handler_invoke_is_deprecated
asio_handler_invoke(Function & function,iterator_connect_op<Protocol,Executor,Iterator,ConnectCondition,IteratorConnectHandler> * this_handler)659 asio_handler_invoke(Function& function,
660 iterator_connect_op<Protocol, Executor, Iterator,
661 ConnectCondition, IteratorConnectHandler>* this_handler)
662 {
663 boost_asio_handler_invoke_helpers::invoke(
664 function, this_handler->handler_);
665 #if defined(BOOST_ASIO_NO_DEPRECATED)
666 return asio_handler_invoke_is_no_longer_used();
667 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
668 }
669
670 template <typename Function, typename Executor, typename Protocol,
671 typename Iterator, typename ConnectCondition,
672 typename IteratorConnectHandler>
673 inline asio_handler_invoke_is_deprecated
asio_handler_invoke(const Function & function,iterator_connect_op<Protocol,Executor,Iterator,ConnectCondition,IteratorConnectHandler> * this_handler)674 asio_handler_invoke(const Function& function,
675 iterator_connect_op<Protocol, Executor, Iterator,
676 ConnectCondition, IteratorConnectHandler>* this_handler)
677 {
678 boost_asio_handler_invoke_helpers::invoke(
679 function, this_handler->handler_);
680 #if defined(BOOST_ASIO_NO_DEPRECATED)
681 return asio_handler_invoke_is_no_longer_used();
682 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
683 }
684
685 template <typename Protocol, typename Executor>
686 class initiate_async_iterator_connect
687 {
688 public:
689 typedef Executor executor_type;
690
initiate_async_iterator_connect(basic_socket<Protocol,Executor> & s)691 explicit initiate_async_iterator_connect(
692 basic_socket<Protocol, Executor>& s)
693 : socket_(s)
694 {
695 }
696
get_executor() const697 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
698 {
699 return socket_.get_executor();
700 }
701
702 template <typename IteratorConnectHandler,
703 typename Iterator, typename ConnectCondition>
operator ()(BOOST_ASIO_MOVE_ARG (IteratorConnectHandler)handler,Iterator begin,Iterator end,const ConnectCondition & connect_condition) const704 void operator()(BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler,
705 Iterator begin, Iterator end,
706 const ConnectCondition& connect_condition) const
707 {
708 // If you get an error on the following line it means that your
709 // handler does not meet the documented type requirements for an
710 // IteratorConnectHandler.
711 BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK(
712 IteratorConnectHandler, handler, Iterator) type_check;
713
714 non_const_lvalue<IteratorConnectHandler> handler2(handler);
715 iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition,
716 typename decay<IteratorConnectHandler>::type>(socket_, begin, end,
717 connect_condition, handler2.value)(boost::system::error_code(), 1);
718 }
719
720 private:
721 basic_socket<Protocol, Executor>& socket_;
722 };
723 } // namespace detail
724
725 #if !defined(GENERATING_DOCUMENTATION)
726
727 template <typename Protocol, typename Executor, typename EndpointSequence,
728 typename ConnectCondition, typename RangeConnectHandler, typename Allocator>
729 struct associated_allocator<
730 detail::range_connect_op<Protocol, Executor, EndpointSequence,
731 ConnectCondition, RangeConnectHandler>, Allocator>
732 {
733 typedef typename associated_allocator<
734 RangeConnectHandler, Allocator>::type type;
735
getboost::asio::associated_allocator736 static type get(
737 const detail::range_connect_op<Protocol, Executor, EndpointSequence,
738 ConnectCondition, RangeConnectHandler>& h,
739 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
740 {
741 return associated_allocator<RangeConnectHandler,
742 Allocator>::get(h.handler_, a);
743 }
744 };
745
746 template <typename Protocol, typename Executor, typename EndpointSequence,
747 typename ConnectCondition, typename RangeConnectHandler, typename Executor1>
748 struct associated_executor<
749 detail::range_connect_op<Protocol, Executor, EndpointSequence,
750 ConnectCondition, RangeConnectHandler>, Executor1>
751 : detail::associated_executor_forwarding_base<RangeConnectHandler, Executor1>
752 {
753 typedef typename associated_executor<
754 RangeConnectHandler, Executor1>::type type;
755
getboost::asio::associated_executor756 static type get(
757 const detail::range_connect_op<Protocol, Executor, EndpointSequence,
758 ConnectCondition, RangeConnectHandler>& h,
759 const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT
760 {
761 return associated_executor<RangeConnectHandler,
762 Executor1>::get(h.handler_, ex);
763 }
764 };
765
766 template <typename Protocol, typename Executor, typename Iterator,
767 typename ConnectCondition, typename IteratorConnectHandler,
768 typename Allocator>
769 struct associated_allocator<
770 detail::iterator_connect_op<Protocol, Executor,
771 Iterator, ConnectCondition, IteratorConnectHandler>,
772 Allocator>
773 {
774 typedef typename associated_allocator<
775 IteratorConnectHandler, Allocator>::type type;
776
getboost::asio::associated_allocator777 static type get(
778 const detail::iterator_connect_op<Protocol, Executor,
779 Iterator, ConnectCondition, IteratorConnectHandler>& h,
780 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
781 {
782 return associated_allocator<IteratorConnectHandler,
783 Allocator>::get(h.handler_, a);
784 }
785 };
786
787 template <typename Protocol, typename Executor, typename Iterator,
788 typename ConnectCondition, typename IteratorConnectHandler,
789 typename Executor1>
790 struct associated_executor<
791 detail::iterator_connect_op<Protocol, Executor,
792 Iterator, ConnectCondition, IteratorConnectHandler>,
793 Executor1>
794 : detail::associated_executor_forwarding_base<
795 IteratorConnectHandler, Executor1>
796 {
797 typedef typename associated_executor<
798 IteratorConnectHandler, Executor1>::type type;
799
getboost::asio::associated_executor800 static type get(
801 const detail::iterator_connect_op<Protocol, Executor,
802 Iterator, ConnectCondition, IteratorConnectHandler>& h,
803 const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT
804 {
805 return associated_executor<IteratorConnectHandler,
806 Executor1>::get(h.handler_, ex);
807 }
808 };
809
810 #endif // !defined(GENERATING_DOCUMENTATION)
811
812 template <typename Protocol, typename Executor, typename EndpointSequence,
813 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
814 typename Protocol::endpoint)) RangeConnectHandler>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,void (boost::system::error_code,typename Protocol::endpoint))815 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,
816 void (boost::system::error_code, typename Protocol::endpoint))
817 async_connect(basic_socket<Protocol, Executor>& s,
818 const EndpointSequence& endpoints,
819 BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler,
820 typename enable_if<is_endpoint_sequence<
821 EndpointSequence>::value>::type*)
822 {
823 return async_initiate<RangeConnectHandler,
824 void (boost::system::error_code, typename Protocol::endpoint)>(
825 detail::initiate_async_range_connect<Protocol, Executor>(s),
826 handler, endpoints, detail::default_connect_condition());
827 }
828
829 #if !defined(BOOST_ASIO_NO_DEPRECATED)
830 template <typename Protocol, typename Executor, typename Iterator,
831 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
832 Iterator)) IteratorConnectHandler>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,void (boost::system::error_code,Iterator))833 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
834 void (boost::system::error_code, Iterator))
835 async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
836 BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler,
837 typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
838 {
839 return async_initiate<IteratorConnectHandler,
840 void (boost::system::error_code, Iterator)>(
841 detail::initiate_async_iterator_connect<Protocol, Executor>(s),
842 handler, begin, Iterator(), detail::default_connect_condition());
843 }
844 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
845
846 template <typename Protocol, typename Executor, typename Iterator,
847 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
848 Iterator)) IteratorConnectHandler>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,void (boost::system::error_code,Iterator))849 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
850 void (boost::system::error_code, Iterator))
851 async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end,
852 BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler)
853 {
854 return async_initiate<IteratorConnectHandler,
855 void (boost::system::error_code, Iterator)>(
856 detail::initiate_async_iterator_connect<Protocol, Executor>(s),
857 handler, begin, end, detail::default_connect_condition());
858 }
859
860 template <typename Protocol, typename Executor,
861 typename EndpointSequence, typename ConnectCondition,
862 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
863 typename Protocol::endpoint)) RangeConnectHandler>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,void (boost::system::error_code,typename Protocol::endpoint))864 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,
865 void (boost::system::error_code, typename Protocol::endpoint))
866 async_connect(basic_socket<Protocol, Executor>& s,
867 const EndpointSequence& endpoints, ConnectCondition connect_condition,
868 BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler,
869 typename enable_if<is_endpoint_sequence<
870 EndpointSequence>::value>::type*)
871 {
872 return async_initiate<RangeConnectHandler,
873 void (boost::system::error_code, typename Protocol::endpoint)>(
874 detail::initiate_async_range_connect<Protocol, Executor>(s),
875 handler, endpoints, connect_condition);
876 }
877
878 #if !defined(BOOST_ASIO_NO_DEPRECATED)
879 template <typename Protocol, typename Executor,
880 typename Iterator, typename ConnectCondition,
881 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
882 Iterator)) IteratorConnectHandler>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,void (boost::system::error_code,Iterator))883 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
884 void (boost::system::error_code, Iterator))
885 async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
886 ConnectCondition connect_condition,
887 BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler,
888 typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
889 {
890 return async_initiate<IteratorConnectHandler,
891 void (boost::system::error_code, Iterator)>(
892 detail::initiate_async_iterator_connect<Protocol, Executor>(s),
893 handler, begin, Iterator(), connect_condition);
894 }
895 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
896
897 template <typename Protocol, typename Executor,
898 typename Iterator, typename ConnectCondition,
899 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
900 Iterator)) IteratorConnectHandler>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,void (boost::system::error_code,Iterator))901 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
902 void (boost::system::error_code, Iterator))
903 async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
904 Iterator end, ConnectCondition connect_condition,
905 BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler)
906 {
907 return async_initiate<IteratorConnectHandler,
908 void (boost::system::error_code, Iterator)>(
909 detail::initiate_async_iterator_connect<Protocol, Executor>(s),
910 handler, begin, end, connect_condition);
911 }
912
913 } // namespace asio
914 } // namespace boost
915
916 #include <boost/asio/detail/pop_options.hpp>
917
918 #endif // BOOST_ASIO_IMPL_CONNECT_HPP
919