Add per-operation error handling policies.
This commit is contained in:
parent
c4761ad928
commit
cc58f99de7
@ -21,6 +21,7 @@
|
|||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include "asio/detail/pop_options.hpp"
|
#include "asio/detail/pop_options.hpp"
|
||||||
|
|
||||||
|
#include "asio/error_handler.hpp"
|
||||||
#include "asio/null_completion_context.hpp"
|
#include "asio/null_completion_context.hpp"
|
||||||
#include "asio/service_factory.hpp"
|
#include "asio/service_factory.hpp"
|
||||||
|
|
||||||
@ -68,22 +69,24 @@ public:
|
|||||||
* @param addr An address on the local machine on which the acceptor will
|
* @param addr An address on the local machine on which the acceptor will
|
||||||
* listen for new connections.
|
* 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.
|
* @throws socket_error Thrown on failure.
|
||||||
*/
|
*/
|
||||||
template <typename Address>
|
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>())),
|
: service_(d.get_service(service_factory<Service>())),
|
||||||
impl_(service_type::null())
|
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
|
/// Construct an acceptor opened on the given address.
|
||||||
/// maximum length of the queue of pending connetions.
|
|
||||||
/**
|
/**
|
||||||
* This constructor creates an acceptor and automatically opens it to listen
|
* This constructor creates an acceptor and automatically opens it to listen
|
||||||
* for new connections on the specified address. The maximum length of the
|
* for new connections on the specified address.
|
||||||
* queue of pending connections is also supplied.
|
|
||||||
*
|
*
|
||||||
* @param d The demuxer object that the acceptor will use to deliver
|
* @param d The demuxer object that the acceptor will use to deliver
|
||||||
* completions for any asynchronous operations performed on the acceptor.
|
* completions for any asynchronous operations performed on the acceptor.
|
||||||
@ -92,16 +95,22 @@ public:
|
|||||||
* listen for new connections.
|
* listen for new connections.
|
||||||
*
|
*
|
||||||
* @param listen_queue The maximum length of the queue of pending
|
* @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>
|
template <typename Address, typename Error_Handler>
|
||||||
basic_socket_acceptor(demuxer_type& d, const Address& addr, int listen_queue)
|
basic_socket_acceptor(demuxer_type& d, const Address& addr, int listen_queue,
|
||||||
|
Error_Handler error_handler)
|
||||||
: service_(d.get_service(service_factory<Service>())),
|
: service_(d.get_service(service_factory<Service>())),
|
||||||
impl_(service_type::null())
|
impl_(service_type::null())
|
||||||
{
|
{
|
||||||
service_.create(impl_, addr, listen_queue);
|
service_.create(impl_, addr, listen_queue, error_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
@ -132,32 +141,39 @@ public:
|
|||||||
* @param addr An address on the local machine on which the acceptor will
|
* @param addr An address on the local machine on which the acceptor will
|
||||||
* listen for new connections.
|
* 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.
|
* @throws socket_error Thrown on failure.
|
||||||
*/
|
*/
|
||||||
template <typename Address>
|
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
|
* This function opens the acceptor to listen for new connections on the
|
||||||
* specified address. The maximum length of the queue of pending connections
|
* specified address.
|
||||||
* is also supplied.
|
|
||||||
*
|
*
|
||||||
* @param addr An address on the local machine on which the acceptor will
|
* @param addr An address on the local machine on which the acceptor will
|
||||||
* listen for new connections.
|
* listen for new connections.
|
||||||
*
|
*
|
||||||
* @param listen_queue The maximum length of the queue of pending
|
* @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>
|
template <typename Address, typename Error_Handler>
|
||||||
void open(const Address& addr, int listen_queue)
|
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.
|
/// Close the acceptor.
|
||||||
@ -186,30 +202,70 @@ public:
|
|||||||
|
|
||||||
/// Set an option on the acceptor.
|
/// 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.
|
* @throws socket_error Thrown on failure.
|
||||||
*/
|
*/
|
||||||
template <typename Option>
|
template <typename Option>
|
||||||
void set_option(const Option& 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.
|
/// 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.
|
* @throws socket_error Thrown on failure.
|
||||||
*/
|
*/
|
||||||
template <typename Option>
|
template <typename Option>
|
||||||
void get_option(Option& 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.
|
/// Accept a new connection.
|
||||||
@ -226,7 +282,30 @@ public:
|
|||||||
template <typename Stream>
|
template <typename Stream>
|
||||||
void accept(Stream& peer_socket)
|
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.
|
/// Start an asynchronous accept.
|
||||||
@ -298,7 +377,36 @@ public:
|
|||||||
template <typename Stream, typename Address>
|
template <typename Stream, typename Address>
|
||||||
void accept_address(Stream& peer_socket, Address& peer_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.
|
/// Start an asynchronous accept.
|
||||||
|
@ -58,21 +58,21 @@ public:
|
|||||||
return demuxer_;
|
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.
|
// Create a new stream socket implementation.
|
||||||
template <typename Address>
|
template <typename Address, typename Error_Handler>
|
||||||
void create(impl_type& impl, const Address& address, int listen_queue)
|
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,
|
socket_holder sock(socket_ops::socket(address.family(), SOCK_STREAM,
|
||||||
IPPROTO_TCP));
|
IPPROTO_TCP));
|
||||||
if (sock.get() == invalid_socket)
|
if (sock.get() == invalid_socket)
|
||||||
throw socket_error(socket_ops::get_error());
|
{
|
||||||
|
error_handler(socket_error(socket_ops::get_error()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int reuse = 1;
|
int reuse = 1;
|
||||||
socket_ops::setsockopt(sock.get(), SOL_SOCKET, SO_REUSEADDR, &reuse,
|
socket_ops::setsockopt(sock.get(), SOL_SOCKET, SO_REUSEADDR, &reuse,
|
||||||
@ -80,12 +80,20 @@ public:
|
|||||||
|
|
||||||
if (socket_ops::bind(sock.get(), address.native_address(),
|
if (socket_ops::bind(sock.get(), address.native_address(),
|
||||||
address.native_size()) == socket_error_retval)
|
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)
|
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();
|
impl = sock.release();
|
||||||
|
|
||||||
|
error_handler(socket_error(socket_error::success));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy a stream socket implementation.
|
// Destroy a stream socket implementation.
|
||||||
@ -98,58 +106,89 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a socket option. Throws a socket_error exception on failure.
|
// Set a socket option.
|
||||||
template <typename Option>
|
template <typename Option, typename Error_Handler>
|
||||||
void set_option(impl_type& impl, const Option& option)
|
void set_option(impl_type& impl, const Option& option,
|
||||||
|
Error_Handler error_handler)
|
||||||
{
|
{
|
||||||
if (socket_ops::setsockopt(impl, option.level(), option.name(),
|
if (socket_ops::setsockopt(impl, option.level(), option.name(),
|
||||||
option.data(), option.size()))
|
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.
|
// Set a socket option.
|
||||||
template <typename Option>
|
template <typename Option, typename Error_Handler>
|
||||||
void get_option(impl_type& impl, Option& option)
|
void get_option(impl_type& impl, Option& option, Error_Handler error_handler)
|
||||||
{
|
{
|
||||||
socket_len_type size = option.size();
|
socket_len_type size = option.size();
|
||||||
if (socket_ops::getsockopt(impl, option.level(), option.name(),
|
if (socket_ops::getsockopt(impl, option.level(), option.name(),
|
||||||
option.data(), &size))
|
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.
|
// Accept a new connection.
|
||||||
template <typename Stream_Socket_Service>
|
template <typename Stream_Socket_Service, typename Error_Handler>
|
||||||
void accept(impl_type& impl,
|
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.
|
// We cannot accept a socket that is already open.
|
||||||
if (peer.impl() != invalid_socket)
|
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);
|
socket_type new_socket = socket_ops::accept(impl, 0, 0);
|
||||||
if (int error = socket_ops::get_error())
|
if (int error = socket_ops::get_error())
|
||||||
throw socket_error(error);
|
{
|
||||||
|
error_handler(socket_error(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
peer.set_impl(new_socket);
|
peer.set_impl(new_socket);
|
||||||
|
|
||||||
|
error_handler(socket_error(socket_error::success));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept a new connection. Throws a socket_error exception on failure.
|
// Accept a new connection.
|
||||||
template <typename Stream_Socket_Service, typename Address>
|
template <typename Stream_Socket_Service, typename Address,
|
||||||
|
typename Error_Handler>
|
||||||
void accept(impl_type& impl,
|
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.
|
// We cannot accept a socket that is already open.
|
||||||
if (peer.impl() != invalid_socket)
|
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_addr_len_type addr_len = peer_address.native_size();
|
||||||
socket_type new_socket = socket_ops::accept(impl,
|
socket_type new_socket = socket_ops::accept(impl,
|
||||||
peer_address.native_address(), &addr_len);
|
peer_address.native_address(), &addr_len);
|
||||||
if (int error = socket_ops::get_error())
|
if (int error = socket_ops::get_error())
|
||||||
throw socket_error(error);
|
{
|
||||||
|
error_handler(socket_error(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
peer_address.native_size(addr_len);
|
peer_address.native_size(addr_len);
|
||||||
|
|
||||||
peer.set_impl(new_socket);
|
peer.set_impl(new_socket);
|
||||||
|
|
||||||
|
error_handler(socket_error(socket_error::success));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Stream_Socket_Service, typename Handler,
|
template <typename Stream_Socket_Service, typename Handler,
|
||||||
|
Loading…
Reference in New Issue
Block a user