mirror of
https://github.com/boostorg/asio.git
synced 2026-01-19 04:02:09 +00:00
Add max_size() function to basic_streambuf.
Make basic_io_object constructor protected. Make a 0-length send or receive on a stream socket into a no-op. Add cancel() function for cancelling asynchronous socket operations. The Win32 implementation only works if all operations for the socket have been issued from the same thread, otherwise it fails with asio::error::not_supported. Add workaround for an apparent Windows bug where using getpeername on a socket accepted using AcceptEx will sometimes return an endpoint that is all zeroes. Make a strand last as long as it has any handlers to dispatch. Make strand a nested class of io_service. Add io_service() function to io_service::work to return a reference to the io_service object on which the work is being performed. Renamed io_service::service::owner() to io_service::service::io_service(). Unset linger object when socket objects are destroyed. Rename asio_handler_dispatch to asio_handler_invoke. Rename basic_socketbuf to basic_socket_streambuf. Update ip::address_v4 and ip::address_v6 classes to match TR2 proposal. Add run_one(), poll() and poll_one() functions to the io_service. Remove need to #define FD_SETSIZE on Win32. Add detection of incorrect inclusion of WinSock.h. Fix some SSL bugs. Add ability to customise the SSL password callback function. Set the reuse_address option by default on acceptors. The macros FIONREAD and FIONBIO are not integer constants on all platforms, and so cannot be used as template arguments. Make the corresponding I/O control commands into proper classes, not templates. Fixes to better support *BSD platforms. Add support for buffer debugging, if the standard library supports iterator debugging (as MSVC8's standard lib does). Ensure the IOCP queue is drained correctly at shutdown. Move basic_resolver and resolver service into the ip namespace. Fix some issues found by the inspect tool. [SVN r35833]
This commit is contained in:
@@ -1 +1,8 @@
|
||||
The passphrase for both the CA and server private keys is "test".
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (c) 2003-2006 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)
|
||||
|
||||
@@ -100,6 +100,7 @@ public:
|
||||
boost::asio::ssl::context::default_workarounds
|
||||
| boost::asio::ssl::context::no_sslv2
|
||||
| boost::asio::ssl::context::single_dh_use);
|
||||
context_.set_password_callback(boost::bind(&server::get_password, this));
|
||||
context_.use_certificate_chain_file("server.pem");
|
||||
context_.use_private_key_file("server.pem", boost::asio::ssl::context::pem);
|
||||
context_.use_tmp_dh_file("dh512.pem");
|
||||
@@ -110,6 +111,11 @@ public:
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
std::string get_password() const
|
||||
{
|
||||
return "test";
|
||||
}
|
||||
|
||||
void handle_accept(session* new_session, const boost::asio::error& error)
|
||||
{
|
||||
if (!error)
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
//
|
||||
// tick_count_timer.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 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)
|
||||
//
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
//
|
||||
// time_t_timer.cpp
|
||||
// ~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 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)
|
||||
//
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
@@ -18,11 +18,9 @@
|
||||
#include <boost/asio/basic_datagram_socket.hpp>
|
||||
#include <boost/asio/basic_deadline_timer.hpp>
|
||||
#include <boost/asio/basic_io_object.hpp>
|
||||
#include <boost/asio/basic_resolver.hpp>
|
||||
#include <boost/asio/basic_socket_acceptor.hpp>
|
||||
#include <boost/asio/basic_socket_iostream.hpp>
|
||||
#include <boost/asio/basic_socketbuf.hpp>
|
||||
#include <boost/asio/basic_strand.hpp>
|
||||
#include <boost/asio/basic_socket_streambuf.hpp>
|
||||
#include <boost/asio/basic_stream_socket.hpp>
|
||||
#include <boost/asio/basic_streambuf.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
@@ -39,18 +37,20 @@
|
||||
#include <boost/asio/error_handler.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/handler_alloc_hook.hpp>
|
||||
#include <boost/asio/handler_dispatch_hook.hpp>
|
||||
#include <boost/asio/handler_invoke_hook.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <boost/asio/ip/address_v4.hpp>
|
||||
#include <boost/asio/ip/address_v6.hpp>
|
||||
#include <boost/asio/ip/basic_endpoint.hpp>
|
||||
#include <boost/asio/ip/basic_resolver.hpp>
|
||||
#include <boost/asio/ip/basic_resolver_entry.hpp>
|
||||
#include <boost/asio/ip/basic_resolver_iterator.hpp>
|
||||
#include <boost/asio/ip/basic_resolver_query.hpp>
|
||||
#include <boost/asio/ip/host_name.hpp>
|
||||
#include <boost/asio/ip/multicast.hpp>
|
||||
#include <boost/asio/ip/resolver_query_base.hpp>
|
||||
#include <boost/asio/ip/resolver_service.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
#include <boost/asio/is_read_buffered.hpp>
|
||||
@@ -58,11 +58,9 @@
|
||||
#include <boost/asio/placeholders.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/read_until.hpp>
|
||||
#include <boost/asio/resolver_service.hpp>
|
||||
#include <boost/asio/socket_acceptor_service.hpp>
|
||||
#include <boost/asio/socket_base.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/strand_service.hpp>
|
||||
#include <boost/asio/stream_socket_service.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
#include <boost/asio/system_exception.hpp>
|
||||
|
||||
@@ -35,13 +35,6 @@ public:
|
||||
/// The underlying implementation type of I/O object.
|
||||
typedef typename service_type::implementation_type implementation_type;
|
||||
|
||||
/// Construct a basic_io_object.
|
||||
explicit basic_io_object(boost::asio::io_service& io_service)
|
||||
: service(boost::asio::use_service<Service>(io_service))
|
||||
{
|
||||
service.construct(implementation);
|
||||
}
|
||||
|
||||
/// Get the io_service associated with the object.
|
||||
/**
|
||||
* This function may be used to obtain the io_service object that the I/O
|
||||
@@ -52,10 +45,17 @@ public:
|
||||
*/
|
||||
boost::asio::io_service& io_service()
|
||||
{
|
||||
return service.owner();
|
||||
return service.io_service();
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Construct a basic_io_object.
|
||||
explicit basic_io_object(boost::asio::io_service& io_service)
|
||||
: service(boost::asio::use_service<Service>(io_service))
|
||||
{
|
||||
service.construct(implementation);
|
||||
}
|
||||
|
||||
/// Protected destructor to prevent deletion through this type.
|
||||
~basic_io_object()
|
||||
{
|
||||
|
||||
@@ -290,6 +290,38 @@ public:
|
||||
return this->service.native(this->implementation);
|
||||
}
|
||||
|
||||
/// Cancel all asynchronous operations associated with the socket.
|
||||
/**
|
||||
* This function causes all outstanding asynchronous connect, send and receive
|
||||
* operations to finish immediately, and the handlers for cancelled operations
|
||||
* will be passed the boost::asio::error::operation_aborted error.
|
||||
*
|
||||
* @throws boost::asio::error Thrown on failure.
|
||||
*/
|
||||
void cancel()
|
||||
{
|
||||
this->service.cancel(this->implementation, throw_error());
|
||||
}
|
||||
|
||||
/// Cancel all asynchronous operations associated with the socket.
|
||||
/**
|
||||
* This function causes all outstanding asynchronous connect, send and receive
|
||||
* operations to finish immediately, and the handlers for cancelled operations
|
||||
* will be passed the boost::asio::error::operation_aborted error.
|
||||
*
|
||||
* @param error_handler A handler to be called when the operation completes,
|
||||
* to indicate whether or not an error has occurred. Copies will be made of
|
||||
* the handler as required. The function signature of the handler must be:
|
||||
* @code void error_handler(
|
||||
* const boost::asio::error& error // Result of operation
|
||||
* ); @endcode
|
||||
*/
|
||||
template <typename Error_Handler>
|
||||
void cancel(Error_Handler error_handler)
|
||||
{
|
||||
this->service.cancel(this->implementation, error_handler);
|
||||
}
|
||||
|
||||
/// Bind the socket to the given local endpoint.
|
||||
/**
|
||||
* This function binds the socket to the specified endpoint on the local
|
||||
|
||||
@@ -115,8 +115,8 @@ public:
|
||||
* @param endpoint An endpoint on the local machine on which the acceptor
|
||||
* will listen for new connections.
|
||||
*
|
||||
* @param listen_backlog The maximum length of the queue of pending
|
||||
* connections. A value of 0 means use the default queue length.
|
||||
* @param reuse_addr Whether the constructor should set the socket option
|
||||
* socket_base::reuse_address.
|
||||
*
|
||||
* @throws boost::asio::error Thrown on failure.
|
||||
*
|
||||
@@ -124,18 +124,26 @@ public:
|
||||
* @code
|
||||
* basic_socket_acceptor<Protocol> acceptor(io_service);
|
||||
* acceptor.open(endpoint.protocol());
|
||||
* if (reuse_addr)
|
||||
* acceptor.set_option(socket_base::reuse_address(true));
|
||||
* acceptor.bind(endpoint);
|
||||
* acceptor.listen(listen_backlog);
|
||||
* @endcode
|
||||
*/
|
||||
basic_socket_acceptor(boost::asio::io_service& io_service,
|
||||
const endpoint_type& endpoint, int listen_backlog = 0)
|
||||
const endpoint_type& endpoint, bool reuse_addr = true)
|
||||
: basic_io_object<Service>(io_service)
|
||||
{
|
||||
this->service.open(this->implementation, endpoint.protocol(),
|
||||
throw_error());
|
||||
if (reuse_addr)
|
||||
{
|
||||
this->service.set_option(this->implementation,
|
||||
socket_base::reuse_address(true), throw_error());
|
||||
}
|
||||
this->service.bind(this->implementation, endpoint, throw_error());
|
||||
this->service.listen(this->implementation, listen_backlog, throw_error());
|
||||
this->service.listen(this->implementation,
|
||||
socket_base::max_connections, throw_error());
|
||||
}
|
||||
|
||||
/// Construct a basic_socket_acceptor on an existing native acceptor.
|
||||
@@ -312,10 +320,9 @@ public:
|
||||
* This function puts the socket acceptor into the state where it may accept
|
||||
* new connections.
|
||||
*
|
||||
* @param backlog The maximum length of the queue of pending connections. A
|
||||
* value of 0 means use the default queue length.
|
||||
* @param backlog The maximum length of the queue of pending connections.
|
||||
*/
|
||||
void listen(int backlog = 0)
|
||||
void listen(int backlog = socket_base::max_connections)
|
||||
{
|
||||
this->service.listen(this->implementation, backlog, throw_error());
|
||||
}
|
||||
@@ -326,8 +333,7 @@ public:
|
||||
* This function puts the socket acceptor into the state where it may accept
|
||||
* new connections.
|
||||
*
|
||||
* @param backlog The maximum length of the queue of pending connections. A
|
||||
* value of 0 means use the default queue length.
|
||||
* @param backlog The maximum length of the queue of pending connections.
|
||||
*
|
||||
* @param error_handler A handler to be called when the operation completes,
|
||||
* to indicate whether or not an error has occurred. Copies will be made of
|
||||
@@ -341,7 +347,8 @@ public:
|
||||
* boost::asio::ip::tcp::acceptor acceptor(io_service);
|
||||
* ...
|
||||
* boost::asio::error error;
|
||||
* acceptor.listen(0, boost::asio::assign_error(error));
|
||||
* acceptor.listen(boost::asio::socket_base::max_connections,
|
||||
* boost::asio::assign_error(error));
|
||||
* if (error)
|
||||
* {
|
||||
* // An error occurred.
|
||||
@@ -413,6 +420,38 @@ public:
|
||||
return this->service.native(this->implementation);
|
||||
}
|
||||
|
||||
/// Cancel all asynchronous operations associated with the acceptor.
|
||||
/**
|
||||
* This function causes all outstanding asynchronous connect, send and receive
|
||||
* operations to finish immediately, and the handlers for cancelled operations
|
||||
* will be passed the boost::asio::error::operation_aborted error.
|
||||
*
|
||||
* @throws boost::asio::error Thrown on failure.
|
||||
*/
|
||||
void cancel()
|
||||
{
|
||||
this->service.cancel(this->implementation, throw_error());
|
||||
}
|
||||
|
||||
/// Cancel all asynchronous operations associated with the acceptor.
|
||||
/**
|
||||
* This function causes all outstanding asynchronous connect, send and receive
|
||||
* operations to finish immediately, and the handlers for cancelled operations
|
||||
* will be passed the boost::asio::error::operation_aborted error.
|
||||
*
|
||||
* @param error_handler A handler to be called when the operation completes,
|
||||
* to indicate whether or not an error has occurred. Copies will be made of
|
||||
* the handler as required. The function signature of the handler must be:
|
||||
* @code void error_handler(
|
||||
* const boost::asio::error& error // Result of operation
|
||||
* ); @endcode
|
||||
*/
|
||||
template <typename Error_Handler>
|
||||
void cancel(Error_Handler error_handler)
|
||||
{
|
||||
this->service.cancel(this->implementation, error_handler);
|
||||
}
|
||||
|
||||
/// Set an option on the acceptor.
|
||||
/**
|
||||
* This function is used to set an option on the acceptor.
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#include <boost/asio/basic_socketbuf.hpp>
|
||||
#include <boost/asio/basic_socket_streambuf.hpp>
|
||||
#include <boost/asio/stream_socket_service.hpp>
|
||||
|
||||
#if !defined(BOOST_ASIO_SOCKET_IOSTREAM_MAX_ARITY)
|
||||
@@ -36,7 +36,7 @@
|
||||
// template < typename T1, ..., typename Tn >
|
||||
// explicit basic_socket_iostream( T1 x1, ..., Tn xn )
|
||||
// : basic_iostream<char>(&this->boost::base_from_member<
|
||||
// basic_socketbuf<Protocol, Service> >::member)
|
||||
// basic_socket_streambuf<Protocol, Service> >::member)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
@@ -55,7 +55,7 @@
|
||||
template < BOOST_PP_ENUM_PARAMS(n, typename T) > \
|
||||
explicit basic_socket_iostream( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \
|
||||
: std::basic_iostream<char>(&this->boost::base_from_member< \
|
||||
basic_socketbuf<Protocol, Service> >::member) \
|
||||
basic_socket_streambuf<Protocol, Service> >::member) \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
@@ -111,14 +111,14 @@ namespace asio {
|
||||
template <typename Protocol,
|
||||
typename Service = stream_socket_service<Protocol> >
|
||||
class basic_socket_iostream
|
||||
: public boost::base_from_member<basic_socketbuf<Protocol, Service> >,
|
||||
: public boost::base_from_member<basic_socket_streambuf<Protocol, Service> >,
|
||||
public std::basic_iostream<char>
|
||||
{
|
||||
public:
|
||||
/// Construct a basic_socket_iostream without establishing a connection.
|
||||
basic_socket_iostream()
|
||||
: std::basic_iostream<char>(&this->boost::base_from_member<
|
||||
basic_socketbuf<Protocol, Service> >::member)
|
||||
basic_socket_streambuf<Protocol, Service> >::member)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -159,11 +159,11 @@ public:
|
||||
}
|
||||
|
||||
/// Return a pointer to the underlying streambuf.
|
||||
basic_socketbuf<Protocol, Service>* rdbuf() const
|
||||
basic_socket_streambuf<Protocol, Service>* rdbuf() const
|
||||
{
|
||||
return const_cast<basic_socketbuf<Protocol, Service>*>(
|
||||
return const_cast<basic_socket_streambuf<Protocol, Service>*>(
|
||||
&this->boost::base_from_member<
|
||||
basic_socketbuf<Protocol, Service> >::member);
|
||||
basic_socket_streambuf<Protocol, Service> >::member);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// basic_socketbuf.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
// basic_socket_streambuf.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
@@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_BASIC_SOCKETBUF_HPP
|
||||
#define BOOST_ASIO_BASIC_SOCKETBUF_HPP
|
||||
#ifndef BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
|
||||
#define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
@@ -32,13 +32,13 @@
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/stream_socket_service.hpp>
|
||||
|
||||
#if !defined(BOOST_ASIO_SOCKETBUF_MAX_ARITY)
|
||||
#define BOOST_ASIO_SOCKETBUF_MAX_ARITY 5
|
||||
#endif // !defined(BOOST_ASIO_SOCKETBUF_MAX_ARITY)
|
||||
#if !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY)
|
||||
#define BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
|
||||
#endif // !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY)
|
||||
|
||||
// A macro that should expand to:
|
||||
// template < typename T1, ..., typename Tn >
|
||||
// explicit basic_socketbuf( T1 x1, ..., Tn xn )
|
||||
// explicit basic_socket_streambuf( T1 x1, ..., Tn xn )
|
||||
// : basic_socket<Protocol, Service>(
|
||||
// boost::base_from_member<io_service>::member)
|
||||
// {
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
#define BOOST_ASIO_PRIVATE_CTR_DEF( z, n, data ) \
|
||||
template < BOOST_PP_ENUM_PARAMS(n, typename T) > \
|
||||
explicit basic_socketbuf( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \
|
||||
explicit basic_socket_streambuf( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \
|
||||
: basic_socket<Protocol, Service>( \
|
||||
boost::base_from_member<io_service>::member) \
|
||||
{ \
|
||||
@@ -92,7 +92,7 @@ namespace asio {
|
||||
/// Iostream streambuf for a socket.
|
||||
template <typename Protocol,
|
||||
typename Service = stream_socket_service<Protocol> >
|
||||
class basic_socketbuf
|
||||
class basic_socket_streambuf
|
||||
: public std::streambuf,
|
||||
private boost::base_from_member<io_service>,
|
||||
public basic_socket<Protocol, Service>
|
||||
@@ -101,8 +101,8 @@ public:
|
||||
/// The endpoint type.
|
||||
typedef typename Protocol::endpoint endpoint_type;
|
||||
|
||||
/// Construct a basic_socketbuf without establishing a connection.
|
||||
basic_socketbuf()
|
||||
/// Construct a basic_socket_streambuf without establishing a connection.
|
||||
basic_socket_streambuf()
|
||||
: basic_socket<Protocol, Service>(
|
||||
boost::base_from_member<boost::asio::io_service>::member)
|
||||
{
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
}
|
||||
|
||||
/// Establish a connection to the specified endpoint.
|
||||
explicit basic_socketbuf(const endpoint_type& endpoint)
|
||||
explicit basic_socket_streambuf(const endpoint_type& endpoint)
|
||||
: basic_socket<Protocol, Service>(
|
||||
boost::base_from_member<boost::asio::io_service>::member)
|
||||
{
|
||||
@@ -126,15 +126,15 @@ public:
|
||||
* a resolver query object.
|
||||
*/
|
||||
template <typename T1, ..., typename TN>
|
||||
explicit basic_socketbuf(T1 t1, ..., TN tn);
|
||||
explicit basic_socket_streambuf(T1 t1, ..., TN tn);
|
||||
#else
|
||||
BOOST_PP_REPEAT_FROM_TO(
|
||||
1, BOOST_PP_INC(BOOST_ASIO_SOCKETBUF_MAX_ARITY),
|
||||
1, BOOST_PP_INC(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY),
|
||||
BOOST_ASIO_PRIVATE_CTR_DEF, _ )
|
||||
#endif
|
||||
|
||||
/// Destructor flushes buffered data.
|
||||
~basic_socketbuf()
|
||||
~basic_socket_streambuf()
|
||||
{
|
||||
sync();
|
||||
}
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
void connect(T1 t1, ..., TN tn);
|
||||
#else
|
||||
BOOST_PP_REPEAT_FROM_TO(
|
||||
1, BOOST_PP_INC(BOOST_ASIO_SOCKETBUF_MAX_ARITY),
|
||||
1, BOOST_PP_INC(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY),
|
||||
BOOST_ASIO_PRIVATE_CONNECT_DEF, _ )
|
||||
#endif
|
||||
|
||||
@@ -279,4 +279,4 @@ private:
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_BASIC_SOCKETBUF_HPP
|
||||
#endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
|
||||
@@ -1,146 +0,0 @@
|
||||
//
|
||||
// basic_strand.hpp
|
||||
// ~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 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 BOOST_ASIO_BASIC_STRAND_HPP
|
||||
#define BOOST_ASIO_BASIC_STRAND_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/basic_io_object.hpp>
|
||||
#include <boost/asio/strand_service.hpp>
|
||||
#include <boost/asio/detail/wrapped_handler.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
/// Provides serialised handler execution.
|
||||
/**
|
||||
* The basic_strand class template provides the ability to post and dispatch
|
||||
* handlers with the guarantee that none of those handlers will execute
|
||||
* concurrently.
|
||||
*
|
||||
* Most applications will use the boost::asio::strand typedef.
|
||||
*
|
||||
* @par Thread Safety:
|
||||
* @e Distinct @e objects: Safe.@n
|
||||
* @e Shared @e objects: Safe.
|
||||
*
|
||||
* @par Concepts:
|
||||
* Dispatcher.
|
||||
*/
|
||||
template <typename Service = strand_service>
|
||||
class basic_strand
|
||||
: public basic_io_object<Service>
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/**
|
||||
* Constructs the strand.
|
||||
*
|
||||
* @param io_service The io_service object that the strand will use to
|
||||
* dispatch handlers that are ready to be run.
|
||||
*/
|
||||
explicit basic_strand(boost::asio::io_service& io_service)
|
||||
: basic_io_object<Service>(io_service)
|
||||
{
|
||||
}
|
||||
|
||||
/// Request the strand to invoke the given handler.
|
||||
/**
|
||||
* This function is used to ask the strand to execute the given handler.
|
||||
*
|
||||
* The strand object guarantees that handlers posted or dispatched through
|
||||
* the strand will not be executed concurrently. The handler may be executed
|
||||
* inside this function if the guarantee can be met. If this function is
|
||||
* called from within a handler that was posted or dispatched through the same
|
||||
* strand, then the new handler will be executed immediately.
|
||||
*
|
||||
* The strand's guarantee is in addition to the guarantee provided by the
|
||||
* underlying io_service. The io_service guarantees that the handler will only
|
||||
* be called in a thread in which the io_service's run member function is
|
||||
* currently being invoked.
|
||||
*
|
||||
* @param handler The handler to be called. The strand will make a copy of the
|
||||
* handler object as required. The function signature of the handler must be:
|
||||
* @code void handler(); @endcode
|
||||
*/
|
||||
template <typename Handler>
|
||||
void dispatch(Handler handler)
|
||||
{
|
||||
this->service.dispatch(this->implementation, handler);
|
||||
}
|
||||
|
||||
/// Request the strand to invoke the given handler and return
|
||||
/// immediately.
|
||||
/**
|
||||
* This function is used to ask the strand to execute the given handler, but
|
||||
* without allowing the strand to call the handler from inside this function.
|
||||
*
|
||||
* The strand object guarantees that handlers posted or dispatched through
|
||||
* the strand will not be executed concurrently. The strand's guarantee is in
|
||||
* addition to the guarantee provided by the underlying io_service. The
|
||||
* io_service guarantees that the handler will only be called in a thread in
|
||||
* which the io_service's run member function is currently being invoked.
|
||||
*
|
||||
* @param handler The handler to be called. The strand will make a copy of the
|
||||
* handler object as required. The function signature of the handler must be:
|
||||
* @code void handler(); @endcode
|
||||
*/
|
||||
template <typename Handler>
|
||||
void post(Handler handler)
|
||||
{
|
||||
this->service.post(this->implementation, handler);
|
||||
}
|
||||
|
||||
/// Create a new handler that automatically dispatches the wrapped handler
|
||||
/// on the strand.
|
||||
/**
|
||||
* This function is used to create a new handler function object that, when
|
||||
* invoked, will automatically pass the wrapped handler to the strand's
|
||||
* dispatch function.
|
||||
*
|
||||
* @param handler The handler to be wrapped. The strand will make a copy of
|
||||
* the handler object as required. The function signature of the handler must
|
||||
* be: @code void handler(A1 a1, ... An an); @endcode
|
||||
*
|
||||
* @return A function object that, when invoked, passes the wrapped handler to
|
||||
* the strand's dispatch function. Given a function object with the signature:
|
||||
* @code R f(A1 a1, ... An an); @endcode
|
||||
* If this function object is passed to the wrap function like so:
|
||||
* @code strand.wrap(f); @endcode
|
||||
* then the return value is a function object with the signature
|
||||
* @code void g(A1 a1, ... An an); @endcode
|
||||
* that, when invoked, executes code equivalent to:
|
||||
* @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode
|
||||
*/
|
||||
template <typename Handler>
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
unspecified
|
||||
#else
|
||||
detail::wrapped_handler<basic_strand<Service>, Handler>
|
||||
#endif
|
||||
wrap(Handler handler)
|
||||
{
|
||||
return detail::wrapped_handler<
|
||||
basic_strand<Service>,
|
||||
Handler>(*this, handler);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_BASIC_STRAND_HPP
|
||||
@@ -69,6 +69,12 @@ public:
|
||||
return pptr() - gptr();
|
||||
}
|
||||
|
||||
/// Return the maximum size of the buffer.
|
||||
std::size_t max_size() const
|
||||
{
|
||||
return max_size_;
|
||||
}
|
||||
|
||||
/// Get a list of buffers that represents the get area.
|
||||
const_buffers_type data() const
|
||||
{
|
||||
@@ -89,7 +95,7 @@ public:
|
||||
{
|
||||
if (pptr() + n > epptr())
|
||||
n = epptr() - pptr();
|
||||
pbump(n);
|
||||
pbump(static_cast<int>(n));
|
||||
}
|
||||
|
||||
/// Move the start of the get area by the specified number of characters.
|
||||
|
||||
@@ -26,6 +26,20 @@
|
||||
#include <vector>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# if defined(_HAS_ITERATOR_DEBUGGING)
|
||||
# if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
|
||||
# define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
|
||||
# endif // defined(_HAS_ITERATOR_DEBUGGING)
|
||||
#endif // defined(BOOST_MSVC)
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
# include <boost/asio/detail/push_options.hpp>
|
||||
# include <boost/function.hpp>
|
||||
# include <boost/asio/detail/pop_options.hpp>
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
@@ -62,6 +76,21 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
mutable_buffer(void* data, std::size_t size,
|
||||
boost::function<void()> debug_check)
|
||||
: data_(data),
|
||||
size_(size),
|
||||
debug_check_(debug_check)
|
||||
{
|
||||
}
|
||||
|
||||
const boost::function<void()>& get_debug_check() const
|
||||
{
|
||||
return debug_check_;
|
||||
}
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
|
||||
private:
|
||||
friend void* boost::asio::detail::buffer_cast_helper(
|
||||
const mutable_buffer& b);
|
||||
@@ -70,12 +99,20 @@ private:
|
||||
|
||||
void* data_;
|
||||
std::size_t size_;
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
boost::function<void()> debug_check_;
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline void* buffer_cast_helper(const mutable_buffer& b)
|
||||
{
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
if (b.debug_check_)
|
||||
b.debug_check_();
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
return b.data_;
|
||||
}
|
||||
|
||||
@@ -115,7 +152,11 @@ inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start)
|
||||
return mutable_buffer();
|
||||
char* new_data = buffer_cast<char*>(b) + start;
|
||||
std::size_t new_size = buffer_size(b) - start;
|
||||
return mutable_buffer(new_data, new_size);
|
||||
return mutable_buffer(new_data, new_size
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, b.get_debug_check()
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a new modifiable buffer that is offset from the start of another.
|
||||
@@ -128,7 +169,11 @@ inline mutable_buffer operator+(std::size_t start, const mutable_buffer& b)
|
||||
return mutable_buffer();
|
||||
char* new_data = buffer_cast<char*>(b) + start;
|
||||
std::size_t new_size = buffer_size(b) - start;
|
||||
return mutable_buffer(new_data, new_size);
|
||||
return mutable_buffer(new_data, new_size
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, b.get_debug_check()
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
);
|
||||
}
|
||||
|
||||
/// Adapts a single modifiable buffer so that it meets the requirements of the
|
||||
@@ -189,9 +234,27 @@ public:
|
||||
const_buffer(const mutable_buffer& b)
|
||||
: data_(boost::asio::detail::buffer_cast_helper(b)),
|
||||
size_(boost::asio::detail::buffer_size_helper(b))
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, debug_check_(b.get_debug_check())
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
const_buffer(const void* data, std::size_t size,
|
||||
boost::function<void()> debug_check)
|
||||
: data_(data),
|
||||
size_(size),
|
||||
debug_check_(debug_check)
|
||||
{
|
||||
}
|
||||
|
||||
const boost::function<void()>& get_debug_check() const
|
||||
{
|
||||
return debug_check_;
|
||||
}
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
|
||||
private:
|
||||
friend const void* boost::asio::detail::buffer_cast_helper(
|
||||
const const_buffer& b);
|
||||
@@ -200,12 +263,20 @@ private:
|
||||
|
||||
const void* data_;
|
||||
std::size_t size_;
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
boost::function<void()> debug_check_;
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline const void* buffer_cast_helper(const const_buffer& b)
|
||||
{
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
if (b.debug_check_)
|
||||
b.debug_check_();
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
return b.data_;
|
||||
}
|
||||
|
||||
@@ -245,7 +316,11 @@ inline const_buffer operator+(const const_buffer& b, std::size_t start)
|
||||
return const_buffer();
|
||||
const char* new_data = buffer_cast<const char*>(b) + start;
|
||||
std::size_t new_size = buffer_size(b) - start;
|
||||
return const_buffer(new_data, new_size);
|
||||
return const_buffer(new_data, new_size
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, b.get_debug_check()
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a new non-modifiable buffer that is offset from the start of another.
|
||||
@@ -258,7 +333,11 @@ inline const_buffer operator+(std::size_t start, const const_buffer& b)
|
||||
return const_buffer();
|
||||
const char* new_data = buffer_cast<const char*>(b) + start;
|
||||
std::size_t new_size = buffer_size(b) - start;
|
||||
return const_buffer(new_data, new_size);
|
||||
return const_buffer(new_data, new_size
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, b.get_debug_check()
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
);
|
||||
}
|
||||
|
||||
/// Adapts a single non-modifiable buffer so that it meets the requirements of
|
||||
@@ -292,6 +371,30 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
namespace detail {
|
||||
|
||||
template <typename Iterator>
|
||||
class buffer_debug_check
|
||||
{
|
||||
public:
|
||||
buffer_debug_check(Iterator iter)
|
||||
: iter_(iter)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
*iter_;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator iter_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
|
||||
/** @defgroup buffer boost::asio::buffer
|
||||
*
|
||||
* @brief The boost::asio::buffer function is used to create a buffer object to
|
||||
@@ -356,7 +459,11 @@ inline mutable_buffer_container_1 buffer(const mutable_buffer& b,
|
||||
return mutable_buffer_container_1(
|
||||
mutable_buffer(buffer_cast<void*>(b),
|
||||
buffer_size(b) < max_size_in_bytes
|
||||
? buffer_size(b) : max_size_in_bytes));
|
||||
? buffer_size(b) : max_size_in_bytes
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, b.get_debug_check()
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a new non-modifiable buffer from an existing buffer.
|
||||
@@ -372,7 +479,11 @@ inline const_buffer_container_1 buffer(const const_buffer& b,
|
||||
return const_buffer_container_1(
|
||||
const_buffer(buffer_cast<const void*>(b),
|
||||
buffer_size(b) < max_size_in_bytes
|
||||
? buffer_size(b) : max_size_in_bytes));
|
||||
? buffer_size(b) : max_size_in_bytes
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, b.get_debug_check()
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a new modifiable buffer that represents the given memory range.
|
||||
@@ -561,7 +672,13 @@ template <typename Pod_Type, typename Allocator>
|
||||
inline mutable_buffer_container_1 buffer(std::vector<Pod_Type, Allocator>& data)
|
||||
{
|
||||
return mutable_buffer_container_1(
|
||||
mutable_buffer(&data[0], data.size() * sizeof(Pod_Type)));
|
||||
mutable_buffer(&data[0], data.size() * sizeof(Pod_Type)
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, detail::buffer_debug_check<
|
||||
typename std::vector<Pod_Type, Allocator>::iterator
|
||||
>(data.begin())
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a new modifiable buffer that represents the given POD vector.
|
||||
@@ -576,7 +693,13 @@ inline mutable_buffer_container_1 buffer(std::vector<Pod_Type, Allocator>& data,
|
||||
return mutable_buffer_container_1(
|
||||
mutable_buffer(&data[0],
|
||||
data.size() * sizeof(Pod_Type) < max_size_in_bytes
|
||||
? data.size() * sizeof(Pod_Type) : max_size_in_bytes));
|
||||
? data.size() * sizeof(Pod_Type) : max_size_in_bytes
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, detail::buffer_debug_check<
|
||||
typename std::vector<Pod_Type, Allocator>::iterator
|
||||
>(data.begin())
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a new non-modifiable buffer that represents the given POD vector.
|
||||
@@ -589,7 +712,13 @@ inline const_buffer_container_1 buffer(
|
||||
const std::vector<Pod_Type, Allocator>& data)
|
||||
{
|
||||
return const_buffer_container_1(
|
||||
const_buffer(&data[0], data.size() * sizeof(Pod_Type)));
|
||||
const_buffer(&data[0], data.size() * sizeof(Pod_Type)
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, detail::buffer_debug_check<
|
||||
typename std::vector<Pod_Type, Allocator>::const_iterator
|
||||
>(data.begin())
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a new non-modifiable buffer that represents the given POD vector.
|
||||
@@ -604,7 +733,13 @@ inline const_buffer_container_1 buffer(
|
||||
return const_buffer_container_1(
|
||||
const_buffer(&data[0],
|
||||
data.size() * sizeof(Pod_Type) < max_size_in_bytes
|
||||
? data.size() * sizeof(Pod_Type) : max_size_in_bytes));
|
||||
? data.size() * sizeof(Pod_Type) : max_size_in_bytes
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, detail::buffer_debug_check<
|
||||
typename std::vector<Pod_Type, Allocator>::const_iterator
|
||||
>(data.begin())
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a new non-modifiable buffer that represents the given string.
|
||||
@@ -614,7 +749,11 @@ inline const_buffer_container_1 buffer(
|
||||
*/
|
||||
inline const_buffer_container_1 buffer(const std::string& data)
|
||||
{
|
||||
return const_buffer_container_1(const_buffer(data.data(), data.size()));
|
||||
return const_buffer_container_1(const_buffer(data.data(), data.size()
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, detail::buffer_debug_check<std::string::const_iterator>(data.begin())
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a new non-modifiable buffer that represents the given string.
|
||||
@@ -628,7 +767,11 @@ inline const_buffer_container_1 buffer(const std::string& data,
|
||||
return const_buffer_container_1(
|
||||
const_buffer(data.data(),
|
||||
data.size() < max_size_in_bytes
|
||||
? data.size() : max_size_in_bytes));
|
||||
? data.size() : max_size_in_bytes
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
, detail::buffer_debug_check<std::string::const_iterator>(data.begin())
|
||||
#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
|
||||
));
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
|
||||
@@ -130,6 +130,13 @@ public:
|
||||
return service_impl_.native(impl);
|
||||
}
|
||||
|
||||
/// Cancel all asynchronous operations associated with the socket.
|
||||
template <typename Error_Handler>
|
||||
void cancel(implementation_type& impl, Error_Handler error_handler)
|
||||
{
|
||||
service_impl_.cancel(impl, error_handler);
|
||||
}
|
||||
|
||||
// Bind the datagram socket to the specified local endpoint.
|
||||
template <typename Error_Handler>
|
||||
void bind(implementation_type& impl, const endpoint_type& endpoint,
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_dispatch_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@@ -65,12 +65,12 @@ inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Handler, typename Arg1>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Handler, typename Arg1>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
binder1<Handler, Arg1>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
@@ -123,13 +123,12 @@ inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Handler, typename Arg1,
|
||||
typename Arg2>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Handler, typename Arg1, typename Arg2>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
binder2<Handler, Arg1, Arg2>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
@@ -185,13 +184,13 @@ inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Handler, typename Arg1,
|
||||
typename Arg2, typename Arg3>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Handler, typename Arg1, typename Arg2,
|
||||
typename Arg3>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
|
||||
@@ -252,13 +251,13 @@ inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Handler, typename Arg1,
|
||||
typename Arg2, typename Arg3, typename Arg4>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Handler, typename Arg1, typename Arg2,
|
||||
typename Arg3, typename Arg4>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
@@ -324,13 +323,13 @@ inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Handler, typename Arg1,
|
||||
typename Arg2, typename Arg3, typename Arg4, typename Arg5>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Handler, typename Arg1, typename Arg2,
|
||||
typename Arg3, typename Arg4, typename Arg5>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
|
||||
@@ -63,6 +63,12 @@ public:
|
||||
scheduler_.add_timer_queue(timer_queue_);
|
||||
}
|
||||
|
||||
// Destructor.
|
||||
~deadline_timer_service()
|
||||
{
|
||||
scheduler_.remove_timer_queue(timer_queue_);
|
||||
}
|
||||
|
||||
// Destroy all user-defined handler objects owned by the service.
|
||||
void shutdown_service()
|
||||
{
|
||||
@@ -164,7 +170,7 @@ public:
|
||||
{
|
||||
impl.might_have_pending_waits = true;
|
||||
scheduler_.schedule_timer(timer_queue_, impl.expiry,
|
||||
wait_handler<Handler>(owner(), handler), &impl);
|
||||
wait_handler<Handler>(io_service(), handler), &impl);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -297,6 +297,21 @@ public:
|
||||
timer_queues_.push_back(&timer_queue);
|
||||
}
|
||||
|
||||
// Remove a timer queue from the reactor.
|
||||
template <typename Time_Traits>
|
||||
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
|
||||
{
|
||||
if (timer_queues_[i] == &timer_queue)
|
||||
{
|
||||
timer_queues_.erase(timer_queues_.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule a timer in the given timer queue to expire at the specified
|
||||
// absolute time. The handler object will be invoked when the timer expires.
|
||||
template <typename Time_Traits, typename Handler>
|
||||
|
||||
@@ -17,48 +17,22 @@
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/socket_types.hpp>
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/posix_fd_set_adapter.hpp>
|
||||
#include <boost/asio/detail/win_fd_set_adapter.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
|
||||
class fd_set_adapter
|
||||
{
|
||||
public:
|
||||
fd_set_adapter()
|
||||
: max_descriptor_(invalid_socket)
|
||||
{
|
||||
FD_ZERO(&fd_set_);
|
||||
}
|
||||
|
||||
void set(socket_type descriptor)
|
||||
{
|
||||
if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_)
|
||||
max_descriptor_ = descriptor;
|
||||
FD_SET(descriptor, &fd_set_);
|
||||
}
|
||||
|
||||
bool is_set(socket_type descriptor) const
|
||||
{
|
||||
return FD_ISSET(descriptor, &fd_set_) != 0;
|
||||
}
|
||||
|
||||
operator fd_set*()
|
||||
{
|
||||
return &fd_set_;
|
||||
}
|
||||
|
||||
socket_type max_descriptor() const
|
||||
{
|
||||
return max_descriptor_;
|
||||
}
|
||||
|
||||
private:
|
||||
fd_set fd_set_;
|
||||
socket_type max_descriptor_;
|
||||
};
|
||||
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||||
typedef win_fd_set_adapter fd_set_adapter;
|
||||
#else
|
||||
typedef posix_fd_set_adapter fd_set_adapter;
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// handler_dispatch_helpers.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// handler_invoke_helpers.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
@@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_DETAIL_HANDLER_DISPATCH_HELPERS_HPP
|
||||
#define BOOST_ASIO_DETAIL_HANDLER_DISPATCH_HELPERS_HPP
|
||||
#ifndef BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
|
||||
#define BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
@@ -21,27 +21,27 @@
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#include <boost/asio/handler_dispatch_hook.hpp>
|
||||
#include <boost/asio/handler_invoke_hook.hpp>
|
||||
|
||||
// Calls to asio_handler_dispatch must be made from a namespace that does not
|
||||
// contain overloads of this function. The boost_asio_handler_dispatch_helpers
|
||||
// Calls to asio_handler_invoke must be made from a namespace that does not
|
||||
// contain overloads of this function. The asio_handler_invoke_helpers
|
||||
// namespace is defined here for that purpose.
|
||||
namespace boost_asio_handler_dispatch_helpers {
|
||||
namespace asio_handler_invoke_helpers {
|
||||
|
||||
template <typename Handler, typename Context>
|
||||
inline void dispatch_handler(const Handler& handler, Context* context)
|
||||
template <typename Function, typename Context>
|
||||
inline void invoke(const Function& function, Context* context)
|
||||
{
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||||
Handler tmp(handler);
|
||||
Function tmp(function);
|
||||
tmp();
|
||||
#else
|
||||
using namespace boost::asio;
|
||||
asio_handler_dispatch(handler, context);
|
||||
asio_handler_invoke(function, context);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace boost_asio_handler_dispatch_helpers
|
||||
} // namespace asio_handler_invoke_helpers
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_DETAIL_HANDLER_DISPATCH_HELPERS_HPP
|
||||
#endif // BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
|
||||
@@ -30,6 +30,16 @@ namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
inline std::size_t calculate_hash_value(const T& t)
|
||||
{
|
||||
// It would be better to use "using boost::hash_value;" here, but it makes
|
||||
// Borland C++ crash.
|
||||
using namespace boost;
|
||||
|
||||
return hash_value(t);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
class hash_map
|
||||
: private noncopyable
|
||||
@@ -85,7 +95,7 @@ public:
|
||||
// Find an entry in the map.
|
||||
iterator find(const K& k)
|
||||
{
|
||||
size_t bucket = boost::hash_value(k) % num_buckets;
|
||||
size_t bucket = calculate_hash_value(k) % num_buckets;
|
||||
iterator it = buckets_[bucket].first;
|
||||
if (it == values_.end())
|
||||
return values_.end();
|
||||
@@ -103,7 +113,7 @@ public:
|
||||
// Find an entry in the map.
|
||||
const_iterator find(const K& k) const
|
||||
{
|
||||
size_t bucket = boost::hash_value(k) % num_buckets;
|
||||
size_t bucket = calculate_hash_value(k) % num_buckets;
|
||||
const_iterator it = buckets_[bucket].first;
|
||||
if (it == values_.end())
|
||||
return it;
|
||||
@@ -121,7 +131,7 @@ public:
|
||||
// Insert a new entry into the map.
|
||||
std::pair<iterator, bool> insert(const value_type& v)
|
||||
{
|
||||
size_t bucket = boost::hash_value(v.first) % num_buckets;
|
||||
size_t bucket = calculate_hash_value(v.first) % num_buckets;
|
||||
iterator it = buckets_[bucket].first;
|
||||
if (it == values_.end())
|
||||
{
|
||||
@@ -146,7 +156,7 @@ public:
|
||||
{
|
||||
assert(it != values_.end());
|
||||
|
||||
size_t bucket = boost::hash_value(it->first) % num_buckets;
|
||||
size_t bucket = calculate_hash_value(it->first) % num_buckets;
|
||||
bool is_first = (it == buckets_[bucket].first);
|
||||
bool is_last = (it == buckets_[bucket].last);
|
||||
if (is_first && is_last)
|
||||
|
||||
@@ -29,19 +29,18 @@ namespace asio {
|
||||
namespace detail {
|
||||
namespace io_control {
|
||||
|
||||
// Helper template for implementing boolean-based IO control commands.
|
||||
template <int Name>
|
||||
class boolean
|
||||
// IO control command for non-blocking I/O.
|
||||
class non_blocking_io
|
||||
{
|
||||
public:
|
||||
// Default constructor.
|
||||
boolean()
|
||||
non_blocking_io()
|
||||
: value_(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Construct with a specific command value.
|
||||
boolean(bool value)
|
||||
non_blocking_io(bool value)
|
||||
: value_(value ? 1 : 0)
|
||||
{
|
||||
}
|
||||
@@ -49,16 +48,16 @@ public:
|
||||
// Get the name of the IO control command.
|
||||
int name() const
|
||||
{
|
||||
return Name;
|
||||
return FIONBIO;
|
||||
}
|
||||
|
||||
// Set the value of the boolean.
|
||||
// Set the value of the I/O control command.
|
||||
void set(bool value)
|
||||
{
|
||||
value_ = value ? 1 : 0;
|
||||
}
|
||||
|
||||
// Get the current value of the boolean.
|
||||
// Get the current value of the I/O control command.
|
||||
bool get() const
|
||||
{
|
||||
return value_ != 0;
|
||||
@@ -80,36 +79,35 @@ private:
|
||||
detail::ioctl_arg_type value_;
|
||||
};
|
||||
|
||||
// Helper template for implementing size-based IO control commands.
|
||||
template <int Name>
|
||||
class size
|
||||
// I/O control command for getting number of bytes available.
|
||||
class bytes_readable
|
||||
{
|
||||
public:
|
||||
// Default constructor.
|
||||
size()
|
||||
bytes_readable()
|
||||
: value_(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Construct with a specific command value.
|
||||
size(std::size_t value)
|
||||
: value_(value)
|
||||
bytes_readable(std::size_t value)
|
||||
: value_(static_cast<detail::ioctl_arg_type>(value))
|
||||
{
|
||||
}
|
||||
|
||||
// Get the name of the IO control command.
|
||||
int name() const
|
||||
{
|
||||
return Name;
|
||||
return FIONREAD;
|
||||
}
|
||||
|
||||
// Set the value of the size.
|
||||
// Set the value of the I/O control command.
|
||||
void set(std::size_t value)
|
||||
{
|
||||
value_ = static_cast<detail::ioctl_arg_type>(value);
|
||||
}
|
||||
|
||||
// Get the current value of the size.
|
||||
// Get the current value of the I/O control command.
|
||||
std::size_t get() const
|
||||
{
|
||||
return static_cast<std::size_t>(value_);
|
||||
|
||||
@@ -286,6 +286,21 @@ public:
|
||||
timer_queues_.push_back(&timer_queue);
|
||||
}
|
||||
|
||||
// Remove a timer queue from the reactor.
|
||||
template <typename Time_Traits>
|
||||
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
|
||||
{
|
||||
if (timer_queues_[i] == &timer_queue)
|
||||
{
|
||||
timer_queues_.erase(timer_queues_.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule a timer in the given timer queue to expire at the specified
|
||||
// absolute time. The handler object will be invoked when the timer expires.
|
||||
template <typename Time_Traits, typename Handler>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// win_local_free_on_block_exit.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// local_free_on_block_exit.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
@@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP
|
||||
#define BOOST_ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP
|
||||
#ifndef BOOST_ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
|
||||
#define BOOST_ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
@@ -30,18 +30,18 @@ namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
class win_local_free_on_block_exit
|
||||
class local_free_on_block_exit
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
// Constructor blocks all signals for the calling thread.
|
||||
explicit win_local_free_on_block_exit(void* p)
|
||||
explicit local_free_on_block_exit(void* p)
|
||||
: p_(p)
|
||||
{
|
||||
}
|
||||
|
||||
// Destructor restores the previous signal mask.
|
||||
~win_local_free_on_block_exit()
|
||||
~local_free_on_block_exit()
|
||||
{
|
||||
::LocalFree(p_);
|
||||
}
|
||||
@@ -58,4 +58,4 @@ private:
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP
|
||||
#endif // BOOST_ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
|
||||
73
include/boost/asio/detail/posix_fd_set_adapter.hpp
Normal file
73
include/boost/asio/detail/posix_fd_set_adapter.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// posix_fd_set_adapter.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 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 BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
|
||||
#define BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/socket_types.hpp>
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
|
||||
class posix_fd_set_adapter
|
||||
{
|
||||
public:
|
||||
posix_fd_set_adapter()
|
||||
: max_descriptor_(invalid_socket)
|
||||
{
|
||||
FD_ZERO(&fd_set_);
|
||||
}
|
||||
|
||||
void set(socket_type descriptor)
|
||||
{
|
||||
if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_)
|
||||
max_descriptor_ = descriptor;
|
||||
FD_SET(descriptor, &fd_set_);
|
||||
}
|
||||
|
||||
bool is_set(socket_type descriptor) const
|
||||
{
|
||||
return FD_ISSET(descriptor, &fd_set_) != 0;
|
||||
}
|
||||
|
||||
operator fd_set*()
|
||||
{
|
||||
return &fd_set_;
|
||||
}
|
||||
|
||||
socket_type max_descriptor() const
|
||||
{
|
||||
return max_descriptor_;
|
||||
}
|
||||
|
||||
private:
|
||||
fd_set fd_set_;
|
||||
socket_type max_descriptor_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
|
||||
@@ -74,7 +74,8 @@ public:
|
||||
{
|
||||
user_set_non_blocking = 1, // The user wants a non-blocking socket.
|
||||
internal_non_blocking = 2, // The socket has been set non-blocking.
|
||||
enable_connection_aborted = 4 // User wants connection_aborted errors.
|
||||
enable_connection_aborted = 4, // User wants connection_aborted errors.
|
||||
user_set_linger = 8 // The user set the linger option.
|
||||
};
|
||||
|
||||
// Flags indicating the current state of the socket.
|
||||
@@ -109,7 +110,29 @@ public:
|
||||
// Destroy a socket implementation.
|
||||
void destroy(implementation_type& impl)
|
||||
{
|
||||
close(impl, boost::asio::ignore_error());
|
||||
if (impl.socket_ != invalid_socket)
|
||||
{
|
||||
reactor_.close_descriptor(impl.socket_);
|
||||
|
||||
if (impl.flags_ & implementation_type::internal_non_blocking)
|
||||
{
|
||||
ioctl_arg_type non_blocking = 0;
|
||||
socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking);
|
||||
impl.flags_ &= ~implementation_type::internal_non_blocking;
|
||||
}
|
||||
|
||||
if (impl.flags_ & implementation_type::user_set_linger)
|
||||
{
|
||||
::linger opt;
|
||||
opt.l_onoff = 0;
|
||||
opt.l_linger = 0;
|
||||
socket_ops::setsockopt(impl.socket_,
|
||||
SOL_SOCKET, SO_LINGER, &opt, sizeof(opt));
|
||||
}
|
||||
|
||||
socket_ops::close(impl.socket_);
|
||||
impl.socket_ = invalid_socket;
|
||||
}
|
||||
}
|
||||
|
||||
// Open a new socket implementation.
|
||||
@@ -193,6 +216,22 @@ public:
|
||||
return impl.socket_;
|
||||
}
|
||||
|
||||
// Cancel all operations associated with the socket.
|
||||
template <typename Error_Handler>
|
||||
void cancel(implementation_type& impl, Error_Handler error_handler)
|
||||
{
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
error_handler(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
reactor_.cancel_ops(impl.socket_);
|
||||
error_handler(boost::asio::error(0));
|
||||
}
|
||||
}
|
||||
|
||||
// Bind the socket to the specified local endpoint.
|
||||
template <typename Error_Handler>
|
||||
void bind(implementation_type& impl, const endpoint_type& endpoint,
|
||||
@@ -210,9 +249,6 @@ public:
|
||||
void listen(implementation_type& impl, int backlog,
|
||||
Error_Handler error_handler)
|
||||
{
|
||||
if (backlog == 0)
|
||||
backlog = SOMAXCONN;
|
||||
|
||||
if (socket_ops::listen(impl.socket_, backlog) == socket_error_retval)
|
||||
error_handler(boost::asio::error(socket_ops::get_error()));
|
||||
else
|
||||
@@ -242,6 +278,12 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
if (option.level(impl.protocol_) == SOL_SOCKET
|
||||
&& option.name(impl.protocol_) == SO_LINGER)
|
||||
{
|
||||
impl.flags_ |= implementation_type::user_set_linger;
|
||||
}
|
||||
|
||||
if (socket_ops::setsockopt(impl.socket_,
|
||||
option.level(impl.protocol_), option.name(impl.protocol_),
|
||||
option.data(impl.protocol_), option.size(impl.protocol_)))
|
||||
@@ -361,12 +403,21 @@ public:
|
||||
typename Const_Buffers::const_iterator iter = buffers.begin();
|
||||
typename Const_Buffers::const_iterator end = buffers.end();
|
||||
size_t i = 0;
|
||||
size_t total_buffer_size = 0;
|
||||
for (; iter != end && i < max_buffers; ++iter, ++i)
|
||||
{
|
||||
boost::asio::const_buffer buffer(*iter);
|
||||
socket_ops::init_buf(bufs[i],
|
||||
boost::asio::buffer_cast<const void*>(buffer),
|
||||
boost::asio::buffer_size(buffer));
|
||||
total_buffer_size += boost::asio::buffer_size(buffer);
|
||||
}
|
||||
|
||||
// A request to receive 0 bytes on a stream socket is a no-op.
|
||||
if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
|
||||
{
|
||||
error_handler(boost::asio::error(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send the data.
|
||||
@@ -472,10 +523,32 @@ public:
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
owner().post(bind_handler(handler, error, 0));
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (impl.protocol_.type() == SOCK_STREAM)
|
||||
{
|
||||
// Determine total size of buffers.
|
||||
typename Const_Buffers::const_iterator iter = buffers.begin();
|
||||
typename Const_Buffers::const_iterator end = buffers.end();
|
||||
size_t i = 0;
|
||||
size_t total_buffer_size = 0;
|
||||
for (; iter != end && i < max_buffers; ++iter, ++i)
|
||||
{
|
||||
boost::asio::const_buffer buffer(*iter);
|
||||
total_buffer_size += boost::asio::buffer_size(buffer);
|
||||
}
|
||||
|
||||
// A request to receive 0 bytes on a stream socket is a no-op.
|
||||
if (total_buffer_size == 0)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::success);
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Make socket non-blocking.
|
||||
if (!(impl.flags_ & implementation_type::internal_non_blocking))
|
||||
{
|
||||
@@ -483,7 +556,7 @@ public:
|
||||
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking))
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error, 0));
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
return;
|
||||
}
|
||||
impl.flags_ |= implementation_type::internal_non_blocking;
|
||||
@@ -491,7 +564,7 @@ public:
|
||||
|
||||
reactor_.start_write_op(impl.socket_,
|
||||
send_handler<Const_Buffers, Handler>(
|
||||
impl.socket_, owner(), buffers, flags, handler));
|
||||
impl.socket_, io_service(), buffers, flags, handler));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,7 +696,7 @@ public:
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
owner().post(bind_handler(handler, error, 0));
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -634,7 +707,7 @@ public:
|
||||
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking))
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error, 0));
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
return;
|
||||
}
|
||||
impl.flags_ |= implementation_type::internal_non_blocking;
|
||||
@@ -642,7 +715,7 @@ public:
|
||||
|
||||
reactor_.start_write_op(impl.socket_,
|
||||
send_to_handler<Const_Buffers, Handler>(
|
||||
impl.socket_, owner(), buffers, destination, flags, handler));
|
||||
impl.socket_, io_service(), buffers, destination, flags, handler));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,12 +729,21 @@ public:
|
||||
typename Mutable_Buffers::const_iterator iter = buffers.begin();
|
||||
typename Mutable_Buffers::const_iterator end = buffers.end();
|
||||
size_t i = 0;
|
||||
size_t total_buffer_size = 0;
|
||||
for (; iter != end && i < max_buffers; ++iter, ++i)
|
||||
{
|
||||
boost::asio::mutable_buffer buffer(*iter);
|
||||
socket_ops::init_buf(bufs[i],
|
||||
boost::asio::buffer_cast<void*>(buffer),
|
||||
boost::asio::buffer_size(buffer));
|
||||
total_buffer_size += boost::asio::buffer_size(buffer);
|
||||
}
|
||||
|
||||
// A request to receive 0 bytes on a stream socket is a no-op.
|
||||
if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
|
||||
{
|
||||
error_handler(boost::asio::error(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Receive some data.
|
||||
@@ -778,10 +860,32 @@ public:
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
owner().post(bind_handler(handler, error, 0));
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (impl.protocol_.type() == SOCK_STREAM)
|
||||
{
|
||||
// Determine total size of buffers.
|
||||
typename Mutable_Buffers::const_iterator iter = buffers.begin();
|
||||
typename Mutable_Buffers::const_iterator end = buffers.end();
|
||||
size_t i = 0;
|
||||
size_t total_buffer_size = 0;
|
||||
for (; iter != end && i < max_buffers; ++iter, ++i)
|
||||
{
|
||||
boost::asio::mutable_buffer buffer(*iter);
|
||||
total_buffer_size += boost::asio::buffer_size(buffer);
|
||||
}
|
||||
|
||||
// A request to receive 0 bytes on a stream socket is a no-op.
|
||||
if (total_buffer_size == 0)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::success);
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Make socket non-blocking.
|
||||
if (!(impl.flags_ & implementation_type::internal_non_blocking))
|
||||
{
|
||||
@@ -789,7 +893,7 @@ public:
|
||||
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking))
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error, 0));
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
return;
|
||||
}
|
||||
impl.flags_ |= implementation_type::internal_non_blocking;
|
||||
@@ -799,13 +903,13 @@ public:
|
||||
{
|
||||
reactor_.start_except_op(impl.socket_,
|
||||
receive_handler<Mutable_Buffers, Handler>(
|
||||
impl.socket_, owner(), buffers, flags, handler));
|
||||
impl.socket_, io_service(), buffers, flags, handler));
|
||||
}
|
||||
else
|
||||
{
|
||||
reactor_.start_read_op(impl.socket_,
|
||||
receive_handler<Mutable_Buffers, Handler>(
|
||||
impl.socket_, owner(), buffers, flags, handler));
|
||||
impl.socket_, io_service(), buffers, flags, handler));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -955,7 +1059,7 @@ public:
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
owner().post(bind_handler(handler, error, 0));
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -966,7 +1070,7 @@ public:
|
||||
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking))
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error, 0));
|
||||
io_service().post(bind_handler(handler, error, 0));
|
||||
return;
|
||||
}
|
||||
impl.flags_ |= implementation_type::internal_non_blocking;
|
||||
@@ -974,7 +1078,7 @@ public:
|
||||
|
||||
reactor_.start_read_op(impl.socket_,
|
||||
receive_from_handler<Mutable_Buffers, Handler>(
|
||||
impl.socket_, owner(), buffers,
|
||||
impl.socket_, io_service(), buffers,
|
||||
sender_endpoint, flags, handler));
|
||||
}
|
||||
}
|
||||
@@ -1197,12 +1301,12 @@ public:
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
}
|
||||
else if (peer.native() != invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::already_connected);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1213,7 +1317,7 @@ public:
|
||||
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking))
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
impl.flags_ |= implementation_type::internal_non_blocking;
|
||||
@@ -1221,7 +1325,7 @@ public:
|
||||
|
||||
reactor_.start_read_op(impl.socket_,
|
||||
accept_handler<Socket, Handler>(
|
||||
impl.socket_, owner(), peer, impl.protocol_,
|
||||
impl.socket_, io_service(), peer, impl.protocol_,
|
||||
(impl.flags_ & implementation_type::enable_connection_aborted) != 0,
|
||||
handler));
|
||||
}
|
||||
@@ -1302,12 +1406,12 @@ public:
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
}
|
||||
else if (peer.native() != invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::already_connected);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1318,7 +1422,7 @@ public:
|
||||
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking))
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
impl.flags_ |= implementation_type::internal_non_blocking;
|
||||
@@ -1326,7 +1430,7 @@ public:
|
||||
|
||||
reactor_.start_read_op(impl.socket_,
|
||||
accept_endp_handler<Socket, Handler>(
|
||||
impl.socket_, owner(), peer, peer_endpoint,
|
||||
impl.socket_, io_service(), peer, peer_endpoint,
|
||||
(impl.flags_ & implementation_type::enable_connection_aborted) != 0,
|
||||
handler));
|
||||
}
|
||||
@@ -1469,7 +1573,7 @@ public:
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1478,7 +1582,7 @@ public:
|
||||
{
|
||||
socket_ops::close(impl.socket_);
|
||||
boost::asio::error error(err);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1490,7 +1594,7 @@ public:
|
||||
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking))
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
impl.flags_ |= implementation_type::internal_non_blocking;
|
||||
@@ -1504,7 +1608,7 @@ public:
|
||||
// The connect operation has finished successfully so we need to post the
|
||||
// handler immediately.
|
||||
boost::asio::error error(boost::asio::error::success);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
}
|
||||
else if (socket_ops::get_error() == boost::asio::error::in_progress
|
||||
|| socket_ops::get_error() == boost::asio::error::would_block)
|
||||
@@ -1514,13 +1618,13 @@ public:
|
||||
boost::shared_ptr<bool> completed(new bool(false));
|
||||
reactor_.start_write_and_except_ops(impl.socket_,
|
||||
connect_handler<Handler>(
|
||||
impl.socket_, completed, owner(), reactor_, handler));
|
||||
impl.socket_, completed, io_service(), reactor_, handler));
|
||||
}
|
||||
else
|
||||
{
|
||||
// The connect operation has failed, so post the handler immediately.
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ public:
|
||||
start_work_thread();
|
||||
work_io_service_->post(
|
||||
resolve_query_handler<Handler>(
|
||||
impl, query, owner(), handler));
|
||||
impl, query, io_service(), handler));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ public:
|
||||
start_work_thread();
|
||||
work_io_service_->post(
|
||||
resolve_endpoint_handler<Handler>(
|
||||
impl, endpoint, owner(), handler));
|
||||
impl, endpoint, io_service(), handler));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -195,6 +195,21 @@ public:
|
||||
timer_queues_.push_back(&timer_queue);
|
||||
}
|
||||
|
||||
// Remove a timer queue from the reactor.
|
||||
template <typename Time_Traits>
|
||||
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
|
||||
{
|
||||
if (timer_queues_[i] == &timer_queue)
|
||||
{
|
||||
timer_queues_.erase(timer_queues_.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule a timer in the given timer queue to expire at the specified
|
||||
// absolute time. The handler object will be invoked when the timer expires.
|
||||
template <typename Time_Traits, typename Handler>
|
||||
|
||||
@@ -561,6 +561,12 @@ inline int gethostname(char* name, int namelen)
|
||||
return error_wrapper(::gethostname(name, namelen));
|
||||
}
|
||||
|
||||
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \
|
||||
|| defined(__MACH__) && defined(__APPLE__)
|
||||
|
||||
// The following functions are only needed for emulation of getaddrinfo and
|
||||
// getnameinfo.
|
||||
|
||||
inline int translate_netdb_error(int error)
|
||||
{
|
||||
switch (error)
|
||||
@@ -1151,7 +1157,6 @@ inline int getaddrinfo_emulation(const char* host, const char* service,
|
||||
case NO_RECOVERY:
|
||||
return EAI_FAIL;
|
||||
case NO_DATA:
|
||||
return EAI_NODATA;
|
||||
default:
|
||||
return EAI_NONAME;
|
||||
}
|
||||
@@ -1240,92 +1245,6 @@ inline int getaddrinfo_emulation(const char* host, const char* service,
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int translate_addrinfo_error(int error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case 0:
|
||||
return boost::asio::error::success;
|
||||
case EAI_AGAIN:
|
||||
return boost::asio::error::host_not_found_try_again;
|
||||
case EAI_BADFLAGS:
|
||||
return boost::asio::error::invalid_argument;
|
||||
case EAI_FAIL:
|
||||
return boost::asio::error::no_recovery;
|
||||
case EAI_FAMILY:
|
||||
return boost::asio::error::address_family_not_supported;
|
||||
case EAI_MEMORY:
|
||||
return boost::asio::error::no_memory;
|
||||
case EAI_NONAME:
|
||||
return boost::asio::error::host_not_found;
|
||||
case EAI_SERVICE:
|
||||
return boost::asio::error::service_not_found;
|
||||
case EAI_SOCKTYPE:
|
||||
return boost::asio::error::socket_type_not_supported;
|
||||
default: // Possibly the non-portable EAI_SYSTEM.
|
||||
return get_error();
|
||||
}
|
||||
}
|
||||
|
||||
inline int getaddrinfo(const char* host, const char* service,
|
||||
const addrinfo_type* hints, addrinfo_type** result)
|
||||
{
|
||||
set_error(0);
|
||||
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||||
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
||||
// Building for Windows XP, Windows Server 2003, or later.
|
||||
int error = ::getaddrinfo(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
# else
|
||||
// Building for Windows 2000 or earlier.
|
||||
typedef int (WSAAPI *gai_t)(const char*,
|
||||
const char*, const addrinfo_type*, addrinfo_type**);
|
||||
if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
|
||||
{
|
||||
if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
|
||||
{
|
||||
int error = gai(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
}
|
||||
}
|
||||
int error = getaddrinfo_emulation(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
# endif
|
||||
#elif defined(__MACH__) && defined(__APPLE__)
|
||||
int error = getaddrinfo_emulation(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
#else
|
||||
int error = ::getaddrinfo(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void freeaddrinfo(addrinfo_type* ai)
|
||||
{
|
||||
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||||
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
||||
// Building for Windows XP, Windows Server 2003, or later.
|
||||
::freeaddrinfo(ai);
|
||||
# else
|
||||
// Building for Windows 2000 or earlier.
|
||||
typedef int (WSAAPI *fai_t)(addrinfo_type*);
|
||||
if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
|
||||
{
|
||||
if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
|
||||
{
|
||||
fai(ai);
|
||||
return;
|
||||
}
|
||||
}
|
||||
freeaddrinfo_emulation(ai);
|
||||
# endif
|
||||
#elif defined(__MACH__) && defined(__APPLE__)
|
||||
freeaddrinfo_emulation(ai);
|
||||
#else
|
||||
::freeaddrinfo(ai);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int getnameinfo_emulation(const socket_addr_type* sa,
|
||||
socket_addr_len_type salen, char* host, std::size_t hostlen,
|
||||
char* serv, std::size_t servlen, int flags)
|
||||
@@ -1453,6 +1372,95 @@ inline int getnameinfo_emulation(const socket_addr_type* sa,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||||
// || defined(__MACH__) && defined(__APPLE__)
|
||||
|
||||
inline int translate_addrinfo_error(int error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case 0:
|
||||
return boost::asio::error::success;
|
||||
case EAI_AGAIN:
|
||||
return boost::asio::error::host_not_found_try_again;
|
||||
case EAI_BADFLAGS:
|
||||
return boost::asio::error::invalid_argument;
|
||||
case EAI_FAIL:
|
||||
return boost::asio::error::no_recovery;
|
||||
case EAI_FAMILY:
|
||||
return boost::asio::error::address_family_not_supported;
|
||||
case EAI_MEMORY:
|
||||
return boost::asio::error::no_memory;
|
||||
case EAI_NONAME:
|
||||
return boost::asio::error::host_not_found;
|
||||
case EAI_SERVICE:
|
||||
return boost::asio::error::service_not_found;
|
||||
case EAI_SOCKTYPE:
|
||||
return boost::asio::error::socket_type_not_supported;
|
||||
default: // Possibly the non-portable EAI_SYSTEM.
|
||||
return get_error();
|
||||
}
|
||||
}
|
||||
|
||||
inline int getaddrinfo(const char* host, const char* service,
|
||||
const addrinfo_type* hints, addrinfo_type** result)
|
||||
{
|
||||
set_error(0);
|
||||
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||||
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
||||
// Building for Windows XP, Windows Server 2003, or later.
|
||||
int error = ::getaddrinfo(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
# else
|
||||
// Building for Windows 2000 or earlier.
|
||||
typedef int (WSAAPI *gai_t)(const char*,
|
||||
const char*, const addrinfo_type*, addrinfo_type**);
|
||||
if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
|
||||
{
|
||||
if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
|
||||
{
|
||||
int error = gai(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
}
|
||||
}
|
||||
int error = getaddrinfo_emulation(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
# endif
|
||||
#elif defined(__MACH__) && defined(__APPLE__)
|
||||
int error = getaddrinfo_emulation(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
#else
|
||||
int error = ::getaddrinfo(host, service, hints, result);
|
||||
return translate_addrinfo_error(error);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void freeaddrinfo(addrinfo_type* ai)
|
||||
{
|
||||
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||||
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
||||
// Building for Windows XP, Windows Server 2003, or later.
|
||||
::freeaddrinfo(ai);
|
||||
# else
|
||||
// Building for Windows 2000 or earlier.
|
||||
typedef int (WSAAPI *fai_t)(addrinfo_type*);
|
||||
if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
|
||||
{
|
||||
if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
|
||||
{
|
||||
fai(ai);
|
||||
return;
|
||||
}
|
||||
}
|
||||
freeaddrinfo_emulation(ai);
|
||||
# endif
|
||||
#elif defined(__MACH__) && defined(__APPLE__)
|
||||
freeaddrinfo_emulation(ai);
|
||||
#else
|
||||
::freeaddrinfo(ai);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int getnameinfo(const socket_addr_type* addr,
|
||||
socket_addr_len_type addrlen, char* host, std::size_t hostlen,
|
||||
char* serv, std::size_t servlen, int flags)
|
||||
@@ -1461,7 +1469,8 @@ inline int getnameinfo(const socket_addr_type* addr,
|
||||
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
||||
// Building for Windows XP, Windows Server 2003, or later.
|
||||
set_error(0);
|
||||
int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
|
||||
int error = ::getnameinfo(addr, addrlen, host, static_cast<DWORD>(hostlen),
|
||||
serv, static_cast<DWORD>(servlen), flags);
|
||||
return translate_addrinfo_error(error);
|
||||
# else
|
||||
// Building for Windows 2000 or earlier.
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||||
# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
|
||||
# error WinSock.h has already been included
|
||||
# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
|
||||
# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
|
||||
# if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
# pragma message("Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately")
|
||||
@@ -56,7 +59,6 @@
|
||||
# define BOOST_ASIO_WSPIAPI_H_DEFINED
|
||||
# endif // !defined(_WSPIAPI_H_)
|
||||
# endif // defined(__BORLANDC__)
|
||||
# define FD_SETSIZE 1024
|
||||
# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN)
|
||||
# if !defined(WIN32_LEAN_AND_MEAN)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
@@ -168,6 +170,13 @@ const int message_do_not_route = MSG_DONTROUTE;
|
||||
const int custom_socket_option_level = 0xA5100000;
|
||||
const int enable_connection_aborted_option = 1;
|
||||
|
||||
#if defined(_WIN64)
|
||||
std::size_t hash_value(SOCKET s)
|
||||
{
|
||||
return static_cast<std::size_t>(s);
|
||||
}
|
||||
#endif // defined(_WIN64)
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
@@ -20,13 +20,14 @@
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
#include <boost/aligned_storage.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/detail/bind_handler.hpp>
|
||||
#include <boost/asio/detail/call_stack.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_dispatch_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <boost/asio/detail/mutex.hpp>
|
||||
#include <boost/asio/detail/noncopyable.hpp>
|
||||
|
||||
@@ -43,18 +44,86 @@ public:
|
||||
class invoke_current_handler;
|
||||
class post_next_waiter_on_exit;
|
||||
|
||||
// The native type of the deadline timer.
|
||||
class implementation_type
|
||||
// The underlying implementation of a strand.
|
||||
class strand_impl
|
||||
{
|
||||
#if defined (__BORLANDC__)
|
||||
public:
|
||||
#else
|
||||
private:
|
||||
#endif
|
||||
void add_ref()
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
++ref_count_;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
--ref_count_;
|
||||
if (ref_count_ == 0)
|
||||
{
|
||||
lock.unlock();
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Only this service will have access to the internal values.
|
||||
friend class strand_service;
|
||||
friend class post_next_waiter_on_exit;
|
||||
friend class invoke_current_handler;
|
||||
|
||||
strand_impl(strand_service& owner)
|
||||
: owner_(owner),
|
||||
current_handler_(0),
|
||||
first_waiter_(0),
|
||||
last_waiter_(0),
|
||||
ref_count_(0)
|
||||
{
|
||||
// Insert implementation into linked list of all implementations.
|
||||
boost::asio::detail::mutex::scoped_lock lock(owner_.mutex_);
|
||||
next_ = owner_.impl_list_;
|
||||
prev_ = 0;
|
||||
if (owner_.impl_list_)
|
||||
owner_.impl_list_->prev_ = this;
|
||||
owner_.impl_list_ = this;
|
||||
}
|
||||
|
||||
~strand_impl()
|
||||
{
|
||||
// Remove implementation from linked list of all implementations.
|
||||
boost::asio::detail::mutex::scoped_lock lock(owner_.mutex_);
|
||||
if (owner_.impl_list_ == this)
|
||||
owner_.impl_list_ = next_;
|
||||
if (prev_)
|
||||
prev_->next_ = next_;
|
||||
if (next_)
|
||||
next_->prev_= prev_;
|
||||
next_ = 0;
|
||||
prev_ = 0;
|
||||
lock.unlock();
|
||||
|
||||
if (current_handler_)
|
||||
{
|
||||
current_handler_->destroy();
|
||||
}
|
||||
|
||||
while (first_waiter_)
|
||||
{
|
||||
handler_base* next = first_waiter_->next_;
|
||||
first_waiter_->destroy();
|
||||
first_waiter_ = next;
|
||||
}
|
||||
}
|
||||
|
||||
// Mutex to protect access to internal data.
|
||||
boost::asio::detail::mutex mutex_;
|
||||
|
||||
// The service that owns this implementation.
|
||||
strand_service& owner_;
|
||||
|
||||
// The handler that is ready to execute. If this pointer is non-null then it
|
||||
// indicates that a handler holds the lock.
|
||||
handler_base* current_handler_;
|
||||
@@ -66,13 +135,37 @@ public:
|
||||
handler_base* last_waiter_;
|
||||
|
||||
// Storage for posted handlers.
|
||||
typedef boost::aligned_storage<64> handler_storage_type;
|
||||
#if defined(__BORLANDC__)
|
||||
boost::aligned_storage<64> handler_storage_;
|
||||
#else
|
||||
handler_storage_type handler_storage_;
|
||||
#endif
|
||||
|
||||
// Pointers to adjacent socket implementations in linked list.
|
||||
implementation_type* next_;
|
||||
implementation_type* prev_;
|
||||
strand_impl* next_;
|
||||
strand_impl* prev_;
|
||||
|
||||
// The reference count on the strand implementation.
|
||||
size_t ref_count_;
|
||||
|
||||
#if !defined(__BORLANDC__)
|
||||
friend void intrusive_ptr_add_ref(strand_impl* p)
|
||||
{
|
||||
p->add_ref();
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_release(strand_impl* p)
|
||||
{
|
||||
p->release();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
friend class strand_impl;
|
||||
|
||||
typedef boost::intrusive_ptr<strand_impl> implementation_type;
|
||||
|
||||
// Base class for all handler types.
|
||||
class handler_base
|
||||
{
|
||||
@@ -105,6 +198,7 @@ public:
|
||||
|
||||
private:
|
||||
friend class strand_service;
|
||||
friend class strand_impl;
|
||||
friend class post_next_waiter_on_exit;
|
||||
handler_base* next_;
|
||||
invoke_func_type invoke_func_;
|
||||
@@ -116,7 +210,7 @@ public:
|
||||
{
|
||||
public:
|
||||
invoke_current_handler(strand_service& service_impl,
|
||||
implementation_type& impl)
|
||||
const implementation_type& impl)
|
||||
: service_impl_(service_impl),
|
||||
impl_(impl)
|
||||
{
|
||||
@@ -124,7 +218,7 @@ public:
|
||||
|
||||
void operator()()
|
||||
{
|
||||
impl_.current_handler_->invoke(service_impl_, impl_);
|
||||
impl_->current_handler_->invoke(service_impl_, impl_);
|
||||
}
|
||||
|
||||
friend void* asio_handler_allocate(std::size_t size,
|
||||
@@ -140,20 +234,24 @@ public:
|
||||
|
||||
void* do_handler_allocate(std::size_t size)
|
||||
{
|
||||
BOOST_ASSERT(size <= impl_.handler_storage_.size);
|
||||
return impl_.handler_storage_.address();
|
||||
#if defined(__BORLANDC__)
|
||||
BOOST_ASSERT(size <= boost::aligned_storage<64>::size);
|
||||
#else
|
||||
BOOST_ASSERT(size <= strand_impl::handler_storage_type::size);
|
||||
#endif
|
||||
return impl_->handler_storage_.address();
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch>
|
||||
friend void asio_handler_dispatch(Handler_To_Dispatch handler,
|
||||
template <typename Function>
|
||||
friend void asio_handler_invoke(Function function,
|
||||
invoke_current_handler*)
|
||||
{
|
||||
handler();
|
||||
function();
|
||||
}
|
||||
|
||||
private:
|
||||
strand_service& service_impl_;
|
||||
implementation_type& impl_;
|
||||
implementation_type impl_;
|
||||
};
|
||||
|
||||
// Helper class to automatically enqueue next waiter on block exit.
|
||||
@@ -172,15 +270,15 @@ public:
|
||||
{
|
||||
if (!cancelled_)
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(impl_.mutex_);
|
||||
impl_.current_handler_ = impl_.first_waiter_;
|
||||
if (impl_.current_handler_)
|
||||
boost::asio::detail::mutex::scoped_lock lock(impl_->mutex_);
|
||||
impl_->current_handler_ = impl_->first_waiter_;
|
||||
if (impl_->current_handler_)
|
||||
{
|
||||
impl_.first_waiter_ = impl_.first_waiter_->next_;
|
||||
if (impl_.first_waiter_ == 0)
|
||||
impl_.last_waiter_ = 0;
|
||||
impl_->first_waiter_ = impl_->first_waiter_->next_;
|
||||
if (impl_->first_waiter_ == 0)
|
||||
impl_->last_waiter_ = 0;
|
||||
lock.unlock();
|
||||
service_impl_.owner().post(
|
||||
service_impl_.io_service().post(
|
||||
invoke_current_handler(service_impl_, impl_));
|
||||
}
|
||||
}
|
||||
@@ -236,10 +334,10 @@ public:
|
||||
ptr.reset();
|
||||
|
||||
// Indicate that this strand is executing on the current thread.
|
||||
call_stack<implementation_type>::context ctx(&impl);
|
||||
call_stack<strand_impl>::context ctx(impl.get());
|
||||
|
||||
// Make the upcall.
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(handler, &handler);
|
||||
asio_handler_invoke_helpers::invoke(handler, &handler);
|
||||
}
|
||||
|
||||
static void do_destroy(handler_base* base)
|
||||
@@ -255,7 +353,7 @@ public:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
// Construct a new timer service for the specified io_service.
|
||||
// Construct a new strand service for the specified io_service.
|
||||
explicit strand_service(boost::asio::io_service& io_service)
|
||||
: boost::asio::io_service::service(io_service),
|
||||
mutex_(),
|
||||
@@ -268,7 +366,7 @@ public:
|
||||
{
|
||||
// Construct a list of all handlers to be destroyed.
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
implementation_type* impl = impl_list_;
|
||||
strand_impl* impl = impl_list_;
|
||||
handler_base* first_handler = 0;
|
||||
while (impl)
|
||||
{
|
||||
@@ -298,62 +396,29 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a new timer implementation.
|
||||
// Construct a new strand implementation.
|
||||
void construct(implementation_type& impl)
|
||||
{
|
||||
impl.current_handler_ = 0;
|
||||
impl.first_waiter_ = 0;
|
||||
impl.last_waiter_ = 0;
|
||||
|
||||
// Insert implementation into linked list of all implementations.
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
impl.next_ = impl_list_;
|
||||
impl.prev_ = 0;
|
||||
if (impl_list_)
|
||||
impl_list_->prev_ = &impl;
|
||||
impl_list_ = &impl;
|
||||
impl = implementation_type(new strand_impl(*this));
|
||||
}
|
||||
|
||||
// Destroy a timer implementation.
|
||||
// Destroy a strand implementation.
|
||||
void destroy(implementation_type& impl)
|
||||
{
|
||||
if (impl.current_handler_)
|
||||
{
|
||||
impl.current_handler_->destroy();
|
||||
impl.current_handler_ = 0;
|
||||
}
|
||||
|
||||
while (impl.first_waiter_)
|
||||
{
|
||||
handler_base* next = impl.first_waiter_->next_;
|
||||
impl.first_waiter_->destroy();
|
||||
impl.first_waiter_ = next;
|
||||
}
|
||||
impl.last_waiter_ = 0;
|
||||
|
||||
// Remove implementation from linked list of all implementations.
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
if (impl_list_ == &impl)
|
||||
impl_list_ = impl.next_;
|
||||
if (impl.prev_)
|
||||
impl.prev_->next_ = impl.next_;
|
||||
if (impl.next_)
|
||||
impl.next_->prev_= impl.prev_;
|
||||
impl.next_ = 0;
|
||||
impl.prev_ = 0;
|
||||
implementation_type().swap(impl);
|
||||
}
|
||||
|
||||
// Request the io_service to invoke the given handler.
|
||||
template <typename Handler>
|
||||
void dispatch(implementation_type& impl, Handler handler)
|
||||
{
|
||||
if (call_stack<implementation_type>::contains(&impl))
|
||||
if (call_stack<strand_impl>::contains(impl.get()))
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(handler, &handler);
|
||||
asio_handler_invoke_helpers::invoke(handler, &handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(impl.mutex_);
|
||||
boost::asio::detail::mutex::scoped_lock lock(impl->mutex_);
|
||||
|
||||
// Allocate and construct an object to wrap the handler.
|
||||
typedef handler_wrapper<Handler> value_type;
|
||||
@@ -361,12 +426,12 @@ public:
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler);
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr, handler);
|
||||
|
||||
if (impl.current_handler_ == 0)
|
||||
if (impl->current_handler_ == 0)
|
||||
{
|
||||
// This handler now has the lock, so can be dispatched immediately.
|
||||
impl.current_handler_ = ptr.get();
|
||||
impl->current_handler_ = ptr.get();
|
||||
lock.unlock();
|
||||
owner().dispatch(invoke_current_handler(*this, impl));
|
||||
io_service().dispatch(invoke_current_handler(*this, impl));
|
||||
ptr.release();
|
||||
}
|
||||
else
|
||||
@@ -374,15 +439,15 @@ public:
|
||||
// Another handler already holds the lock, so this handler must join
|
||||
// the list of waiters. The handler will be posted automatically when
|
||||
// its turn comes.
|
||||
if (impl.last_waiter_)
|
||||
if (impl->last_waiter_)
|
||||
{
|
||||
impl.last_waiter_->next_ = ptr.get();
|
||||
impl.last_waiter_ = impl.last_waiter_->next_;
|
||||
impl->last_waiter_->next_ = ptr.get();
|
||||
impl->last_waiter_ = impl->last_waiter_->next_;
|
||||
}
|
||||
else
|
||||
{
|
||||
impl.first_waiter_ = ptr.get();
|
||||
impl.last_waiter_ = ptr.get();
|
||||
impl->first_waiter_ = ptr.get();
|
||||
impl->last_waiter_ = ptr.get();
|
||||
}
|
||||
ptr.release();
|
||||
}
|
||||
@@ -393,7 +458,7 @@ public:
|
||||
template <typename Handler>
|
||||
void post(implementation_type& impl, Handler handler)
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(impl.mutex_);
|
||||
boost::asio::detail::mutex::scoped_lock lock(impl->mutex_);
|
||||
|
||||
// Allocate and construct an object to wrap the handler.
|
||||
typedef handler_wrapper<Handler> value_type;
|
||||
@@ -401,12 +466,12 @@ public:
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler);
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr, handler);
|
||||
|
||||
if (impl.current_handler_ == 0)
|
||||
if (impl->current_handler_ == 0)
|
||||
{
|
||||
// This handler now has the lock, so can be dispatched immediately.
|
||||
impl.current_handler_ = ptr.get();
|
||||
impl->current_handler_ = ptr.get();
|
||||
lock.unlock();
|
||||
owner().post(invoke_current_handler(*this, impl));
|
||||
io_service().post(invoke_current_handler(*this, impl));
|
||||
ptr.release();
|
||||
}
|
||||
else
|
||||
@@ -414,15 +479,15 @@ public:
|
||||
// Another handler already holds the lock, so this handler must join the
|
||||
// list of waiters. The handler will be posted automatically when its turn
|
||||
// comes.
|
||||
if (impl.last_waiter_)
|
||||
if (impl->last_waiter_)
|
||||
{
|
||||
impl.last_waiter_->next_ = ptr.get();
|
||||
impl.last_waiter_ = impl.last_waiter_->next_;
|
||||
impl->last_waiter_->next_ = ptr.get();
|
||||
impl->last_waiter_ = impl->last_waiter_->next_;
|
||||
}
|
||||
else
|
||||
{
|
||||
impl.first_waiter_ = ptr.get();
|
||||
impl.last_waiter_ = ptr.get();
|
||||
impl->first_waiter_ = ptr.get();
|
||||
impl->last_waiter_ = ptr.get();
|
||||
}
|
||||
ptr.release();
|
||||
}
|
||||
@@ -433,13 +498,33 @@ private:
|
||||
boost::asio::detail::mutex mutex_;
|
||||
|
||||
// The head of a linked list of all implementations.
|
||||
implementation_type* impl_list_;
|
||||
strand_impl* impl_list_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
|
||||
namespace boost {
|
||||
|
||||
inline void intrusive_ptr_add_ref(
|
||||
boost::asio::detail::strand_service::strand_impl* p)
|
||||
{
|
||||
p->add_ref();
|
||||
}
|
||||
|
||||
inline void intrusive_ptr_release(
|
||||
boost::asio::detail::strand_service::strand_impl* p)
|
||||
{
|
||||
p->release();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // defined(__BORLANDC__)
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <boost/asio/detail/call_stack.hpp>
|
||||
#include <boost/asio/detail/event.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_dispatch_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <boost/asio/detail/mutex.hpp>
|
||||
#include <boost/asio/detail/task_io_service_fwd.hpp>
|
||||
|
||||
@@ -69,8 +69,8 @@ public:
|
||||
handler_queue_end_ = &task_handler_;
|
||||
}
|
||||
|
||||
// Run the event processing loop.
|
||||
void run()
|
||||
// Run the event loop until interrupted or no more work.
|
||||
size_t run()
|
||||
{
|
||||
typename call_stack<task_io_service>::context ctx(this);
|
||||
|
||||
@@ -80,72 +80,49 @@ public:
|
||||
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
|
||||
while (!interrupted_ && outstanding_work_ > 0)
|
||||
{
|
||||
if (handler_queue_)
|
||||
{
|
||||
// Prepare to execute first handler from queue.
|
||||
handler_base* h = handler_queue_;
|
||||
handler_queue_ = h->next_;
|
||||
if (handler_queue_ == 0)
|
||||
handler_queue_end_ = 0;
|
||||
bool more_handlers = (handler_queue_ != 0);
|
||||
lock.unlock();
|
||||
size_t n = 0;
|
||||
while (do_one(lock, &this_idle_thread))
|
||||
if (n != (std::numeric_limits<size_t>::max)())
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
if (h == &task_handler_)
|
||||
{
|
||||
task_cleanup c(lock, handler_queue_,
|
||||
handler_queue_end_, task_handler_);
|
||||
// Run until interrupted or one operation is performed.
|
||||
size_t run_one()
|
||||
{
|
||||
typename call_stack<task_io_service>::context ctx(this);
|
||||
|
||||
// Run the task. May throw an exception. Only block if the handler
|
||||
// queue is empty, otherwise we want to return as soon as possible to
|
||||
// execute the handlers.
|
||||
task_.run(!more_handlers);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler_cleanup c(lock, outstanding_work_);
|
||||
idle_thread_info this_idle_thread;
|
||||
this_idle_thread.prev = &this_idle_thread;
|
||||
this_idle_thread.next = &this_idle_thread;
|
||||
|
||||
// Invoke the handler. May throw an exception.
|
||||
h->call(); // call() deletes the handler object
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to run right now, so just wait for work to do.
|
||||
if (first_idle_thread_)
|
||||
{
|
||||
this_idle_thread.next = first_idle_thread_;
|
||||
this_idle_thread.prev = first_idle_thread_->prev;
|
||||
first_idle_thread_->prev->next = &this_idle_thread;
|
||||
first_idle_thread_->prev = &this_idle_thread;
|
||||
}
|
||||
first_idle_thread_ = &this_idle_thread;
|
||||
this_idle_thread.wakeup_event.clear();
|
||||
lock.unlock();
|
||||
this_idle_thread.wakeup_event.wait();
|
||||
lock.lock();
|
||||
if (this_idle_thread.next == &this_idle_thread)
|
||||
{
|
||||
first_idle_thread_ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first_idle_thread_ == &this_idle_thread)
|
||||
first_idle_thread_ = this_idle_thread.next;
|
||||
this_idle_thread.next->prev = this_idle_thread.prev;
|
||||
this_idle_thread.prev->next = this_idle_thread.next;
|
||||
this_idle_thread.next = &this_idle_thread;
|
||||
this_idle_thread.prev = &this_idle_thread;
|
||||
}
|
||||
}
|
||||
}
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
|
||||
if (!interrupted_)
|
||||
{
|
||||
// No more work to do!
|
||||
interrupt_all_threads();
|
||||
}
|
||||
return do_one(lock, &this_idle_thread);
|
||||
}
|
||||
|
||||
// Poll for operations without blocking.
|
||||
size_t poll()
|
||||
{
|
||||
typename call_stack<task_io_service>::context ctx(this);
|
||||
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
|
||||
size_t n = 0;
|
||||
while (do_one(lock, 0))
|
||||
if (n != (std::numeric_limits<size_t>::max)())
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
// Poll for one operation without blocking.
|
||||
size_t poll_one()
|
||||
{
|
||||
typename call_stack<task_io_service>::context ctx(this);
|
||||
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
|
||||
return do_one(lock, 0);
|
||||
}
|
||||
|
||||
// Interrupt the event processing loop.
|
||||
@@ -182,7 +159,7 @@ public:
|
||||
void dispatch(Handler handler)
|
||||
{
|
||||
if (call_stack<task_io_service>::contains(this))
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(handler, &handler);
|
||||
asio_handler_invoke_helpers::invoke(handler, &handler);
|
||||
else
|
||||
post(handler);
|
||||
}
|
||||
@@ -225,6 +202,93 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
struct idle_thread_info;
|
||||
|
||||
size_t do_one(boost::asio::detail::mutex::scoped_lock& lock,
|
||||
idle_thread_info* this_idle_thread)
|
||||
{
|
||||
if (outstanding_work_ == 0 && !interrupted_)
|
||||
{
|
||||
interrupt_all_threads();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool polling = !this_idle_thread;
|
||||
bool task_has_run = false;
|
||||
while (!interrupted_)
|
||||
{
|
||||
if (handler_queue_)
|
||||
{
|
||||
// Prepare to execute first handler from queue.
|
||||
handler_base* h = handler_queue_;
|
||||
handler_queue_ = h->next_;
|
||||
if (handler_queue_ == 0)
|
||||
handler_queue_end_ = 0;
|
||||
bool more_handlers = (handler_queue_ != 0);
|
||||
lock.unlock();
|
||||
|
||||
if (h == &task_handler_)
|
||||
{
|
||||
// If the task has already run and we're polling then we're done.
|
||||
if (task_has_run && polling)
|
||||
return 0;
|
||||
task_has_run = true;
|
||||
|
||||
task_cleanup c(lock, *this);
|
||||
|
||||
// Run the task. May throw an exception. Only block if the handler
|
||||
// queue is empty and we have an idle_thread_info object, otherwise
|
||||
// we want to return as soon as possible.
|
||||
task_.run(!more_handlers && !polling);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler_cleanup c(lock, *this);
|
||||
|
||||
// Invoke the handler. May throw an exception.
|
||||
h->call(); // call() deletes the handler object
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (this_idle_thread)
|
||||
{
|
||||
// Nothing to run right now, so just wait for work to do.
|
||||
if (first_idle_thread_)
|
||||
{
|
||||
this_idle_thread->next = first_idle_thread_;
|
||||
this_idle_thread->prev = first_idle_thread_->prev;
|
||||
first_idle_thread_->prev->next = this_idle_thread;
|
||||
first_idle_thread_->prev = this_idle_thread;
|
||||
}
|
||||
first_idle_thread_ = this_idle_thread;
|
||||
this_idle_thread->wakeup_event.clear();
|
||||
lock.unlock();
|
||||
this_idle_thread->wakeup_event.wait();
|
||||
lock.lock();
|
||||
if (this_idle_thread->next == this_idle_thread)
|
||||
{
|
||||
first_idle_thread_ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first_idle_thread_ == this_idle_thread)
|
||||
first_idle_thread_ = this_idle_thread->next;
|
||||
this_idle_thread->next->prev = this_idle_thread->prev;
|
||||
this_idle_thread->prev->next = this_idle_thread->next;
|
||||
this_idle_thread->next = this_idle_thread;
|
||||
this_idle_thread->prev = this_idle_thread;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Interrupt the task and all idle threads.
|
||||
void interrupt_all_threads()
|
||||
{
|
||||
@@ -332,7 +396,7 @@ private:
|
||||
ptr.reset();
|
||||
|
||||
// Make the upcall.
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(handler, &handler);
|
||||
asio_handler_invoke_helpers::invoke(handler, &handler);
|
||||
}
|
||||
|
||||
static void do_destroy(handler_base* base)
|
||||
@@ -349,16 +413,15 @@ private:
|
||||
};
|
||||
|
||||
// Helper class to perform task-related operations on block exit.
|
||||
class task_cleanup;
|
||||
friend class task_cleanup;
|
||||
class task_cleanup
|
||||
{
|
||||
public:
|
||||
task_cleanup(boost::asio::detail::mutex::scoped_lock& lock,
|
||||
handler_base*& handler_queue, handler_base*& handler_queue_end,
|
||||
handler_base& task_handler)
|
||||
task_io_service& task_io_svc)
|
||||
: lock_(lock),
|
||||
handler_queue_(handler_queue),
|
||||
handler_queue_end_(handler_queue_end),
|
||||
task_handler_(task_handler)
|
||||
task_io_service_(task_io_svc)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -366,45 +429,50 @@ private:
|
||||
{
|
||||
// Reinsert the task at the end of the handler queue.
|
||||
lock_.lock();
|
||||
task_handler_.next_ = 0;
|
||||
if (handler_queue_end_)
|
||||
task_io_service_.task_handler_.next_ = 0;
|
||||
if (task_io_service_.handler_queue_end_)
|
||||
{
|
||||
handler_queue_end_->next_ = &task_handler_;
|
||||
handler_queue_end_ = &task_handler_;
|
||||
task_io_service_.handler_queue_end_->next_
|
||||
= &task_io_service_.task_handler_;
|
||||
task_io_service_.handler_queue_end_
|
||||
= &task_io_service_.task_handler_;
|
||||
}
|
||||
else
|
||||
{
|
||||
handler_queue_ = handler_queue_end_ = &task_handler_;
|
||||
task_io_service_.handler_queue_
|
||||
= task_io_service_.handler_queue_end_
|
||||
= &task_io_service_.task_handler_;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::detail::mutex::scoped_lock& lock_;
|
||||
handler_base*& handler_queue_;
|
||||
handler_base*& handler_queue_end_;
|
||||
handler_base& task_handler_;
|
||||
task_io_service& task_io_service_;
|
||||
};
|
||||
|
||||
// Helper class to perform handler-related operations on block exit.
|
||||
class handler_cleanup;
|
||||
friend class handler_cleanup;
|
||||
class handler_cleanup
|
||||
{
|
||||
public:
|
||||
handler_cleanup(boost::asio::detail::mutex::scoped_lock& lock,
|
||||
int& outstanding_work)
|
||||
task_io_service& task_io_svc)
|
||||
: lock_(lock),
|
||||
outstanding_work_(outstanding_work)
|
||||
task_io_service_(task_io_svc)
|
||||
{
|
||||
}
|
||||
|
||||
~handler_cleanup()
|
||||
{
|
||||
lock_.lock();
|
||||
--outstanding_work_;
|
||||
if (--task_io_service_.outstanding_work_ == 0)
|
||||
task_io_service_.interrupt_all_threads();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::detail::mutex::scoped_lock& lock_;
|
||||
int& outstanding_work_;
|
||||
task_io_service& task_io_service_;
|
||||
};
|
||||
|
||||
// Mutex to protect access to internal data.
|
||||
|
||||
86
include/boost/asio/detail/win_fd_set_adapter.hpp
Normal file
86
include/boost/asio/detail/win_fd_set_adapter.hpp
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// win_fd_set_adapter.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 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 BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
|
||||
#define BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/socket_types.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
|
||||
class win_fd_set_adapter
|
||||
{
|
||||
public:
|
||||
enum { win_fd_set_size = 1024 };
|
||||
|
||||
win_fd_set_adapter()
|
||||
: max_descriptor_(invalid_socket)
|
||||
{
|
||||
fd_set_.fd_count = 0;
|
||||
}
|
||||
|
||||
void set(socket_type descriptor)
|
||||
{
|
||||
for (u_int i = 0; i < fd_set_.fd_count; ++i)
|
||||
if (fd_set_.fd_array[i] == descriptor)
|
||||
return;
|
||||
if (fd_set_.fd_count < win_fd_set_size)
|
||||
fd_set_.fd_array[fd_set_.fd_count++] = descriptor;
|
||||
}
|
||||
|
||||
bool is_set(socket_type descriptor) const
|
||||
{
|
||||
return !!__WSAFDIsSet(descriptor,
|
||||
const_cast<fd_set*>(reinterpret_cast<const fd_set*>(&fd_set_)));
|
||||
}
|
||||
|
||||
operator fd_set*()
|
||||
{
|
||||
return reinterpret_cast<fd_set*>(&fd_set_);
|
||||
}
|
||||
|
||||
socket_type max_descriptor() const
|
||||
{
|
||||
return max_descriptor_;
|
||||
}
|
||||
|
||||
private:
|
||||
// This structure is defined to be compatible with the Windows API fd_set
|
||||
// structure, but without being dependent on the value of FD_SETSIZE.
|
||||
struct win_fd_set
|
||||
{
|
||||
u_int fd_count;
|
||||
SOCKET fd_array[win_fd_set_size];
|
||||
};
|
||||
|
||||
win_fd_set fd_set_;
|
||||
socket_type max_descriptor_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
|
||||
@@ -22,6 +22,7 @@
|
||||
#if defined(BOOST_ASIO_HAS_IOCP)
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
#include <limits>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
@@ -29,7 +30,7 @@
|
||||
#include <boost/asio/system_exception.hpp>
|
||||
#include <boost/asio/detail/call_stack.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_dispatch_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <boost/asio/detail/socket_types.hpp>
|
||||
#include <boost/asio/detail/win_iocp_operation.hpp>
|
||||
|
||||
@@ -74,10 +75,11 @@ public:
|
||||
DWORD_PTR completion_key = 0;
|
||||
#endif
|
||||
LPOVERLAPPED overlapped = 0;
|
||||
::GetQueuedCompletionStatus(iocp_.handle,
|
||||
::SetLastError(0);
|
||||
BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle,
|
||||
&bytes_transferred, &completion_key, &overlapped, 0);
|
||||
DWORD last_error = ::GetLastError();
|
||||
if (last_error == WAIT_TIMEOUT)
|
||||
if (!ok && overlapped == 0 && last_error == WAIT_TIMEOUT)
|
||||
break;
|
||||
if (overlapped)
|
||||
static_cast<operation*>(overlapped)->destroy();
|
||||
@@ -91,79 +93,56 @@ public:
|
||||
::CreateIoCompletionPort(sock_as_handle, iocp_.handle, 0, 0);
|
||||
}
|
||||
|
||||
struct auto_work
|
||||
{
|
||||
auto_work(win_iocp_io_service& io_service)
|
||||
: io_service_(io_service)
|
||||
{
|
||||
io_service_.work_started();
|
||||
}
|
||||
|
||||
~auto_work()
|
||||
{
|
||||
io_service_.work_finished();
|
||||
}
|
||||
|
||||
private:
|
||||
win_iocp_io_service& io_service_;
|
||||
};
|
||||
|
||||
// Run the event processing loop.
|
||||
void run()
|
||||
// Run the event loop until interrupted or no more work.
|
||||
size_t run()
|
||||
{
|
||||
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
call_stack<win_iocp_io_service>::context ctx(this);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// Get the next operation from the queue.
|
||||
DWORD bytes_transferred = 0;
|
||||
#if (WINVER < 0x0500)
|
||||
DWORD completion_key = 0;
|
||||
#else
|
||||
DWORD_PTR completion_key = 0;
|
||||
#endif
|
||||
LPOVERLAPPED overlapped = 0;
|
||||
::SetLastError(0);
|
||||
::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
|
||||
&completion_key, &overlapped, INFINITE);
|
||||
DWORD last_error = ::GetLastError();
|
||||
size_t n = 0;
|
||||
while (do_one(true))
|
||||
if (n != (std::numeric_limits<size_t>::max)())
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
if (overlapped)
|
||||
{
|
||||
// We may have been passed a last_error value in the completion_key.
|
||||
if (last_error == 0)
|
||||
{
|
||||
last_error = completion_key;
|
||||
}
|
||||
// Run until interrupted or one operation is performed.
|
||||
size_t run_one()
|
||||
{
|
||||
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
|
||||
return 0;
|
||||
|
||||
// Ensure that the io_service does not exit due to running out of work
|
||||
// while we make the upcall.
|
||||
auto_work work(*this);
|
||||
call_stack<win_iocp_io_service>::context ctx(this);
|
||||
|
||||
// Dispatch the operation.
|
||||
operation* op = static_cast<operation*>(overlapped);
|
||||
op->do_completion(last_error, bytes_transferred);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The interrupted_ flag is always checked to ensure that any leftover
|
||||
// interrupts from a previous run invocation are ignored.
|
||||
if (::InterlockedExchangeAdd(&interrupted_, 0) != 0)
|
||||
{
|
||||
// Wake up next thread that is blocked on GetQueuedCompletionStatus.
|
||||
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
|
||||
{
|
||||
DWORD last_error = ::GetLastError();
|
||||
system_exception e("pqcs", last_error);
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return do_one(true);
|
||||
}
|
||||
|
||||
// Poll for operations without blocking.
|
||||
size_t poll()
|
||||
{
|
||||
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
|
||||
return 0;
|
||||
|
||||
call_stack<win_iocp_io_service>::context ctx(this);
|
||||
|
||||
size_t n = 0;
|
||||
while (do_one(false))
|
||||
if (n != (std::numeric_limits<size_t>::max)())
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
// Poll for one operation without blocking.
|
||||
size_t poll_one()
|
||||
{
|
||||
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
|
||||
return 0;
|
||||
|
||||
call_stack<win_iocp_io_service>::context ctx(this);
|
||||
|
||||
return do_one(false);
|
||||
}
|
||||
|
||||
// Interrupt the event processing loop.
|
||||
@@ -199,68 +178,12 @@ public:
|
||||
interrupt();
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
struct handler_operation
|
||||
: public operation
|
||||
{
|
||||
handler_operation(win_iocp_io_service& io_service,
|
||||
Handler handler)
|
||||
: operation(&handler_operation<Handler>::do_completion_impl,
|
||||
&handler_operation<Handler>::destroy_impl),
|
||||
io_service_(io_service),
|
||||
handler_(handler)
|
||||
{
|
||||
io_service_.work_started();
|
||||
}
|
||||
|
||||
~handler_operation()
|
||||
{
|
||||
io_service_.work_finished();
|
||||
}
|
||||
|
||||
private:
|
||||
// Prevent copying and assignment.
|
||||
handler_operation(const handler_operation&);
|
||||
void operator=(const handler_operation&);
|
||||
|
||||
static void do_completion_impl(operation* op, DWORD, size_t)
|
||||
{
|
||||
// Take ownership of the operation object.
|
||||
typedef handler_operation<Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
|
||||
// Free the memory associated with the handler.
|
||||
ptr.reset();
|
||||
|
||||
// Make the upcall.
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(handler, &handler);
|
||||
}
|
||||
|
||||
static void destroy_impl(operation* op)
|
||||
{
|
||||
// Take ownership of the operation object.
|
||||
typedef handler_operation<Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
|
||||
}
|
||||
|
||||
win_iocp_io_service& io_service_;
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
// Request invocation of the given handler.
|
||||
template <typename Handler>
|
||||
void dispatch(Handler handler)
|
||||
{
|
||||
if (call_stack<win_iocp_io_service>::contains(this))
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(handler, &handler);
|
||||
asio_handler_invoke_helpers::invoke(handler, &handler);
|
||||
else
|
||||
post(handler);
|
||||
}
|
||||
@@ -306,6 +229,140 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// Dequeues at most one operation from the I/O completion port, and then
|
||||
// executes it. Returns the number of operations that were dequeued (i.e.
|
||||
// either 0 or 1).
|
||||
size_t do_one(bool block)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
// Get the next operation from the queue.
|
||||
DWORD bytes_transferred = 0;
|
||||
#if (WINVER < 0x0500)
|
||||
DWORD completion_key = 0;
|
||||
#else
|
||||
DWORD_PTR completion_key = 0;
|
||||
#endif
|
||||
LPOVERLAPPED overlapped = 0;
|
||||
::SetLastError(0);
|
||||
BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
|
||||
&completion_key, &overlapped, block ? INFINITE : 0);
|
||||
DWORD last_error = ::GetLastError();
|
||||
|
||||
if (!ok && overlapped == 0)
|
||||
return 0;
|
||||
|
||||
if (overlapped)
|
||||
{
|
||||
// We may have been passed a last_error value in the completion_key.
|
||||
if (last_error == 0)
|
||||
{
|
||||
last_error = completion_key;
|
||||
}
|
||||
|
||||
// Ensure that the io_service does not exit due to running out of work
|
||||
// while we make the upcall.
|
||||
auto_work work(*this);
|
||||
|
||||
// Dispatch the operation.
|
||||
operation* op = static_cast<operation*>(overlapped);
|
||||
op->do_completion(last_error, bytes_transferred);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The interrupted_ flag is always checked to ensure that any leftover
|
||||
// interrupts from a previous run invocation are ignored.
|
||||
if (::InterlockedExchangeAdd(&interrupted_, 0) != 0)
|
||||
{
|
||||
// Wake up next thread that is blocked on GetQueuedCompletionStatus.
|
||||
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
|
||||
{
|
||||
DWORD last_error = ::GetLastError();
|
||||
system_exception e("pqcs", last_error);
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct auto_work
|
||||
{
|
||||
auto_work(win_iocp_io_service& io_service)
|
||||
: io_service_(io_service)
|
||||
{
|
||||
io_service_.work_started();
|
||||
}
|
||||
|
||||
~auto_work()
|
||||
{
|
||||
io_service_.work_finished();
|
||||
}
|
||||
|
||||
private:
|
||||
win_iocp_io_service& io_service_;
|
||||
};
|
||||
|
||||
template <typename Handler>
|
||||
struct handler_operation
|
||||
: public operation
|
||||
{
|
||||
handler_operation(win_iocp_io_service& io_service,
|
||||
Handler handler)
|
||||
: operation(&handler_operation<Handler>::do_completion_impl,
|
||||
&handler_operation<Handler>::destroy_impl),
|
||||
io_service_(io_service),
|
||||
handler_(handler)
|
||||
{
|
||||
io_service_.work_started();
|
||||
}
|
||||
|
||||
~handler_operation()
|
||||
{
|
||||
io_service_.work_finished();
|
||||
}
|
||||
|
||||
private:
|
||||
// Prevent copying and assignment.
|
||||
handler_operation(const handler_operation&);
|
||||
void operator=(const handler_operation&);
|
||||
|
||||
static void do_completion_impl(operation* op, DWORD, size_t)
|
||||
{
|
||||
// Take ownership of the operation object.
|
||||
typedef handler_operation<Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
|
||||
// Free the memory associated with the handler.
|
||||
ptr.reset();
|
||||
|
||||
// Make the upcall.
|
||||
asio_handler_invoke_helpers::invoke(handler, &handler);
|
||||
}
|
||||
|
||||
static void destroy_impl(operation* op)
|
||||
{
|
||||
// Take ownership of the operation object.
|
||||
typedef handler_operation<Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
|
||||
}
|
||||
|
||||
win_iocp_io_service& io_service_;
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
// The IO completion port used for queueing operations.
|
||||
struct iocp_holder
|
||||
{
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <boost/asio/socket_base.hpp>
|
||||
#include <boost/asio/detail/bind_handler.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_dispatch_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <boost/asio/detail/mutex.hpp>
|
||||
#include <boost/asio/detail/select_reactor.hpp>
|
||||
#include <boost/asio/detail/socket_holder.hpp>
|
||||
@@ -65,7 +65,49 @@ public:
|
||||
typedef boost::weak_ptr<void> weak_cancel_token_type;
|
||||
|
||||
// The native type of a socket.
|
||||
typedef socket_type native_type;
|
||||
class native_type
|
||||
{
|
||||
public:
|
||||
native_type(socket_type s)
|
||||
: socket_(s),
|
||||
have_remote_endpoint_(false)
|
||||
{
|
||||
}
|
||||
|
||||
native_type(socket_type s, const endpoint_type& ep)
|
||||
: socket_(s),
|
||||
have_remote_endpoint_(true),
|
||||
remote_endpoint_(ep)
|
||||
{
|
||||
}
|
||||
|
||||
void operator=(socket_type s)
|
||||
{
|
||||
socket_ = s;
|
||||
have_remote_endpoint_ = false;
|
||||
remote_endpoint_ = endpoint_type();
|
||||
}
|
||||
|
||||
operator socket_type() const
|
||||
{
|
||||
return socket_;
|
||||
}
|
||||
|
||||
bool have_remote_endpoint() const
|
||||
{
|
||||
return have_remote_endpoint_;
|
||||
}
|
||||
|
||||
endpoint_type remote_endpoint() const
|
||||
{
|
||||
return remote_endpoint_;
|
||||
}
|
||||
|
||||
private:
|
||||
socket_type socket_;
|
||||
bool have_remote_endpoint_;
|
||||
endpoint_type remote_endpoint_;
|
||||
};
|
||||
|
||||
// The implementation type of the socket.
|
||||
class implementation_type
|
||||
@@ -87,11 +129,12 @@ public:
|
||||
friend class win_iocp_socket_service;
|
||||
|
||||
// The native socket representation.
|
||||
socket_type socket_;
|
||||
native_type socket_;
|
||||
|
||||
enum
|
||||
{
|
||||
enable_connection_aborted = 1 // User wants connection_aborted errors.
|
||||
enable_connection_aborted = 1, // User wants connection_aborted errors.
|
||||
user_set_linger = 2 // The user set the linger option.
|
||||
};
|
||||
|
||||
// Flags indicating the current state of the socket.
|
||||
@@ -108,6 +151,12 @@ public:
|
||||
// The protocol associated with the socket.
|
||||
protocol_type protocol_;
|
||||
|
||||
// The ID of the thread from which it is safe to cancel asynchronous
|
||||
// operations. 0 means no asynchronous operations have been started yet.
|
||||
// ~0 means asynchronous operations have been started from more than one
|
||||
// thread, and cancellation is not supported for the socket.
|
||||
DWORD safe_cancellation_thread_id_;
|
||||
|
||||
// Pointers to adjacent socket implementations in linked list.
|
||||
implementation_type* next_;
|
||||
implementation_type* prev_;
|
||||
@@ -147,6 +196,7 @@ public:
|
||||
{
|
||||
impl.socket_ = invalid_socket;
|
||||
impl.cancel_token_.reset();
|
||||
impl.safe_cancellation_thread_id_ = 0;
|
||||
|
||||
// Insert implementation into linked list of all implementations.
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
@@ -160,7 +210,31 @@ public:
|
||||
// Destroy a socket implementation.
|
||||
void destroy(implementation_type& impl)
|
||||
{
|
||||
close(impl, boost::asio::ignore_error());
|
||||
if (impl.socket_ != invalid_socket)
|
||||
{
|
||||
// Check if the reactor was created, in which case we need to close the
|
||||
// socket on the reactor as well to cancel any operations that might be
|
||||
// running there.
|
||||
reactor_type* reactor = static_cast<reactor_type*>(
|
||||
interlocked_compare_exchange_pointer(
|
||||
reinterpret_cast<void**>(&reactor_), 0, 0));
|
||||
if (reactor)
|
||||
reactor->close_descriptor(impl.socket_);
|
||||
|
||||
if (impl.flags_ & implementation_type::user_set_linger)
|
||||
{
|
||||
::linger opt;
|
||||
opt.l_onoff = 0;
|
||||
opt.l_linger = 0;
|
||||
socket_ops::setsockopt(impl.socket_,
|
||||
SOL_SOCKET, SO_LINGER, &opt, sizeof(opt));
|
||||
}
|
||||
|
||||
socket_ops::close(impl.socket_);
|
||||
impl.socket_ = invalid_socket;
|
||||
impl.cancel_token_.reset();
|
||||
impl.safe_cancellation_thread_id_ = 0;
|
||||
}
|
||||
|
||||
// Remove implementation from linked list of all implementations.
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
@@ -238,6 +312,7 @@ public:
|
||||
{
|
||||
impl.socket_ = invalid_socket;
|
||||
impl.cancel_token_.reset();
|
||||
impl.safe_cancellation_thread_id_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +325,44 @@ public:
|
||||
return impl.socket_;
|
||||
}
|
||||
|
||||
// Cancel all operations associated with the socket.
|
||||
template <typename Error_Handler>
|
||||
void cancel(implementation_type& impl, Error_Handler error_handler)
|
||||
{
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
error_handler(error);
|
||||
}
|
||||
else if (impl.safe_cancellation_thread_id_ == 0)
|
||||
{
|
||||
// No operations have been started, so there's nothing to cancel.
|
||||
error_handler(boost::asio::error(0));
|
||||
}
|
||||
else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
|
||||
{
|
||||
// Asynchronous operations have been started from the current thread only,
|
||||
// so it is safe to try to cancel them using CancelIo.
|
||||
socket_type sock = impl.socket_;
|
||||
HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
|
||||
if (!::CancelIo(sock_as_handle))
|
||||
{
|
||||
DWORD last_error = ::GetLastError();
|
||||
error_handler(boost::asio::error(last_error));
|
||||
}
|
||||
else
|
||||
{
|
||||
error_handler(boost::asio::error(0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Asynchronous operations have been started from more than one thread,
|
||||
// so cancellation is not safe.
|
||||
error_handler(boost::asio::error(boost::asio::error::not_supported));
|
||||
}
|
||||
}
|
||||
|
||||
// Bind the socket to the specified local endpoint.
|
||||
template <typename Error_Handler>
|
||||
void bind(implementation_type& impl, const endpoint_type& endpoint,
|
||||
@@ -267,9 +380,6 @@ public:
|
||||
void listen(implementation_type& impl, int backlog,
|
||||
Error_Handler error_handler)
|
||||
{
|
||||
if (backlog == 0)
|
||||
backlog = SOMAXCONN;
|
||||
|
||||
if (socket_ops::listen(impl.socket_, backlog) == socket_error_retval)
|
||||
error_handler(boost::asio::error(socket_ops::get_error()));
|
||||
else
|
||||
@@ -299,6 +409,12 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
if (option.level(impl.protocol_) == SOL_SOCKET
|
||||
&& option.name(impl.protocol_) == SO_LINGER)
|
||||
{
|
||||
impl.flags_ |= implementation_type::user_set_linger;
|
||||
}
|
||||
|
||||
if (socket_ops::setsockopt(impl.socket_,
|
||||
option.level(impl.protocol_), option.name(impl.protocol_),
|
||||
option.data(impl.protocol_), option.size(impl.protocol_)))
|
||||
@@ -375,15 +491,38 @@ public:
|
||||
void get_remote_endpoint(const implementation_type& impl,
|
||||
endpoint_type& endpoint, Error_Handler error_handler) const
|
||||
{
|
||||
socket_addr_len_type addr_len = endpoint.capacity();
|
||||
if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len))
|
||||
if (impl.socket_.have_remote_endpoint())
|
||||
{
|
||||
error_handler(boost::asio::error(socket_ops::get_error()));
|
||||
return;
|
||||
}
|
||||
// Check if socket is still connected.
|
||||
DWORD connect_time = 0;
|
||||
size_t connect_time_len = sizeof(connect_time);
|
||||
if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME,
|
||||
&connect_time, &connect_time_len) == socket_error_retval)
|
||||
{
|
||||
error_handler(boost::asio::error(socket_ops::get_error()));
|
||||
return;
|
||||
}
|
||||
if (connect_time == 0xFFFFFFFF)
|
||||
{
|
||||
error_handler(boost::asio::error(boost::asio::error::not_connected));
|
||||
return;
|
||||
}
|
||||
|
||||
endpoint.resize(addr_len);
|
||||
error_handler(boost::asio::error(0));
|
||||
endpoint = impl.socket_.remote_endpoint();
|
||||
error_handler(boost::asio::error(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
socket_addr_len_type addr_len = endpoint.capacity();
|
||||
if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len))
|
||||
{
|
||||
error_handler(boost::asio::error(socket_ops::get_error()));
|
||||
return;
|
||||
}
|
||||
|
||||
endpoint.resize(addr_len);
|
||||
error_handler(boost::asio::error(0));
|
||||
}
|
||||
}
|
||||
|
||||
/// Disable sends or receives on the socket.
|
||||
@@ -407,12 +546,21 @@ public:
|
||||
typename Const_Buffers::const_iterator iter = buffers.begin();
|
||||
typename Const_Buffers::const_iterator end = buffers.end();
|
||||
DWORD i = 0;
|
||||
size_t total_buffer_size = 0;
|
||||
for (; iter != end && i < max_buffers; ++iter, ++i)
|
||||
{
|
||||
boost::asio::const_buffer buffer(*iter);
|
||||
bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
|
||||
bufs[i].buf = const_cast<char*>(
|
||||
boost::asio::buffer_cast<const char*>(buffer));
|
||||
total_buffer_size += boost::asio::buffer_size(buffer);
|
||||
}
|
||||
|
||||
// A request to receive 0 bytes on a stream socket is a no-op.
|
||||
if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
|
||||
{
|
||||
error_handler(boost::asio::error(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send the data.
|
||||
@@ -460,6 +608,20 @@ public:
|
||||
typedef handler_alloc_traits<Handler, op_type> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
// Check whether buffers are still valid.
|
||||
typename Const_Buffers::const_iterator iter
|
||||
= handler_op->buffers_.begin();
|
||||
typename Const_Buffers::const_iterator end
|
||||
= handler_op->buffers_.end();
|
||||
while (iter != end)
|
||||
{
|
||||
boost::asio::const_buffer buffer(*iter);
|
||||
boost::asio::buffer_cast<const char*>(buffer);
|
||||
++iter;
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
|
||||
// Map ERROR_NETNAME_DELETED to more useful error.
|
||||
if (last_error == ERROR_NETNAME_DELETED)
|
||||
{
|
||||
@@ -478,7 +640,7 @@ public:
|
||||
|
||||
// Call the handler.
|
||||
boost::asio::error error(last_error);
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
detail::bind_handler(handler, error, bytes_transferred), &handler);
|
||||
}
|
||||
|
||||
@@ -503,24 +665,41 @@ public:
|
||||
void async_send(implementation_type& impl, const Const_Buffers& buffers,
|
||||
socket_base::message_flags flags, Handler handler)
|
||||
{
|
||||
// Update the ID of the thread from which cancellation is safe.
|
||||
if (impl.safe_cancellation_thread_id_ == 0)
|
||||
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
|
||||
else
|
||||
impl.safe_cancellation_thread_id_ = ~DWORD(0);
|
||||
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef send_operation<Const_Buffers, Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler);
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr,
|
||||
owner(), impl.cancel_token_, buffers, handler);
|
||||
io_service(), impl.cancel_token_, buffers, handler);
|
||||
|
||||
// Copy buffers into WSABUF array.
|
||||
::WSABUF bufs[max_buffers];
|
||||
typename Const_Buffers::const_iterator iter = buffers.begin();
|
||||
typename Const_Buffers::const_iterator end = buffers.end();
|
||||
DWORD i = 0;
|
||||
size_t total_buffer_size = 0;
|
||||
for (; iter != end && i < max_buffers; ++iter, ++i)
|
||||
{
|
||||
boost::asio::const_buffer buffer(*iter);
|
||||
bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
|
||||
bufs[i].buf = const_cast<char*>(
|
||||
boost::asio::buffer_cast<const char*>(buffer));
|
||||
total_buffer_size += boost::asio::buffer_size(buffer);
|
||||
}
|
||||
|
||||
// A request to receive 0 bytes on a stream socket is a no-op.
|
||||
if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
|
||||
{
|
||||
ptr.reset();
|
||||
boost::asio::error error(boost::asio::error::success);
|
||||
iocp_service_.post(bind_handler(handler, error, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the data.
|
||||
@@ -603,6 +782,20 @@ public:
|
||||
typedef handler_alloc_traits<Handler, op_type> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
// Check whether buffers are still valid.
|
||||
typename Const_Buffers::const_iterator iter
|
||||
= handler_op->buffers_.begin();
|
||||
typename Const_Buffers::const_iterator end
|
||||
= handler_op->buffers_.end();
|
||||
while (iter != end)
|
||||
{
|
||||
boost::asio::const_buffer buffer(*iter);
|
||||
boost::asio::buffer_cast<const char*>(buffer);
|
||||
++iter;
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
@@ -612,7 +805,7 @@ public:
|
||||
|
||||
// Call the handler.
|
||||
boost::asio::error error(last_error);
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
detail::bind_handler(handler, error, bytes_transferred), &handler);
|
||||
}
|
||||
|
||||
@@ -637,11 +830,17 @@ public:
|
||||
const endpoint_type& destination, socket_base::message_flags flags,
|
||||
Handler handler)
|
||||
{
|
||||
// Update the ID of the thread from which cancellation is safe.
|
||||
if (impl.safe_cancellation_thread_id_ == 0)
|
||||
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
|
||||
else
|
||||
impl.safe_cancellation_thread_id_ = ~DWORD(0);
|
||||
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef send_to_operation<Const_Buffers, Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler);
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr, owner(), buffers, handler);
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr, io_service(), buffers, handler);
|
||||
|
||||
// Copy buffers into WSABUF array.
|
||||
::WSABUF bufs[max_buffers];
|
||||
@@ -685,11 +884,20 @@ public:
|
||||
typename Mutable_Buffers::const_iterator iter = buffers.begin();
|
||||
typename Mutable_Buffers::const_iterator end = buffers.end();
|
||||
DWORD i = 0;
|
||||
size_t total_buffer_size = 0;
|
||||
for (; iter != end && i < max_buffers; ++iter, ++i)
|
||||
{
|
||||
boost::asio::mutable_buffer buffer(*iter);
|
||||
bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
|
||||
bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
|
||||
total_buffer_size += boost::asio::buffer_size(buffer);
|
||||
}
|
||||
|
||||
// A request to receive 0 bytes on a stream socket is a no-op.
|
||||
if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
|
||||
{
|
||||
error_handler(boost::asio::error(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Receive some data.
|
||||
@@ -743,6 +951,20 @@ public:
|
||||
typedef handler_alloc_traits<Handler, op_type> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
// Check whether buffers are still valid.
|
||||
typename Mutable_Buffers::const_iterator iter
|
||||
= handler_op->buffers_.begin();
|
||||
typename Mutable_Buffers::const_iterator end
|
||||
= handler_op->buffers_.end();
|
||||
while (iter != end)
|
||||
{
|
||||
boost::asio::mutable_buffer buffer(*iter);
|
||||
boost::asio::buffer_cast<char*>(buffer);
|
||||
++iter;
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
|
||||
// Map ERROR_NETNAME_DELETED to more useful error.
|
||||
if (last_error == ERROR_NETNAME_DELETED)
|
||||
{
|
||||
@@ -767,7 +989,7 @@ public:
|
||||
|
||||
// Call the handler.
|
||||
boost::asio::error error(last_error);
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
detail::bind_handler(handler, error, bytes_transferred), &handler);
|
||||
}
|
||||
|
||||
@@ -792,23 +1014,40 @@ public:
|
||||
void async_receive(implementation_type& impl, const Mutable_Buffers& buffers,
|
||||
socket_base::message_flags flags, Handler handler)
|
||||
{
|
||||
// Update the ID of the thread from which cancellation is safe.
|
||||
if (impl.safe_cancellation_thread_id_ == 0)
|
||||
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
|
||||
else
|
||||
impl.safe_cancellation_thread_id_ = ~DWORD(0);
|
||||
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef receive_operation<Mutable_Buffers, Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler);
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr,
|
||||
owner(), impl.cancel_token_, buffers, handler);
|
||||
io_service(), impl.cancel_token_, buffers, handler);
|
||||
|
||||
// Copy buffers into WSABUF array.
|
||||
::WSABUF bufs[max_buffers];
|
||||
typename Mutable_Buffers::const_iterator iter = buffers.begin();
|
||||
typename Mutable_Buffers::const_iterator end = buffers.end();
|
||||
DWORD i = 0;
|
||||
size_t total_buffer_size = 0;
|
||||
for (; iter != end && i < max_buffers; ++iter, ++i)
|
||||
{
|
||||
boost::asio::mutable_buffer buffer(*iter);
|
||||
bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
|
||||
bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
|
||||
total_buffer_size += boost::asio::buffer_size(buffer);
|
||||
}
|
||||
|
||||
// A request to receive 0 bytes on a stream socket is a no-op.
|
||||
if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
|
||||
{
|
||||
ptr.reset();
|
||||
boost::asio::error error(boost::asio::error::success);
|
||||
iocp_service_.post(bind_handler(handler, error, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Receive some data.
|
||||
@@ -906,6 +1145,20 @@ public:
|
||||
typedef handler_alloc_traits<Handler, op_type> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
// Check whether buffers are still valid.
|
||||
typename Mutable_Buffers::const_iterator iter
|
||||
= handler_op->buffers_.begin();
|
||||
typename Mutable_Buffers::const_iterator end
|
||||
= handler_op->buffers_.end();
|
||||
while (iter != end)
|
||||
{
|
||||
boost::asio::mutable_buffer buffer(*iter);
|
||||
boost::asio::buffer_cast<char*>(buffer);
|
||||
++iter;
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
|
||||
// Check for connection closed.
|
||||
if (last_error == 0 && bytes_transferred == 0)
|
||||
{
|
||||
@@ -924,7 +1177,7 @@ public:
|
||||
|
||||
// Call the handler.
|
||||
boost::asio::error error(last_error);
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
detail::bind_handler(handler, error, bytes_transferred), &handler);
|
||||
}
|
||||
|
||||
@@ -952,12 +1205,18 @@ public:
|
||||
const Mutable_Buffers& buffers, endpoint_type& sender_endp,
|
||||
socket_base::message_flags flags, Handler handler)
|
||||
{
|
||||
// Update the ID of the thread from which cancellation is safe.
|
||||
if (impl.safe_cancellation_thread_id_ == 0)
|
||||
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
|
||||
else
|
||||
impl.safe_cancellation_thread_id_ = ~DWORD(0);
|
||||
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef receive_from_operation<Mutable_Buffers, Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler);
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr,
|
||||
owner(), sender_endp, buffers, handler);
|
||||
io_service(), sender_endp, buffers, handler);
|
||||
|
||||
// Copy buffers into WSABUF array.
|
||||
::WSABUF bufs[max_buffers];
|
||||
@@ -1104,7 +1363,7 @@ public:
|
||||
new_socket_(new_socket),
|
||||
peer_(peer),
|
||||
protocol_(protocol),
|
||||
work_(io_service.owner()),
|
||||
work_(io_service.io_service()),
|
||||
enable_connection_aborted_(enable_connection_aborted),
|
||||
handler_(handler)
|
||||
{
|
||||
@@ -1194,13 +1453,37 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Get the address of the peer.
|
||||
endpoint_type peer_endpoint;
|
||||
if (last_error == 0)
|
||||
{
|
||||
LPSOCKADDR local_addr = 0;
|
||||
int local_addr_length = 0;
|
||||
LPSOCKADDR remote_addr = 0;
|
||||
int remote_addr_length = 0;
|
||||
GetAcceptExSockaddrs(handler_op->output_buffer(), 0,
|
||||
handler_op->address_length(), handler_op->address_length(),
|
||||
&local_addr, &local_addr_length, &remote_addr, &remote_addr_length);
|
||||
if (remote_addr_length > peer_endpoint.capacity())
|
||||
{
|
||||
last_error = boost::asio::error::invalid_argument;
|
||||
}
|
||||
else
|
||||
{
|
||||
using namespace std; // For memcpy.
|
||||
memcpy(peer_endpoint.data(), remote_addr, remote_addr_length);
|
||||
peer_endpoint.resize(remote_addr_length);
|
||||
}
|
||||
}
|
||||
|
||||
// Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
|
||||
// and getpeername will work on the accepted socket.
|
||||
if (last_error == 0)
|
||||
{
|
||||
DWORD update_ctx_param = handler_op->socket_;
|
||||
if (socket_ops::setsockopt(handler_op->new_socket_.get(), SOL_SOCKET,
|
||||
SO_UPDATE_ACCEPT_CONTEXT, &update_ctx_param, sizeof(DWORD)) != 0)
|
||||
SOCKET update_ctx_param = handler_op->socket_;
|
||||
if (socket_ops::setsockopt(handler_op->new_socket_.get(),
|
||||
SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
|
||||
&update_ctx_param, sizeof(SOCKET)) != 0)
|
||||
{
|
||||
last_error = socket_ops::get_error();
|
||||
}
|
||||
@@ -1212,7 +1495,7 @@ public:
|
||||
{
|
||||
boost::asio::error temp_error;
|
||||
handler_op->peer_.assign(handler_op->protocol_,
|
||||
handler_op->new_socket_.get(),
|
||||
native_type(handler_op->new_socket_.get(), peer_endpoint),
|
||||
boost::asio::assign_error(temp_error));
|
||||
if (temp_error)
|
||||
last_error = temp_error.code();
|
||||
@@ -1229,7 +1512,7 @@ public:
|
||||
|
||||
// Call the handler.
|
||||
boost::asio::error error(last_error);
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
detail::bind_handler(handler, error), &handler);
|
||||
}
|
||||
|
||||
@@ -1258,11 +1541,17 @@ public:
|
||||
template <typename Socket, typename Handler>
|
||||
void async_accept(implementation_type& impl, Socket& peer, Handler handler)
|
||||
{
|
||||
// Update the ID of the thread from which cancellation is safe.
|
||||
if (impl.safe_cancellation_thread_id_ == 0)
|
||||
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
|
||||
else
|
||||
impl.safe_cancellation_thread_id_ = ~DWORD(0);
|
||||
|
||||
// Check whether acceptor has been initialised.
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1270,7 +1559,7 @@ public:
|
||||
if (peer.native() != invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::already_connected);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1280,7 +1569,7 @@ public:
|
||||
if (sock.get() == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1347,7 +1636,7 @@ public:
|
||||
peer_(peer),
|
||||
protocol_(protocol),
|
||||
peer_endpoint_(peer_endpoint),
|
||||
work_(io_service.owner()),
|
||||
work_(io_service.io_service()),
|
||||
enable_connection_aborted_(enable_connection_aborted),
|
||||
handler_(handler)
|
||||
{
|
||||
@@ -1453,10 +1742,10 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
handler_op->peer_endpoint_.resize(remote_addr_length);
|
||||
using namespace std; // For memcpy.
|
||||
memcpy(handler_op->peer_endpoint_.data(),
|
||||
remote_addr, remote_addr_length);
|
||||
handler_op->peer_endpoint_.resize(remote_addr_length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1464,9 +1753,10 @@ public:
|
||||
// and getpeername will work on the accepted socket.
|
||||
if (last_error == 0)
|
||||
{
|
||||
DWORD update_ctx_param = handler_op->socket_;
|
||||
if (socket_ops::setsockopt(handler_op->new_socket_.get(), SOL_SOCKET,
|
||||
SO_UPDATE_ACCEPT_CONTEXT, &update_ctx_param, sizeof(DWORD)) != 0)
|
||||
SOCKET update_ctx_param = handler_op->socket_;
|
||||
if (socket_ops::setsockopt(handler_op->new_socket_.get(),
|
||||
SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
|
||||
&update_ctx_param, sizeof(SOCKET)) != 0)
|
||||
{
|
||||
last_error = socket_ops::get_error();
|
||||
}
|
||||
@@ -1478,7 +1768,8 @@ public:
|
||||
{
|
||||
boost::asio::error temp_error;
|
||||
handler_op->peer_.assign(handler_op->peer_endpoint_.protocol(),
|
||||
handler_op->new_socket_.get(),
|
||||
native_type(handler_op->new_socket_.get(),
|
||||
handler_op->peer_endpoint_),
|
||||
boost::asio::assign_error(temp_error));
|
||||
if (temp_error)
|
||||
last_error = temp_error.code();
|
||||
@@ -1495,7 +1786,7 @@ public:
|
||||
|
||||
// Call the handler.
|
||||
boost::asio::error error(last_error);
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
detail::bind_handler(handler, error), &handler);
|
||||
}
|
||||
|
||||
@@ -1526,11 +1817,17 @@ public:
|
||||
void async_accept_endpoint(implementation_type& impl, Socket& peer,
|
||||
endpoint_type& peer_endpoint, Handler handler)
|
||||
{
|
||||
// Update the ID of the thread from which cancellation is safe.
|
||||
if (impl.safe_cancellation_thread_id_ == 0)
|
||||
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
|
||||
else
|
||||
impl.safe_cancellation_thread_id_ = ~DWORD(0);
|
||||
|
||||
// Check whether acceptor has been initialised.
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::bad_descriptor);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1538,7 +1835,7 @@ public:
|
||||
if (peer.native() != invalid_socket)
|
||||
{
|
||||
boost::asio::error error(boost::asio::error::already_connected);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1548,7 +1845,7 @@ public:
|
||||
if (sock.get() == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1713,13 +2010,19 @@ public:
|
||||
void async_connect(implementation_type& impl,
|
||||
const endpoint_type& peer_endpoint, Handler handler)
|
||||
{
|
||||
// Update the ID of the thread from which cancellation is safe.
|
||||
if (impl.safe_cancellation_thread_id_ == 0)
|
||||
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
|
||||
else
|
||||
impl.safe_cancellation_thread_id_ = ~DWORD(0);
|
||||
|
||||
// Check if the reactor was already obtained from the io_service.
|
||||
reactor_type* reactor = static_cast<reactor_type*>(
|
||||
interlocked_compare_exchange_pointer(
|
||||
reinterpret_cast<void**>(&reactor_), 0, 0));
|
||||
if (!reactor)
|
||||
{
|
||||
reactor = &(boost::asio::use_service<reactor_type>(owner()));
|
||||
reactor = &(boost::asio::use_service<reactor_type>(io_service()));
|
||||
interlocked_exchange_pointer(
|
||||
reinterpret_cast<void**>(&reactor_), reactor);
|
||||
}
|
||||
@@ -1737,7 +2040,7 @@ public:
|
||||
if (impl.socket_ == invalid_socket)
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
iocp_service_.register_socket(impl.socket_);
|
||||
@@ -1749,7 +2052,7 @@ public:
|
||||
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking))
|
||||
{
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1760,7 +2063,7 @@ public:
|
||||
// The connect operation has finished successfully so we need to post the
|
||||
// handler immediately.
|
||||
boost::asio::error error(boost::asio::error::success);
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
}
|
||||
else if (socket_ops::get_error() == boost::asio::error::in_progress
|
||||
|| socket_ops::get_error() == boost::asio::error::would_block)
|
||||
@@ -1770,13 +2073,13 @@ public:
|
||||
boost::shared_ptr<bool> completed(new bool(false));
|
||||
reactor->start_write_and_except_ops(impl.socket_,
|
||||
connect_handler<Handler>(
|
||||
impl.socket_, completed, owner(), *reactor, handler));
|
||||
impl.socket_, completed, io_service(), *reactor, handler));
|
||||
}
|
||||
else
|
||||
{
|
||||
// The connect operation has failed, so post the handler immediately.
|
||||
boost::asio::error error(socket_ops::get_error());
|
||||
owner().post(bind_handler(handler, error));
|
||||
io_service().post(bind_handler(handler, error));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include <boost/asio/detail/bind_handler.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_dispatch_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@@ -163,21 +163,21 @@ public:
|
||||
Context context_;
|
||||
};
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Dispatcher, typename Handler>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Dispatcher, typename Handler>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
wrapped_handler<Dispatcher, Handler>* this_handler)
|
||||
{
|
||||
this_handler->dispatcher_.dispatch(
|
||||
rewrapped_handler<Handler_To_Dispatch, Handler>(
|
||||
handler, this_handler->handler_));
|
||||
rewrapped_handler<Function, Handler>(
|
||||
function, this_handler->handler_));
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Dispatcher, typename Handler>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Dispatcher, typename Handler>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
rewrapped_handler<Dispatcher, Handler>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->context_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->context_);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/local_free_on_block_exit.hpp>
|
||||
#include <boost/asio/detail/socket_types.hpp>
|
||||
#include <boost/asio/detail/win_local_free_on_block_exit.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@@ -233,7 +233,7 @@ public:
|
||||
| FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS, 0, code_,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0);
|
||||
detail::win_local_free_on_block_exit local_free_obj(msg);
|
||||
detail::local_free_on_block_exit local_free_obj(msg);
|
||||
if (length && msg[length - 1] == '\n')
|
||||
msg[--length] = '\0';
|
||||
if (length && msg[length - 1] == '\r')
|
||||
@@ -273,7 +273,8 @@ public:
|
||||
default:
|
||||
#if defined(__sun) || defined(__QNX__)
|
||||
return strerror(code_);
|
||||
#elif defined(__MACH__) && defined(__APPLE__) || defined(__NetBSD__)
|
||||
#elif defined(__MACH__) && defined(__APPLE__) \
|
||||
|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
try
|
||||
{
|
||||
char buf[256] = "";
|
||||
|
||||
@@ -79,7 +79,7 @@ inline void* asio_handler_allocate(std::size_t size, ...)
|
||||
inline void asio_handler_deallocate(void* pointer, std::size_t size, ...)
|
||||
{
|
||||
(void)(size);
|
||||
return ::operator delete(pointer);
|
||||
::operator delete(pointer);
|
||||
}
|
||||
|
||||
} // namespace asio
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// handler_dispatch_hook.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// handler_invoke_hook.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
@@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_HANDLER_DISPATCH_HOOK_HPP
|
||||
#define BOOST_ASIO_HANDLER_DISPATCH_HOOK_HPP
|
||||
#ifndef BOOST_ASIO_HANDLER_INVOKE_HOOK_HPP
|
||||
#define BOOST_ASIO_HANDLER_INVOKE_HOOK_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
@@ -20,47 +20,47 @@
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
/// Default dispatch function for handlers.
|
||||
/// Default invoke function for handlers.
|
||||
/**
|
||||
* Completion handlers for asynchronous operations are invoked by the
|
||||
* io_service associated with the corresponding object (e.g. a socket or
|
||||
* deadline_timer). Certain guarantees are made on when the handler may be
|
||||
* invoked, in particular that a handler can only be invoked from a thread that
|
||||
* is currently calling boost::asio::io_service::run() on the corresponding
|
||||
* io_service object. Handlers may subsequently be dispatched through other
|
||||
* io_service object. Handlers may subsequently be invoked through other
|
||||
* objects (such as boost::asio::strand objects) that provide additional
|
||||
* guarantees.
|
||||
*
|
||||
* When asynchronous operations are composed from other asynchronous
|
||||
* operations, all intermediate handlers should be dispatched using the same
|
||||
* operations, all intermediate handlers should be invoked using the same
|
||||
* method as the final handler. This is required to ensure that user-defined
|
||||
* objects are not accessed in a way that may violate the guarantees. This
|
||||
* hooking function ensures that the dispatch method used for the final handler
|
||||
* hooking function ensures that the invoked method used for the final handler
|
||||
* is accessible at each intermediate step.
|
||||
*
|
||||
* Implement asio_handler_dispatch for your own handlers to specify a custom
|
||||
* dispatching strategy.
|
||||
* Implement asio_handler_invoke for your own handlers to specify a custom
|
||||
* invocation strategy.
|
||||
*
|
||||
* This default implementation is simply:
|
||||
* @code
|
||||
* handler();
|
||||
* function();
|
||||
* @endcode
|
||||
*
|
||||
* @par Example:
|
||||
* @code
|
||||
* class my_handler;
|
||||
*
|
||||
* template <typename Handler>
|
||||
* void asio_handler_dispatch(Handler handler, my_handler* context)
|
||||
* template <typename Function>
|
||||
* void asio_handler_invoke(Function function, my_handler* context)
|
||||
* {
|
||||
* context->strand_.dispatch(handler);
|
||||
* context->strand_.dispatch(function);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
template <typename Handler>
|
||||
inline void asio_handler_dispatch(Handler handler, ...)
|
||||
template <typename Function>
|
||||
inline void asio_handler_invoke(Function function, ...)
|
||||
{
|
||||
handler();
|
||||
function();
|
||||
}
|
||||
|
||||
} // namespace asio
|
||||
@@ -68,4 +68,4 @@ inline void asio_handler_dispatch(Handler handler, ...)
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_HANDLER_DISPATCH_HOOK_HPP
|
||||
#endif // BOOST_ASIO_HANDLER_INVOKE_HOOK_HPP
|
||||
@@ -32,9 +32,24 @@ inline io_service::io_service()
|
||||
{
|
||||
}
|
||||
|
||||
inline void io_service::run()
|
||||
inline size_t io_service::run()
|
||||
{
|
||||
impl_.run();
|
||||
return impl_.run();
|
||||
}
|
||||
|
||||
inline size_t io_service::run_one()
|
||||
{
|
||||
return impl_.run_one();
|
||||
}
|
||||
|
||||
inline size_t io_service::poll()
|
||||
{
|
||||
return impl_.poll();
|
||||
}
|
||||
|
||||
inline size_t io_service::poll_one()
|
||||
{
|
||||
return impl_.poll_one();
|
||||
}
|
||||
|
||||
inline void io_service::interrupt()
|
||||
@@ -70,24 +85,29 @@ io_service::wrap(Handler handler)
|
||||
return detail::wrapped_handler<io_service, Handler>(*this, handler);
|
||||
}
|
||||
|
||||
inline io_service::work::work(io_service& io_service)
|
||||
: impl_(io_service.impl_)
|
||||
inline io_service::work::work(boost::asio::io_service& io_service)
|
||||
: io_service_(io_service)
|
||||
{
|
||||
impl_.work_started();
|
||||
io_service_.impl_.work_started();
|
||||
}
|
||||
|
||||
inline io_service::work::work(const work& other)
|
||||
: impl_(other.impl_)
|
||||
: io_service_(other.io_service_)
|
||||
{
|
||||
impl_.work_started();
|
||||
io_service_.impl_.work_started();
|
||||
}
|
||||
|
||||
inline io_service::work::~work()
|
||||
{
|
||||
impl_.work_finished();
|
||||
io_service_.impl_.work_finished();
|
||||
}
|
||||
|
||||
inline io_service::service::service(io_service& owner)
|
||||
inline boost::asio::io_service& io_service::work::io_service()
|
||||
{
|
||||
return io_service_;
|
||||
}
|
||||
|
||||
inline io_service::service::service(boost::asio::io_service& owner)
|
||||
: owner_(owner),
|
||||
type_info_(0),
|
||||
next_(0)
|
||||
@@ -98,7 +118,7 @@ inline io_service::service::~service()
|
||||
{
|
||||
}
|
||||
|
||||
inline io_service& io_service::service::owner()
|
||||
inline boost::asio::io_service& io_service::service::io_service()
|
||||
{
|
||||
return owner_;
|
||||
}
|
||||
@@ -112,7 +132,7 @@ inline Service& use_service(io_service& ios)
|
||||
template <typename Service>
|
||||
void add_service(io_service& ios, Service* svc)
|
||||
{
|
||||
if (&ios != &svc->owner())
|
||||
if (&ios != &svc->io_service())
|
||||
boost::throw_exception(invalid_service_owner());
|
||||
if (!ios.service_registry_.template add_service<Service>(svc))
|
||||
boost::throw_exception(service_already_exists());
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <boost/asio/detail/bind_handler.hpp>
|
||||
#include <boost/asio/detail/consuming_buffers.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_dispatch_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@@ -167,14 +167,14 @@ namespace detail
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Async_Read_Stream,
|
||||
template <typename Function, typename Async_Read_Stream,
|
||||
typename Mutable_Buffers, typename Completion_Condition, typename Handler>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
read_handler<Async_Read_Stream, Mutable_Buffers,
|
||||
Completion_Condition, Handler>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
@@ -258,14 +258,14 @@ namespace detail
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Async_Read_Stream,
|
||||
template <typename Function, typename Async_Read_Stream,
|
||||
typename Allocator, typename Completion_Condition, typename Handler>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
read_streambuf_handler<Async_Read_Stream, Allocator,
|
||||
Completion_Condition, Handler>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <boost/asio/detail/bind_handler.hpp>
|
||||
#include <boost/asio/detail/const_buffers_iterator.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_dispatch_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@@ -312,14 +312,14 @@ namespace detail
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Async_Read_Stream,
|
||||
typename Allocator, typename Handler>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Async_Read_Stream, typename Allocator,
|
||||
typename Handler>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
read_until_delim_handler<Async_Read_Stream,
|
||||
Allocator, Handler>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
@@ -448,14 +448,14 @@ namespace detail
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Async_Read_Stream,
|
||||
template <typename Function, typename Async_Read_Stream,
|
||||
typename Allocator, typename Handler>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
read_until_delim_string_handler<Async_Read_Stream,
|
||||
Allocator, Handler>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
@@ -601,14 +601,14 @@ namespace detail
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Async_Read_Stream,
|
||||
typename Allocator, typename Handler>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Async_Read_Stream, typename Allocator,
|
||||
typename Handler>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
read_until_expr_handler<Async_Read_Stream,
|
||||
Allocator, Handler>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <boost/asio/detail/bind_handler.hpp>
|
||||
#include <boost/asio/detail/consuming_buffers.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_dispatch_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@@ -159,14 +159,14 @@ namespace detail
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Async_Write_Stream,
|
||||
template <typename Function, typename Async_Write_Stream,
|
||||
typename Const_Buffers, typename Completion_Condition, typename Handler>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
write_handler<Async_Write_Stream, Const_Buffers,
|
||||
Completion_Condition, Handler>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
@@ -231,14 +231,14 @@ namespace detail
|
||||
pointer, size, &this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Handler_To_Dispatch, typename Async_Write_Stream,
|
||||
typename Allocator, typename Handler>
|
||||
inline void asio_handler_dispatch(const Handler_To_Dispatch& handler,
|
||||
template <typename Function, typename Async_Write_Stream, typename Allocator,
|
||||
typename Handler>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
write_streambuf_handler<Async_Write_Stream,
|
||||
Allocator, Handler>* this_handler)
|
||||
{
|
||||
boost_asio_handler_dispatch_helpers::dispatch_handler(
|
||||
handler, &this_handler->handler_);
|
||||
asio_handler_invoke_helpers::invoke(
|
||||
function, &this_handler->handler_);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -83,6 +83,8 @@ public:
|
||||
|
||||
class service;
|
||||
|
||||
class strand;
|
||||
|
||||
/// Default constructor.
|
||||
io_service();
|
||||
|
||||
@@ -97,14 +99,44 @@ public:
|
||||
*
|
||||
* The run() function may be safely called again once it has completed only
|
||||
* after a call to reset().
|
||||
*
|
||||
* @return The number of handlers that were executed.
|
||||
*/
|
||||
void run();
|
||||
size_t run();
|
||||
|
||||
/// Run the io_service's event processing loop to execute at most one handler.
|
||||
/**
|
||||
* The run_one() function blocks until one handler has been dispatched, or
|
||||
* until the io_service has been interrupted.
|
||||
*
|
||||
* @return The number of handlers that were executed.
|
||||
*/
|
||||
size_t run_one();
|
||||
|
||||
/// Run the io_service's event processing loop to execute ready handlers.
|
||||
/**
|
||||
* The poll() function runs handlers that are ready to run, without blocking,
|
||||
* until the io_service has been interrupted or there are no more ready
|
||||
* handlers.
|
||||
*
|
||||
* @return The number of handlers that were executed.
|
||||
*/
|
||||
size_t poll();
|
||||
|
||||
/// Run the io_service's event processing loop to execute one ready handler.
|
||||
/**
|
||||
* The poll_one() function runs at most one handler that is ready to run,
|
||||
* without blocking.
|
||||
*
|
||||
* @return The number of handlers that were executed.
|
||||
*/
|
||||
size_t poll_one();
|
||||
|
||||
/// Interrupt the io_service's event processing loop.
|
||||
/**
|
||||
* This function does not block, but instead simply signals to the io_service
|
||||
* that all invocations of its run() member function should return as soon as
|
||||
* possible.
|
||||
* that all invocations of its run() or run_one() member functions should
|
||||
* return as soon as possible.
|
||||
*
|
||||
* Note that if the run() function is interrupted and is not called again
|
||||
* later then its work may not have finished and handlers may not be
|
||||
@@ -117,11 +149,12 @@ public:
|
||||
/// Reset the io_service in preparation for a subsequent run() invocation.
|
||||
/**
|
||||
* This function must be called prior to any second or later set of
|
||||
* invocations of the run() function. It allows the io_service to reset any
|
||||
* internal state, such as an interrupt flag.
|
||||
* invocations of the run(), run_one(), poll() or poll_one() functions. It
|
||||
* allows the io_service to reset any internal state, such as an interrupt
|
||||
* flag.
|
||||
*
|
||||
* This function must not be called while there are any unfinished calls to
|
||||
* the run() function.
|
||||
* the run(), run_one(), poll() or poll_one() functions.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
@@ -130,8 +163,9 @@ public:
|
||||
* This function is used to ask the io_service to execute the given handler.
|
||||
*
|
||||
* The io_service guarantees that the handler will only be called in a thread
|
||||
* in which the run() member function is currently being invoked. The handler
|
||||
* may be executed inside this function if the guarantee can be met.
|
||||
* in which the run(), run_one(), poll() or poll_one() member functions is
|
||||
* currently being invoked. The handler may be executed inside this function
|
||||
* if the guarantee can be met.
|
||||
*
|
||||
* @param handler The handler to be called. The io_service will make
|
||||
* a copy of the handler object as required. The function signature of the
|
||||
@@ -147,7 +181,8 @@ public:
|
||||
* function.
|
||||
*
|
||||
* The io_service guarantees that the handler will only be called in a thread
|
||||
* in which the run() member function is currently being invoked.
|
||||
* in which the run(), run_one(), poll() or poll_one() member functions is
|
||||
* currently being invoked.
|
||||
*
|
||||
* @param handler The handler to be called. The io_service will make
|
||||
* a copy of the handler object as required. The function signature of the
|
||||
@@ -265,7 +300,7 @@ public:
|
||||
* This ensures that the io_service's run() function will not exit while the
|
||||
* work is underway.
|
||||
*/
|
||||
explicit work(io_service& io_service);
|
||||
explicit work(boost::asio::io_service& io_service);
|
||||
|
||||
/// Copy constructor notifies the io_service that work is starting.
|
||||
/**
|
||||
@@ -283,12 +318,15 @@ public:
|
||||
*/
|
||||
~work();
|
||||
|
||||
/// Get the io_service associated with the work.
|
||||
boost::asio::io_service& io_service();
|
||||
|
||||
private:
|
||||
// Prevent assignment.
|
||||
void operator=(const work& other);
|
||||
|
||||
// The io_service's implementation.
|
||||
io_service::impl_type& impl_;
|
||||
// The io_service.
|
||||
boost::asio::io_service& io_service_;
|
||||
};
|
||||
|
||||
/// Base class for all io_service services.
|
||||
@@ -297,14 +335,14 @@ class io_service::service
|
||||
{
|
||||
public:
|
||||
/// Get the io_service object that owns the service.
|
||||
io_service& owner();
|
||||
boost::asio::io_service& io_service();
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
/**
|
||||
* @param owner The io_service object that owns the service.
|
||||
*/
|
||||
service(io_service& owner);
|
||||
service(boost::asio::io_service& owner);
|
||||
|
||||
/// Destructor.
|
||||
virtual ~service();
|
||||
@@ -313,8 +351,8 @@ private:
|
||||
/// Destroy all user-defined handler objects owned by the service.
|
||||
virtual void shutdown_service() = 0;
|
||||
|
||||
friend class detail::service_registry<io_service>;
|
||||
io_service& owner_;
|
||||
friend class detail::service_registry<boost::asio::io_service>;
|
||||
boost::asio::io_service& owner_;
|
||||
const std::type_info* type_info_;
|
||||
service* next_;
|
||||
};
|
||||
@@ -347,15 +385,17 @@ public:
|
||||
*
|
||||
* If an exception is thrown from a handler, the exception is allowed to
|
||||
* propagate through the throwing thread's invocation of
|
||||
* boost::asio::io_service::run(). No other threads that are calling
|
||||
* boost::asio::io_service::run() are affected. It is then the responsibility of
|
||||
* the application to catch the exception.
|
||||
* boost::asio::io_service::run(), boost::asio::io_service::run_one(),
|
||||
* boost::asio::io_service::poll() or boost::asio::io_service::poll_one().
|
||||
* No other threads that are calling any of these functions are affected. It is
|
||||
* then the responsibility of the application to catch the exception.
|
||||
*
|
||||
* After the exception has been caught, the boost::asio::io_service::run() call
|
||||
* may be restarted @em without the need for an intervening call to
|
||||
* After the exception has been caught, the
|
||||
* boost::asio::io_service::run(), boost::asio::io_service::run_one(),
|
||||
* boost::asio::io_service::poll() or boost::asio::io_service::poll_one()
|
||||
* call may be restarted @em without the need for an intervening call to
|
||||
* boost::asio::io_service::reset(). This allows the thread to rejoin the
|
||||
* io_service's thread pool without impacting any other threads in the
|
||||
* pool.
|
||||
* io_service's thread pool without impacting any other threads in the pool.
|
||||
*
|
||||
* @par Example:
|
||||
* @code
|
||||
|
||||
@@ -79,13 +79,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assign from an unsigned long.
|
||||
address_v4& operator=(unsigned long addr)
|
||||
{
|
||||
addr_.s_addr = boost::asio::detail::socket_ops::host_to_network_long(addr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Get the address in bytes.
|
||||
bytes_type to_bytes() const
|
||||
{
|
||||
@@ -164,29 +157,23 @@ public:
|
||||
}
|
||||
|
||||
/// Determine whether the address is a class A address.
|
||||
bool is_class_A() const
|
||||
bool is_class_a() const
|
||||
{
|
||||
return IN_CLASSA(to_ulong());
|
||||
}
|
||||
|
||||
/// Determine whether the address is a class B address.
|
||||
bool is_class_B() const
|
||||
bool is_class_b() const
|
||||
{
|
||||
return IN_CLASSB(to_ulong());
|
||||
}
|
||||
|
||||
/// Determine whether the address is a class C address.
|
||||
bool is_class_C() const
|
||||
bool is_class_c() const
|
||||
{
|
||||
return IN_CLASSC(to_ulong());
|
||||
}
|
||||
|
||||
/// Determine whether the address is a class D address.
|
||||
bool is_class_D() const
|
||||
{
|
||||
return IN_CLASSD(to_ulong());
|
||||
}
|
||||
|
||||
/// Determine whether the address is a multicast address.
|
||||
bool is_multicast() const
|
||||
{
|
||||
@@ -211,6 +198,24 @@ public:
|
||||
return a1.to_ulong() < a2.to_ulong();
|
||||
}
|
||||
|
||||
/// Compare addresses for ordering.
|
||||
friend bool operator>(const address_v4& a1, const address_v4& a2)
|
||||
{
|
||||
return a1.to_ulong() > a2.to_ulong();
|
||||
}
|
||||
|
||||
/// Compare addresses for ordering.
|
||||
friend bool operator<=(const address_v4& a1, const address_v4& a2)
|
||||
{
|
||||
return a1.to_ulong() <= a2.to_ulong();
|
||||
}
|
||||
|
||||
/// Compare addresses for ordering.
|
||||
friend bool operator>=(const address_v4& a1, const address_v4& a2)
|
||||
{
|
||||
return a1.to_ulong() >= a2.to_ulong();
|
||||
}
|
||||
|
||||
/// Obtain an address object that represents any address.
|
||||
static address_v4 any()
|
||||
{
|
||||
@@ -229,6 +234,26 @@ public:
|
||||
return address_v4(static_cast<unsigned long>(INADDR_BROADCAST));
|
||||
}
|
||||
|
||||
/// Obtain an address object that represents the broadcast address that
|
||||
/// corresponds to the specified address and netmask.
|
||||
static address_v4 broadcast(const address_v4& addr, const address_v4& mask)
|
||||
{
|
||||
return address_v4(addr.to_ulong() | ~mask.to_ulong());
|
||||
}
|
||||
|
||||
/// Obtain the netmask that corresponds to the address, based on its address
|
||||
/// class.
|
||||
static address_v4 netmask(const address_v4& addr)
|
||||
{
|
||||
if (addr.is_class_a())
|
||||
return address_v4(0xFF000000);
|
||||
if (addr.is_class_b())
|
||||
return address_v4(0xFFFF0000);
|
||||
if (addr.is_class_c())
|
||||
return address_v4(0xFFFFFF00);
|
||||
return address_v4(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
private:
|
||||
// The underlying IPv4 address.
|
||||
boost::asio::detail::in4_addr_type addr_;
|
||||
@@ -250,7 +275,13 @@ template <typename Elem, typename Traits>
|
||||
std::basic_ostream<Elem, Traits>& operator<<(
|
||||
std::basic_ostream<Elem, Traits>& os, const address_v4& addr)
|
||||
{
|
||||
os << addr.to_string();
|
||||
boost::asio::error e;
|
||||
std::string s = addr.to_string(boost::asio::assign_error(e));
|
||||
if (e)
|
||||
os.setstate(std::ios_base::failbit);
|
||||
else
|
||||
for (std::string::iterator i = s.begin(); i != s.end(); ++i)
|
||||
os << os.widen(*i);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <typeinfo>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include <boost/asio/error_handler.hpp>
|
||||
#include <boost/asio/detail/socket_ops.hpp>
|
||||
#include <boost/asio/detail/socket_types.hpp>
|
||||
#include <boost/asio/ip/address_v4.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@@ -163,18 +165,50 @@ public:
|
||||
return from_string(str.c_str(), error_handler);
|
||||
}
|
||||
|
||||
/// Converts an IPv4-mapped or IPv4-compatible address to an IPv4 address.
|
||||
address_v4 to_v4() const
|
||||
{
|
||||
if (!is_v4_mapped() && !is_v4_compatible())
|
||||
throw std::bad_cast();
|
||||
address_v4::bytes_type v4_bytes = { addr_.s6_addr[12],
|
||||
addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] };
|
||||
return address_v4(v4_bytes);
|
||||
}
|
||||
|
||||
/// Determine whether the address is a loopback address.
|
||||
bool is_loopback() const
|
||||
{
|
||||
#if defined(__BORLANDC__)
|
||||
return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
|
||||
&& (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
|
||||
&& (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
|
||||
&& (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
|
||||
&& (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
|
||||
&& (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
|
||||
&& (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
|
||||
&& (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1));
|
||||
#else
|
||||
using namespace boost::asio::detail;
|
||||
return IN6_IS_ADDR_LOOPBACK(&addr_) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Determine whether the address is unspecified.
|
||||
bool is_unspecified() const
|
||||
{
|
||||
#if defined(__BORLANDC__)
|
||||
return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
|
||||
&& (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
|
||||
&& (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
|
||||
&& (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
|
||||
&& (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
|
||||
&& (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
|
||||
&& (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
|
||||
&& (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0));
|
||||
#else
|
||||
using namespace boost::asio::detail;
|
||||
return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Determine whether the address is link local.
|
||||
@@ -192,14 +226,14 @@ public:
|
||||
}
|
||||
|
||||
/// Determine whether the address is a mapped IPv4 address.
|
||||
bool is_ipv4_mapped() const
|
||||
bool is_v4_mapped() const
|
||||
{
|
||||
using namespace boost::asio::detail;
|
||||
return IN6_IS_ADDR_V4MAPPED(&addr_) != 0;
|
||||
}
|
||||
|
||||
/// Determine whether the address is an IPv4-compatible address.
|
||||
bool is_ipv4_compatible() const
|
||||
bool is_v4_compatible() const
|
||||
{
|
||||
using namespace boost::asio::detail;
|
||||
return IN6_IS_ADDR_V4COMPAT(&addr_) != 0;
|
||||
@@ -278,6 +312,24 @@ public:
|
||||
return a1.scope_id_ < a2.scope_id_;
|
||||
}
|
||||
|
||||
/// Compare addresses for ordering.
|
||||
friend bool operator>(const address_v6& a1, const address_v6& a2)
|
||||
{
|
||||
return a2 < a1;
|
||||
}
|
||||
|
||||
/// Compare addresses for ordering.
|
||||
friend bool operator<=(const address_v6& a1, const address_v6& a2)
|
||||
{
|
||||
return !(a2 < a1);
|
||||
}
|
||||
|
||||
/// Compare addresses for ordering.
|
||||
friend bool operator>=(const address_v6& a1, const address_v6& a2)
|
||||
{
|
||||
return !(a1 < a2);
|
||||
}
|
||||
|
||||
/// Obtain an address object that represents any address.
|
||||
static address_v6 any()
|
||||
{
|
||||
@@ -293,6 +345,24 @@ public:
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/// Create an IPv4-mapped IPv6 address.
|
||||
static address_v6 v4_mapped(const address_v4& addr)
|
||||
{
|
||||
address_v4::bytes_type v4_bytes = addr.to_bytes();
|
||||
bytes_type v6_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF,
|
||||
v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] };
|
||||
return address_v6(v6_bytes);
|
||||
}
|
||||
|
||||
/// Create an IPv4-compatible IPv6 address.
|
||||
static address_v6 v4_compatible(const address_v4& addr)
|
||||
{
|
||||
address_v4::bytes_type v4_bytes = addr.to_bytes();
|
||||
bytes_type v6_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] };
|
||||
return address_v6(v6_bytes);
|
||||
}
|
||||
|
||||
private:
|
||||
// The underlying IPv6 address.
|
||||
boost::asio::detail::in6_addr_type addr_;
|
||||
@@ -317,7 +387,13 @@ template <typename Elem, typename Traits>
|
||||
std::basic_ostream<Elem, Traits>& operator<<(
|
||||
std::basic_ostream<Elem, Traits>& os, const address_v6& addr)
|
||||
{
|
||||
os << addr.to_string();
|
||||
boost::asio::error e;
|
||||
std::string s = addr.to_string(boost::asio::assign_error(e));
|
||||
if (e)
|
||||
os.setstate(std::ios_base::failbit);
|
||||
else
|
||||
for (std::string::iterator i = s.begin(); i != s.end(); ++i)
|
||||
os << os.widen(*i);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ public:
|
||||
|
||||
/// Default constructor.
|
||||
basic_endpoint()
|
||||
: data_()
|
||||
{
|
||||
boost::asio::detail::sockaddr_in4_type& data
|
||||
= reinterpret_cast<boost::asio::detail::sockaddr_in4_type&>(data_);
|
||||
@@ -97,6 +98,7 @@ public:
|
||||
* @endcode
|
||||
*/
|
||||
basic_endpoint(const Protocol& protocol, unsigned short port_num)
|
||||
: data_()
|
||||
{
|
||||
using namespace std; // For memcpy.
|
||||
if (protocol.family() == PF_INET)
|
||||
@@ -126,6 +128,7 @@ public:
|
||||
/// constructor may be used for accepting connections on a specific interface
|
||||
/// or for making a connection to a remote endpoint.
|
||||
basic_endpoint(const boost::asio::ip::address& addr, unsigned short port_num)
|
||||
: data_()
|
||||
{
|
||||
using namespace std; // For memcpy.
|
||||
if (addr.is_v4())
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_BASIC_RESOLVER_HPP
|
||||
#define BOOST_ASIO_BASIC_RESOLVER_HPP
|
||||
#ifndef BOOST_ASIO_IP_BASIC_RESOLVER_HPP
|
||||
#define BOOST_ASIO_IP_BASIC_RESOLVER_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
@@ -20,10 +20,11 @@
|
||||
#include <boost/asio/basic_io_object.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/error_handler.hpp>
|
||||
#include <boost/asio/resolver_service.hpp>
|
||||
#include <boost/asio/ip/resolver_service.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace ip {
|
||||
|
||||
/// Provides endpoint resolution functionality.
|
||||
/**
|
||||
@@ -246,9 +247,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ip
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_BASIC_RESOLVER_HPP
|
||||
#endif // BOOST_ASIO_IP_BASIC_RESOLVER_HPP
|
||||
@@ -80,7 +80,9 @@ public:
|
||||
{
|
||||
using namespace std; // For memcpy.
|
||||
typename Protocol::endpoint endpoint;
|
||||
endpoint.resize(address_info->ai_addrlen);
|
||||
endpoint.resize(
|
||||
static_cast<boost::asio::detail::socket_addr_len_type>(
|
||||
address_info->ai_addrlen));
|
||||
memcpy(endpoint.data(), address_info->ai_addr,
|
||||
address_info->ai_addrlen);
|
||||
iter.values_->push_back(
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_RESOLVER_SERVICE_HPP
|
||||
#define BOOST_ASIO_RESOLVER_SERVICE_HPP
|
||||
#ifndef BOOST_ASIO_IP_RESOLVER_SERVICE_HPP
|
||||
#define BOOST_ASIO_IP_RESOLVER_SERVICE_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace ip {
|
||||
|
||||
/// Default service implementation for a resolver.
|
||||
template <typename Protocol>
|
||||
@@ -43,7 +44,7 @@ public:
|
||||
|
||||
private:
|
||||
// The type of the platform-specific implementation.
|
||||
typedef detail::resolver_service<Protocol> service_impl_type;
|
||||
typedef boost::asio::detail::resolver_service<Protocol> service_impl_type;
|
||||
|
||||
public:
|
||||
/// The type of a resolver implementation.
|
||||
@@ -120,9 +121,10 @@ private:
|
||||
service_impl_type& service_impl_;
|
||||
};
|
||||
|
||||
} // namespace ip
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_RESOLVER_SERVICE_HPP
|
||||
#endif // BOOST_ASIO_IP_RESOLVER_SERVICE_HPP
|
||||
@@ -17,11 +17,11 @@
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/basic_resolver.hpp>
|
||||
#include <boost/asio/basic_socket_acceptor.hpp>
|
||||
#include <boost/asio/basic_socket_iostream.hpp>
|
||||
#include <boost/asio/basic_stream_socket.hpp>
|
||||
#include <boost/asio/ip/basic_endpoint.hpp>
|
||||
#include <boost/asio/ip/basic_resolver.hpp>
|
||||
#include <boost/asio/ip/basic_resolver_iterator.hpp>
|
||||
#include <boost/asio/ip/basic_resolver_query.hpp>
|
||||
#include <boost/asio/detail/socket_option.hpp>
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/basic_datagram_socket.hpp>
|
||||
#include <boost/asio/basic_resolver.hpp>
|
||||
#include <boost/asio/ip/basic_endpoint.hpp>
|
||||
#include <boost/asio/ip/basic_resolver.hpp>
|
||||
#include <boost/asio/ip/basic_resolver_iterator.hpp>
|
||||
#include <boost/asio/ip/basic_resolver_query.hpp>
|
||||
#include <boost/asio/detail/socket_types.hpp>
|
||||
|
||||
@@ -110,6 +110,13 @@ public:
|
||||
service_impl_.assign(impl, protocol, native_acceptor, error_handler);
|
||||
}
|
||||
|
||||
/// Cancel all asynchronous operations associated with the acceptor.
|
||||
template <typename Error_Handler>
|
||||
void cancel(implementation_type& impl, Error_Handler error_handler)
|
||||
{
|
||||
service_impl_.cancel(impl, error_handler);
|
||||
}
|
||||
|
||||
/// Bind the socket acceptor to the specified local endpoint.
|
||||
template <typename Error_Handler>
|
||||
void bind(implementation_type& impl, const endpoint_type& endpoint,
|
||||
|
||||
@@ -430,7 +430,7 @@ public:
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
typedef implementation_defined non_blocking_io;
|
||||
#else
|
||||
typedef boost::asio::detail::io_control::boolean<FIONBIO> non_blocking_io;
|
||||
typedef boost::asio::detail::io_control::non_blocking_io non_blocking_io;
|
||||
#endif
|
||||
|
||||
/// IO control command to get the amount of data that can be read without
|
||||
@@ -453,7 +453,14 @@ public:
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
typedef implementation_defined bytes_readable;
|
||||
#else
|
||||
typedef boost::asio::detail::io_control::size<FIONREAD> bytes_readable;
|
||||
typedef boost::asio::detail::io_control::bytes_readable bytes_readable;
|
||||
#endif
|
||||
|
||||
/// The maximum length of the queue of pending incoming connections.
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
static const int max_connections = implementation_defined;
|
||||
#else
|
||||
BOOST_STATIC_CONSTANT(int, max_connections = SOMAXCONN);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
@@ -404,6 +404,54 @@ public:
|
||||
service_.use_tmp_dh_file(impl_, filename, error_handler);
|
||||
}
|
||||
|
||||
/// Set the password callback.
|
||||
/**
|
||||
* This function is used to specify a callback function to obtain password
|
||||
* information about an encrypted key in PEM format.
|
||||
*
|
||||
* @param callback The function object to be used for obtaining the password.
|
||||
* The function signature of the handler must be:
|
||||
* @code std::string password_callback(
|
||||
* std::size_t max_length, // The maximum size for a password.
|
||||
* password_purpose purpose // Whether password is for reading or writing.
|
||||
* ); @endcode
|
||||
* The return value of the callback is a string containing the password.
|
||||
*
|
||||
* @throws boost::asio::error Thrown on failure.
|
||||
*/
|
||||
template <typename Password_Callback>
|
||||
void set_password_callback(Password_Callback callback)
|
||||
{
|
||||
service_.set_password_callback(impl_, callback, throw_error());
|
||||
}
|
||||
|
||||
/// Set the password callback.
|
||||
/**
|
||||
* This function is used to specify a callback function to obtain password
|
||||
* information about an encrypted key in PEM format.
|
||||
*
|
||||
* @param callback The function object to be used for obtaining the password.
|
||||
* The function signature of the handler must be:
|
||||
* @code std::string password_callback(
|
||||
* std::size_t max_length, // The maximum size for a password.
|
||||
* password_purpose purpose // Whether password is for reading or writing.
|
||||
* ); @endcode
|
||||
* The return value of the callback is a string containing the password.
|
||||
*
|
||||
* @param error_handler A handler to be called when the operation completes,
|
||||
* to indicate whether or not an error has occurred. Copies will be made of
|
||||
* the handler as required. The function signature of the handler must be:
|
||||
* @code void error_handler(
|
||||
* const boost::asio::error& error // Result of operation
|
||||
* ); @endcode
|
||||
*/
|
||||
template <typename Password_Callback, typename Error_Handler>
|
||||
void set_password_callback(Password_Callback callback,
|
||||
Error_Handler error_handler)
|
||||
{
|
||||
service_.set_password_callback(impl_, callback, error_handler);
|
||||
}
|
||||
|
||||
private:
|
||||
/// The backend service implementation.
|
||||
service_type& service_;
|
||||
|
||||
@@ -134,6 +134,16 @@ public:
|
||||
BOOST_STATIC_CONSTANT(int, verify_client_once = SSL_VERIFY_CLIENT_ONCE);
|
||||
#endif
|
||||
|
||||
/// Purpose of PEM password.
|
||||
enum password_purpose
|
||||
{
|
||||
/// The password is needed for reading/decryption.
|
||||
for_reading,
|
||||
|
||||
/// The password is needed for writing/encryption.
|
||||
for_writing
|
||||
};
|
||||
|
||||
protected:
|
||||
/// Protected destructor to prevent deletion through this type.
|
||||
~context_base()
|
||||
|
||||
@@ -151,6 +151,14 @@ public:
|
||||
service_impl_.use_tmp_dh_file(impl, filename, error_handler);
|
||||
}
|
||||
|
||||
/// Set the password callback.
|
||||
template <typename Password_Callback, typename Error_Handler>
|
||||
void set_password_callback(impl_type& impl, Password_Callback callback,
|
||||
Error_Handler error_handler)
|
||||
{
|
||||
service_impl_.set_password_callback(impl, callback, error_handler);
|
||||
}
|
||||
|
||||
private:
|
||||
// The service that provides the platform-specific implementation.
|
||||
service_impl_type& service_impl_;
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#include <boost/asio/error.hpp>
|
||||
@@ -40,6 +42,10 @@ public:
|
||||
// The native type of the context.
|
||||
typedef ::SSL_CTX* impl_type;
|
||||
|
||||
// The type for the password callback function object.
|
||||
typedef boost::function<std::string(std::size_t,
|
||||
context_base::password_purpose)> password_callback_type;
|
||||
|
||||
// Constructor.
|
||||
openssl_context_service(boost::asio::io_service& io_service)
|
||||
: boost::asio::io_service::service(io_service)
|
||||
@@ -110,6 +116,15 @@ public:
|
||||
{
|
||||
if (impl != null())
|
||||
{
|
||||
if (impl->default_passwd_callback_userdata)
|
||||
{
|
||||
password_callback_type* callback =
|
||||
static_cast<password_callback_type*>(
|
||||
impl->default_passwd_callback_userdata);
|
||||
delete callback;
|
||||
impl->default_passwd_callback_userdata = 0;
|
||||
}
|
||||
|
||||
::SSL_CTX_free(impl);
|
||||
impl = null();
|
||||
}
|
||||
@@ -322,6 +337,52 @@ public:
|
||||
error_handler(e);
|
||||
}
|
||||
|
||||
static int password_callback(char* buf, int size, int purpose, void* data)
|
||||
{
|
||||
using namespace std; // For strncat and strlen.
|
||||
|
||||
if (data)
|
||||
{
|
||||
password_callback_type* callback =
|
||||
static_cast<password_callback_type*>(data);
|
||||
std::string passwd = (*callback)(static_cast<std::size_t>(size),
|
||||
purpose ? context_base::for_writing : context_base::for_reading);
|
||||
*buf = '\0';
|
||||
strncat(buf, passwd.c_str(), size);
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set the password callback.
|
||||
template <typename Password_Callback, typename Error_Handler>
|
||||
void set_password_callback(impl_type& impl, Password_Callback callback,
|
||||
Error_Handler error_handler)
|
||||
{
|
||||
// Allocate callback function object if not already present.
|
||||
if (impl->default_passwd_callback_userdata)
|
||||
{
|
||||
password_callback_type* callback_function =
|
||||
static_cast<password_callback_type*>(
|
||||
impl->default_passwd_callback_userdata);
|
||||
*callback_function = callback;
|
||||
}
|
||||
else
|
||||
{
|
||||
password_callback_type* callback_function =
|
||||
new password_callback_type(callback);
|
||||
impl->default_passwd_callback_userdata = callback_function;
|
||||
}
|
||||
|
||||
// Set the password callback.
|
||||
SSL_CTX_set_default_passwd_cb(impl,
|
||||
&openssl_context_service::password_callback);
|
||||
|
||||
boost::asio::error e;
|
||||
error_handler(e);
|
||||
}
|
||||
|
||||
private:
|
||||
// Ensure openssl is initialised.
|
||||
openssl_init<> init_;
|
||||
|
||||
@@ -61,6 +61,12 @@ private:
|
||||
if (Do_Init)
|
||||
{
|
||||
::CRYPTO_set_locking_callback(0);
|
||||
::ERR_free_strings();
|
||||
::ERR_remove_state(0);
|
||||
::EVP_cleanup();
|
||||
::CRYPTO_cleanup_all_ex_data();
|
||||
::CONF_modules_unload(1);
|
||||
::ENGINE_cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/placeholders.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/asio/detail/socket_ops.hpp>
|
||||
#include <boost/asio/ssl/detail/openssl_types.hpp>
|
||||
|
||||
namespace boost {
|
||||
@@ -133,6 +134,7 @@ public:
|
||||
int start()
|
||||
{
|
||||
int rc = primitive_( session_ );
|
||||
int sys_error_code = ERR_get_error();
|
||||
bool is_operation_done = (rc > 0);
|
||||
// For connect/accept/shutdown, the operation
|
||||
// is done, when return code is 1
|
||||
@@ -166,9 +168,14 @@ public:
|
||||
|
||||
if (!is_operation_done && !is_read_needed && !is_write_needed
|
||||
&& !is_shut_down_sent)
|
||||
{
|
||||
// The operation has failed... It is not completed and does
|
||||
// not want network communication nor does want to send shutdown out...
|
||||
return handler_(boost::asio::error(error_code), rc);
|
||||
if (error_code == SSL_ERROR_SYSCALL)
|
||||
return handler_(boost::asio::error(sys_error_code), rc);
|
||||
else
|
||||
return handler_(boost::asio::error(error_code + 1000000), rc);
|
||||
}
|
||||
|
||||
if (!is_operation_done && !is_write_needed)
|
||||
{
|
||||
|
||||
@@ -236,7 +236,7 @@ public:
|
||||
typedef handshake_handler<Stream, Handler> connect_handler;
|
||||
|
||||
connect_handler* local_handler =
|
||||
new connect_handler(handler, owner());
|
||||
new connect_handler(handler, io_service());
|
||||
|
||||
openssl_operation<Stream>* op = new openssl_operation<Stream>
|
||||
(
|
||||
@@ -257,7 +257,7 @@ public:
|
||||
);
|
||||
local_handler->set_operation(op);
|
||||
|
||||
owner().post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
}
|
||||
|
||||
// Shut down SSL on the stream.
|
||||
@@ -292,7 +292,7 @@ public:
|
||||
typedef shutdown_handler<Stream, Handler> disconnect_handler;
|
||||
|
||||
disconnect_handler* local_handler =
|
||||
new disconnect_handler(handler, owner());
|
||||
new disconnect_handler(handler, io_service());
|
||||
|
||||
openssl_operation<Stream>* op = new openssl_operation<Stream>
|
||||
(
|
||||
@@ -311,7 +311,7 @@ public:
|
||||
);
|
||||
local_handler->set_operation(op);
|
||||
|
||||
owner().post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
}
|
||||
|
||||
// Write some data to the stream.
|
||||
@@ -353,7 +353,7 @@ public:
|
||||
{
|
||||
typedef io_handler<Stream, Handler> send_handler;
|
||||
|
||||
send_handler* local_handler = new send_handler(handler, owner());
|
||||
send_handler* local_handler = new send_handler(handler, io_service());
|
||||
|
||||
boost::function<int (SSL*)> send_func =
|
||||
boost::bind(&::SSL_write, boost::arg<1>(),
|
||||
@@ -377,7 +377,7 @@ public:
|
||||
);
|
||||
local_handler->set_operation(op);
|
||||
|
||||
owner().post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
}
|
||||
|
||||
// Read some data from the stream.
|
||||
@@ -419,7 +419,7 @@ public:
|
||||
{
|
||||
typedef io_handler<Stream, Handler> recv_handler;
|
||||
|
||||
recv_handler* local_handler = new recv_handler(handler, owner());
|
||||
recv_handler* local_handler = new recv_handler(handler, io_service());
|
||||
|
||||
boost::function<int (SSL*)> recv_func =
|
||||
boost::bind(&::SSL_read, boost::arg<1>(),
|
||||
@@ -443,7 +443,7 @@ public:
|
||||
);
|
||||
local_handler->set_operation(op);
|
||||
|
||||
owner().post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
}
|
||||
|
||||
// Peek at the incoming data on the stream.
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/engine.h>
|
||||
#include <openssl/err.h>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
@@ -17,13 +17,148 @@
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/basic_strand.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/detail/strand_service.hpp>
|
||||
#include <boost/asio/detail/wrapped_handler.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
/// Typedef for the typical usage of strand.
|
||||
typedef basic_strand<> strand;
|
||||
/// Provides serialised handler execution.
|
||||
/**
|
||||
* The io_service::strand class provides the ability to post and dispatch
|
||||
* handlers with the guarantee that none of those handlers will execute
|
||||
* concurrently.
|
||||
*
|
||||
* @par Thread Safety:
|
||||
* @e Distinct @e objects: Safe.@n
|
||||
* @e Shared @e objects: Safe.
|
||||
*
|
||||
* @par Concepts:
|
||||
* Dispatcher.
|
||||
*/
|
||||
class io_service::strand
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/**
|
||||
* Constructs the strand.
|
||||
*
|
||||
* @param io_service The io_service object that the strand will use to
|
||||
* dispatch handlers that are ready to be run.
|
||||
*/
|
||||
explicit strand(boost::asio::io_service& io_service)
|
||||
: service_(boost::asio::use_service<
|
||||
boost::asio::detail::strand_service>(io_service))
|
||||
{
|
||||
service_.construct(impl_);
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
~strand()
|
||||
{
|
||||
service_.destroy(impl_);
|
||||
}
|
||||
|
||||
/// Get the io_service associated with the strand.
|
||||
/**
|
||||
* This function may be used to obtain the io_service object that the strand
|
||||
* uses to dispatch handlers for asynchronous operations.
|
||||
*
|
||||
* @return A reference to the io_service object that the strand will use to
|
||||
* dispatch handlers. Ownership is not transferred to the caller.
|
||||
*/
|
||||
boost::asio::io_service& io_service()
|
||||
{
|
||||
return service_.io_service();
|
||||
}
|
||||
|
||||
/// Request the strand to invoke the given handler.
|
||||
/**
|
||||
* This function is used to ask the strand to execute the given handler.
|
||||
*
|
||||
* The strand object guarantees that handlers posted or dispatched through
|
||||
* the strand will not be executed concurrently. The handler may be executed
|
||||
* inside this function if the guarantee can be met. If this function is
|
||||
* called from within a handler that was posted or dispatched through the same
|
||||
* strand, then the new handler will be executed immediately.
|
||||
*
|
||||
* The strand's guarantee is in addition to the guarantee provided by the
|
||||
* underlying io_service. The io_service guarantees that the handler will only
|
||||
* be called in a thread in which the io_service's run member function is
|
||||
* currently being invoked.
|
||||
*
|
||||
* @param handler The handler to be called. The strand will make a copy of the
|
||||
* handler object as required. The function signature of the handler must be:
|
||||
* @code void handler(); @endcode
|
||||
*/
|
||||
template <typename Handler>
|
||||
void dispatch(Handler handler)
|
||||
{
|
||||
service_.dispatch(impl_, handler);
|
||||
}
|
||||
|
||||
/// Request the strand to invoke the given handler and return
|
||||
/// immediately.
|
||||
/**
|
||||
* This function is used to ask the strand to execute the given handler, but
|
||||
* without allowing the strand to call the handler from inside this function.
|
||||
*
|
||||
* The strand object guarantees that handlers posted or dispatched through
|
||||
* the strand will not be executed concurrently. The strand's guarantee is in
|
||||
* addition to the guarantee provided by the underlying io_service. The
|
||||
* io_service guarantees that the handler will only be called in a thread in
|
||||
* which the io_service's run member function is currently being invoked.
|
||||
*
|
||||
* @param handler The handler to be called. The strand will make a copy of the
|
||||
* handler object as required. The function signature of the handler must be:
|
||||
* @code void handler(); @endcode
|
||||
*/
|
||||
template <typename Handler>
|
||||
void post(Handler handler)
|
||||
{
|
||||
service_.post(impl_, handler);
|
||||
}
|
||||
|
||||
/// Create a new handler that automatically dispatches the wrapped handler
|
||||
/// on the strand.
|
||||
/**
|
||||
* This function is used to create a new handler function object that, when
|
||||
* invoked, will automatically pass the wrapped handler to the strand's
|
||||
* dispatch function.
|
||||
*
|
||||
* @param handler The handler to be wrapped. The strand will make a copy of
|
||||
* the handler object as required. The function signature of the handler must
|
||||
* be: @code void handler(A1 a1, ... An an); @endcode
|
||||
*
|
||||
* @return A function object that, when invoked, passes the wrapped handler to
|
||||
* the strand's dispatch function. Given a function object with the signature:
|
||||
* @code R f(A1 a1, ... An an); @endcode
|
||||
* If this function object is passed to the wrap function like so:
|
||||
* @code strand.wrap(f); @endcode
|
||||
* then the return value is a function object with the signature
|
||||
* @code void g(A1 a1, ... An an); @endcode
|
||||
* that, when invoked, executes code equivalent to:
|
||||
* @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode
|
||||
*/
|
||||
template <typename Handler>
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
unspecified
|
||||
#else
|
||||
detail::wrapped_handler<strand, Handler>
|
||||
#endif
|
||||
wrap(Handler handler)
|
||||
{
|
||||
return detail::wrapped_handler<io_service::strand, Handler>(*this, handler);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::detail::strand_service& service_;
|
||||
boost::asio::detail::strand_service::implementation_type impl_;
|
||||
};
|
||||
|
||||
/// Typedef for backwards compatibility.
|
||||
typedef boost::asio::io_service::strand strand;
|
||||
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
//
|
||||
// strand_service.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 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 BOOST_ASIO_STRAND_SERVICE_HPP
|
||||
#define BOOST_ASIO_STRAND_SERVICE_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/detail/strand_service.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
/// Default service implementation for a strand.
|
||||
class strand_service
|
||||
: public boost::asio::io_service::service
|
||||
{
|
||||
private:
|
||||
// The type of the platform-specific implementation.
|
||||
typedef detail::strand_service service_impl_type;
|
||||
|
||||
public:
|
||||
/// The implementation type of the strand.
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
typedef implementation_defined implementation_type;
|
||||
#else
|
||||
typedef service_impl_type::implementation_type implementation_type;
|
||||
#endif
|
||||
|
||||
/// Construct a new timer service for the specified io_service.
|
||||
explicit strand_service(boost::asio::io_service& io_service)
|
||||
: boost::asio::io_service::service(io_service),
|
||||
service_impl_(boost::asio::use_service<service_impl_type>(io_service))
|
||||
{
|
||||
}
|
||||
|
||||
/// Destroy all user-defined handler objects owned by the service.
|
||||
void shutdown_service()
|
||||
{
|
||||
}
|
||||
|
||||
/// Construct a new timer implementation.
|
||||
void construct(implementation_type& impl)
|
||||
{
|
||||
service_impl_.construct(impl);
|
||||
}
|
||||
|
||||
/// Destroy a timer implementation.
|
||||
void destroy(implementation_type& impl)
|
||||
{
|
||||
service_impl_.destroy(impl);
|
||||
}
|
||||
|
||||
/// Request the io_service to invoke the given handler.
|
||||
template <typename Handler>
|
||||
void dispatch(implementation_type& impl, Handler handler)
|
||||
{
|
||||
service_impl_.dispatch(impl, handler);
|
||||
}
|
||||
|
||||
/// Request the io_service to invoke the given handler and return immediately.
|
||||
template <typename Handler>
|
||||
void post(implementation_type& impl, Handler handler)
|
||||
{
|
||||
service_impl_.post(impl, handler);
|
||||
}
|
||||
|
||||
private:
|
||||
// The service that provides the platform-specific implementation.
|
||||
service_impl_type& service_impl_;
|
||||
};
|
||||
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_STRAND_SERVICE_HPP
|
||||
@@ -130,6 +130,13 @@ public:
|
||||
return service_impl_.native(impl);
|
||||
}
|
||||
|
||||
/// Cancel all asynchronous operations associated with the socket.
|
||||
template <typename Error_Handler>
|
||||
void cancel(implementation_type& impl, Error_Handler error_handler)
|
||||
{
|
||||
service_impl_.cancel(impl, error_handler);
|
||||
}
|
||||
|
||||
/// Bind the stream socket to the specified local endpoint.
|
||||
template <typename Error_Handler>
|
||||
void bind(implementation_type& impl, const endpoint_type& endpoint,
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/win_local_free_on_block_exit.hpp>
|
||||
#include <boost/asio/detail/local_free_on_block_exit.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
| FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS, 0, code_,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0);
|
||||
detail::win_local_free_on_block_exit local_free_obj(msg);
|
||||
detail::local_free_on_block_exit local_free_obj(msg);
|
||||
if (length && msg[length - 1] == '\n')
|
||||
msg[--length] = '\0';
|
||||
if (length && msg[length - 1] == '\r')
|
||||
@@ -108,7 +108,8 @@ public:
|
||||
}
|
||||
#elif defined(__sun) || defined(__QNX__)
|
||||
return strerror(code_);
|
||||
#elif defined(__MACH__) && defined(__APPLE__) || defined(__NetBSD__)
|
||||
#elif defined(__MACH__) && defined(__APPLE__) \
|
||||
|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
try
|
||||
{
|
||||
char buf[256] = "";
|
||||
|
||||
81
test/Jamfile
81
test/Jamfile
@@ -33,45 +33,44 @@ template asio_unit_test
|
||||
|
||||
test-suite "asio"
|
||||
:
|
||||
[ link basic_datagram_socket_test.cpp <template>asio_unit_test ]
|
||||
[ link basic_deadline_timer_test.cpp <template>asio_unit_test ]
|
||||
[ link basic_resolver_test.cpp <template>asio_unit_test ]
|
||||
[ link basic_socket_acceptor_test.cpp <template>asio_unit_test ]
|
||||
[ link basic_strand_test.cpp <template>asio_unit_test ]
|
||||
[ link basic_stream_socket_test.cpp <template>asio_unit_test ]
|
||||
[ run buffer_test.cpp <template>asio_unit_test ]
|
||||
[ run buffered_read_stream_test.cpp <template>asio_unit_test ]
|
||||
[ run buffered_stream_test.cpp <template>asio_unit_test ]
|
||||
[ run buffered_write_stream_test.cpp <template>asio_unit_test ]
|
||||
[ link completion_condition_test.cpp <template>asio_unit_test ]
|
||||
[ link datagram_socket_service_test.cpp <template>asio_unit_test ]
|
||||
[ link deadline_timer_service_test.cpp <template>asio_unit_test ]
|
||||
[ run deadline_timer_test.cpp <template>asio_unit_test ]
|
||||
[ run error_handler_test.cpp <template>asio_unit_test ]
|
||||
[ run error_test.cpp <template>asio_unit_test ]
|
||||
[ run io_service_test.cpp <template>asio_unit_test ]
|
||||
[ link ip/address_test.cpp <template>asio_unit_test ]
|
||||
[ link ip/address_v4_test.cpp <template>asio_unit_test ]
|
||||
[ link ip/address_v6_test.cpp <template>asio_unit_test ]
|
||||
[ link ip/basic_endpoint_test.cpp <template>asio_unit_test ]
|
||||
[ link ip/basic_resolver_entry_test.cpp <template>asio_unit_test ]
|
||||
[ link ip/basic_resolver_iterator_test.cpp <template>asio_unit_test ]
|
||||
[ link ip/basic_resolver_query_test.cpp <template>asio_unit_test ]
|
||||
[ run ip/host_name_test.cpp <template>asio_unit_test ]
|
||||
[ link ip/multicast_test.cpp <template>asio_unit_test ]
|
||||
[ link ip/resolver_query_base_test.cpp <template>asio_unit_test ]
|
||||
[ run ip/tcp_test.cpp <template>asio_unit_test ]
|
||||
[ run ip/udp_test.cpp <template>asio_unit_test ]
|
||||
[ run is_read_buffered_test.cpp <template>asio_unit_test ]
|
||||
[ run is_write_buffered_test.cpp <template>asio_unit_test ]
|
||||
[ link placeholders_test.cpp <template>asio_unit_test ]
|
||||
[ run read_test.cpp <template>asio_unit_test ]
|
||||
[ link resolver_service_test.cpp <template>asio_unit_test ]
|
||||
[ link socket_acceptor_service_test.cpp <template>asio_unit_test ]
|
||||
[ run socket_base_test.cpp <template>asio_unit_test ]
|
||||
[ link strand_service_test.cpp <template>asio_unit_test ]
|
||||
[ run strand_test.cpp <template>asio_unit_test ]
|
||||
[ link stream_socket_service_test.cpp <template>asio_unit_test ]
|
||||
[ link time_traits_test.cpp <template>asio_unit_test ]
|
||||
[ run write_test.cpp <template>asio_unit_test ]
|
||||
[ link basic_datagram_socket.cpp <template>asio_unit_test ]
|
||||
[ link basic_deadline_timer.cpp <template>asio_unit_test ]
|
||||
[ link basic_socket_acceptor.cpp <template>asio_unit_test ]
|
||||
[ link basic_stream_socket.cpp <template>asio_unit_test ]
|
||||
[ run buffer.cpp <template>asio_unit_test ]
|
||||
[ run buffered_read_stream.cpp <template>asio_unit_test ]
|
||||
[ run buffered_stream.cpp <template>asio_unit_test ]
|
||||
[ run buffered_write_stream.cpp <template>asio_unit_test ]
|
||||
[ link completion_condition.cpp <template>asio_unit_test ]
|
||||
[ link datagram_socket_service.cpp <template>asio_unit_test ]
|
||||
[ link deadline_timer_service.cpp <template>asio_unit_test ]
|
||||
[ run deadline_timer.cpp <template>asio_unit_test ]
|
||||
[ run error_handler.cpp <template>asio_unit_test ]
|
||||
[ run error.cpp <template>asio_unit_test ]
|
||||
[ run io_service.cpp <template>asio_unit_test ]
|
||||
[ link ip/address.cpp <template>asio_unit_test ]
|
||||
[ link ip/address_v4.cpp <template>asio_unit_test ]
|
||||
[ link ip/address_v6.cpp <template>asio_unit_test ]
|
||||
[ link ip/basic_endpoint.cpp <template>asio_unit_test ]
|
||||
[ link ip/basic_resolver.cpp <template>asio_unit_test ]
|
||||
[ link ip/basic_resolver_entry.cpp <template>asio_unit_test ]
|
||||
[ link ip/basic_resolver_iterator.cpp <template>asio_unit_test ]
|
||||
[ link ip/basic_resolver_query.cpp <template>asio_unit_test ]
|
||||
[ run ip/host_name.cpp <template>asio_unit_test ]
|
||||
[ link ip/multicast.cpp <template>asio_unit_test ]
|
||||
[ link ip/resolver_query_base.cpp <template>asio_unit_test ]
|
||||
[ link ip/resolver_service.cpp <template>asio_unit_test ]
|
||||
[ run ip/tcp.cpp <template>asio_unit_test ]
|
||||
[ run ip/udp.cpp <template>asio_unit_test ]
|
||||
[ run is_read_buffered.cpp <template>asio_unit_test ]
|
||||
[ run is_write_buffered.cpp <template>asio_unit_test ]
|
||||
[ link placeholders.cpp <template>asio_unit_test ]
|
||||
[ run read.cpp <template>asio_unit_test ]
|
||||
[ link read_until.cpp <template>asio_unit_test ]
|
||||
[ link socket_acceptor_service.cpp <template>asio_unit_test ]
|
||||
[ run socket_base.cpp <template>asio_unit_test ]
|
||||
[ run strand.cpp <template>asio_unit_test ]
|
||||
[ link stream_socket_service.cpp <template>asio_unit_test ]
|
||||
[ link time_traits.cpp <template>asio_unit_test ]
|
||||
[ run write.cpp <template>asio_unit_test ]
|
||||
;
|
||||
|
||||
162
test/Jamfile.v2
162
test/Jamfile.v2
@@ -38,86 +38,84 @@ project
|
||||
;
|
||||
|
||||
test-suite "asio" :
|
||||
[ link basic_datagram_socket_test.cpp ]
|
||||
[ link basic_datagram_socket_test.cpp : $(USE_SELECT) : basic_datagram_socket_test_select ]
|
||||
[ link basic_deadline_timer_test.cpp ]
|
||||
[ link basic_deadline_timer_test.cpp : $(USE_SELECT) : basic_deadline_timer_test_select ]
|
||||
[ link basic_resolver_test.cpp ]
|
||||
[ link basic_resolver_test.cpp : $(USE_SELECT) : basic_resolver_test_select ]
|
||||
[ link basic_socket_acceptor_test.cpp ]
|
||||
[ link basic_socket_acceptor_test.cpp : $(USE_SELECT) : basic_socket_acceptor_test_select ]
|
||||
[ link basic_strand_test.cpp ]
|
||||
[ link basic_strand_test.cpp : $(USE_SELECT) : basic_strand_test_select ]
|
||||
[ link basic_stream_socket_test.cpp ]
|
||||
[ link basic_stream_socket_test.cpp : $(USE_SELECT) : basic_stream_socket_test_select ]
|
||||
[ run buffer_test.cpp ]
|
||||
[ run buffer_test.cpp : : : $(USE_SELECT) : buffer_test_select ]
|
||||
[ run buffered_read_stream_test.cpp ]
|
||||
[ run buffered_read_stream_test.cpp : : : $(USE_SELECT) : buffered_read_stream_test_select ]
|
||||
[ run buffered_stream_test.cpp ]
|
||||
[ run buffered_stream_test.cpp : : : $(USE_SELECT) : buffered_stream_test_select ]
|
||||
[ run buffered_write_stream_test.cpp ]
|
||||
[ run buffered_write_stream_test.cpp : : : $(USE_SELECT) : buffered_write_stream_test_select ]
|
||||
[ link completion_condition_test.cpp ]
|
||||
[ link completion_condition_test.cpp : $(USE_SELECT) : completion_condition_test_select ]
|
||||
[ link datagram_socket_service_test.cpp ]
|
||||
[ link datagram_socket_service_test.cpp : $(USE_SELECT) : datagram_socket_service_test_select ]
|
||||
[ link deadline_timer_service_test.cpp ]
|
||||
[ link deadline_timer_service_test.cpp : $(USE_SELECT) : deadline_timer_service_test_select ]
|
||||
[ run deadline_timer_test.cpp ]
|
||||
[ run deadline_timer_test.cpp : : : $(USE_SELECT) : deadline_timer_test_select ]
|
||||
[ run error_handler_test.cpp ]
|
||||
[ run error_handler_test.cpp : : : $(USE_SELECT) : error_handler_test_select ]
|
||||
[ run error_test.cpp ]
|
||||
[ run error_test.cpp : : : $(USE_SELECT) : error_test_select ]
|
||||
[ run io_service_test.cpp ]
|
||||
[ run io_service_test.cpp : : : $(USE_SELECT) : io_service_test_select ]
|
||||
[ link ip/address_test.cpp ]
|
||||
[ link ip/address_test.cpp : $(USE_SELECT) : ip/address_test_select ]
|
||||
[ link ip/address_v4_test.cpp ]
|
||||
[ link ip/address_v4_test.cpp : $(USE_SELECT) : ip/address_v4_test_select ]
|
||||
[ link ip/address_v6_test.cpp ]
|
||||
[ link ip/address_v6_test.cpp : $(USE_SELECT) : ip/address_v6_test_select ]
|
||||
[ link ip/basic_endpoint_test.cpp ]
|
||||
[ link ip/basic_endpoint_test.cpp : $(USE_SELECT) : ip/basic_endpoint_test_select ]
|
||||
[ link ip/basic_resolver_entry_test.cpp ]
|
||||
[ link ip/basic_resolver_entry_test.cpp : $(USE_SELECT) : ip/basic_resolver_entry_test_select ]
|
||||
[ link ip/basic_resolver_iterator_test.cpp ]
|
||||
[ link ip/basic_resolver_iterator_test.cpp : $(USE_SELECT) : ip/basic_resolver_iterator_test_select ]
|
||||
[ link ip/basic_resolver_query_test.cpp ]
|
||||
[ link ip/basic_resolver_query_test.cpp : $(USE_SELECT) : ip/basic_resolver_query_test_select ]
|
||||
[ run ip/host_name_test.cpp ]
|
||||
[ run ip/host_name_test.cpp : : : $(USE_SELECT) : ip/host_name_test_select ]
|
||||
[ link ip/multicast_test.cpp ]
|
||||
[ link ip/multicast_test.cpp : $(USE_SELECT) : ip/multicast_test_select ]
|
||||
[ link ip/resolver_query_base_test.cpp ]
|
||||
[ link ip/resolver_query_base_test.cpp : $(USE_SELECT) : ip/resolver_query_base_test_select ]
|
||||
[ run ip/tcp_test.cpp ]
|
||||
[ run ip/tcp_test.cpp : : : $(USE_SELECT) : ip/tcp_test_select ]
|
||||
[ run ip/udp_test.cpp ]
|
||||
[ run ip/udp_test.cpp : : : $(USE_SELECT) : ip/udp_test_select ]
|
||||
[ run is_read_buffered_test.cpp ]
|
||||
[ run is_read_buffered_test.cpp : : : $(USE_SELECT) : is_read_buffered_test_select ]
|
||||
[ run is_write_buffered_test.cpp ]
|
||||
[ run is_write_buffered_test.cpp : : : $(USE_SELECT) : is_write_buffered_test_select ]
|
||||
[ link placeholders_test.cpp ]
|
||||
[ link placeholders_test.cpp : $(USE_SELECT) : placeholders_test_select ]
|
||||
[ run read_test.cpp ]
|
||||
[ run read_test.cpp : : : $(USE_SELECT) : read_test_select ]
|
||||
[ link resolver_service_test.cpp ]
|
||||
[ link resolver_service_test.cpp : $(USE_SELECT) : resolver_service_test_select ]
|
||||
[ link socket_acceptor_service_test.cpp ]
|
||||
[ link socket_acceptor_service_test.cpp : $(USE_SELECT) : socket_acceptor_service_test_select ]
|
||||
[ run socket_base_test.cpp ]
|
||||
[ run socket_base_test.cpp : : : $(USE_SELECT) : socket_base_test_select ]
|
||||
[ link strand_service_test.cpp ]
|
||||
[ link strand_service_test.cpp : $(USE_SELECT) : strand_service_test_select ]
|
||||
[ run strand_test.cpp ]
|
||||
[ run strand_test.cpp : : : $(USE_SELECT) : strand_test_select ]
|
||||
[ link stream_socket_service_test.cpp ]
|
||||
[ link stream_socket_service_test.cpp : $(USE_SELECT) : stream_socket_service_test_select ]
|
||||
[ link time_traits_test.cpp ]
|
||||
[ link time_traits_test.cpp : $(USE_SELECT) : time_traits_test_select ]
|
||||
[ run write_test.cpp ]
|
||||
[ run write_test.cpp : : : $(USE_SELECT) : write_test_select ]
|
||||
[ link basic_datagram_socket.cpp ]
|
||||
[ link basic_datagram_socket.cpp : $(USE_SELECT) : basic_datagram_socket_select ]
|
||||
[ link basic_deadline_timer.cpp ]
|
||||
[ link basic_deadline_timer.cpp : $(USE_SELECT) : basic_deadline_timer_select ]
|
||||
[ link basic_socket_acceptor.cpp ]
|
||||
[ link basic_socket_acceptor.cpp : $(USE_SELECT) : basic_socket_acceptor_select ]
|
||||
[ link basic_stream_socket.cpp ]
|
||||
[ link basic_stream_socket.cpp : $(USE_SELECT) : basic_stream_socket_select ]
|
||||
[ run buffer.cpp ]
|
||||
[ run buffer.cpp : : : $(USE_SELECT) : buffer_select ]
|
||||
[ run buffered_read_stream.cpp ]
|
||||
[ run buffered_read_stream.cpp : : : $(USE_SELECT) : buffered_read_stream_select ]
|
||||
[ run buffered_stream.cpp ]
|
||||
[ run buffered_stream.cpp : : : $(USE_SELECT) : buffered_stream_select ]
|
||||
[ run buffered_write_stream.cpp ]
|
||||
[ run buffered_write_stream.cpp : : : $(USE_SELECT) : buffered_write_stream_select ]
|
||||
[ link completion_condition.cpp ]
|
||||
[ link completion_condition.cpp : $(USE_SELECT) : completion_condition_select ]
|
||||
[ link datagram_socket_service.cpp ]
|
||||
[ link datagram_socket_service.cpp : $(USE_SELECT) : datagram_socket_service_select ]
|
||||
[ link deadline_timer_service.cpp ]
|
||||
[ link deadline_timer_service.cpp : $(USE_SELECT) : deadline_timer_service_select ]
|
||||
[ run deadline_timer.cpp ]
|
||||
[ run deadline_timer.cpp : : : $(USE_SELECT) : deadline_timer_select ]
|
||||
[ run error_handler.cpp ]
|
||||
[ run error_handler.cpp : : : $(USE_SELECT) : error_handler_select ]
|
||||
[ run error.cpp ]
|
||||
[ run error.cpp : : : $(USE_SELECT) : error_select ]
|
||||
[ run io_service.cpp ]
|
||||
[ run io_service.cpp : : : $(USE_SELECT) : io_service_select ]
|
||||
[ link ip/address.cpp ]
|
||||
[ link ip/address.cpp : $(USE_SELECT) : ip/address_select ]
|
||||
[ link ip/address_v4.cpp ]
|
||||
[ link ip/address_v4.cpp : $(USE_SELECT) : ip/address_v4_select ]
|
||||
[ link ip/address_v6.cpp ]
|
||||
[ link ip/address_v6.cpp : $(USE_SELECT) : ip/address_v6_select ]
|
||||
[ link ip/basic_endpoint.cpp ]
|
||||
[ link ip/basic_endpoint.cpp : $(USE_SELECT) : ip/basic_endpoint_select ]
|
||||
[ link ip/basic_resolver.cpp ]
|
||||
[ link ip/basic_resolver.cpp : $(USE_SELECT) : ip/basic_resolver_select ]
|
||||
[ link ip/basic_resolver_entry.cpp ]
|
||||
[ link ip/basic_resolver_entry.cpp : $(USE_SELECT) : ip/basic_resolver_entry_select ]
|
||||
[ link ip/basic_resolver_iterator.cpp ]
|
||||
[ link ip/basic_resolver_iterator.cpp : $(USE_SELECT) : ip/basic_resolver_iterator_select ]
|
||||
[ link ip/basic_resolver_query.cpp ]
|
||||
[ link ip/basic_resolver_query.cpp : $(USE_SELECT) : ip/basic_resolver_query_select ]
|
||||
[ run ip/host_name.cpp ]
|
||||
[ run ip/host_name.cpp : : : $(USE_SELECT) : ip/host_name_select ]
|
||||
[ link ip/multicast.cpp ]
|
||||
[ link ip/multicast.cpp : $(USE_SELECT) : ip/multicast_select ]
|
||||
[ link ip/resolver_query_base.cpp ]
|
||||
[ link ip/resolver_query_base.cpp : $(USE_SELECT) : ip/resolver_query_base_select ]
|
||||
[ link ip/resolver_service.cpp ]
|
||||
[ link ip/resolver_service.cpp : $(USE_SELECT) : ip/resolver_service_select ]
|
||||
[ run ip/tcp.cpp ]
|
||||
[ run ip/tcp.cpp : : : $(USE_SELECT) : ip/tcp_select ]
|
||||
[ run ip/udp.cpp ]
|
||||
[ run ip/udp.cpp : : : $(USE_SELECT) : ip/udp_select ]
|
||||
[ run is_read_buffered.cpp ]
|
||||
[ run is_read_buffered.cpp : : : $(USE_SELECT) : is_read_buffered_select ]
|
||||
[ run is_write_buffered.cpp ]
|
||||
[ run is_write_buffered.cpp : : : $(USE_SELECT) : is_write_buffered_select ]
|
||||
[ link placeholders.cpp ]
|
||||
[ link placeholders.cpp : $(USE_SELECT) : placeholders_select ]
|
||||
[ run read.cpp ]
|
||||
[ run read.cpp : : : $(USE_SELECT) : read_select ]
|
||||
[ run read_until.cpp ]
|
||||
[ run read_until.cpp : : : $(USE_SELECT) : read_until_select ]
|
||||
[ link socket_acceptor_service.cpp ]
|
||||
[ link socket_acceptor_service.cpp : $(USE_SELECT) : socket_acceptor_service_select ]
|
||||
[ run socket_base.cpp ]
|
||||
[ run socket_base.cpp : : : $(USE_SELECT) : socket_base_select ]
|
||||
[ run strand.cpp ]
|
||||
[ run strand.cpp : : : $(USE_SELECT) : strand_select ]
|
||||
[ link stream_socket_service.cpp ]
|
||||
[ link stream_socket_service.cpp : $(USE_SELECT) : stream_socket_service_select ]
|
||||
[ link time_traits.cpp ]
|
||||
[ link time_traits.cpp : $(USE_SELECT) : time_traits_select ]
|
||||
[ run write.cpp ]
|
||||
[ run write.cpp : : : $(USE_SELECT) : write_select ]
|
||||
;
|
||||
|
||||
133
test/ip/address_v4.cpp
Normal file
133
test/ip/address_v4.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// address_v4_test.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 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 <boost/asio/ip/address_v4.hpp>
|
||||
|
||||
#include "../unit_test.hpp"
|
||||
#include <sstream>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// ip_address_v4_compile test
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// The following test checks that all public member functions on the class
|
||||
// ip::address_v4 compile and link correctly. Runtime failures are ignored.
|
||||
|
||||
namespace ip_address_v4_compile {
|
||||
|
||||
using namespace boost::asio;
|
||||
|
||||
void error_handler(const error&)
|
||||
{
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
try
|
||||
{
|
||||
// address_v4 constructors.
|
||||
|
||||
ip::address_v4 addr1;
|
||||
const ip::address_v4::bytes_type const_bytes_value = { 127, 0, 0, 1 };
|
||||
ip::address_v4 addr2(const_bytes_value);
|
||||
const unsigned long const_ulong_value = 0x7F00001;
|
||||
ip::address_v4 addr3(const_ulong_value);
|
||||
|
||||
// address_v4 functions.
|
||||
|
||||
bool b = addr1.is_class_a();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_class_b();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_class_c();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast();
|
||||
(void)b;
|
||||
|
||||
ip::address_v4::bytes_type bytes_value = addr1.to_bytes();
|
||||
(void)bytes_value;
|
||||
|
||||
unsigned long ulong_value = addr1.to_ulong();
|
||||
(void)ulong_value;
|
||||
|
||||
std::string string_value = addr1.to_string();
|
||||
string_value = addr1.to_string(error_handler);
|
||||
|
||||
// address_v4 static functions.
|
||||
|
||||
addr1 = ip::address_v4::from_string("127.0.0.1");
|
||||
addr1 = ip::address_v4::from_string("127.0.0.1", error_handler);
|
||||
addr1 = ip::address_v4::from_string(string_value);
|
||||
addr1 = ip::address_v4::from_string(string_value, error_handler);
|
||||
|
||||
addr1 = ip::address_v4::any();
|
||||
|
||||
addr1 = ip::address_v4::loopback();
|
||||
|
||||
addr1 = ip::address_v4::broadcast();
|
||||
|
||||
addr1 = ip::address_v4::broadcast(addr2, addr3);
|
||||
|
||||
addr1 = ip::address_v4::netmask(addr2);
|
||||
|
||||
// address_v4 comparisons.
|
||||
|
||||
b = (addr1 == addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 != addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 < addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 > addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 <= addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 >= addr2);
|
||||
(void)b;
|
||||
|
||||
// address_v4 I/O.
|
||||
|
||||
std::ostringstream os;
|
||||
os << addr1;
|
||||
|
||||
#if !defined(BOOST_NO_STD_WSTREAMBUF)
|
||||
std::wostringstream wos;
|
||||
wos << addr1;
|
||||
#endif // !defined(BOOST_NO_STD_WSTREAMBUF)
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ip_address_v4_compile
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
test_suite* init_unit_test_suite(int argc, char* argv[])
|
||||
{
|
||||
test_suite* test = BOOST_TEST_SUITE("ip/address_v4");
|
||||
test->add(BOOST_TEST_CASE(&ip_address_v4_compile::test));
|
||||
return test;
|
||||
}
|
||||
154
test/ip/address_v6.cpp
Normal file
154
test/ip/address_v6.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// address_v6_test.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 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 <boost/asio/ip/address_v6.hpp>
|
||||
|
||||
#include "../unit_test.hpp"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// ip_address_v6_compile test
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// The following test checks that all public member functions on the class
|
||||
// ip::address_v6 compile and link correctly. Runtime failures are ignored.
|
||||
|
||||
namespace ip_address_v6_compile {
|
||||
|
||||
using namespace boost::asio;
|
||||
|
||||
void error_handler(const error&)
|
||||
{
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
try
|
||||
{
|
||||
// address_v6 constructors.
|
||||
|
||||
ip::address_v6 addr1;
|
||||
const ip::address_v6::bytes_type const_bytes_value = { 0 };
|
||||
ip::address_v6 addr2(const_bytes_value);
|
||||
|
||||
// address_v6 functions.
|
||||
|
||||
unsigned long scope_id = addr1.scope_id();
|
||||
addr1.scope_id(scope_id);
|
||||
|
||||
bool b = addr1.is_unspecified();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_loopback();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_link_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_site_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_v4_mapped();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_v4_compatible();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast_node_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast_link_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast_site_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast_org_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast_global();
|
||||
(void)b;
|
||||
|
||||
ip::address_v6::bytes_type bytes_value = addr1.to_bytes();
|
||||
(void)bytes_value;
|
||||
|
||||
std::string string_value = addr1.to_string();
|
||||
string_value = addr1.to_string(error_handler);
|
||||
|
||||
ip::address_v4 addr3 = addr1.to_v4();
|
||||
|
||||
// address_v6 static functions.
|
||||
|
||||
addr1 = ip::address_v6::from_string("0::0");
|
||||
addr1 = ip::address_v6::from_string("0::0", error_handler);
|
||||
addr1 = ip::address_v6::from_string(string_value);
|
||||
addr1 = ip::address_v6::from_string(string_value, error_handler);
|
||||
|
||||
addr1 = ip::address_v6::any();
|
||||
|
||||
addr1 = ip::address_v6::loopback();
|
||||
|
||||
addr1 = ip::address_v6::v4_mapped(addr3);
|
||||
|
||||
addr1 = ip::address_v6::v4_compatible(addr3);
|
||||
|
||||
// address_v6 comparisons.
|
||||
|
||||
b = (addr1 == addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 != addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 < addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 > addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 <= addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 >= addr2);
|
||||
(void)b;
|
||||
|
||||
// address_v6 I/O.
|
||||
|
||||
std::ostringstream os;
|
||||
os << addr1;
|
||||
|
||||
#if !defined(BOOST_NO_STD_WSTREAMBUF)
|
||||
std::wostringstream wos;
|
||||
wos << addr1;
|
||||
#endif // !defined(BOOST_NO_STD_WSTREAMBUF)
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ip_address_v6_compile
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
test_suite* init_unit_test_suite(int argc, char* argv[])
|
||||
{
|
||||
test_suite* test = BOOST_TEST_SUITE("ip/address_v6");
|
||||
test->add(BOOST_TEST_CASE(&ip_address_v6_compile::test));
|
||||
return test;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// address_v6_test.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2006 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 <boost/asio/ip/address_v6.hpp>
|
||||
|
||||
#include "../unit_test.hpp"
|
||||
|
||||
test_suite* init_unit_test_suite(int argc, char* argv[])
|
||||
{
|
||||
test_suite* test = BOOST_TEST_SUITE("ip/address_v6");
|
||||
return test;
|
||||
}
|
||||
@@ -14,12 +14,12 @@
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/asio/basic_resolver.hpp>
|
||||
#include <boost/asio/ip/basic_resolver.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "../unit_test.hpp"
|
||||
|
||||
test_suite* init_unit_test_suite(int argc, char* argv[])
|
||||
{
|
||||
test_suite* test = BOOST_TEST_SUITE("basic_resolver");
|
||||
test_suite* test = BOOST_TEST_SUITE("ip/basic_resolver");
|
||||
return test;
|
||||
}
|
||||
@@ -14,12 +14,12 @@
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/asio/resolver_service.hpp>
|
||||
#include <boost/asio/ip/resolver_service.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "../unit_test.hpp"
|
||||
|
||||
test_suite* init_unit_test_suite(int argc, char* argv[])
|
||||
{
|
||||
test_suite* test = BOOST_TEST_SUITE("resolver_service");
|
||||
test_suite* test = BOOST_TEST_SUITE("ip/resolver_service");
|
||||
return test;
|
||||
}
|
||||
@@ -103,6 +103,9 @@ void test()
|
||||
ip::tcp::socket::native_type native_socket4 = socket1.native();
|
||||
(void)native_socket4;
|
||||
|
||||
socket1.cancel();
|
||||
socket1.cancel(error_handler);
|
||||
|
||||
socket1.bind(ip::tcp::endpoint(ip::tcp::v4(), 0));
|
||||
socket1.bind(ip::tcp::endpoint(ip::tcp::v6(), 0));
|
||||
socket1.bind(ip::tcp::endpoint(ip::tcp::v4(), 0), error_handler);
|
||||
@@ -95,6 +95,9 @@ void test()
|
||||
ip::udp::socket::native_type native_socket4 = socket1.native();
|
||||
(void)native_socket4;
|
||||
|
||||
socket1.cancel();
|
||||
socket1.cancel(error_handler);
|
||||
|
||||
socket1.bind(ip::udp::endpoint(ip::udp::v4(), 0));
|
||||
socket1.bind(ip::udp::endpoint(ip::udp::v6(), 0));
|
||||
socket1.bind(ip::udp::endpoint(ip::udp::v4(), 0), error_handler);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user