Add per-operation error handling policies.

This commit is contained in:
chris 2003-11-11 07:07:42 +00:00
parent c4761ad928
commit cc58f99de7
2 changed files with 206 additions and 59 deletions

View File

@ -21,6 +21,7 @@
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error_handler.hpp"
#include "asio/null_completion_context.hpp"
#include "asio/service_factory.hpp"
@ -68,22 +69,24 @@ public:
* @param addr An address on the local machine on which the acceptor will
* listen for new connections.
*
* @param listen_queue The maximum length of the queue of pending
* connections. A value of 0 means use the default queue length.
*
* @throws socket_error Thrown on failure.
*/
template <typename Address>
basic_socket_acceptor(demuxer_type& d, const Address& addr)
basic_socket_acceptor(demuxer_type& d, const Address& addr,
int listen_queue = 0)
: service_(d.get_service(service_factory<Service>())),
impl_(service_type::null())
{
service_.create(impl_, addr);
service_.create(impl_, addr, listen_queue, default_error_handler());
}
/// Construct an acceptor opened on the given address, specifying the
/// maximum length of the queue of pending connetions.
/// Construct an acceptor opened on the given address.
/**
* This constructor creates an acceptor and automatically opens it to listen
* for new connections on the specified address. The maximum length of the
* queue of pending connections is also supplied.
* for new connections on the specified address.
*
* @param d The demuxer object that the acceptor will use to deliver
* completions for any asynchronous operations performed on the acceptor.
@ -92,16 +95,22 @@ public:
* listen for new connections.
*
* @param listen_queue The maximum length of the queue of pending
* connections.
* connections. A value of 0 means use the default queue length.
*
* @throws socket_error Thrown on failure.
* @param error_handler The handler to be called when an error occurs or when
* the function completes successfully. Copies will be made of the handler as
* required. The equivalent function signature of the handler must be:
* @code void error_handler(
* const asio::socket_error& error // Result of operation
* ); @endcode
*/
template <typename Address>
basic_socket_acceptor(demuxer_type& d, const Address& addr, int listen_queue)
template <typename Address, typename Error_Handler>
basic_socket_acceptor(demuxer_type& d, const Address& addr, int listen_queue,
Error_Handler error_handler)
: service_(d.get_service(service_factory<Service>())),
impl_(service_type::null())
{
service_.create(impl_, addr, listen_queue);
service_.create(impl_, addr, listen_queue, error_handler);
}
/// Destructor.
@ -132,32 +141,39 @@ public:
* @param addr An address on the local machine on which the acceptor will
* listen for new connections.
*
* @param listen_queue The maximum length of the queue of pending
* connections. A value of 0 means use the default queue length.
*
* @throws socket_error Thrown on failure.
*/
template <typename Address>
void open(const Address& addr)
void open(const Address& addr, int listen_queue = 0)
{
service_.create(impl_, addr);
service_.create(impl_, addr, listen_queue, default_error_handler());
}
/// Open the acceptor using the given address and length of the listen queue.
/// Open the acceptor using the given address.
/**
* This function opens the acceptor to listen for new connections on the
* specified address. The maximum length of the queue of pending connections
* is also supplied.
* specified address.
*
* @param addr An address on the local machine on which the acceptor will
* listen for new connections.
*
* @param listen_queue The maximum length of the queue of pending
* connections.
* connections. A value of 0 means use the default queue length.
*
* @throws socket_error Thrown on failure.
* @param error_handler The handler to be called when an error occurs or when
* the function completes successfully. Copies will be made of the handler as
* required. The equivalent function signature of the handler must be:
* @code void error_handler(
* const asio::socket_error& error // Result of operation
* ); @endcode
*/
template <typename Address>
void open(const Address& addr, int listen_queue)
template <typename Address, typename Error_Handler>
void open(const Address& addr, int listen_queue, Error_Handler error_handler)
{
service_.create(impl_, addr, listen_queue);
service_.create(impl_, addr, listen_queue, error_handler);
}
/// Close the acceptor.
@ -186,30 +202,70 @@ public:
/// Set an option on the acceptor.
/**
* This function is used to set an option on the socket.
* This function is used to set an option on the acceptor.
*
* @param option The new option value to be set on the socket.
* @param option The new option value to be set on the acceptor.
*
* @throws socket_error Thrown on failure.
*/
template <typename Option>
void set_option(const Option& option)
{
service_.set_option(impl_, option);
service_.set_option(impl_, option, default_error_handler());
}
/// Set an option on the acceptor.
/**
* This function is used to set an option on the acceptor.
*
* @param option The new option value to be set on the acceptor.
*
* @param error_handler The handler to be called when an error occurs or when
* the function completes successfully. Copies will be made of the handler as
* required. The equivalent function signature of the handler must be:
* @code void error_handler(
* const asio::socket_error& error // Result of operation
* ); @endcode
*/
template <typename Option, typename Error_Handler>
void set_option(const Option& option, Error_Handler error_handler)
{
service_.set_option(impl_, option, error_handler);
}
/// Get an option from the acceptor.
/**
* This function is used to get the current value of an option on the socket.
* This function is used to get the current value of an option on the
* acceptor.
*
* @param option The option value to be obtained from the socket.
* @param option The option value to be obtained from the acceptor.
*
* @throws socket_error Thrown on failure.
*/
template <typename Option>
void get_option(Option& option)
{
service_.get_option(impl_, option);
service_.get_option(impl_, option, default_error_handler());
}
/// Get an option from the acceptor.
/**
* This function is used to get the current value of an option on the
* acceptor.
*
* @param option The option value to be obtained from the acceptor.
*
* @param error_handler The handler to be called when an error occurs or when
* the function completes successfully. Copies will be made of the handler as
* required. The equivalent function signature of the handler must be:
* @code void error_handler(
* const asio::socket_error& error // Result of operation
* ); @endcode
*/
template <typename Option, typename Error_Handler>
void get_option(Option& option, Error_Handler error_handler)
{
service_.get_option(impl_, option, error_handler);
}
/// Accept a new connection.
@ -226,7 +282,30 @@ public:
template <typename Stream>
void accept(Stream& peer_socket)
{
service_.accept(impl_, peer_socket.lowest_layer());
service_.accept(impl_, peer_socket.lowest_layer(),
default_error_handler());
}
/// Accept a new connection.
/**
* This function is used to accept a new connection from a peer into the
* given stream socket. The function call will block until a new connection
* has been accepted successfully or an error occurs.
*
* @param peer_socket The stream socket into which the new connection will be
* accepted.
*
* @param error_handler The handler to be called when an error occurs or when
* the function completes successfully. Copies will be made of the handler as
* required. The equivalent function signature of the handler must be:
* @code void error_handler(
* const asio::socket_error& error // Result of operation
* ); @endcode
*/
template <typename Stream, typename Error_Handler>
void accept(Stream& peer_socket, Error_Handler error_handler)
{
service_.accept(impl_, peer_socket.lowest_layer(), error_handler);
}
/// Start an asynchronous accept.
@ -298,7 +377,36 @@ public:
template <typename Stream, typename Address>
void accept_address(Stream& peer_socket, Address& peer_address)
{
service_.accept(impl_, peer_socket.lowest_layer(), peer_address);
service_.accept(impl_, peer_socket.lowest_layer(), peer_address,
default_error_handler());
}
/// Accept a new connection and obtain the address of the peer
/**
* This function is used to accept a new connection from a peer into the
* given stream socket, and additionally provide the address of the remote
* peer. The function call will block until a new connection has been
* accepted successfully or an error occurs.
*
* @param peer_socket The stream socket into which the new connection will be
* accepted.
*
* @param peer_address An address object which will receive the network
* address of the remote peer.
*
* @param error_handler The handler to be called when an error occurs or when
* the function completes successfully. Copies will be made of the handler as
* required. The equivalent function signature of the handler must be:
* @code void error_handler(
* const asio::socket_error& error // Result of operation
* ); @endcode
*/
template <typename Stream, typename Address, typename Error_Handler>
void accept_address(Stream& peer_socket, Address& peer_address,
Error_Handler error_handler)
{
service_.accept(impl_, peer_socket.lowest_layer(), peer_address,
error_handler);
}
/// Start an asynchronous accept.

View File

@ -58,21 +58,21 @@ public:
return demuxer_;
}
// Create a new socket acceptor implementation.
template <typename Address>
void create(impl_type& impl, const Address& address)
{
create(impl, address, SOMAXCONN);
}
// Create a new stream socket implementation.
template <typename Address>
void create(impl_type& impl, const Address& address, int listen_queue)
template <typename Address, typename Error_Handler>
void create(impl_type& impl, const Address& address, int listen_queue,
Error_Handler error_handler)
{
if (listen_queue == 0)
listen_queue = SOMAXCONN;
socket_holder sock(socket_ops::socket(address.family(), SOCK_STREAM,
IPPROTO_TCP));
if (sock.get() == invalid_socket)
throw socket_error(socket_ops::get_error());
{
error_handler(socket_error(socket_ops::get_error()));
return;
}
int reuse = 1;
socket_ops::setsockopt(sock.get(), SOL_SOCKET, SO_REUSEADDR, &reuse,
@ -80,12 +80,20 @@ public:
if (socket_ops::bind(sock.get(), address.native_address(),
address.native_size()) == socket_error_retval)
throw socket_error(socket_ops::get_error());
{
error_handler(socket_error(socket_ops::get_error()));
return;
}
if (socket_ops::listen(sock.get(), listen_queue) == socket_error_retval)
throw socket_error(socket_ops::get_error());
{
error_handler(socket_error(socket_ops::get_error()));
return;
}
impl = sock.release();
error_handler(socket_error(socket_error::success));
}
// Destroy a stream socket implementation.
@ -98,58 +106,89 @@ public:
}
}
// Set a socket option. Throws a socket_error exception on failure.
template <typename Option>
void set_option(impl_type& impl, const Option& option)
// Set a socket option.
template <typename Option, typename Error_Handler>
void set_option(impl_type& impl, const Option& option,
Error_Handler error_handler)
{
if (socket_ops::setsockopt(impl, option.level(), option.name(),
option.data(), option.size()))
throw socket_error(socket_ops::get_error());
{
error_handler(socket_error(socket_ops::get_error()));
return;
}
error_handler(socket_error(socket_error::success));
}
// Set a socket option. Throws a socket_error exception on failure.
template <typename Option>
void get_option(impl_type& impl, Option& option)
// Set a socket option.
template <typename Option, typename Error_Handler>
void get_option(impl_type& impl, Option& option, Error_Handler error_handler)
{
socket_len_type size = option.size();
if (socket_ops::getsockopt(impl, option.level(), option.name(),
option.data(), &size))
throw socket_error(socket_ops::get_error());
{
error_handler(socket_error(socket_ops::get_error()));
return;
}
error_handler(socket_error(socket_error::success));
}
// Accept a new connection. Throws a socket_error exception on failure.
template <typename Stream_Socket_Service>
// Accept a new connection.
template <typename Stream_Socket_Service, typename Error_Handler>
void accept(impl_type& impl,
basic_stream_socket<Stream_Socket_Service>& peer)
basic_stream_socket<Stream_Socket_Service>& peer,
Error_Handler error_handler)
{
// We cannot accept a socket that is already open.
if (peer.impl() != invalid_socket)
throw socket_error(socket_error::already_connected);
{
error_handler(socket_error(socket_error::already_connected));
return;
}
socket_type new_socket = socket_ops::accept(impl, 0, 0);
if (int error = socket_ops::get_error())
throw socket_error(error);
{
error_handler(socket_error(error));
return;
}
peer.set_impl(new_socket);
error_handler(socket_error(socket_error::success));
}
// Accept a new connection. Throws a socket_error exception on failure.
template <typename Stream_Socket_Service, typename Address>
// Accept a new connection.
template <typename Stream_Socket_Service, typename Address,
typename Error_Handler>
void accept(impl_type& impl,
basic_stream_socket<Stream_Socket_Service>& peer, Address& peer_address)
basic_stream_socket<Stream_Socket_Service>& peer, Address& peer_address,
Error_Handler error_handler)
{
// We cannot accept a socket that is already open.
if (peer.impl() != invalid_socket)
throw socket_error(socket_error::already_connected);
{
error_handler(socket_error(socket_error::already_connected));
return;
}
socket_addr_len_type addr_len = peer_address.native_size();
socket_type new_socket = socket_ops::accept(impl,
peer_address.native_address(), &addr_len);
if (int error = socket_ops::get_error())
throw socket_error(error);
{
error_handler(socket_error(error));
return;
}
peer_address.native_size(addr_len);
peer.set_impl(new_socket);
error_handler(socket_error(socket_error::success));
}
template <typename Stream_Socket_Service, typename Handler,