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 BOOST_ASIO_IMPL_CONNECT_HPP
12#define BOOST_ASIO_IMPL_CONNECT_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/bind_handler.hpp>
19#include <boost/asio/detail/consuming_buffers.hpp>
20#include <boost/asio/detail/handler_alloc_helpers.hpp>
21#include <boost/asio/detail/handler_cont_helpers.hpp>
22#include <boost/asio/detail/handler_invoke_helpers.hpp>
23#include <boost/asio/detail/handler_type_requirements.hpp>
24#include <boost/asio/detail/throw_error.hpp>
25#include <boost/asio/error.hpp>
26
27#include <boost/asio/detail/push_options.hpp>
28
29namespace boost {
30namespace asio {
31
32namespace detail
33{
34 struct default_connect_condition
35 {
36 template <typename Iterator>
37 Iterator operator()(const boost::system::error_code&, Iterator next)
38 {
39 return next;
40 }
41 };
42}
43
44template <typename Protocol, typename SocketService, typename Iterator>
45Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin)
46{
47 boost::system::error_code ec;
48 Iterator result = connect(s, begin, ec);
49 boost::asio::detail::throw_error(ec, "connect");
50 return result;
51}
52
53template <typename Protocol, typename SocketService, typename Iterator>
54inline Iterator connect(basic_socket<Protocol, SocketService>& s,
55 Iterator begin, boost::system::error_code& ec)
56{
57 return connect(s, begin, Iterator(), detail::default_connect_condition(), ec);
58}
59
60template <typename Protocol, typename SocketService, typename Iterator>
61Iterator connect(basic_socket<Protocol, SocketService>& s,
62 Iterator begin, Iterator end)
63{
64 boost::system::error_code ec;
65 Iterator result = connect(s, begin, end, ec);
66 boost::asio::detail::throw_error(ec, "connect");
67 return result;
68}
69
70template <typename Protocol, typename SocketService, typename Iterator>
71inline Iterator connect(basic_socket<Protocol, SocketService>& s,
72 Iterator begin, Iterator end, boost::system::error_code& ec)
73{
74 return connect(s, begin, end, detail::default_connect_condition(), ec);
75}
76
77template <typename Protocol, typename SocketService,
78 typename Iterator, typename ConnectCondition>
79Iterator connect(basic_socket<Protocol, SocketService>& s,
80 Iterator begin, ConnectCondition connect_condition)
81{
82 boost::system::error_code ec;
83 Iterator result = connect(s, begin, connect_condition, ec);
84 boost::asio::detail::throw_error(ec, "connect");
85 return result;
86}
87
88template <typename Protocol, typename SocketService,
89 typename Iterator, typename ConnectCondition>
90inline Iterator connect(basic_socket<Protocol, SocketService>& s,
91 Iterator begin, ConnectCondition connect_condition,
92 boost::system::error_code& ec)
93{
94 return connect(s, begin, Iterator(), connect_condition, ec);
95}
96
97template <typename Protocol, typename SocketService,
98 typename Iterator, typename ConnectCondition>
99Iterator connect(basic_socket<Protocol, SocketService>& s,
100 Iterator begin, Iterator end, ConnectCondition connect_condition)
101{
102 boost::system::error_code ec;
103 Iterator result = connect(s, begin, end, connect_condition, ec);
104 boost::asio::detail::throw_error(ec, "connect");
105 return result;
106}
107
108template <typename Protocol, typename SocketService,
109 typename Iterator, typename ConnectCondition>
110Iterator connect(basic_socket<Protocol, SocketService>& s,
111 Iterator begin, Iterator end, ConnectCondition connect_condition,
112 boost::system::error_code& ec)
113{
114 ec = boost::system::error_code();
115
116 for (Iterator iter = begin; iter != end; ++iter)
117 {
118 iter = connect_condition(ec, iter);
119 if (iter != end)
120 {
121 s.close(ec);
122 s.connect(*iter, ec);
123 if (!ec)
124 return iter;
125 }
126 }
127
128 if (!ec)
129 ec = boost::asio::error::not_found;
130
131 return end;
132}
133
134namespace detail
135{
136 // Enable the empty base class optimisation for the connect condition.
137 template <typename ConnectCondition>
138 class base_from_connect_condition
139 {
140 protected:
141 explicit base_from_connect_condition(
142 const ConnectCondition& connect_condition)
143 : connect_condition_(connect_condition)
144 {
145 }
146
147 template <typename Iterator>
148 void check_condition(const boost::system::error_code& ec,
149 Iterator& iter, Iterator& end)
150 {
151 if (iter != end)
152 iter = connect_condition_(ec, static_cast<const Iterator&>(iter));
153 }
154
155 private:
156 ConnectCondition connect_condition_;
157 };
158
159 // The default_connect_condition implementation is essentially a no-op. This
160 // template specialisation lets us eliminate all costs associated with it.
161 template <>
162 class base_from_connect_condition<default_connect_condition>
163 {
164 protected:
165 explicit base_from_connect_condition(const default_connect_condition&)
166 {
167 }
168
169 template <typename Iterator>
170 void check_condition(const boost::system::error_code&, Iterator&, Iterator&)
171 {
172 }
173 };
174
175 template <typename Protocol, typename SocketService, typename Iterator,
176 typename ConnectCondition, typename ComposedConnectHandler>
177 class connect_op : base_from_connect_condition<ConnectCondition>
178 {
179 public:
180 connect_op(basic_socket<Protocol, SocketService>& sock,
181 const Iterator& begin, const Iterator& end,
182 const ConnectCondition& connect_condition,
183 ComposedConnectHandler& handler)
184 : base_from_connect_condition<ConnectCondition>(connect_condition),
185 socket_(sock),
186 iter_(begin),
187 end_(end),
188 start_(0),
189 handler_(BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler))
190 {
191 }
192
193#if defined(BOOST_ASIO_HAS_MOVE)
194 connect_op(const connect_op& other)
195 : base_from_connect_condition<ConnectCondition>(other),
196 socket_(other.socket_),
197 iter_(other.iter_),
198 end_(other.end_),
199 start_(other.start_),
200 handler_(other.handler_)
201 {
202 }
203
204 connect_op(connect_op&& other)
205 : base_from_connect_condition<ConnectCondition>(other),
206 socket_(other.socket_),
207 iter_(other.iter_),
208 end_(other.end_),
209 start_(other.start_),
210 handler_(BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(other.handler_))
211 {
212 }
213#endif // defined(BOOST_ASIO_HAS_MOVE)
214
215 void operator()(boost::system::error_code ec, int start = 0)
216 {
217 switch (start_ = start)
218 {
219 case 1:
220 for (;;)
221 {
222 this->check_condition(ec, iter_, end_);
223
224 if (iter_ != end_)
225 {
226 socket_.close(ec);
227 socket_.async_connect(*iter_,
228 BOOST_ASIO_MOVE_CAST(connect_op)(*this));
229 return;
230 }
231
232 if (start)
233 {
234 ec = boost::asio::error::not_found;
235 socket_.get_io_service().post(detail::bind_handler(*this, ec));
236 return;
237 }
238
239 default:
240
241 if (iter_ == end_)
242 break;
243
244 if (!socket_.is_open())
245 {
246 ec = boost::asio::error::operation_aborted;
247 break;
248 }
249
250 if (!ec)
251 break;
252
253 ++iter_;
254 }
255
256 handler_(static_cast<const boost::system::error_code&>(ec),
257 static_cast<const Iterator&>(iter_));
258 }
259 }
260
261 //private:
262 basic_socket<Protocol, SocketService>& socket_;
263 Iterator iter_;
264 Iterator end_;
265 int start_;
266 ComposedConnectHandler handler_;
267 };
268
269 template <typename Protocol, typename SocketService, typename Iterator,
270 typename ConnectCondition, typename ComposedConnectHandler>
271 inline void* asio_handler_allocate(std::size_t size,
272 connect_op<Protocol, SocketService, Iterator,
273 ConnectCondition, ComposedConnectHandler>* this_handler)
274 {
275 return boost_asio_handler_alloc_helpers::allocate(
276 size, this_handler->handler_);
277 }
278
279 template <typename Protocol, typename SocketService, typename Iterator,
280 typename ConnectCondition, typename ComposedConnectHandler>
281 inline void asio_handler_deallocate(void* pointer, std::size_t size,
282 connect_op<Protocol, SocketService, Iterator,
283 ConnectCondition, ComposedConnectHandler>* this_handler)
284 {
285 boost_asio_handler_alloc_helpers::deallocate(
286 pointer, size, this_handler->handler_);
287 }
288
289 template <typename Protocol, typename SocketService, typename Iterator,
290 typename ConnectCondition, typename ComposedConnectHandler>
291 inline bool asio_handler_is_continuation(
292 connect_op<Protocol, SocketService, Iterator,
293 ConnectCondition, ComposedConnectHandler>* this_handler)
294 {
295 return boost_asio_handler_cont_helpers::is_continuation(
296 this_handler->handler_);
297 }
298
299 template <typename Function, typename Protocol,
300 typename SocketService, typename Iterator,
301 typename ConnectCondition, typename ComposedConnectHandler>
302 inline void asio_handler_invoke(Function& function,
303 connect_op<Protocol, SocketService, Iterator,
304 ConnectCondition, ComposedConnectHandler>* this_handler)
305 {
306 boost_asio_handler_invoke_helpers::invoke(
307 function, this_handler->handler_);
308 }
309
310 template <typename Function, typename Protocol,
311 typename SocketService, typename Iterator,
312 typename ConnectCondition, typename ComposedConnectHandler>
313 inline void asio_handler_invoke(const Function& function,
314 connect_op<Protocol, SocketService, Iterator,
315 ConnectCondition, ComposedConnectHandler>* this_handler)
316 {
317 boost_asio_handler_invoke_helpers::invoke(
318 function, this_handler->handler_);
319 }
320} // namespace detail
321
322template <typename Protocol, typename SocketService,
323 typename Iterator, typename ComposedConnectHandler>
324inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,
325 void (boost::system::error_code, Iterator))
326async_connect(basic_socket<Protocol, SocketService>& s,
327 Iterator begin, BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler)
328{
329 // If you get an error on the following line it means that your handler does
330 // not meet the documented type requirements for a ComposedConnectHandler.
331 BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK(
332 ComposedConnectHandler, handler, Iterator) type_check;
333
334 detail::async_result_init<ComposedConnectHandler,
335 void (boost::system::error_code, Iterator)> init(
336 BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler));
337
338 detail::connect_op<Protocol, SocketService, Iterator,
339 detail::default_connect_condition, BOOST_ASIO_HANDLER_TYPE(
340 ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s,
341 begin, Iterator(), detail::default_connect_condition(), init.handler)(
342 boost::system::error_code(), 1);
343
344 return init.result.get();
345}
346
347template <typename Protocol, typename SocketService,
348 typename Iterator, typename ComposedConnectHandler>
349inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,
350 void (boost::system::error_code, Iterator))
351async_connect(basic_socket<Protocol, SocketService>& s,
352 Iterator begin, Iterator end,
353 BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler)
354{
355 // If you get an error on the following line it means that your handler does
356 // not meet the documented type requirements for a ComposedConnectHandler.
357 BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK(
358 ComposedConnectHandler, handler, Iterator) type_check;
359
360 detail::async_result_init<ComposedConnectHandler,
361 void (boost::system::error_code, Iterator)> init(
362 BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler));
363
364 detail::connect_op<Protocol, SocketService, Iterator,
365 detail::default_connect_condition, BOOST_ASIO_HANDLER_TYPE(
366 ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s,
367 begin, end, detail::default_connect_condition(), init.handler)(
368 boost::system::error_code(), 1);
369
370 return init.result.get();
371}
372
373template <typename Protocol, typename SocketService, typename Iterator,
374 typename ConnectCondition, typename ComposedConnectHandler>
375inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,
376 void (boost::system::error_code, Iterator))
377async_connect(basic_socket<Protocol, SocketService>& s,
378 Iterator begin, ConnectCondition connect_condition,
379 BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler)
380{
381 // If you get an error on the following line it means that your handler does
382 // not meet the documented type requirements for a ComposedConnectHandler.
383 BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK(
384 ComposedConnectHandler, handler, Iterator) type_check;
385
386 detail::async_result_init<ComposedConnectHandler,
387 void (boost::system::error_code, Iterator)> init(
388 BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler));
389
390 detail::connect_op<Protocol, SocketService, Iterator,
391 ConnectCondition, BOOST_ASIO_HANDLER_TYPE(
392 ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s,
393 begin, Iterator(), connect_condition, init.handler)(
394 boost::system::error_code(), 1);
395
396 return init.result.get();
397}
398
399template <typename Protocol, typename SocketService, typename Iterator,
400 typename ConnectCondition, typename ComposedConnectHandler>
401inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,
402 void (boost::system::error_code, Iterator))
403async_connect(basic_socket<Protocol, SocketService>& s,
404 Iterator begin, Iterator end, ConnectCondition connect_condition,
405 BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler)
406{
407 // If you get an error on the following line it means that your handler does
408 // not meet the documented type requirements for a ComposedConnectHandler.
409 BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK(
410 ComposedConnectHandler, handler, Iterator) type_check;
411
412 detail::async_result_init<ComposedConnectHandler,
413 void (boost::system::error_code, Iterator)> init(
414 BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler));
415
416 detail::connect_op<Protocol, SocketService, Iterator,
417 ConnectCondition, BOOST_ASIO_HANDLER_TYPE(
418 ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s,
419 begin, end, connect_condition, init.handler)(
420 boost::system::error_code(), 1);
421
422 return init.result.get();
423}
424
425} // namespace asio
426} // namespace boost
427
428#include <boost/asio/detail/pop_options.hpp>
429
430#endif // BOOST_ASIO_IMPL_CONNECT_HPP
431