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