File indexing completed on 2025-09-17 08:23:31
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 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
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
0227
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
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 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
0401
0402
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 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
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
0561
0562
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 }
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
0641
0642 }
0643 }
0644
0645 #include <boost/asio/detail/pop_options.hpp>
0646
0647 #endif