Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:23:31

0001 //
0002 // impl/connect.hpp
0003 // ~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_IMPL_CONNECT_HPP
0012 #define BOOST_ASIO_IMPL_CONNECT_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <algorithm>
0019 #include <boost/asio/associator.hpp>
0020 #include <boost/asio/detail/base_from_cancellation_state.hpp>
0021 #include <boost/asio/detail/bind_handler.hpp>
0022 #include <boost/asio/detail/handler_cont_helpers.hpp>
0023 #include <boost/asio/detail/handler_tracking.hpp>
0024 #include <boost/asio/detail/handler_type_requirements.hpp>
0025 #include <boost/asio/detail/non_const_lvalue.hpp>
0026 #include <boost/asio/detail/throw_error.hpp>
0027 #include <boost/asio/detail/type_traits.hpp>
0028 #include <boost/asio/error.hpp>
0029 #include <boost/asio/post.hpp>
0030 
0031 #include <boost/asio/detail/push_options.hpp>
0032 
0033 namespace boost {
0034 namespace asio {
0035 
0036 namespace detail
0037 {
0038   template <typename Protocol, typename Iterator>
0039   inline typename Protocol::endpoint deref_connect_result(
0040       Iterator iter, boost::system::error_code& ec)
0041   {
0042     return ec ? typename Protocol::endpoint() : *iter;
0043   }
0044 
0045   template <typename ConnectCondition, typename Iterator>
0046   inline Iterator call_connect_condition(ConnectCondition& connect_condition,
0047       const boost::system::error_code& ec, Iterator next, Iterator end,
0048       constraint_t<
0049         is_same<
0050           result_of_t<ConnectCondition(boost::system::error_code, Iterator)>,
0051           Iterator
0052         >::value
0053       > = 0)
0054   {
0055     if (next != end)
0056       return connect_condition(ec, next);
0057     return end;
0058   }
0059 
0060   template <typename ConnectCondition, typename Iterator>
0061   inline Iterator call_connect_condition(ConnectCondition& connect_condition,
0062       const boost::system::error_code& ec, Iterator next, Iterator end,
0063       constraint_t<
0064         is_same<
0065           result_of_t<ConnectCondition(boost::system::error_code,
0066             decltype(*declval<Iterator>()))>,
0067           bool
0068         >::value
0069       > = 0)
0070   {
0071     for (;next != end; ++next)
0072       if (connect_condition(ec, *next))
0073         return next;
0074     return end;
0075   }
0076 } // namespace detail
0077 
0078 template <typename Protocol, typename Executor, typename EndpointSequence>
0079 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
0080     const EndpointSequence& endpoints,
0081     constraint_t<
0082       is_endpoint_sequence<EndpointSequence>::value
0083     >)
0084 {
0085   boost::system::error_code ec;
0086   typename Protocol::endpoint result = connect(s, endpoints, ec);
0087   boost::asio::detail::throw_error(ec, "connect");
0088   return result;
0089 }
0090 
0091 template <typename Protocol, typename Executor, typename EndpointSequence>
0092 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
0093     const EndpointSequence& endpoints, boost::system::error_code& ec,
0094     constraint_t<
0095       is_endpoint_sequence<EndpointSequence>::value
0096     >)
0097 {
0098   return detail::deref_connect_result<Protocol>(
0099       connect(s, endpoints.begin(), endpoints.end(),
0100         detail::default_connect_condition(), ec), ec);
0101 }
0102 
0103 template <typename Protocol, typename Executor, typename Iterator>
0104 Iterator connect(basic_socket<Protocol, Executor>& s,
0105     Iterator begin, Iterator end)
0106 {
0107   boost::system::error_code ec;
0108   Iterator result = connect(s, begin, end, ec);
0109   boost::asio::detail::throw_error(ec, "connect");
0110   return result;
0111 }
0112 
0113 template <typename Protocol, typename Executor, typename Iterator>
0114 inline Iterator connect(basic_socket<Protocol, Executor>& s,
0115     Iterator begin, Iterator end, boost::system::error_code& ec)
0116 {
0117   return connect(s, begin, end, detail::default_connect_condition(), ec);
0118 }
0119 
0120 template <typename Protocol, typename Executor,
0121     typename EndpointSequence, typename ConnectCondition>
0122 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
0123     const EndpointSequence& endpoints, ConnectCondition connect_condition,
0124     constraint_t<
0125       is_endpoint_sequence<EndpointSequence>::value
0126     >,
0127     constraint_t<
0128       is_connect_condition<ConnectCondition,
0129         decltype(declval<const EndpointSequence&>().begin())>::value
0130     >)
0131 {
0132   boost::system::error_code ec;
0133   typename Protocol::endpoint result = connect(
0134       s, endpoints, connect_condition, ec);
0135   boost::asio::detail::throw_error(ec, "connect");
0136   return result;
0137 }
0138 
0139 template <typename Protocol, typename Executor,
0140     typename EndpointSequence, typename ConnectCondition>
0141 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
0142     const EndpointSequence& endpoints, ConnectCondition connect_condition,
0143     boost::system::error_code& ec,
0144     constraint_t<
0145       is_endpoint_sequence<EndpointSequence>::value
0146     >,
0147     constraint_t<
0148       is_connect_condition<ConnectCondition,
0149         decltype(declval<const EndpointSequence&>().begin())>::value
0150     >)
0151 {
0152   return detail::deref_connect_result<Protocol>(
0153       connect(s, endpoints.begin(), endpoints.end(),
0154         connect_condition, ec), ec);
0155 }
0156 
0157 template <typename Protocol, typename Executor,
0158     typename Iterator, typename ConnectCondition>
0159 Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
0160     Iterator end, ConnectCondition connect_condition,
0161     constraint_t<
0162       is_connect_condition<ConnectCondition, Iterator>::value
0163     >)
0164 {
0165   boost::system::error_code ec;
0166   Iterator result = connect(s, begin, end, connect_condition, ec);
0167   boost::asio::detail::throw_error(ec, "connect");
0168   return result;
0169 }
0170 
0171 template <typename Protocol, typename Executor,
0172     typename Iterator, typename ConnectCondition>
0173 Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
0174     Iterator end, ConnectCondition connect_condition,
0175     boost::system::error_code& ec,
0176     constraint_t<
0177       is_connect_condition<ConnectCondition, Iterator>::value
0178     >)
0179 {
0180   ec = boost::system::error_code();
0181 
0182   for (Iterator iter = begin; iter != end; ++iter)
0183   {
0184     iter = (detail::call_connect_condition(connect_condition, ec, iter, end));
0185     if (iter != end)
0186     {
0187       s.close(ec);
0188       s.connect(*iter, ec);
0189       if (!ec)
0190         return iter;
0191     }
0192     else
0193       break;
0194   }
0195 
0196   if (!ec)
0197     ec = boost::asio::error::not_found;
0198 
0199   return end;
0200 }
0201 
0202 namespace detail
0203 {
0204   // Enable the empty base class optimisation for the connect condition.
0205   template <typename ConnectCondition>
0206   class base_from_connect_condition
0207   {
0208   protected:
0209     explicit base_from_connect_condition(
0210         const ConnectCondition& connect_condition)
0211       : connect_condition_(connect_condition)
0212     {
0213     }
0214 
0215     template <typename Iterator>
0216     void check_condition(const boost::system::error_code& ec,
0217         Iterator& iter, Iterator& end)
0218     {
0219       iter = detail::call_connect_condition(connect_condition_, ec, iter, end);
0220     }
0221 
0222   private:
0223     ConnectCondition connect_condition_;
0224   };
0225 
0226   // The default_connect_condition implementation is essentially a no-op. This
0227   // template specialisation lets us eliminate all costs associated with it.
0228   template <>
0229   class base_from_connect_condition<default_connect_condition>
0230   {
0231   protected:
0232     explicit base_from_connect_condition(const default_connect_condition&)
0233     {
0234     }
0235 
0236     template <typename Iterator>
0237     void check_condition(const boost::system::error_code&, Iterator&, Iterator&)
0238     {
0239     }
0240   };
0241 
0242   template <typename Protocol, typename Executor, typename EndpointSequence,
0243       typename ConnectCondition, typename RangeConnectHandler>
0244   class range_connect_op
0245     : public base_from_cancellation_state<RangeConnectHandler>,
0246       base_from_connect_condition<ConnectCondition>
0247   {
0248   public:
0249     range_connect_op(basic_socket<Protocol, Executor>& sock,
0250         const EndpointSequence& endpoints,
0251         const ConnectCondition& connect_condition,
0252         RangeConnectHandler& handler)
0253       : base_from_cancellation_state<RangeConnectHandler>(
0254           handler, enable_partial_cancellation()),
0255         base_from_connect_condition<ConnectCondition>(connect_condition),
0256         socket_(sock),
0257         endpoints_(endpoints),
0258         index_(0),
0259         start_(0),
0260         handler_(static_cast<RangeConnectHandler&&>(handler))
0261     {
0262     }
0263 
0264     range_connect_op(const range_connect_op& other)
0265       : base_from_cancellation_state<RangeConnectHandler>(other),
0266         base_from_connect_condition<ConnectCondition>(other),
0267         socket_(other.socket_),
0268         endpoints_(other.endpoints_),
0269         index_(other.index_),
0270         start_(other.start_),
0271         handler_(other.handler_)
0272     {
0273     }
0274 
0275     range_connect_op(range_connect_op&& other)
0276       : base_from_cancellation_state<RangeConnectHandler>(
0277           static_cast<base_from_cancellation_state<RangeConnectHandler>&&>(
0278             other)),
0279         base_from_connect_condition<ConnectCondition>(other),
0280         socket_(other.socket_),
0281         endpoints_(other.endpoints_),
0282         index_(other.index_),
0283         start_(other.start_),
0284         handler_(static_cast<RangeConnectHandler&&>(other.handler_))
0285     {
0286     }
0287 
0288     void operator()(boost::system::error_code ec, int start = 0)
0289     {
0290       this->process(ec, start,
0291           const_cast<const EndpointSequence&>(endpoints_).begin(),
0292           const_cast<const EndpointSequence&>(endpoints_).end());
0293     }
0294 
0295   //private:
0296     template <typename Iterator>
0297     void process(boost::system::error_code ec,
0298         int start, Iterator begin, Iterator end)
0299     {
0300       Iterator iter = begin;
0301       std::advance(iter, index_);
0302 
0303       switch (start_ = start)
0304       {
0305         case 1:
0306         for (;;)
0307         {
0308           this->check_condition(ec, iter, end);
0309           index_ = std::distance(begin, iter);
0310 
0311           if (iter != end)
0312           {
0313             socket_.close(ec);
0314             BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
0315             socket_.async_connect(*iter,
0316                 static_cast<range_connect_op&&>(*this));
0317             return;
0318           }
0319 
0320           if (start)
0321           {
0322             ec = boost::asio::error::not_found;
0323             BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
0324             boost::asio::post(socket_.get_executor(),
0325                 detail::bind_handler(
0326                   static_cast<range_connect_op&&>(*this), ec));
0327             return;
0328           }
0329 
0330           /* fall-through */ default:
0331 
0332           if (iter == end)
0333             break;
0334 
0335           if (!socket_.is_open())
0336           {
0337             ec = boost::asio::error::operation_aborted;
0338             break;
0339           }
0340 
0341           if (!ec)
0342             break;
0343 
0344           if (this->cancelled() != cancellation_type::none)
0345           {
0346             ec = boost::asio::error::operation_aborted;
0347             break;
0348           }
0349 
0350           ++iter;
0351           ++index_;
0352         }
0353 
0354         static_cast<RangeConnectHandler&&>(handler_)(
0355             static_cast<const boost::system::error_code&>(ec),
0356             static_cast<const typename Protocol::endpoint&>(
0357               ec || iter == end ? typename Protocol::endpoint() : *iter));
0358       }
0359     }
0360 
0361     basic_socket<Protocol, Executor>& socket_;
0362     EndpointSequence endpoints_;
0363     std::size_t index_;
0364     int start_;
0365     RangeConnectHandler handler_;
0366   };
0367 
0368   template <typename Protocol, typename Executor, typename EndpointSequence,
0369       typename ConnectCondition, typename RangeConnectHandler>
0370   inline bool asio_handler_is_continuation(
0371       range_connect_op<Protocol, Executor, EndpointSequence,
0372         ConnectCondition, RangeConnectHandler>* this_handler)
0373   {
0374     return boost_asio_handler_cont_helpers::is_continuation(
0375         this_handler->handler_);
0376   }
0377 
0378   template <typename Protocol, typename Executor>
0379   class initiate_async_range_connect
0380   {
0381   public:
0382     typedef Executor executor_type;
0383 
0384     explicit initiate_async_range_connect(basic_socket<Protocol, Executor>& s)
0385       : socket_(s)
0386     {
0387     }
0388 
0389     executor_type get_executor() const noexcept
0390     {
0391       return socket_.get_executor();
0392     }
0393 
0394     template <typename RangeConnectHandler,
0395         typename EndpointSequence, typename ConnectCondition>
0396     void operator()(RangeConnectHandler&& handler,
0397         const EndpointSequence& endpoints,
0398         const ConnectCondition& connect_condition) const
0399     {
0400       // If you get an error on the following line it means that your
0401       // handler does not meet the documented type requirements for an
0402       // RangeConnectHandler.
0403       BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK(RangeConnectHandler,
0404           handler, typename Protocol::endpoint) type_check;
0405 
0406       non_const_lvalue<RangeConnectHandler> handler2(handler);
0407       range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition,
0408         decay_t<RangeConnectHandler>>(socket_, endpoints,
0409           connect_condition, handler2.value)(boost::system::error_code(), 1);
0410     }
0411 
0412   private:
0413     basic_socket<Protocol, Executor>& socket_;
0414   };
0415 
0416   template <typename Protocol, typename Executor, typename Iterator,
0417       typename ConnectCondition, typename IteratorConnectHandler>
0418   class iterator_connect_op
0419     : public base_from_cancellation_state<IteratorConnectHandler>,
0420       base_from_connect_condition<ConnectCondition>
0421   {
0422   public:
0423     iterator_connect_op(basic_socket<Protocol, Executor>& sock,
0424         const Iterator& begin, const Iterator& end,
0425         const ConnectCondition& connect_condition,
0426         IteratorConnectHandler& handler)
0427       : base_from_cancellation_state<IteratorConnectHandler>(
0428           handler, enable_partial_cancellation()),
0429         base_from_connect_condition<ConnectCondition>(connect_condition),
0430         socket_(sock),
0431         iter_(begin),
0432         end_(end),
0433         start_(0),
0434         handler_(static_cast<IteratorConnectHandler&&>(handler))
0435     {
0436     }
0437 
0438     iterator_connect_op(const iterator_connect_op& other)
0439       : base_from_cancellation_state<IteratorConnectHandler>(other),
0440         base_from_connect_condition<ConnectCondition>(other),
0441         socket_(other.socket_),
0442         iter_(other.iter_),
0443         end_(other.end_),
0444         start_(other.start_),
0445         handler_(other.handler_)
0446     {
0447     }
0448 
0449     iterator_connect_op(iterator_connect_op&& other)
0450       : base_from_cancellation_state<IteratorConnectHandler>(
0451           static_cast<base_from_cancellation_state<IteratorConnectHandler>&&>(
0452             other)),
0453         base_from_connect_condition<ConnectCondition>(other),
0454         socket_(other.socket_),
0455         iter_(other.iter_),
0456         end_(other.end_),
0457         start_(other.start_),
0458         handler_(static_cast<IteratorConnectHandler&&>(other.handler_))
0459     {
0460     }
0461 
0462     void operator()(boost::system::error_code ec, int start = 0)
0463     {
0464       switch (start_ = start)
0465       {
0466         case 1:
0467         for (;;)
0468         {
0469           this->check_condition(ec, iter_, end_);
0470 
0471           if (iter_ != end_)
0472           {
0473             socket_.close(ec);
0474             BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
0475             socket_.async_connect(*iter_,
0476                 static_cast<iterator_connect_op&&>(*this));
0477             return;
0478           }
0479 
0480           if (start)
0481           {
0482             ec = boost::asio::error::not_found;
0483             BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
0484             boost::asio::post(socket_.get_executor(),
0485                 detail::bind_handler(
0486                   static_cast<iterator_connect_op&&>(*this), ec));
0487             return;
0488           }
0489 
0490           /* fall-through */ default:
0491 
0492           if (iter_ == end_)
0493             break;
0494 
0495           if (!socket_.is_open())
0496           {
0497             ec = boost::asio::error::operation_aborted;
0498             break;
0499           }
0500 
0501           if (!ec)
0502             break;
0503 
0504           if (this->cancelled() != cancellation_type::none)
0505           {
0506             ec = boost::asio::error::operation_aborted;
0507             break;
0508           }
0509 
0510           ++iter_;
0511         }
0512 
0513         static_cast<IteratorConnectHandler&&>(handler_)(
0514             static_cast<const boost::system::error_code&>(ec),
0515             static_cast<const Iterator&>(iter_));
0516       }
0517     }
0518 
0519   //private:
0520     basic_socket<Protocol, Executor>& socket_;
0521     Iterator iter_;
0522     Iterator end_;
0523     int start_;
0524     IteratorConnectHandler handler_;
0525   };
0526 
0527   template <typename Protocol, typename Executor, typename Iterator,
0528       typename ConnectCondition, typename IteratorConnectHandler>
0529   inline bool asio_handler_is_continuation(
0530       iterator_connect_op<Protocol, Executor, Iterator,
0531         ConnectCondition, IteratorConnectHandler>* this_handler)
0532   {
0533     return boost_asio_handler_cont_helpers::is_continuation(
0534         this_handler->handler_);
0535   }
0536 
0537   template <typename Protocol, typename Executor>
0538   class initiate_async_iterator_connect
0539   {
0540   public:
0541     typedef Executor executor_type;
0542 
0543     explicit initiate_async_iterator_connect(
0544         basic_socket<Protocol, Executor>& s)
0545       : socket_(s)
0546     {
0547     }
0548 
0549     executor_type get_executor() const noexcept
0550     {
0551       return socket_.get_executor();
0552     }
0553 
0554     template <typename IteratorConnectHandler,
0555         typename Iterator, typename ConnectCondition>
0556     void operator()(IteratorConnectHandler&& handler,
0557         Iterator begin, Iterator end,
0558         const ConnectCondition& connect_condition) const
0559     {
0560       // If you get an error on the following line it means that your
0561       // handler does not meet the documented type requirements for an
0562       // IteratorConnectHandler.
0563       BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK(
0564           IteratorConnectHandler, handler, Iterator) type_check;
0565 
0566       non_const_lvalue<IteratorConnectHandler> handler2(handler);
0567       iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition,
0568         decay_t<IteratorConnectHandler>>(socket_, begin, end,
0569           connect_condition, handler2.value)(boost::system::error_code(), 1);
0570     }
0571 
0572   private:
0573     basic_socket<Protocol, Executor>& socket_;
0574   };
0575 } // namespace detail
0576 
0577 #if !defined(GENERATING_DOCUMENTATION)
0578 
0579 template <template <typename, typename> class Associator,
0580     typename Protocol, typename Executor, typename EndpointSequence,
0581     typename ConnectCondition, typename RangeConnectHandler,
0582     typename DefaultCandidate>
0583 struct associator<Associator,
0584     detail::range_connect_op<Protocol, Executor,
0585       EndpointSequence, ConnectCondition, RangeConnectHandler>,
0586     DefaultCandidate>
0587   : Associator<RangeConnectHandler, DefaultCandidate>
0588 {
0589   static typename Associator<RangeConnectHandler, DefaultCandidate>::type get(
0590       const detail::range_connect_op<Protocol, Executor, EndpointSequence,
0591         ConnectCondition, RangeConnectHandler>& h) noexcept
0592   {
0593     return Associator<RangeConnectHandler, DefaultCandidate>::get(h.handler_);
0594   }
0595 
0596   static auto get(
0597       const detail::range_connect_op<Protocol, Executor,
0598         EndpointSequence, ConnectCondition, RangeConnectHandler>& h,
0599       const DefaultCandidate& c) noexcept
0600     -> decltype(
0601       Associator<RangeConnectHandler, DefaultCandidate>::get(
0602         h.handler_, c))
0603   {
0604     return Associator<RangeConnectHandler, DefaultCandidate>::get(
0605         h.handler_, c);
0606   }
0607 };
0608 
0609 template <template <typename, typename> class Associator,
0610     typename Protocol, typename Executor, typename Iterator,
0611     typename ConnectCondition, typename IteratorConnectHandler,
0612     typename DefaultCandidate>
0613 struct associator<Associator,
0614     detail::iterator_connect_op<Protocol, Executor,
0615       Iterator, ConnectCondition, IteratorConnectHandler>,
0616     DefaultCandidate>
0617   : Associator<IteratorConnectHandler, DefaultCandidate>
0618 {
0619   static typename Associator<IteratorConnectHandler, DefaultCandidate>::type
0620   get(const detail::iterator_connect_op<Protocol, Executor, Iterator,
0621         ConnectCondition, IteratorConnectHandler>& h) noexcept
0622   {
0623     return Associator<IteratorConnectHandler, DefaultCandidate>::get(
0624         h.handler_);
0625   }
0626 
0627   static auto get(
0628       const detail::iterator_connect_op<Protocol, Executor,
0629         Iterator, ConnectCondition, IteratorConnectHandler>& h,
0630       const DefaultCandidate& c) noexcept
0631     -> decltype(
0632       Associator<IteratorConnectHandler, DefaultCandidate>::get(
0633         h.handler_, c))
0634   {
0635     return Associator<IteratorConnectHandler, DefaultCandidate>::get(
0636         h.handler_, c);
0637   }
0638 };
0639 
0640 #endif // !defined(GENERATING_DOCUMENTATION)
0641 
0642 } // namespace asio
0643 } // namespace boost
0644 
0645 #include <boost/asio/detail/pop_options.hpp>
0646 
0647 #endif // BOOST_ASIO_IMPL_CONNECT_HPP