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