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
26namespace asio {
27
28namespace detail
29{
30  struct default_connect_condition
31  {
32    template <typename Iterator>
33    Iterator operator()(const asio::error_code&, Iterator next)
34    {
35      return next;
36    }
37  };
38}
39
40template <typename Protocol, typename SocketService, typename Iterator>
41Iterator 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
49template <typename Protocol, typename SocketService, typename Iterator>
50inline 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
56template <typename Protocol, typename SocketService, typename Iterator>
57Iterator 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
66template <typename Protocol, typename SocketService, typename Iterator>
67inline 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
73template <typename Protocol, typename SocketService,
74    typename Iterator, typename ConnectCondition>
75Iterator 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
84template <typename Protocol, typename SocketService,
85    typename Iterator, typename ConnectCondition>
86inline 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
93template <typename Protocol, typename SocketService,
94    typename Iterator, typename ConnectCondition>
95Iterator 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
104template <typename Protocol, typename SocketService,
105    typename Iterator, typename ConnectCondition>
106Iterator 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
130namespace 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:
137    explicit base_from_connect_condition(
138        const ConnectCondition& connect_condition)
139      : connect_condition_(connect_condition)
140    {
141    }
142
143    template <typename Iterator>
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:
161    explicit base_from_connect_condition(const default_connect_condition&)
162    {
163    }
164
165    template <typename 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:
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
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
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
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>
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>
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>
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>
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>
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
316template <typename Protocol, typename SocketService,
317    typename Iterator, typename ComposedConnectHandler>
318inline ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,
319    void (asio::error_code, Iterator))
320async_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
341template <typename Protocol, typename SocketService,
342    typename Iterator, typename ComposedConnectHandler>
343inline ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,
344    void (asio::error_code, Iterator))
345async_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
367template <typename Protocol, typename SocketService, typename Iterator,
368    typename ConnectCondition, typename ComposedConnectHandler>
369inline ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,
370    void (asio::error_code, Iterator))
371async_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
393template <typename Protocol, typename SocketService, typename Iterator,
394    typename ConnectCondition, typename ComposedConnectHandler>
395inline ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,
396    void (asio::error_code, Iterator))
397async_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