Add new free functions connect() and async_connect(). These try

each endpoint in a list until the socket is successfully connected.
This commit is contained in:
Christopher Kohlhoff 2011-02-08 18:26:30 +11:00
parent f8d583bbb5
commit 066e739628
22 changed files with 1205 additions and 166 deletions

View File

@ -21,6 +21,7 @@ nobase_include_HEADERS = \
asio/buffer.hpp \
asio/buffers_iterator.hpp \
asio/completion_condition.hpp \
asio/connect.hpp \
asio/datagram_socket_service.hpp \
asio/deadline_timer.hpp \
asio/deadline_timer_service.hpp \
@ -200,6 +201,7 @@ nobase_include_HEADERS = \
asio/handler_alloc_hook.hpp \
asio/handler_invoke_hook.hpp \
asio.hpp \
asio/impl/connect.hpp \
asio/impl/error_code.ipp \
asio/impl/error.ipp \
asio/impl/io_service.hpp \

View File

@ -34,6 +34,7 @@
#include "asio/buffered_write_stream.hpp"
#include "asio/buffers_iterator.hpp"
#include "asio/completion_condition.hpp"
#include "asio/connect.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/deadline_timer.hpp"

View File

@ -0,0 +1,799 @@
//
// connect.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_CONNECT_HPP
#define ASIO_CONNECT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/**
* @defgroup connect asio::connect
*
* @brief Establishes a socket connection by trying each endpoint in a sequence.
*/
/*@{*/
/// Establishes a socket connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
* function, once for each endpoint in the sequence, until a connection is
* successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @returns On success, an iterator denoting the successfully connected
* endpoint. Otherwise, the end iterator.
*
* @throws asio::system_error Thrown on failure. If the sequence is
* empty, the associated @c error_code is asio::error::not_found.
* Otherwise, contains the error from the last connection attempt.
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*
* @par Example
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_service);
* asio::connect(s, r.resolve(q)); @endcode
*/
template <typename Socket, typename Iterator>
Iterator connect(Socket& s, Iterator begin);
/// Establishes a socket connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
* function, once for each endpoint in the sequence, until a connection is
* successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param ec Set to indicate what error occurred, if any. If the sequence is
* empty, set to asio::error::not_found. Otherwise, contains the error
* from the last connection attempt.
*
* @returns On success, an iterator denoting the successfully connected
* endpoint. Otherwise, the end iterator.
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*
* @par Example
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_service);
* asio::error_code ec;
* asio::connect(s, r.resolve(q), ec);
* if (ec)
* {
* // An error occurred.
* } @endcode
*/
template <typename Socket, typename Iterator>
Iterator connect(Socket& s, Iterator begin, asio::error_code& ec);
/// Establishes a socket connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
* function, once for each endpoint in the sequence, until a connection is
* successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param end An iterator pointing to the end of a sequence of endpoints.
*
* @returns On success, an iterator denoting the successfully connected
* endpoint. Otherwise, the end iterator.
*
* @throws asio::system_error Thrown on failure. If the sequence is
* empty, the associated @c error_code is asio::error::not_found.
* Otherwise, contains the error from the last connection attempt.
*
* @par Example
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::resolver::iterator i = r.resolve(q), end;
* tcp::socket s(io_service);
* asio::connect(s, i, end); @endcode
*/
template <typename Socket, typename Iterator>
Iterator connect(Socket& s, Iterator begin, Iterator end);
/// Establishes a socket connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
* function, once for each endpoint in the sequence, until a connection is
* successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param end An iterator pointing to the end of a sequence of endpoints.
*
* @param ec Set to indicate what error occurred, if any. If the sequence is
* empty, set to asio::error::not_found. Otherwise, contains the error
* from the last connection attempt.
*
* @returns On success, an iterator denoting the successfully connected
* endpoint. Otherwise, the end iterator.
*
* @par Example
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::resolver::iterator i = r.resolve(q), end;
* tcp::socket s(io_service);
* asio::error_code ec;
* asio::connect(s, i, end, ec);
* if (ec)
* {
* // An error occurred.
* } @endcode
*/
template <typename Socket, typename Iterator>
Iterator connect(Socket& s, Iterator begin, Iterator end,
asio::error_code& ec);
/// Establishes a socket connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
* function, once for each endpoint in the sequence, until a connection is
* successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param connect_condition A function object that is called prior to each
* connection attempt. The signature of the function object must be:
* @code Iterator connect_condition(
* const asio::error_code& ec,
* Iterator next); @endcode
* The @c ec parameter contains the result from the most recent connect
* operation. Before the first connection attempt, @c ec is always set to
* indicate success. The @c next parameter is an iterator pointing to the next
* endpoint to be tried. The function object should return the next iterator,
* but is permitted to return a different iterator so that endpoints may be
* skipped. The implementation guarantees that the function object will never
* be called with the end iterator.
*
* @returns On success, an iterator denoting the successfully connected
* endpoint. Otherwise, the end iterator.
*
* @throws asio::system_error Thrown on failure. If the sequence is
* empty, the associated @c error_code is asio::error::not_found.
* Otherwise, contains the error from the last connection attempt.
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*
* @par Example
* The following connect condition function object can be used to output
* information about the individual connection attempts:
* @code struct my_connect_condition
* {
* template <typename Iterator>
* Iterator operator()(
* const asio::error_code& ec,
* Iterator next)
* {
* if (ec) std::cout << "Error: " << ec.message() << std::endl;
* std::cout << "Trying: " << next->endpoint() << std::endl;
* return next;
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_service);
* tcp::resolver::iterator i = asio::connect(
* s, r.resolve(q), my_connect_condition());
* std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode
*/
template <typename Socket, typename Iterator, typename ConnectCondition>
Iterator connect(Socket& s, Iterator begin, ConnectCondition connect_condition);
/// Establishes a socket connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
* function, once for each endpoint in the sequence, until a connection is
* successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param connect_condition A function object that is called prior to each
* connection attempt. The signature of the function object must be:
* @code Iterator connect_condition(
* const asio::error_code& ec,
* Iterator next); @endcode
* The @c ec parameter contains the result from the most recent connect
* operation. Before the first connection attempt, @c ec is always set to
* indicate success. The @c next parameter is an iterator pointing to the next
* endpoint to be tried. The function object should return the next iterator,
* but is permitted to return a different iterator so that endpoints may be
* skipped. The implementation guarantees that the function object will never
* be called with the end iterator.
*
* @param ec Set to indicate what error occurred, if any. If the sequence is
* empty, set to asio::error::not_found. Otherwise, contains the error
* from the last connection attempt.
*
* @returns On success, an iterator denoting the successfully connected
* endpoint. Otherwise, the end iterator.
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*
* @par Example
* The following connect condition function object can be used to output
* information about the individual connection attempts:
* @code struct my_connect_condition
* {
* template <typename Iterator>
* Iterator operator()(
* const asio::error_code& ec,
* Iterator next)
* {
* if (ec) std::cout << "Error: " << ec.message() << std::endl;
* std::cout << "Trying: " << next->endpoint() << std::endl;
* return next;
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_service);
* asio::error_code ec;
* tcp::resolver::iterator i = asio::connect(
* s, r.resolve(q), my_connect_condition(), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* std::cout << "Connected to: " << i->endpoint() << std::endl;
* } @endcode
*/
template <typename Socket, typename Iterator, typename ConnectCondition>
Iterator connect(Socket& s, Iterator begin,
ConnectCondition connect_condition, asio::error_code& ec);
/// Establishes a socket connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
* function, once for each endpoint in the sequence, until a connection is
* successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param end An iterator pointing to the end of a sequence of endpoints.
*
* @param connect_condition A function object that is called prior to each
* connection attempt. The signature of the function object must be:
* @code Iterator connect_condition(
* const asio::error_code& ec,
* Iterator next); @endcode
* The @c ec parameter contains the result from the most recent connect
* operation. Before the first connection attempt, @c ec is always set to
* indicate success. The @c next parameter is an iterator pointing to the next
* endpoint to be tried. The function object should return the next iterator,
* but is permitted to return a different iterator so that endpoints may be
* skipped. The implementation guarantees that the function object will never
* be called with the end iterator.
*
* @returns On success, an iterator denoting the successfully connected
* endpoint. Otherwise, the end iterator.
*
* @throws asio::system_error Thrown on failure. If the sequence is
* empty, the associated @c error_code is asio::error::not_found.
* Otherwise, contains the error from the last connection attempt.
*
* @par Example
* The following connect condition function object can be used to output
* information about the individual connection attempts:
* @code struct my_connect_condition
* {
* template <typename Iterator>
* Iterator operator()(
* const asio::error_code& ec,
* Iterator next)
* {
* if (ec) std::cout << "Error: " << ec.message() << std::endl;
* std::cout << "Trying: " << next->endpoint() << std::endl;
* return next;
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::resolver::iterator i = r.resolve(q), end;
* tcp::socket s(io_service);
* i = asio::connect(s, i, end, my_connect_condition());
* std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode
*/
template <typename Socket, typename Iterator, typename ConnectCondition>
Iterator connect(Socket& s, Iterator begin, Iterator end,
ConnectCondition connect_condition);
/// Establishes a socket connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
* function, once for each endpoint in the sequence, until a connection is
* successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param end An iterator pointing to the end of a sequence of endpoints.
*
* @param connect_condition A function object that is called prior to each
* connection attempt. The signature of the function object must be:
* @code Iterator connect_condition(
* const asio::error_code& ec,
* Iterator next); @endcode
* The @c ec parameter contains the result from the most recent connect
* operation. Before the first connection attempt, @c ec is always set to
* indicate success. The @c next parameter is an iterator pointing to the next
* endpoint to be tried. The function object should return the next iterator,
* but is permitted to return a different iterator so that endpoints may be
* skipped. The implementation guarantees that the function object will never
* be called with the end iterator.
*
* @param ec Set to indicate what error occurred, if any. If the sequence is
* empty, set to asio::error::not_found. Otherwise, contains the error
* from the last connection attempt.
*
* @returns On success, an iterator denoting the successfully connected
* endpoint. Otherwise, the end iterator.
*
* @par Example
* The following connect condition function object can be used to output
* information about the individual connection attempts:
* @code struct my_connect_condition
* {
* template <typename Iterator>
* Iterator operator()(
* const asio::error_code& ec,
* Iterator next)
* {
* if (ec) std::cout << "Error: " << ec.message() << std::endl;
* std::cout << "Trying: " << next->endpoint() << std::endl;
* return next;
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::resolver::iterator i = r.resolve(q), end;
* tcp::socket s(io_service);
* asio::error_code ec;
* i = asio::connect(s, i, end, my_connect_condition(), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* std::cout << "Connected to: " << i->endpoint() << std::endl;
* } @endcode
*/
template <typename Socket, typename Iterator, typename ConnectCondition>
Iterator connect(Socket& s, Iterator begin, Iterator end,
ConnectCondition connect_condition, asio::error_code& ec);
/*@}*/
/**
* @defgroup async_connect asio::async_connect
*
* @brief Asynchronously establishes a socket connection by trying each
* endpoint in a sequence.
*/
/*@{*/
/// Asynchronously establishes a socket connection by trying each endpoint in a
/// sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection
* is successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param handler The handler to be called when the connect operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the
* // error from the last connection attempt.
* const asio::error_code& error,
*
* // On success, an iterator denoting the successfully
* // connected endpoint. Otherwise, the end iterator.
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*
* @par Example
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_service);
*
* // ...
*
* r.async_resolve(q, resolve_handler);
*
* // ...
*
* void resolve_handler(
* const asio::error_code& ec,
* tcp::resolver::iterator i)
* {
* if (!ec)
* {
* asio::async_connect(s, i, connect_handler);
* }
* }
*
* // ...
*
* void connect_handler(
* const asio::error_code& ec,
* tcp::resolver::iterator i)
* {
* // ...
* } @endcode
*/
template <typename Socket, typename Iterator, typename ComposedConnectHandler>
void async_connect(Socket& s, Iterator begin, ComposedConnectHandler handler);
/// Asynchronously establishes a socket connection by trying each endpoint in a
/// sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection
* is successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param end An iterator pointing to the end of a sequence of endpoints.
*
* @param handler The handler to be called when the connect operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the
* // error from the last connection attempt.
* const asio::error_code& error,
*
* // On success, an iterator denoting the successfully
* // connected endpoint. Otherwise, the end iterator.
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @par Example
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_service);
*
* // ...
*
* r.async_resolve(q, resolve_handler);
*
* // ...
*
* void resolve_handler(
* const asio::error_code& ec,
* tcp::resolver::iterator i)
* {
* if (!ec)
* {
* tcp::resolver::iterator end;
* asio::async_connect(s, i, end, connect_handler);
* }
* }
*
* // ...
*
* void connect_handler(
* const asio::error_code& ec,
* tcp::resolver::iterator i)
* {
* // ...
* } @endcode
*/
template <typename Socket, typename Iterator, typename ComposedConnectHandler>
void async_connect(Socket& s, Iterator begin, Iterator end,
ComposedConnectHandler handler);
/// Asynchronously establishes a socket connection by trying each endpoint in a
/// sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection
* is successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param connect_condition A function object that is called prior to each
* connection attempt. The signature of the function object must be:
* @code Iterator connect_condition(
* const asio::error_code& ec,
* Iterator next); @endcode
* The @c ec parameter contains the result from the most recent connect
* operation. Before the first connection attempt, @c ec is always set to
* indicate success. The @c next parameter is an iterator pointing to the next
* endpoint to be tried. The function object should return the next iterator,
* but is permitted to return a different iterator so that endpoints may be
* skipped. The implementation guarantees that the function object will never
* be called with the end iterator.
*
* @param handler The handler to be called when the connect operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the
* // error from the last connection attempt.
* const asio::error_code& error,
*
* // On success, an iterator denoting the successfully
* // connected endpoint. Otherwise, the end iterator.
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*
* @par Example
* The following connect condition function object can be used to output
* information about the individual connection attempts:
* @code struct my_connect_condition
* {
* template <typename Iterator>
* Iterator operator()(
* const asio::error_code& ec,
* Iterator next)
* {
* if (ec) std::cout << "Error: " << ec.message() << std::endl;
* std::cout << "Trying: " << next->endpoint() << std::endl;
* return next;
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_service);
*
* // ...
*
* r.async_resolve(q, resolve_handler);
*
* // ...
*
* void resolve_handler(
* const asio::error_code& ec,
* tcp::resolver::iterator i)
* {
* if (!ec)
* {
* asio::async_connect(s, i,
* my_connect_condition(),
* connect_handler);
* }
* }
*
* // ...
*
* void connect_handler(
* const asio::error_code& ec,
* tcp::resolver::iterator i)
* {
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* std::cout << "Connected to: " << i->endpoint() << std::endl;
* }
* } @endcode
*/
template <typename Socket, typename Iterator,
typename ConnectCondition, typename ComposedConnectHandler>
void async_connect(Socket& s, Iterator begin,
ConnectCondition connect_condition, ComposedConnectHandler handler);
/// Asynchronously establishes a socket connection by trying each endpoint in a
/// sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection
* is successfully established.
*
* @param s The socket to be connected. If the socket is already open, it will
* be closed.
*
* @param begin An iterator pointing to the start of a sequence of endpoints.
*
* @param end An iterator pointing to the end of a sequence of endpoints.
*
* @param connect_condition A function object that is called prior to each
* connection attempt. The signature of the function object must be:
* @code Iterator connect_condition(
* const asio::error_code& ec,
* Iterator next); @endcode
* The @c ec parameter contains the result from the most recent connect
* operation. Before the first connection attempt, @c ec is always set to
* indicate success. The @c next parameter is an iterator pointing to the next
* endpoint to be tried. The function object should return the next iterator,
* but is permitted to return a different iterator so that endpoints may be
* skipped. The implementation guarantees that the function object will never
* be called with the end iterator.
*
* @param handler The handler to be called when the connect operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the
* // error from the last connection attempt.
* const asio::error_code& error,
*
* // On success, an iterator denoting the successfully
* // connected endpoint. Otherwise, the end iterator.
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @par Example
* The following connect condition function object can be used to output
* information about the individual connection attempts:
* @code struct my_connect_condition
* {
* template <typename Iterator>
* Iterator operator()(
* const asio::error_code& ec,
* Iterator next)
* {
* if (ec) std::cout << "Error: " << ec.message() << std::endl;
* std::cout << "Trying: " << next->endpoint() << std::endl;
* return next;
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_service);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_service);
*
* // ...
*
* r.async_resolve(q, resolve_handler);
*
* // ...
*
* void resolve_handler(
* const asio::error_code& ec,
* tcp::resolver::iterator i)
* {
* if (!ec)
* {
* tcp::resolver::iterator end;
* asio::async_connect(s, i, end,
* my_connect_condition(),
* connect_handler);
* }
* }
*
* // ...
*
* void connect_handler(
* const asio::error_code& ec,
* tcp::resolver::iterator i)
* {
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* std::cout << "Connected to: " << i->endpoint() << std::endl;
* }
* } @endcode
*/
template <typename Socket, typename Iterator,
typename ConnectCondition, typename ComposedConnectHandler>
void async_connect(Socket& s, Iterator begin, Iterator end,
ConnectCondition connect_condition, ComposedConnectHandler handler);
/*@}*/
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/connect.hpp"
#endif

View File

@ -0,0 +1,311 @@
//
// impl/connect.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_IMPL_CONNECT_HPP
#define ASIO_IMPL_CONNECT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/consuming_buffers.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail
{
struct default_connect_condition
{
template <typename Iterator>
Iterator operator()(const asio::error_code&, Iterator next)
{
return next;
}
};
}
template <typename Socket, typename Iterator>
Iterator connect(Socket& s, Iterator begin)
{
asio::error_code ec;
Iterator result = connect(s, begin, ec);
asio::detail::throw_error(ec);
return result;
}
template <typename Socket, typename Iterator>
inline Iterator connect(Socket& s, Iterator begin,
asio::error_code& ec)
{
return connect(s, begin, Iterator(), detail::default_connect_condition(), ec);
}
template <typename Socket, typename Iterator>
Iterator connect(Socket& s, Iterator begin, Iterator end)
{
asio::error_code ec;
Iterator result = connect(s, begin, end, ec);
asio::detail::throw_error(ec);
return result;
}
template <typename Socket, typename Iterator>
inline Iterator connect(Socket& s, Iterator begin, Iterator end,
asio::error_code& ec)
{
return connect(s, begin, end, detail::default_connect_condition(), ec);
}
template <typename Socket, typename Iterator, typename ConnectCondition>
Iterator connect(Socket& s, Iterator begin,
ConnectCondition connect_condition)
{
asio::error_code ec;
Iterator result = connect(s, begin, connect_condition, ec);
asio::detail::throw_error(ec);
return result;
}
template <typename Socket, typename Iterator, typename ConnectCondition>
inline Iterator connect(Socket& s, Iterator begin,
ConnectCondition connect_condition, asio::error_code& ec)
{
return connect(s, begin, Iterator(), connect_condition, ec);
}
template <typename Socket, typename Iterator, typename ConnectCondition>
Iterator connect(Socket& s, Iterator begin, Iterator end,
ConnectCondition connect_condition)
{
asio::error_code ec;
Iterator result = connect(s, begin, end, connect_condition, ec);
asio::detail::throw_error(ec);
return result;
}
template <typename Socket, typename Iterator, typename ConnectCondition>
Iterator connect(Socket& s, Iterator begin, Iterator end,
ConnectCondition connect_condition, asio::error_code& ec)
{
ec = asio::error_code();
for (Iterator iter = begin; iter != end; ++iter)
{
iter = connect_condition(ec, iter);
if (iter != end)
{
s.close(ec);
s.connect(*iter, ec);
if (!ec)
return iter;
}
}
if (!ec)
ec = asio::error::not_found;
return end;
}
namespace detail
{
// Enable the empty base class optimisation for the connect condition.
template <typename ConnectCondition>
class base_from_connect_condition
{
protected:
explicit base_from_connect_condition(
const ConnectCondition& connect_condition)
: connect_condition_(connect_condition)
{
}
template <typename Iterator>
void check_condition(const asio::error_code& ec,
Iterator& iter, Iterator& end)
{
if (iter != end)
iter = connect_condition_(ec, static_cast<const Iterator&>(iter));
}
private:
ConnectCondition connect_condition_;
};
// The default_connect_condition implementation is essentially a no-op. This
// template specialisation lets us eliminate all costs associated with it.
template <>
class base_from_connect_condition<default_connect_condition>
{
protected:
explicit base_from_connect_condition(const default_connect_condition&)
{
}
template <typename Iterator>
void check_condition(const asio::error_code&, Iterator&, Iterator&)
{
}
};
template <typename Socket, typename Iterator,
typename ConnectCondition, typename ComposedConnectHandler>
class connect_op : base_from_connect_condition<ConnectCondition>
{
public:
connect_op(Socket& sock,
const Iterator& begin, const Iterator& end,
const ConnectCondition& connect_condition,
ComposedConnectHandler& handler)
: base_from_connect_condition<ConnectCondition>(connect_condition),
socket_(sock),
iter_(begin),
end_(end),
handler_(ASIO_MOVE_CAST(ComposedConnectHandler)(handler))
{
}
void operator()(asio::error_code ec, int start = 0)
{
switch (start)
{
case 1:
for (;;)
{
this->check_condition(ec, iter_, end_);
if (iter_ != end_)
{
socket_.close(ec);
socket_.async_connect(*iter_, *this);
return;
}
if (start)
{
ec = asio::error::not_found;
socket_.get_io_service().post(detail::bind_handler(*this, ec));
return;
}
default:
if (iter_ == end_)
break;
if (!socket_.is_open())
{
ec = asio::error::operation_aborted;
break;
}
if (!ec)
break;
++iter_;
}
handler_(static_cast<const asio::error_code&>(ec),
static_cast<const Iterator&>(iter_));
}
}
//private:
Socket& socket_;
Iterator iter_;
Iterator end_;
ComposedConnectHandler handler_;
};
template <typename Socket, typename Iterator,
typename ConnectCondition, typename ComposedConnectHandler>
inline void* asio_handler_allocate(std::size_t size,
connect_op<Socket, Iterator, ConnectCondition,
ComposedConnectHandler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Socket, typename Iterator,
typename ConnectCondition, typename ComposedConnectHandler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
connect_op<Socket, Iterator, ConnectCondition,
ComposedConnectHandler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Function, typename Socket, typename Iterator,
typename ConnectCondition, typename ComposedConnectHandler>
inline void asio_handler_invoke(const Function& function,
connect_op<Socket, Iterator, ConnectCondition,
ComposedConnectHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
} // namespace detail
template <typename Socket, typename Iterator, typename ComposedConnectHandler>
inline void async_connect(Socket& s, Iterator begin,
ComposedConnectHandler handler)
{
detail::connect_op<Socket, Iterator,
detail::default_connect_condition, ComposedConnectHandler>(
s, begin, Iterator(), detail::default_connect_condition(), handler)(
asio::error_code(), 1);
}
template <typename Socket, typename Iterator, typename ComposedConnectHandler>
inline void async_connect(Socket& s, Iterator begin, Iterator end,
ComposedConnectHandler handler)
{
detail::connect_op<Socket, Iterator,
detail::default_connect_condition, ComposedConnectHandler>(
s, begin, end, detail::default_connect_condition(), handler)(
asio::error_code(), 1);
}
template <typename Socket, typename Iterator,
typename ConnectCondition, typename ComposedConnectHandler>
inline void async_connect(Socket& s, Iterator begin,
ConnectCondition connect_condition, ComposedConnectHandler handler)
{
detail::connect_op<Socket, Iterator,
ConnectCondition, ComposedConnectHandler>(
s, begin, Iterator(), connect_condition, handler)(
asio::error_code(), 1);
}
template <typename Socket, typename Iterator,
typename ConnectCondition, typename ComposedConnectHandler>
void async_connect(Socket& s, Iterator begin, Iterator end,
ConnectCondition connect_condition, ComposedConnectHandler handler)
{
detail::connect_op<Socket, Iterator,
ConnectCondition, ComposedConnectHandler>(
s, begin, end, connect_condition, handler)(
asio::error_code(), 1);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_CONNECT_HPP

View File

@ -22,6 +22,7 @@ check_PROGRAMS = \
tests/unit/buffer \
tests/unit/buffers_iterator \
tests/unit/completion_condition \
tests/unit/connect \
tests/unit/datagram_socket_service \
tests/unit/deadline_timer_service \
tests/unit/deadline_timer \
@ -174,6 +175,7 @@ TESTS = \
tests/unit/buffer \
tests/unit/buffers_iterator \
tests/unit/completion_condition \
tests/unit/connect \
tests/unit/datagram_socket_service \
tests/unit/deadline_timer_service \
tests/unit/deadline_timer \
@ -274,6 +276,7 @@ tests_unit_buffered_read_stream_SOURCES = tests/unit/buffered_read_stream.cpp te
tests_unit_buffered_stream_SOURCES = tests/unit/buffered_stream.cpp tests/unit/unit_test.cpp
tests_unit_buffered_write_stream_SOURCES = tests/unit/buffered_write_stream.cpp tests/unit/unit_test.cpp
tests_unit_completion_condition_SOURCES = tests/unit/completion_condition.cpp tests/unit/unit_test.cpp
tests_unit_connect_SOURCES = tests/unit/connect.cpp tests/unit/unit_test.cpp
tests_unit_datagram_socket_service_SOURCES = tests/unit/datagram_socket_service.cpp tests/unit/unit_test.cpp
tests_unit_deadline_timer_service_SOURCES = tests/unit/deadline_timer_service.cpp tests/unit/unit_test.cpp
tests_unit_deadline_timer_SOURCES = tests/unit/deadline_timer.cpp tests/unit/unit_test.cpp

View File

@ -25,6 +25,7 @@ UNIT_TEST_EXES = \
tests/unit/buffer.exe \
tests/unit/buffers_iterator.exe \
tests/unit/completion_condition.exe \
tests/unit/connect.exe \
tests/unit/datagram_socket_service.exe \
tests/unit/deadline_timer_service.exe \
tests/unit/deadline_timer.exe \

View File

@ -90,6 +90,7 @@ UNIT_TEST_EXES = \
tests\unit\buffer.exe \
tests\unit\buffers_iterator.exe \
tests\unit\completion_condition.exe \
tests\unit\connect.exe \
tests\unit\datagram_socket_service.exe \
tests\unit\deadline_timer_service.exe \
tests\unit\deadline_timer.exe \

View File

@ -27,10 +27,9 @@ public:
: io_service_(io_service),
socket_(io_service)
{
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
asio::async_connect(socket_, endpoint_iterator,
boost::bind(&chat_client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
asio::placeholders::error));
}
void write(const chat_message& msg)
@ -45,8 +44,7 @@ public:
private:
void handle_connect(const asio::error_code& error,
tcp::resolver::iterator endpoint_iterator)
void handle_connect(const asio::error_code& error)
{
if (!error)
{
@ -55,14 +53,6 @@ private:
boost::bind(&chat_client::handle_read_header, this,
asio::placeholders::error));
}
else if (endpoint_iterator != tcp::resolver::iterator())
{
socket_.close();
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
boost::bind(&chat_client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
}
}
void handle_read_header(const asio::error_code& error)

View File

@ -31,17 +31,14 @@ public:
output_(io_service, ::dup(STDOUT_FILENO)),
input_buffer_(chat_message::max_body_length)
{
// Try connecting to the first endpoint.
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
asio::async_connect(socket_, endpoint_iterator,
boost::bind(&posix_chat_client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
asio::placeholders::error));
}
private:
void handle_connect(const asio::error_code& error,
tcp::resolver::iterator endpoint_iterator)
void handle_connect(const asio::error_code& error)
{
if (!error)
{
@ -57,15 +54,6 @@ private:
asio::placeholders::error,
asio::placeholders::bytes_transferred));
}
else if (endpoint_iterator != tcp::resolver::iterator())
{
// That endpoint didn't work, try the next one.
socket_.close();
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
boost::bind(&posix_chat_client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
}
}
void handle_read_header(const asio::error_code& error)

View File

@ -34,7 +34,7 @@ int main(int argc, char* argv[])
tcp::resolver::iterator iterator = resolver.resolve(query);
tcp::socket s(io_service);
s.connect(*iterator);
asio::connect(s, iterator);
using namespace std; // For strlen.
std::cout << "Enter message: ";

View File

@ -49,12 +49,11 @@ private:
{
if (!err)
{
// Attempt a connection to the first endpoint in the list. Each endpoint
// will be tried until we successfully establish a connection.
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
// Attempt a connection to each endpoint in the list until we
// successfully establish a connection.
asio::async_connect(socket_, endpoint_iterator,
boost::bind(&client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
asio::placeholders::error));
}
else
{
@ -62,8 +61,7 @@ private:
}
}
void handle_connect(const asio::error_code& err,
tcp::resolver::iterator endpoint_iterator)
void handle_connect(const asio::error_code& err)
{
if (!err)
{
@ -72,15 +70,6 @@ private:
boost::bind(&client::handle_write_request, this,
asio::placeholders::error));
}
else if (endpoint_iterator != tcp::resolver::iterator())
{
// The connection failed. Try the next endpoint in the list.
socket_.close();
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
boost::bind(&client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
}
else
{
std::cout << "Error: " << err.message() << "\n";

View File

@ -34,18 +34,10 @@ int main(int argc, char* argv[])
tcp::resolver resolver(io_service);
tcp::resolver::query query(argv[1], "http");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
// Try each endpoint until we successfully establish a connection.
tcp::socket socket(io_service);
asio::error_code error = asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
socket.close();
socket.connect(*endpoint_iterator++, error);
}
if (error)
throw asio::system_error(error);
asio::connect(socket, endpoint_iterator);
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
@ -99,6 +91,7 @@ int main(int argc, char* argv[])
std::cout << &response;
// Read until EOF, writing data to output as we go.
asio::error_code error;
while (asio::read(socket, response,
asio::transfer_at_least(1), error))
std::cout << &response;

View File

@ -32,17 +32,15 @@ public:
asio::ip::tcp::resolver::query query(host, service);
asio::ip::tcp::resolver::iterator endpoint_iterator =
resolver.resolve(query);
asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
// Start an asynchronous connect operation.
connection_.socket().async_connect(endpoint,
asio::async_connect(connection_.socket(), endpoint_iterator,
boost::bind(&client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
asio::placeholders::error));
}
/// Handle completion of a connect operation.
void handle_connect(const asio::error_code& e,
asio::ip::tcp::resolver::iterator endpoint_iterator)
void handle_connect(const asio::error_code& e)
{
if (!e)
{
@ -53,15 +51,6 @@ public:
boost::bind(&client::handle_read, this,
asio::placeholders::error));
}
else if (endpoint_iterator != asio::ip::tcp::resolver::iterator())
{
// Try the next endpoint.
connection_.socket().close();
asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
connection_.socket().async_connect(endpoint,
boost::bind(&client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
}
else
{
// An error occurred. Log it and return. Since we are not starting a new

View File

@ -32,8 +32,7 @@ void read_handler(const asio::error_code& e,
}
}
void connect_handler(const asio::error_code& e, debug_stream_socket* s,
asio::ip::tcp::resolver::iterator endpoint_iterator)
void connect_handler(const asio::error_code& e, debug_stream_socket* s)
{
if (!e)
{
@ -41,14 +40,6 @@ void connect_handler(const asio::error_code& e, debug_stream_socket* s,
boost::bind(read_handler, asio::placeholders::error,
asio::placeholders::bytes_transferred, s));
}
else if (endpoint_iterator != asio::ip::tcp::resolver::iterator())
{
s->close();
asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
s->async_connect(endpoint,
boost::bind(connect_handler,
asio::placeholders::error, s, ++endpoint_iterator));
}
else
{
std::cerr << e.message() << std::endl;
@ -75,13 +66,12 @@ int main(int argc, char* argv[])
asio::ip::tcp::resolver resolver(io_service);
asio::ip::tcp::resolver::query query(argv[1], "daytime");
asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
asio::ip::tcp::endpoint endpoint = *iterator;
// Start an asynchronous connect.
debug_stream_socket socket(io_service);
socket.async_connect(endpoint,
asio::async_connect(socket, iterator,
boost::bind(connect_handler,
asio::placeholders::error, &socket, ++iterator));
asio::placeholders::error, &socket));
// Run the io_service until all operations have finished.
io_service.run();

View File

@ -37,19 +37,11 @@ int main(int argc, char* argv[])
tcp::resolver resolver(io_service);
tcp::resolver::query socks_query(argv[1], argv[2]);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(socks_query);
tcp::resolver::iterator end;
// Try each endpoint until we successfully establish a connection to the
// SOCKS 4 server.
tcp::socket socket(io_service);
asio::error_code error = asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
socket.close();
socket.connect(*endpoint_iterator++, error);
}
if (error)
throw asio::system_error(error);
asio::connect(socket, endpoint_iterator);
// Get an endpoint for the Boost website. This will be passed to the SOCKS
// 4 server. Explicitly specify IPv4 since SOCKS 4 does not support IPv6.
@ -87,6 +79,7 @@ int main(int argc, char* argv[])
// Read until EOF, writing data to output as we go.
boost::array<char, 512> response;
asio::error_code error;
while (std::size_t s = socket.read_some(
asio::buffer(response), error))
std::cout.write(response.data(), s);

View File

@ -23,14 +23,12 @@ public:
asio::ip::tcp::resolver::iterator endpoint_iterator)
: socket_(io_service, context)
{
asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
socket_.lowest_layer().async_connect(endpoint,
asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
asio::placeholders::error));
}
void handle_connect(const asio::error_code& error,
asio::ip::tcp::resolver::iterator endpoint_iterator)
void handle_connect(const asio::error_code& error)
{
if (!error)
{
@ -38,14 +36,6 @@ public:
boost::bind(&client::handle_handshake, this,
asio::placeholders::error));
}
else if (endpoint_iterator != asio::ip::tcp::resolver::iterator())
{
socket_.lowest_layer().close();
asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
socket_.lowest_layer().async_connect(endpoint,
boost::bind(&client::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator));
}
else
{
std::cout << "Connect failed: " << error << "\n";

View File

@ -8,6 +8,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "asio/connect.hpp"
#include "asio/deadline_timer.hpp"
#include "asio/io_service.hpp"
#include "asio/ip/tcp.hpp"
@ -73,47 +74,36 @@ public:
tcp::resolver::query query(host, service);
tcp::resolver::iterator iter = tcp::resolver(io_service_).resolve(query);
// Set a deadline for the asynchronous operation. The host name may resolve
// to multiple endpoints, and this function tries to connect to each one in
// turn. Setting the deadline here means it applies to the entire sequence.
// Set a deadline for the asynchronous operation. As a host name may
// resolve to multiple endpoints, this function uses the composed operation
// async_connect. The deadline applies to the entire operation, rather than
// individual connection attempts.
deadline_.expires_from_now(timeout);
asio::error_code ec;
// Set up the variable that receives the result of the asynchronous
// operation. The error code is set to would_block to signal that the
// operation is incomplete. Asio guarantees that its asynchronous
// operations will never fail with would_block, so any other value in
// ec indicates completion.
asio::error_code ec = asio::error::would_block;
for (; iter != tcp::resolver::iterator(); ++iter)
{
// We may have an open socket from a previous connection attempt. This
// socket cannot be reused, so we must close it before trying to connect
// again.
socket_.close();
// Start the asynchronous operation itself. The boost::lambda function
// object is used as a callback and will update the ec variable when the
// operation completes. The blocking_udp_client.cpp example shows how you
// can use boost::bind rather than boost::lambda.
asio::async_connect(socket_, iter, var(ec) = _1);
// Set up the variable that receives the result of the asynchronous
// operation. The error code is set to would_block to signal that the
// operation is incomplete. Asio guarantees that its asynchronous
// operations will never fail with would_block, so any other value in
// ec indicates completion.
ec = asio::error::would_block;
// Block until the asynchronous operation has completed.
do io_service_.run_one(); while (ec == asio::error::would_block);
// Start the asynchronous operation itself. The boost::lambda function
// object is used as a callback and will update the ec variable when the
// operation completes. The blocking_udp_client.cpp example shows how you
// can use boost::bind rather than boost::lambda.
socket_.async_connect(iter->endpoint(), var(ec) = _1);
// Block until the asynchronous operation has completed.
do io_service_.run_one(); while (ec == asio::error::would_block);
// Determine whether a connection was successfully established. The
// deadline actor may have had a chance to run and close our socket, even
// though the connect operation notionally succeeded. Therefore we must
// check whether the socket is still open before deciding that the we
// were successful.
if (!ec && socket_.is_open())
return;
}
throw asio::system_error(
ec ? ec : asio::error::host_not_found);
// Determine whether a connection was successfully established. The
// deadline actor may have had a chance to run and close our socket, even
// though the connect operation notionally succeeded. Therefore we must
// check whether the socket is still open before deciding if we succeeded
// or failed.
if (ec || !socket_.is_open())
throw asio::system_error(
ec ? ec : asio::error::operation_aborted);
}
std::string read_line(boost::posix_time::time_duration timeout)

View File

@ -29,17 +29,9 @@ int main(int argc, char* argv[])
tcp::resolver resolver(io_service);
tcp::resolver::query query(argv[1], "daytime");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
tcp::socket socket(io_service);
asio::error_code error = asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
socket.close();
socket.connect(*endpoint_iterator++, error);
}
if (error)
throw asio::system_error(error);
asio::connect(socket, endpoint_iterator);
for (;;)
{

View File

@ -41,17 +41,17 @@ and the name of the service, in this case <tt>"daytime"</tt>.
\until tcp::resolver::query
The list of endpoints is returned using an iterator of type
asio::ip::tcp::resolver::iterator. A default constructed
asio::ip::tcp::resolver::iterator object is used as the end iterator.
asio::ip::tcp::resolver::iterator. (Note that a default constructed
asio::ip::tcp::resolver::iterator object can be used as an end iterator.)
\until tcp::resolver::iterator end;
\until tcp::resolver::iterator
Now we create and connect the socket. The list of endpoints obtained above may
contain both IPv4 and IPv6 endpoints, so we need to try each of them until we
find one that works. This keeps the client program independent of a specific IP
version.
version. The asio::connect() function does this for us automatically.
\until throw
\until asio::connect
The connection is open. All we need to do now is read the response from the
daytime service.

View File

@ -76,10 +76,9 @@ public:
void start(asio::ip::tcp::resolver::iterator endpoint_iterator)
{
asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
asio::async_connect(socket_, endpoint_iterator,
strand_.wrap(boost::bind(&session::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator)));
asio::placeholders::error)));
}
void stop()
@ -88,8 +87,7 @@ public:
}
private:
void handle_connect(const asio::error_code& err,
asio::ip::tcp::resolver::iterator endpoint_iterator)
void handle_connect(const asio::error_code& err)
{
if (!err)
{
@ -113,14 +111,6 @@ private:
asio::placeholders::bytes_transferred))));
}
}
else if (endpoint_iterator != asio::ip::tcp::resolver::iterator())
{
socket_.close();
asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
strand_.wrap(boost::bind(&session::handle_connect, this,
asio::placeholders::error, ++endpoint_iterator)));
}
}
void handle_read(const asio::error_code& err, size_t length)

View File

@ -18,6 +18,7 @@ buffered_stream
buffered_write_stream
buffers_iterator
completion_condition
connect
datagram_socket_service
deadline_timer
deadline_timer_service

View File

@ -0,0 +1,26 @@
//
// connect.cpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Disable autolinking for unit tests.
#if !defined(BOOST_ALL_NO_LIB)
#define BOOST_ALL_NO_LIB 1
#endif // !defined(BOOST_ALL_NO_LIB)
// Test that header file is self-contained.
#include "asio/connect.hpp"
#include "unit_test.hpp"
test_suite* init_unit_test_suite(int, char*[])
{
test_suite* test = BOOST_TEST_SUITE("connect");
test->add(BOOST_TEST_CASE(&null_test));
return test;
}