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