From cc58f99de72b322b383e07dc599ee1ffdc241e57 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 11 Nov 2003 07:07:42 +0000 Subject: [PATCH] Add per-operation error handling policies. --- asio/include/asio/basic_socket_acceptor.hpp | 166 +++++++++++++++--- .../reactive_socket_acceptor_service.hpp | 99 +++++++---- 2 files changed, 206 insertions(+), 59 deletions(-) diff --git a/asio/include/asio/basic_socket_acceptor.hpp b/asio/include/asio/basic_socket_acceptor.hpp index ae63bdd0..bc3bccf1 100644 --- a/asio/include/asio/basic_socket_acceptor.hpp +++ b/asio/include/asio/basic_socket_acceptor.hpp @@ -21,6 +21,7 @@ #include #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 - 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())), 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 - basic_socket_acceptor(demuxer_type& d, const Address& addr, int listen_queue) + template + basic_socket_acceptor(demuxer_type& d, const Address& addr, int listen_queue, + Error_Handler error_handler) : service_(d.get_service(service_factory())), 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 - 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 - void open(const Address& addr, int listen_queue) + template + 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 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 + 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 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 + 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 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 + 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 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 + 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. diff --git a/asio/include/asio/detail/reactive_socket_acceptor_service.hpp b/asio/include/asio/detail/reactive_socket_acceptor_service.hpp index 067d5349..75c4a893 100644 --- a/asio/include/asio/detail/reactive_socket_acceptor_service.hpp +++ b/asio/include/asio/detail/reactive_socket_acceptor_service.hpp @@ -58,21 +58,21 @@ public: return demuxer_; } - // Create a new socket acceptor implementation. - template - void create(impl_type& impl, const Address& address) - { - create(impl, address, SOMAXCONN); - } - // Create a new stream socket implementation. - template - void create(impl_type& impl, const Address& address, int listen_queue) + template + 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 - void set_option(impl_type& impl, const Option& option) + // Set a socket option. + template + 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 - void get_option(impl_type& impl, Option& option) + // Set a socket option. + template + 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 + // Accept a new connection. + template void accept(impl_type& impl, - basic_stream_socket& peer) + basic_stream_socket& 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 + // Accept a new connection. + template void accept(impl_type& impl, - basic_stream_socket& peer, Address& peer_address) + basic_stream_socket& 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