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>
operator ()asio::detail::default_connect_condition33 Iterator operator()(const asio::error_code&, Iterator next)
34 {
35 return next;
36 }
37 };
38 }
39
40 template <typename Protocol, typename SocketService, typename Iterator>
connect(basic_socket<Protocol,SocketService> & s,Iterator begin)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>
connect(basic_socket<Protocol,SocketService> & s,Iterator begin,asio::error_code & ec)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>
connect(basic_socket<Protocol,SocketService> & s,Iterator begin,Iterator end)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>
connect(basic_socket<Protocol,SocketService> & s,Iterator begin,Iterator end,asio::error_code & ec)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>
connect(basic_socket<Protocol,SocketService> & s,Iterator begin,ConnectCondition connect_condition)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>
connect(basic_socket<Protocol,SocketService> & s,Iterator begin,ConnectCondition connect_condition,asio::error_code & ec)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>
connect(basic_socket<Protocol,SocketService> & s,Iterator begin,Iterator end,ConnectCondition connect_condition)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>
connect(basic_socket<Protocol,SocketService> & s,Iterator begin,Iterator end,ConnectCondition connect_condition,asio::error_code & ec)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:
base_from_connect_condition(const ConnectCondition & connect_condition)137 explicit base_from_connect_condition(
138 const ConnectCondition& connect_condition)
139 : connect_condition_(connect_condition)
140 {
141 }
142
143 template <typename Iterator>
check_condition(const asio::error_code & ec,Iterator & iter,Iterator & end)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:
base_from_connect_condition(const default_connect_condition &)161 explicit base_from_connect_condition(const default_connect_condition&)
162 {
163 }
164
165 template <typename Iterator>
check_condition(const asio::error_code &,Iterator &,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:
connect_op(basic_socket<Protocol,SocketService> & sock,const Iterator & begin,const Iterator & end,const ConnectCondition & connect_condition,ComposedConnectHandler & handler)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
connect_op(const connect_op & other)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
connect_op(connect_op && other)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
operator ()(asio::error_code ec,int start=0)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>
asio_handler_allocate(std::size_t size,connect_op<Protocol,SocketService,Iterator,ConnectCondition,ComposedConnectHandler> * this_handler)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>
asio_handler_deallocate(void * pointer,std::size_t size,connect_op<Protocol,SocketService,Iterator,ConnectCondition,ComposedConnectHandler> * this_handler)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>
asio_handler_is_continuation(connect_op<Protocol,SocketService,Iterator,ConnectCondition,ComposedConnectHandler> * this_handler)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>
asio_handler_invoke(Function & function,connect_op<Protocol,SocketService,Iterator,ConnectCondition,ComposedConnectHandler> * this_handler)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>
asio_handler_invoke(const Function & function,connect_op<Protocol,SocketService,Iterator,ConnectCondition,ComposedConnectHandler> * this_handler)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>
ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,void (asio::error_code,Iterator))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>
ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,void (asio::error_code,Iterator))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>
ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,void (asio::error_code,Iterator))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>
ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,void (asio::error_code,Iterator))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