diff --git a/asio/TODO b/asio/TODO index 58687419..0a0064e9 100644 --- a/asio/TODO +++ b/asio/TODO @@ -1,12 +1,17 @@ asio to-do items ================ -Add functions for setting socket options ----------------------------------------- -Add functions to the basic_stream_socket and basic_dgram_socket that allow the -various socket options to be set. May want to consider not exposing the option -for non-blocking I/O, and simply state that using the asynchronous operations -is the portable way to go about it. +Add more socket options +----------------------- +Add support for additional socket options beyond the sample few that exist now. +May want to consider not exposing the option for non-blocking I/O, and simply +state that using the asynchronous operations is the portable way to go about +it. + +Add vectored send/recv functions +-------------------------------- +Add the sendv and recvv functions to basic_stream_socket and presumably also to +the buffered stream templates. Add encode_send/async_encode_send functions ------------------------------------------- diff --git a/asio/include/Makefile.am b/asio/include/Makefile.am index a94f4085..ec2ca60b 100644 --- a/asio/include/Makefile.am +++ b/asio/include/Makefile.am @@ -62,6 +62,7 @@ nobase_include_HEADERS = \ asio/socket_acceptor.hpp \ asio/socket_connector.hpp \ asio/socket_error.hpp \ + asio/socket_option.hpp \ asio/stream_socket.hpp \ asio/timer.hpp \ asio/timer_base.hpp diff --git a/asio/include/asio.hpp b/asio/include/asio.hpp index 25688c05..c6839905 100644 --- a/asio/include/asio.hpp +++ b/asio/include/asio.hpp @@ -36,6 +36,7 @@ #include "asio/socket_acceptor.hpp" #include "asio/socket_connector.hpp" #include "asio/socket_error.hpp" +#include "asio/socket_option.hpp" #include "asio/stream_socket.hpp" #include "asio/timer.hpp" #include "asio/timer_base.hpp" diff --git a/asio/include/asio/basic_dgram_socket.hpp b/asio/include/asio/basic_dgram_socket.hpp index 38b949b4..c3758bb2 100644 --- a/asio/include/asio/basic_dgram_socket.hpp +++ b/asio/include/asio/basic_dgram_socket.hpp @@ -138,6 +138,34 @@ public: return impl_; } + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @throws socket_error Thrown on failure. + */ + template + void set_option(const Option& option) + { + service_.set_option(impl_, option); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @throws socket_error Thrown on failure. + */ + template + void get_option(Option& option) + { + service_.get_option(impl_, option); + } + /// Send a datagram to the specified address. /** * This function is used to send a datagram to the specified remote address. diff --git a/asio/include/asio/basic_socket_acceptor.hpp b/asio/include/asio/basic_socket_acceptor.hpp index 6646e869..ae63bdd0 100644 --- a/asio/include/asio/basic_socket_acceptor.hpp +++ b/asio/include/asio/basic_socket_acceptor.hpp @@ -184,6 +184,34 @@ public: return impl_; } + /// Set an option on the acceptor. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @throws socket_error Thrown on failure. + */ + template + void set_option(const Option& option) + { + service_.set_option(impl_, option); + } + + /// Get an option from the acceptor. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @throws socket_error Thrown on failure. + */ + template + void get_option(Option& option) + { + service_.get_option(impl_, option); + } + /// Accept a new connection. /** * This function is used to accept a new connection from a peer into the diff --git a/asio/include/asio/basic_stream_socket.hpp b/asio/include/asio/basic_stream_socket.hpp index ddfefcc1..57527096 100644 --- a/asio/include/asio/basic_stream_socket.hpp +++ b/asio/include/asio/basic_stream_socket.hpp @@ -128,6 +128,34 @@ public: service_.create(impl_, new_impl); } + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @throws socket_error Thrown on failure. + */ + template + void set_option(const Option& option) + { + service_.set_option(impl_, option); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @throws socket_error Thrown on failure. + */ + template + void get_option(Option& option) + { + service_.get_option(impl_, option); + } + /// Send the given data to the peer. /** * This function is used to send data to the stream socket's peer. The diff --git a/asio/include/asio/counting_completion_context.hpp b/asio/include/asio/counting_completion_context.hpp index b4871f55..4b4e52b3 100644 --- a/asio/include/asio/counting_completion_context.hpp +++ b/asio/include/asio/counting_completion_context.hpp @@ -22,7 +22,7 @@ namespace asio { /// The counting_completion_context class is a concrete implementation of the -/// completion_context class that allows a limitation on the number of +/// Completion_Context concept. It allows a limitation on the number of /// concurrent upcalls to completion handlers that may be associated with the /// context. class counting_completion_context diff --git a/asio/include/asio/detail/reactive_dgram_socket_service.hpp b/asio/include/asio/detail/reactive_dgram_socket_service.hpp index dc49eba5..873845af 100644 --- a/asio/include/asio/detail/reactive_dgram_socket_service.hpp +++ b/asio/include/asio/detail/reactive_dgram_socket_service.hpp @@ -87,6 +87,25 @@ public: } } + // Set a socket option. Throws a socket_error exception on failure. + template + void set_option(impl_type& impl, const Option& option) + { + if (socket_ops::setsockopt(impl, option.level(), option.name(), + option.data(), option.size())) + throw socket_error(socket_ops::get_error()); + } + + // Set a socket option. Throws a socket_error exception on failure. + template + void get_option(impl_type& impl, Option& option) + { + 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()); + } + // Send a datagram to the specified address. Returns the number of bytes // sent. Throws a socket_error exception on failure. template diff --git a/asio/include/asio/detail/reactive_socket_acceptor_service.hpp b/asio/include/asio/detail/reactive_socket_acceptor_service.hpp index 3be4398b..067d5349 100644 --- a/asio/include/asio/detail/reactive_socket_acceptor_service.hpp +++ b/asio/include/asio/detail/reactive_socket_acceptor_service.hpp @@ -98,6 +98,25 @@ public: } } + // Set a socket option. Throws a socket_error exception on failure. + template + void set_option(impl_type& impl, const Option& option) + { + if (socket_ops::setsockopt(impl, option.level(), option.name(), + option.data(), option.size())) + throw socket_error(socket_ops::get_error()); + } + + // Set a socket option. Throws a socket_error exception on failure. + template + void get_option(impl_type& impl, Option& option) + { + 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()); + } + // Accept a new connection. Throws a socket_error exception on failure. template void accept(impl_type& impl, diff --git a/asio/include/asio/detail/reactive_stream_socket_service.hpp b/asio/include/asio/detail/reactive_stream_socket_service.hpp index e03ac762..69fe4008 100644 --- a/asio/include/asio/detail/reactive_stream_socket_service.hpp +++ b/asio/include/asio/detail/reactive_stream_socket_service.hpp @@ -72,6 +72,25 @@ public: } } + // Set a socket option. Throws a socket_error exception on failure. + template + void set_option(impl_type& impl, const Option& option) + { + if (socket_ops::setsockopt(impl, option.level(), option.name(), + option.data(), option.size())) + throw socket_error(socket_ops::get_error()); + } + + // Set a socket option. Throws a socket_error exception on failure. + template + void get_option(impl_type& impl, Option& option) + { + 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()); + } + // Send the given data to the peer. Returns the number of bytes sent or // 0 if the connection was closed cleanly. Throws a socket_error exception // on failure. diff --git a/asio/include/asio/detail/win_iocp_dgram_socket_service.hpp b/asio/include/asio/detail/win_iocp_dgram_socket_service.hpp index b47e6ab1..15ecfae7 100644 --- a/asio/include/asio/detail/win_iocp_dgram_socket_service.hpp +++ b/asio/include/asio/detail/win_iocp_dgram_socket_service.hpp @@ -94,6 +94,25 @@ public: } } + // Set a socket option. Throws a socket_error exception on failure. + template + void set_option(impl_type& impl, const Option& option) + { + if (socket_ops::setsockopt(impl, option.level(), option.name(), + option.data(), option.size())) + throw socket_error(socket_ops::get_error()); + } + + // Set a socket option. Throws a socket_error exception on failure. + template + void get_option(impl_type& impl, Option& option) + { + 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()); + } + // Send a datagram to the specified address. Returns the number of bytes // sent. Throws a socket_error exception on failure. template diff --git a/asio/include/asio/detail/win_iocp_stream_socket_service.hpp b/asio/include/asio/detail/win_iocp_stream_socket_service.hpp index 9cde6a2a..08917624 100644 --- a/asio/include/asio/detail/win_iocp_stream_socket_service.hpp +++ b/asio/include/asio/detail/win_iocp_stream_socket_service.hpp @@ -78,6 +78,25 @@ public: } } + // Set a socket option. Throws a socket_error exception on failure. + template + void set_option(impl_type& impl, const Option& option) + { + if (socket_ops::setsockopt(impl, option.level(), option.name(), + option.data(), option.size())) + throw socket_error(socket_ops::get_error()); + } + + // Set a socket option. Throws a socket_error exception on failure. + template + void get_option(impl_type& impl, Option& option) + { + 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()); + } + // Send the given data to the peer. Returns the number of bytes sent or // 0 if the connection was closed cleanly. Throws a socket_error exception // on failure. diff --git a/asio/include/asio/null_completion_context.hpp b/asio/include/asio/null_completion_context.hpp index de3c84b0..6cef12ee 100644 --- a/asio/include/asio/null_completion_context.hpp +++ b/asio/include/asio/null_completion_context.hpp @@ -36,10 +36,10 @@ namespace detail template Type global::instance; } -/// The completion_context class is the abstract base class for all completion -/// context implementations. A completion context is used to determine when -/// an upcall can be made to the completion handler of an asynchronous -/// operation. +/// The null_completion_context class is a concrete implementation of the +/// Completion_Context concept. It does not place any limits on the number of +/// concurrent upcalls to completion handlers that may be associated with the +/// context. class null_completion_context : private boost::noncopyable { diff --git a/asio/include/asio/socket_option.hpp b/asio/include/asio/socket_option.hpp new file mode 100644 index 00000000..9c4c62fa --- /dev/null +++ b/asio/include/asio/socket_option.hpp @@ -0,0 +1,167 @@ +// +// socket_option.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003 Christopher M. Kohlhoff (chris@kohlhoff.com) +// +// Permission to use, copy, modify, distribute and sell this software and its +// documentation for any purpose is hereby granted without fee, provided that +// the above copyright notice appears in all copies and that both the copyright +// notice and this permission notice appear in supporting documentation. This +// software is provided "as is" without express or implied warranty, and with +// no claim as to its suitability for any purpose. +// + +#ifndef ASIO_SOCKET_OPTION_HPP +#define ASIO_SOCKET_OPTION_HPP + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/socket_types.hpp" + +namespace asio { +namespace socket_option { + +/// Helper template for implementing flag-based options. +template +class flag +{ +public: + /// Default constructor. + flag() + : value_(0) + { + } + + /// Construct to be either enabled or disabled. + flag(bool enabled) + : value_(enabled ? 1 : 0) + { + } + + /// Get the level of the socket option. + int level() const + { + return Level; + } + + /// Get the name of the socket option. + int name() const + { + return Name; + } + + /// Set the value of the flag. + void set(bool enabled) + { + value_ = enabled ? 1 : 0; + } + + /// Get the current value of the flag. + bool get() const + { + return value_; + } + + /// Get the address of the flag data. + void* data() + { + return &value_; + } + + /// Get the address of the flag data. + const void* data() const + { + return &value_; + } + + /// Get the size of the flag data. + size_t size() const + { + return sizeof(value_); + } + +private: + /// The underlying value of the flag. + int value_; +}; + +/// Helper template for implementing integer options. +template +class integer +{ +public: + /// Default constructor. + integer() + : value_(0) + { + } + + /// Construct with a specific option value. + integer(int value) + : value_(value) + { + } + + /// Get the level of the socket option. + int level() const + { + return Level; + } + + /// Get the name of the socket option. + int name() const + { + return Name; + } + + /// Set the value of the int option. + void set(int value) + { + value_ = value; + } + + /// Get the current value of the int option. + int get() const + { + return value_; + } + + /// Get the address of the int data. + void* data() + { + return &value_; + } + + /// Get the address of the int data. + const void* data() const + { + return &value_; + } + + /// Get the size of the int data. + size_t size() const + { + return sizeof(value_); + } + +private: + /// The underlying value of the int option. + int value_; +}; + +/// Permit sending of broadcast datagrams. +typedef flag tcp_no_delay; + +/// The receive buffer size for a socket. +typedef integer send_buffer_size; + +/// The send buffer size for a socket. +typedef integer recv_buffer_size; + +} // namespace socket_option +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SOCKET_OPTION_HPP diff --git a/asio/src/doc/asio_dox.txt b/asio/src/doc/asio_dox.txt index 103d1cd0..ccf3e2e7 100644 --- a/asio/src/doc/asio_dox.txt +++ b/asio/src/doc/asio_dox.txt @@ -3,6 +3,11 @@ \brief The asio namespace defines all user-accessible classes and templates. */ +/** +\namespace asio::socket_option +\brief The asio::socket_option namespace defines the supported socket options. +*/ + /** \mainpage @@ -13,6 +18,7 @@

Namespaces

\li ::asio +\li ::asio::socket_option

Core Classes

diff --git a/asio/src/tests/tpc_echo_server_test.cpp b/asio/src/tests/tpc_echo_server_test.cpp index 965e5115..ae701998 100644 --- a/asio/src/tests/tpc_echo_server_test.cpp +++ b/asio/src/tests/tpc_echo_server_test.cpp @@ -12,9 +12,12 @@ void tpc_echo_session(stream_socket_ptr sock) { try { - enum { max_length = 512 }; + enum { max_length = 8192 }; char data[max_length]; + sock->set_option(socket_option::recv_buffer_size(max_length)); + sock->set_option(socket_option::send_buffer_size(max_length)); + int length; while ((length = recv(*sock, data, max_length)) > 0) if (send_n(*sock, data, length) <= 0)