File indexing completed on 2025-07-12 08:08:12
0001
0002
0003
0004
0005
0006
0007
0008
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
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 }
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 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0104 template <typename Protocol, typename Executor, typename Iterator>
0105 Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
0106 constraint_t<
0107 !is_endpoint_sequence<Iterator>::value
0108 >)
0109 {
0110 boost::system::error_code ec;
0111 Iterator result = connect(s, begin, ec);
0112 boost::asio::detail::throw_error(ec, "connect");
0113 return result;
0114 }
0115
0116 template <typename Protocol, typename Executor, typename Iterator>
0117 inline Iterator connect(basic_socket<Protocol, Executor>& s,
0118 Iterator begin, boost::system::error_code& ec,
0119 constraint_t<
0120 !is_endpoint_sequence<Iterator>::value
0121 >)
0122 {
0123 return connect(s, begin, Iterator(), detail::default_connect_condition(), ec);
0124 }
0125 #endif
0126
0127 template <typename Protocol, typename Executor, typename Iterator>
0128 Iterator connect(basic_socket<Protocol, Executor>& s,
0129 Iterator begin, Iterator end)
0130 {
0131 boost::system::error_code ec;
0132 Iterator result = connect(s, begin, end, ec);
0133 boost::asio::detail::throw_error(ec, "connect");
0134 return result;
0135 }
0136
0137 template <typename Protocol, typename Executor, typename Iterator>
0138 inline Iterator connect(basic_socket<Protocol, Executor>& s,
0139 Iterator begin, Iterator end, boost::system::error_code& ec)
0140 {
0141 return connect(s, begin, end, detail::default_connect_condition(), ec);
0142 }
0143
0144 template <typename Protocol, typename Executor,
0145 typename EndpointSequence, typename ConnectCondition>
0146 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
0147 const EndpointSequence& endpoints, ConnectCondition connect_condition,
0148 constraint_t<
0149 is_endpoint_sequence<EndpointSequence>::value
0150 >,
0151 constraint_t<
0152 is_connect_condition<ConnectCondition,
0153 decltype(declval<const EndpointSequence&>().begin())>::value
0154 >)
0155 {
0156 boost::system::error_code ec;
0157 typename Protocol::endpoint result = connect(
0158 s, endpoints, connect_condition, ec);
0159 boost::asio::detail::throw_error(ec, "connect");
0160 return result;
0161 }
0162
0163 template <typename Protocol, typename Executor,
0164 typename EndpointSequence, typename ConnectCondition>
0165 typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
0166 const EndpointSequence& endpoints, ConnectCondition connect_condition,
0167 boost::system::error_code& ec,
0168 constraint_t<
0169 is_endpoint_sequence<EndpointSequence>::value
0170 >,
0171 constraint_t<
0172 is_connect_condition<ConnectCondition,
0173 decltype(declval<const EndpointSequence&>().begin())>::value
0174 >)
0175 {
0176 return detail::deref_connect_result<Protocol>(
0177 connect(s, endpoints.begin(), endpoints.end(),
0178 connect_condition, ec), ec);
0179 }
0180
0181 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0182 template <typename Protocol, typename Executor,
0183 typename Iterator, typename ConnectCondition>
0184 Iterator connect(basic_socket<Protocol, Executor>& s,
0185 Iterator begin, ConnectCondition connect_condition,
0186 constraint_t<
0187 !is_endpoint_sequence<Iterator>::value
0188 >,
0189 constraint_t<
0190 is_connect_condition<ConnectCondition, Iterator>::value
0191 >)
0192 {
0193 boost::system::error_code ec;
0194 Iterator result = connect(s, begin, connect_condition, ec);
0195 boost::asio::detail::throw_error(ec, "connect");
0196 return result;
0197 }
0198
0199 template <typename Protocol, typename Executor,
0200 typename Iterator, typename ConnectCondition>
0201 inline Iterator connect(basic_socket<Protocol, Executor>& s,
0202 Iterator begin, ConnectCondition connect_condition,
0203 boost::system::error_code& ec,
0204 constraint_t<
0205 !is_endpoint_sequence<Iterator>::value
0206 >,
0207 constraint_t<
0208 is_connect_condition<ConnectCondition, Iterator>::value
0209 >)
0210 {
0211 return connect(s, begin, Iterator(), connect_condition, ec);
0212 }
0213 #endif
0214
0215 template <typename Protocol, typename Executor,
0216 typename Iterator, typename ConnectCondition>
0217 Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
0218 Iterator end, ConnectCondition connect_condition,
0219 constraint_t<
0220 is_connect_condition<ConnectCondition, Iterator>::value
0221 >)
0222 {
0223 boost::system::error_code ec;
0224 Iterator result = connect(s, begin, end, connect_condition, ec);
0225 boost::asio::detail::throw_error(ec, "connect");
0226 return result;
0227 }
0228
0229 template <typename Protocol, typename Executor,
0230 typename Iterator, typename ConnectCondition>
0231 Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
0232 Iterator end, ConnectCondition connect_condition,
0233 boost::system::error_code& ec,
0234 constraint_t<
0235 is_connect_condition<ConnectCondition, Iterator>::value
0236 >)
0237 {
0238 ec = boost::system::error_code();
0239
0240 for (Iterator iter = begin; iter != end; ++iter)
0241 {
0242 iter = (detail::call_connect_condition(connect_condition, ec, iter, end));
0243 if (iter != end)
0244 {
0245 s.close(ec);
0246 s.connect(*iter, ec);
0247 if (!ec)
0248 return iter;
0249 }
0250 else
0251 break;
0252 }
0253
0254 if (!ec)
0255 ec = boost::asio::error::not_found;
0256
0257 return end;
0258 }
0259
0260 namespace detail
0261 {
0262
0263 template <typename ConnectCondition>
0264 class base_from_connect_condition
0265 {
0266 protected:
0267 explicit base_from_connect_condition(
0268 const ConnectCondition& connect_condition)
0269 : connect_condition_(connect_condition)
0270 {
0271 }
0272
0273 template <typename Iterator>
0274 void check_condition(const boost::system::error_code& ec,
0275 Iterator& iter, Iterator& end)
0276 {
0277 iter = detail::call_connect_condition(connect_condition_, ec, iter, end);
0278 }
0279
0280 private:
0281 ConnectCondition connect_condition_;
0282 };
0283
0284
0285
0286 template <>
0287 class base_from_connect_condition<default_connect_condition>
0288 {
0289 protected:
0290 explicit base_from_connect_condition(const default_connect_condition&)
0291 {
0292 }
0293
0294 template <typename Iterator>
0295 void check_condition(const boost::system::error_code&, Iterator&, Iterator&)
0296 {
0297 }
0298 };
0299
0300 template <typename Protocol, typename Executor, typename EndpointSequence,
0301 typename ConnectCondition, typename RangeConnectHandler>
0302 class range_connect_op
0303 : public base_from_cancellation_state<RangeConnectHandler>,
0304 base_from_connect_condition<ConnectCondition>
0305 {
0306 public:
0307 range_connect_op(basic_socket<Protocol, Executor>& sock,
0308 const EndpointSequence& endpoints,
0309 const ConnectCondition& connect_condition,
0310 RangeConnectHandler& handler)
0311 : base_from_cancellation_state<RangeConnectHandler>(
0312 handler, enable_partial_cancellation()),
0313 base_from_connect_condition<ConnectCondition>(connect_condition),
0314 socket_(sock),
0315 endpoints_(endpoints),
0316 index_(0),
0317 start_(0),
0318 handler_(static_cast<RangeConnectHandler&&>(handler))
0319 {
0320 }
0321
0322 range_connect_op(const range_connect_op& other)
0323 : base_from_cancellation_state<RangeConnectHandler>(other),
0324 base_from_connect_condition<ConnectCondition>(other),
0325 socket_(other.socket_),
0326 endpoints_(other.endpoints_),
0327 index_(other.index_),
0328 start_(other.start_),
0329 handler_(other.handler_)
0330 {
0331 }
0332
0333 range_connect_op(range_connect_op&& other)
0334 : base_from_cancellation_state<RangeConnectHandler>(
0335 static_cast<base_from_cancellation_state<RangeConnectHandler>&&>(
0336 other)),
0337 base_from_connect_condition<ConnectCondition>(other),
0338 socket_(other.socket_),
0339 endpoints_(other.endpoints_),
0340 index_(other.index_),
0341 start_(other.start_),
0342 handler_(static_cast<RangeConnectHandler&&>(other.handler_))
0343 {
0344 }
0345
0346 void operator()(boost::system::error_code ec, int start = 0)
0347 {
0348 this->process(ec, start,
0349 const_cast<const EndpointSequence&>(endpoints_).begin(),
0350 const_cast<const EndpointSequence&>(endpoints_).end());
0351 }
0352
0353
0354 template <typename Iterator>
0355 void process(boost::system::error_code ec,
0356 int start, Iterator begin, Iterator end)
0357 {
0358 Iterator iter = begin;
0359 std::advance(iter, index_);
0360
0361 switch (start_ = start)
0362 {
0363 case 1:
0364 for (;;)
0365 {
0366 this->check_condition(ec, iter, end);
0367 index_ = std::distance(begin, iter);
0368
0369 if (iter != end)
0370 {
0371 socket_.close(ec);
0372 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
0373 socket_.async_connect(*iter,
0374 static_cast<range_connect_op&&>(*this));
0375 return;
0376 }
0377
0378 if (start)
0379 {
0380 ec = boost::asio::error::not_found;
0381 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
0382 boost::asio::post(socket_.get_executor(),
0383 detail::bind_handler(
0384 static_cast<range_connect_op&&>(*this), ec));
0385 return;
0386 }
0387
0388 default:
0389
0390 if (iter == end)
0391 break;
0392
0393 if (!socket_.is_open())
0394 {
0395 ec = boost::asio::error::operation_aborted;
0396 break;
0397 }
0398
0399 if (!ec)
0400 break;
0401
0402 if (this->cancelled() != cancellation_type::none)
0403 {
0404 ec = boost::asio::error::operation_aborted;
0405 break;
0406 }
0407
0408 ++iter;
0409 ++index_;
0410 }
0411
0412 static_cast<RangeConnectHandler&&>(handler_)(
0413 static_cast<const boost::system::error_code&>(ec),
0414 static_cast<const typename Protocol::endpoint&>(
0415 ec || iter == end ? typename Protocol::endpoint() : *iter));
0416 }
0417 }
0418
0419 basic_socket<Protocol, Executor>& socket_;
0420 EndpointSequence endpoints_;
0421 std::size_t index_;
0422 int start_;
0423 RangeConnectHandler handler_;
0424 };
0425
0426 template <typename Protocol, typename Executor, typename EndpointSequence,
0427 typename ConnectCondition, typename RangeConnectHandler>
0428 inline bool asio_handler_is_continuation(
0429 range_connect_op<Protocol, Executor, EndpointSequence,
0430 ConnectCondition, RangeConnectHandler>* this_handler)
0431 {
0432 return boost_asio_handler_cont_helpers::is_continuation(
0433 this_handler->handler_);
0434 }
0435
0436 template <typename Protocol, typename Executor>
0437 class initiate_async_range_connect
0438 {
0439 public:
0440 typedef Executor executor_type;
0441
0442 explicit initiate_async_range_connect(basic_socket<Protocol, Executor>& s)
0443 : socket_(s)
0444 {
0445 }
0446
0447 executor_type get_executor() const noexcept
0448 {
0449 return socket_.get_executor();
0450 }
0451
0452 template <typename RangeConnectHandler,
0453 typename EndpointSequence, typename ConnectCondition>
0454 void operator()(RangeConnectHandler&& handler,
0455 const EndpointSequence& endpoints,
0456 const ConnectCondition& connect_condition) const
0457 {
0458
0459
0460
0461 BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK(RangeConnectHandler,
0462 handler, typename Protocol::endpoint) type_check;
0463
0464 non_const_lvalue<RangeConnectHandler> handler2(handler);
0465 range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition,
0466 decay_t<RangeConnectHandler>>(socket_, endpoints,
0467 connect_condition, handler2.value)(boost::system::error_code(), 1);
0468 }
0469
0470 private:
0471 basic_socket<Protocol, Executor>& socket_;
0472 };
0473
0474 template <typename Protocol, typename Executor, typename Iterator,
0475 typename ConnectCondition, typename IteratorConnectHandler>
0476 class iterator_connect_op
0477 : public base_from_cancellation_state<IteratorConnectHandler>,
0478 base_from_connect_condition<ConnectCondition>
0479 {
0480 public:
0481 iterator_connect_op(basic_socket<Protocol, Executor>& sock,
0482 const Iterator& begin, const Iterator& end,
0483 const ConnectCondition& connect_condition,
0484 IteratorConnectHandler& handler)
0485 : base_from_cancellation_state<IteratorConnectHandler>(
0486 handler, enable_partial_cancellation()),
0487 base_from_connect_condition<ConnectCondition>(connect_condition),
0488 socket_(sock),
0489 iter_(begin),
0490 end_(end),
0491 start_(0),
0492 handler_(static_cast<IteratorConnectHandler&&>(handler))
0493 {
0494 }
0495
0496 iterator_connect_op(const iterator_connect_op& other)
0497 : base_from_cancellation_state<IteratorConnectHandler>(other),
0498 base_from_connect_condition<ConnectCondition>(other),
0499 socket_(other.socket_),
0500 iter_(other.iter_),
0501 end_(other.end_),
0502 start_(other.start_),
0503 handler_(other.handler_)
0504 {
0505 }
0506
0507 iterator_connect_op(iterator_connect_op&& other)
0508 : base_from_cancellation_state<IteratorConnectHandler>(
0509 static_cast<base_from_cancellation_state<IteratorConnectHandler>&&>(
0510 other)),
0511 base_from_connect_condition<ConnectCondition>(other),
0512 socket_(other.socket_),
0513 iter_(other.iter_),
0514 end_(other.end_),
0515 start_(other.start_),
0516 handler_(static_cast<IteratorConnectHandler&&>(other.handler_))
0517 {
0518 }
0519
0520 void operator()(boost::system::error_code ec, int start = 0)
0521 {
0522 switch (start_ = start)
0523 {
0524 case 1:
0525 for (;;)
0526 {
0527 this->check_condition(ec, iter_, end_);
0528
0529 if (iter_ != end_)
0530 {
0531 socket_.close(ec);
0532 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
0533 socket_.async_connect(*iter_,
0534 static_cast<iterator_connect_op&&>(*this));
0535 return;
0536 }
0537
0538 if (start)
0539 {
0540 ec = boost::asio::error::not_found;
0541 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
0542 boost::asio::post(socket_.get_executor(),
0543 detail::bind_handler(
0544 static_cast<iterator_connect_op&&>(*this), ec));
0545 return;
0546 }
0547
0548 default:
0549
0550 if (iter_ == end_)
0551 break;
0552
0553 if (!socket_.is_open())
0554 {
0555 ec = boost::asio::error::operation_aborted;
0556 break;
0557 }
0558
0559 if (!ec)
0560 break;
0561
0562 if (this->cancelled() != cancellation_type::none)
0563 {
0564 ec = boost::asio::error::operation_aborted;
0565 break;
0566 }
0567
0568 ++iter_;
0569 }
0570
0571 static_cast<IteratorConnectHandler&&>(handler_)(
0572 static_cast<const boost::system::error_code&>(ec),
0573 static_cast<const Iterator&>(iter_));
0574 }
0575 }
0576
0577
0578 basic_socket<Protocol, Executor>& socket_;
0579 Iterator iter_;
0580 Iterator end_;
0581 int start_;
0582 IteratorConnectHandler handler_;
0583 };
0584
0585 template <typename Protocol, typename Executor, typename Iterator,
0586 typename ConnectCondition, typename IteratorConnectHandler>
0587 inline bool asio_handler_is_continuation(
0588 iterator_connect_op<Protocol, Executor, Iterator,
0589 ConnectCondition, IteratorConnectHandler>* this_handler)
0590 {
0591 return boost_asio_handler_cont_helpers::is_continuation(
0592 this_handler->handler_);
0593 }
0594
0595 template <typename Protocol, typename Executor>
0596 class initiate_async_iterator_connect
0597 {
0598 public:
0599 typedef Executor executor_type;
0600
0601 explicit initiate_async_iterator_connect(
0602 basic_socket<Protocol, Executor>& s)
0603 : socket_(s)
0604 {
0605 }
0606
0607 executor_type get_executor() const noexcept
0608 {
0609 return socket_.get_executor();
0610 }
0611
0612 template <typename IteratorConnectHandler,
0613 typename Iterator, typename ConnectCondition>
0614 void operator()(IteratorConnectHandler&& handler,
0615 Iterator begin, Iterator end,
0616 const ConnectCondition& connect_condition) const
0617 {
0618
0619
0620
0621 BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK(
0622 IteratorConnectHandler, handler, Iterator) type_check;
0623
0624 non_const_lvalue<IteratorConnectHandler> handler2(handler);
0625 iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition,
0626 decay_t<IteratorConnectHandler>>(socket_, begin, end,
0627 connect_condition, handler2.value)(boost::system::error_code(), 1);
0628 }
0629
0630 private:
0631 basic_socket<Protocol, Executor>& socket_;
0632 };
0633 }
0634
0635 #if !defined(GENERATING_DOCUMENTATION)
0636
0637 template <template <typename, typename> class Associator,
0638 typename Protocol, typename Executor, typename EndpointSequence,
0639 typename ConnectCondition, typename RangeConnectHandler,
0640 typename DefaultCandidate>
0641 struct associator<Associator,
0642 detail::range_connect_op<Protocol, Executor,
0643 EndpointSequence, ConnectCondition, RangeConnectHandler>,
0644 DefaultCandidate>
0645 : Associator<RangeConnectHandler, DefaultCandidate>
0646 {
0647 static typename Associator<RangeConnectHandler, DefaultCandidate>::type get(
0648 const detail::range_connect_op<Protocol, Executor, EndpointSequence,
0649 ConnectCondition, RangeConnectHandler>& h) noexcept
0650 {
0651 return Associator<RangeConnectHandler, DefaultCandidate>::get(h.handler_);
0652 }
0653
0654 static auto get(
0655 const detail::range_connect_op<Protocol, Executor,
0656 EndpointSequence, ConnectCondition, RangeConnectHandler>& h,
0657 const DefaultCandidate& c) noexcept
0658 -> decltype(
0659 Associator<RangeConnectHandler, DefaultCandidate>::get(
0660 h.handler_, c))
0661 {
0662 return Associator<RangeConnectHandler, DefaultCandidate>::get(
0663 h.handler_, c);
0664 }
0665 };
0666
0667 template <template <typename, typename> class Associator,
0668 typename Protocol, typename Executor, typename Iterator,
0669 typename ConnectCondition, typename IteratorConnectHandler,
0670 typename DefaultCandidate>
0671 struct associator<Associator,
0672 detail::iterator_connect_op<Protocol, Executor,
0673 Iterator, ConnectCondition, IteratorConnectHandler>,
0674 DefaultCandidate>
0675 : Associator<IteratorConnectHandler, DefaultCandidate>
0676 {
0677 static typename Associator<IteratorConnectHandler, DefaultCandidate>::type
0678 get(const detail::iterator_connect_op<Protocol, Executor, Iterator,
0679 ConnectCondition, IteratorConnectHandler>& h) noexcept
0680 {
0681 return Associator<IteratorConnectHandler, DefaultCandidate>::get(
0682 h.handler_);
0683 }
0684
0685 static auto get(
0686 const detail::iterator_connect_op<Protocol, Executor,
0687 Iterator, ConnectCondition, IteratorConnectHandler>& h,
0688 const DefaultCandidate& c) noexcept
0689 -> decltype(
0690 Associator<IteratorConnectHandler, DefaultCandidate>::get(
0691 h.handler_, c))
0692 {
0693 return Associator<IteratorConnectHandler, DefaultCandidate>::get(
0694 h.handler_, c);
0695 }
0696 };
0697
0698 #endif
0699
0700 }
0701 }
0702
0703 #include <boost/asio/detail/pop_options.hpp>
0704
0705 #endif