Home | History | Annotate | Download | only in impl
      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>
     33     Iterator operator()(const asio::error_code&, Iterator next)
     34     {
     35       return next;
     36     }
     37   };
     38 }
     39 
     40 template <typename Protocol, typename SocketService, typename Iterator>
     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>
     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>
     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>
     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>
     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>
     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>
     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>
    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:
    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 
    316 template <typename Protocol, typename SocketService,
    317     typename Iterator, typename ComposedConnectHandler>
    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>
    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>
    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>
    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