Remove asio, updating next revision

This commit is contained in:
Andrew Resch 2008-07-02 02:00:44 +00:00
parent 71555ebd0a
commit c4a4121060
266 changed files with 0 additions and 58823 deletions

View File

@ -1,4 +0,0 @@
Copyright (c) 2003-2007 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)

View File

@ -1,23 +0,0 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,803 +0,0 @@
//
// basic_datagram_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BASIC_DATAGRAM_SOCKET_HPP
#define ASIO_BASIC_DATAGRAM_SOCKET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides datagram-oriented socket functionality.
/**
* The basic_datagram_socket class template provides asynchronous and blocking
* datagram-oriented socket functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol,
typename DatagramSocketService = datagram_socket_service<Protocol> >
class basic_datagram_socket
: public basic_socket<Protocol, DatagramSocketService>
{
public:
/// The native representation of a socket.
typedef typename DatagramSocketService::native_type native_type;
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct a basic_datagram_socket without opening it.
/**
* This constructor creates a datagram socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param io_service The io_service object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
*/
explicit basic_datagram_socket(asio::io_service& io_service)
: basic_socket<Protocol, DatagramSocketService>(io_service)
{
}
/// Construct and open a basic_datagram_socket.
/**
* This constructor creates and opens a datagram socket.
*
* @param io_service The io_service object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_service& io_service,
const protocol_type& protocol)
: basic_socket<Protocol, DatagramSocketService>(io_service, protocol)
{
}
/// Construct a basic_datagram_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a datagram socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_service The io_service object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
*
* @param endpoint An endpoint on the local machine to which the datagram
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_service& io_service,
const endpoint_type& endpoint)
: basic_socket<Protocol, DatagramSocketService>(io_service, endpoint)
{
}
/// Construct a basic_datagram_socket on an existing native socket.
/**
* This constructor creates a datagram socket object to hold an existing
* native socket.
*
* @param io_service The io_service object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_service& io_service,
const protocol_type& protocol, const native_type& native_socket)
: basic_socket<Protocol, DatagramSocketService>(
io_service, protocol, native_socket)
{
}
/// Send some data on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One ore more data buffers to be sent on the socket.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @note The send operation can only be used with a connected socket. Use
* the send_to function to send data on an unconnected datagram socket.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code socket.send(asio::buffer(data, size)); @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.send(this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send some data on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One ore more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @note The send operation can only be used with a connected socket. Use
* the send_to function to send data on an unconnected datagram socket.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.send(
this->implementation, buffers, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send some data on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes sent.
*
* @note The send operation can only be used with a connected socket. Use
* the send_to function to send data on an unconnected datagram socket.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->service.send(this->implementation, buffers, flags, ec);
}
/// Start an asynchronous send on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the handler is called.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected datagram
* socket.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_send(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(const ConstBufferSequence& buffers, WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, 0, handler);
}
/// Start an asynchronous send on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the handler is called.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected datagram
* socket.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, flags, handler);
}
/// Send a datagram to the specified endpoint.
/**
* This function is used to send a datagram to the specified remote endpoint.
* The function call will block until the data has been sent successfully or
* an error occurs.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
*
* @param destination The remote endpoint to which the data will be sent.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* asio::ip::udp::endpoint destination(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* socket.send_to(asio::buffer(data, size), destination);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination)
{
asio::error_code ec;
std::size_t s = this->service.send_to(
this->implementation, buffers, destination, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send a datagram to the specified endpoint.
/**
* This function is used to send a datagram to the specified remote endpoint.
* The function call will block until the data has been sent successfully or
* an error occurs.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
*
* @param destination The remote endpoint to which the data will be sent.
*
* @param flags Flags specifying how the send call is to be made.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ConstBufferSequence>
std::size_t send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination, socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.send_to(
this->implementation, buffers, destination, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send a datagram to the specified endpoint.
/**
* This function is used to send a datagram to the specified remote endpoint.
* The function call will block until the data has been sent successfully or
* an error occurs.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
*
* @param destination The remote endpoint to which the data will be sent.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes sent.
*/
template <typename ConstBufferSequence>
std::size_t send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination, socket_base::message_flags flags,
asio::error_code& ec)
{
return this->service.send_to(this->implementation,
buffers, destination, flags, ec);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send a datagram to the specified
* remote endpoint. The function call always returns immediately.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param destination The remote endpoint to which the data will be sent.
* Copies will be made of the endpoint as required.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* asio::ip::udp::endpoint destination(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* socket.async_send_to(
* asio::buffer(data, size), destination, handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination, WriteHandler handler)
{
this->service.async_send_to(this->implementation, buffers, destination, 0,
handler);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send a datagram to the specified
* remote endpoint. The function call always returns immediately.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param destination The remote endpoint to which the data will be sent.
* Copies will be made of the endpoint as required.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination, socket_base::message_flags flags,
WriteHandler handler)
{
this->service.async_send_to(this->implementation, buffers, destination,
flags, handler);
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the datagram socket. The function
* call will block until data has been received successfully or an error
* occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure.
*
* @note The receive operation can only be used with a connected socket. Use
* the receive_from function to receive data on an unconnected datagram
* socket.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code socket.receive(asio::buffer(data, size)); @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.receive(
this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the datagram socket. The function
* call will block until data has been received successfully or an error
* occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure.
*
* @note The receive operation can only be used with a connected socket. Use
* the receive_from function to receive data on an unconnected datagram
* socket.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.receive(
this->implementation, buffers, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the datagram socket. The function
* call will block until data has been received successfully or an error
* occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes received.
*
* @note The receive operation can only be used with a connected socket. Use
* the receive_from function to receive data on an unconnected datagram
* socket.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->service.receive(this->implementation, buffers, flags, ec);
}
/// Start an asynchronous receive on a connected socket.
/**
* This function is used to asynchronously receive data from the datagram
* socket. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
* datagram socket.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(const MutableBufferSequence& buffers, ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, 0, handler);
}
/// Start an asynchronous receive on a connected socket.
/**
* This function is used to asynchronously receive data from the datagram
* socket. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
* datagram socket.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, flags, handler);
}
/// Receive a datagram with the endpoint of the sender.
/**
* This function is used to receive a datagram. The function call will block
* until data has been received successfully or an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* asio::ip::udp::endpoint sender_endpoint;
* socket.receive_from(
* asio::buffer(data, size), sender_endpoint);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint)
{
asio::error_code ec;
std::size_t s = this->service.receive_from(
this->implementation, buffers, sender_endpoint, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive a datagram with the endpoint of the sender.
/**
* This function is used to receive a datagram. The function call will block
* until data has been received successfully or an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename MutableBufferSequence>
std::size_t receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint, socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.receive_from(
this->implementation, buffers, sender_endpoint, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive a datagram with the endpoint of the sender.
/**
* This function is used to receive a datagram. The function call will block
* until data has been received successfully or an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes received.
*/
template <typename MutableBufferSequence>
std::size_t receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint, socket_base::message_flags flags,
asio::error_code& ec)
{
return this->service.receive_from(this->implementation, buffers,
sender_endpoint, flags, ec);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive a datagram. The function
* call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram. Ownership of the sender_endpoint object
* is retained by the caller, which must guarantee that it is valid until the
* handler is called.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code socket.async_receive_from(
* asio::buffer(data, size), 0, sender_endpoint, handler); @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint, ReadHandler handler)
{
this->service.async_receive_from(this->implementation, buffers,
sender_endpoint, 0, handler);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive a datagram. The function
* call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram. Ownership of the sender_endpoint object
* is retained by the caller, which must guarantee that it is valid until the
* handler is called.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint, socket_base::message_flags flags,
ReadHandler handler)
{
this->service.async_receive_from(this->implementation, buffers,
sender_endpoint, flags, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_DATAGRAM_SOCKET_HPP

View File

@ -1,381 +0,0 @@
//
// basic_deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BASIC_DEADLINE_TIMER_HPP
#define ASIO_BASIC_DEADLINE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides waitable timer functionality.
/**
* The basic_deadline_timer class template provides the ability to perform a
* blocking or asynchronous wait for a timer to expire.
*
* Most applications will use the asio::deadline_timer typedef.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Examples
* Performing a blocking wait:
* @code
* // Construct a timer without setting an expiry time.
* asio::deadline_timer timer(io_service);
*
* // Set an expiry time relative to now.
* timer.expires_from_now(boost::posix_time::seconds(5));
*
* // Wait for the timer to expire.
* timer.wait();
* @endcode
*
* @par
* Performing an asynchronous wait:
* @code
* void handler(const asio::error_code& error)
* {
* if (!error)
* {
* // Timer expired.
* }
* }
*
* ...
*
* // Construct a timer with an absolute expiry time.
* asio::deadline_timer timer(io_service,
* boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
*
* // Start an asynchronous wait.
* timer.async_wait(handler);
* @endcode
*
* @par Changing an active deadline_timer's expiry time
*
* Changing the expiry time of a timer while there are pending asynchronous
* waits causes those wait operations to be cancelled. To ensure that the action
* associated with the timer is performed only once, use something like this:
* used:
*
* @code
* void on_some_event()
* {
* if (my_timer.expires_from_now(seconds(5)) > 0)
* {
* // We managed to cancel the timer. Start new asynchronous wait.
* my_timer.async_wait(on_timeout);
* }
* else
* {
* // Too late, timer has already expired!
* }
* }
*
* void on_timeout(const asio::error_code& e)
* {
* if (e != asio::error::operation_aborted)
* {
* // Timer was not cancelled, take necessary action.
* }
* }
* @endcode
*
* @li The asio::basic_deadline_timer::expires_from_now() function
* cancels any pending asynchronous waits, and returns the number of
* asynchronous waits that were cancelled. If it returns 0 then you were too
* late and the wait handler has already been executed, or will soon be
* executed. If it returns 1 then the wait handler was successfully cancelled.
*
* @li If a wait handler is cancelled, the asio::error_code passed to
* it contains the value asio::error::operation_aborted.
*/
template <typename Time,
typename TimeTraits = asio::time_traits<Time>,
typename TimerService = deadline_timer_service<Time, TimeTraits> >
class basic_deadline_timer
: public basic_io_object<TimerService>
{
public:
/// The time traits type.
typedef TimeTraits traits_type;
/// The time type.
typedef typename traits_type::time_type time_type;
/// The duration type.
typedef typename traits_type::duration_type duration_type;
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param io_service The io_service object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
*/
explicit basic_deadline_timer(asio::io_service& io_service)
: basic_io_object<TimerService>(io_service)
{
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_service The io_service object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_deadline_timer(asio::io_service& io_service,
const time_type& expiry_time)
: basic_io_object<TimerService>(io_service)
{
asio::error_code ec;
this->service.expires_at(this->implementation, expiry_time, ec);
asio::detail::throw_error(ec);
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_service The io_service object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_deadline_timer(asio::io_service& io_service,
const duration_type& expiry_time)
: basic_io_object<TimerService>(io_service)
{
asio::error_code ec;
this->service.expires_from_now(this->implementation, expiry_time, ec);
asio::detail::throw_error(ec);
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*/
std::size_t cancel()
{
asio::error_code ec;
std::size_t s = this->service.cancel(this->implementation, ec);
asio::detail::throw_error(ec);
return s;
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*/
std::size_t cancel(asio::error_code& ec)
{
return this->service.cancel(this->implementation, ec);
}
/// Get the timer's expiry time as an absolute time.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
time_type expires_at() const
{
return this->service.expires_at(this->implementation);
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*/
std::size_t expires_at(const time_type& expiry_time)
{
asio::error_code ec;
std::size_t s = this->service.expires_at(
this->implementation, expiry_time, ec);
asio::detail::throw_error(ec);
return s;
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*/
std::size_t expires_at(const time_type& expiry_time,
asio::error_code& ec)
{
return this->service.expires_at(this->implementation, expiry_time, ec);
}
/// Get the timer's expiry time relative to now.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
duration_type expires_from_now() const
{
return this->service.expires_from_now(this->implementation);
}
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*/
std::size_t expires_from_now(const duration_type& expiry_time)
{
asio::error_code ec;
std::size_t s = this->service.expires_from_now(
this->implementation, expiry_time, ec);
asio::detail::throw_error(ec);
return s;
}
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*/
std::size_t expires_from_now(const duration_type& expiry_time,
asio::error_code& ec)
{
return this->service.expires_from_now(
this->implementation, expiry_time, ec);
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @throws asio::system_error Thrown on failure.
*/
void wait()
{
asio::error_code ec;
this->service.wait(this->implementation, ec);
asio::detail::throw_error(ec);
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @param ec Set to indicate what error occurred, if any.
*/
void wait(asio::error_code& ec)
{
this->service.wait(this->implementation, ec);
}
/// Start an asynchronous wait on the timer.
/**
* This function may be used to initiate an asynchronous wait against the
* timer. It always returns immediately.
*
* For each call to async_wait(), the supplied handler will be called exactly
* once. The handler will be called when:
*
* @li The timer has expired.
*
* @li The timer was cancelled, in which case the handler is passed the error
* code asio::error::operation_aborted.
*
* @param handler The handler to be called when the timer expires. Copies
* will be made of the handler as required. The function signature of the
* handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*/
template <typename WaitHandler>
void async_wait(WaitHandler handler)
{
this->service.async_wait(this->implementation, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_DEADLINE_TIMER_HPP

View File

@ -1,89 +0,0 @@
//
// basic_io_object.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BASIC_IO_OBJECT_HPP
#define ASIO_BASIC_IO_OBJECT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Base class for all I/O objects.
template <typename IoObjectService>
class basic_io_object
: private noncopyable
{
public:
/// The type of the service that will be used to provide I/O operations.
typedef IoObjectService service_type;
/// The underlying implementation type of I/O object.
typedef typename service_type::implementation_type implementation_type;
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object.
/**
* This function may be used to obtain the io_service object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_service object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_service& io_service()
{
return service.get_io_service();
}
/// Get the io_service associated with the object.
/**
* This function may be used to obtain the io_service object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_service object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_service& get_io_service()
{
return service.get_io_service();
}
protected:
/// Construct a basic_io_object.
explicit basic_io_object(asio::io_service& io_service)
: service(asio::use_service<IoObjectService>(io_service))
{
service.construct(implementation);
}
/// Protected destructor to prevent deletion through this type.
~basic_io_object()
{
service.destroy(implementation);
}
// The backend service implementation.
service_type& service;
// The underlying native implementation.
implementation_type implementation;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_IO_OBJECT_HPP

View File

@ -1,252 +0,0 @@
//
// basic_resolver.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 ASIO_BASIC_RESOLVER_HPP
#define ASIO_BASIC_RESOLVER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/error.hpp"
#include "asio/error_handler.hpp"
#include "asio/resolver_service.hpp"
namespace asio {
/// Provides endpoint resolution functionality.
/**
* The basic_resolver class template provides the ability to resolve a query
* to a list of endpoints.
*
* @par Thread Safety:
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* Async_Object, Error_Source.
*/
template <typename Protocol, typename Service = resolver_service<Protocol> >
class basic_resolver
: public basic_io_object<Service>
{
public:
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// The query type.
typedef typename Protocol::resolver_query query;
/// The iterator type.
typedef typename Protocol::resolver_iterator iterator;
/// The type used for reporting errors.
typedef asio::error error_type;
/// Constructor.
/**
* This constructor creates a basic_resolver.
*
* @param io_service The io_service object that the resolver will use to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_resolver(asio::io_service& io_service)
: basic_io_object<Service>(io_service)
{
}
/// Cancel any asynchronous operations that are waiting on the resolver.
/**
* This function forces the completion of any pending asynchronous
* operations on the host resolver. The handler for each cancelled operation
* will be invoked with the asio::error::operation_aborted error code.
*/
void cancel()
{
return this->service.cancel(this->implementation);
}
/// Resolve a query to a list of entries.
/**
* This function is used to resolve a query into a list of endpoint entries.
*
* @param q A query object that determines what endpoints will be returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries.
*
* @throws asio::error Thrown on failure.
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
iterator resolve(const query& q)
{
return this->service.resolve(this->implementation, q, throw_error());
}
/// Resolve a query to a list of entries.
/**
* This function is used to resolve a query into a list of endpoint entries.
*
* @param q A query object that determines what endpoints will be returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries. Returns a default constructed iterator if an error
* occurs.
*
* @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 asio::error& error // Result of operation.
* ); @endcode
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
template <typename Error_Handler>
iterator resolve(const query& q, Error_Handler error_handler)
{
return this->service.resolve(this->implementation, q, error_handler);
}
/// Asynchronously resolve a query to a list of entries.
/**
* This function is used to asynchronously resolve a query into a list of
* endpoint entries.
*
* @param q A query object that determines what endpoints will be returned.
*
* @param handler The handler to be called when the resolve operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error& error, // Result of operation.
* resolver::iterator iterator // Forward-only iterator that can be used to
* // traverse the list of endpoint entries.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful resolve operation is guaranteed to pass at least one
* entry to the handler.
*/
template <typename Handler>
void async_resolve(const query& q, Handler handler)
{
return this->service.async_resolve(this->implementation, q, handler);
}
/// Resolve an endpoint to a list of entries.
/**
* This function is used to resolve an endpoint into a list of endpoint
* entries.
*
* @param e An endpoint object that determines what endpoints will be
* returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries.
*
* @throws asio::error Thrown on failure.
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
iterator resolve(const endpoint_type& e)
{
return this->service.resolve(this->implementation, e, throw_error());
}
/// Resolve an endpoint to a list of entries.
/**
* This function is used to resolve an endpoint into a list of endpoint
* entries.
*
* @param e An endpoint object that determines what endpoints will be
* returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries. Returns a default constructed iterator if an error
* occurs.
*
* @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 asio::error& error // Result of operation.
* ); @endcode
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
template <typename Error_Handler>
iterator resolve(const endpoint_type& e, Error_Handler error_handler)
{
return this->service.resolve(this->implementation, e, error_handler);
}
/// Asynchronously resolve an endpoint to a list of entries.
/**
* This function is used to asynchronously resolve an endpoint into a list of
* endpoint entries.
*
* @param e An endpoint object that determines what endpoints will be
* returned.
*
* @param handler The handler to be called when the resolve operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error& error, // Result of operation.
* resolver::iterator iterator // Forward-only iterator that can be used to
* // traverse the list of endpoint entries.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful resolve operation is guaranteed to pass at least one
* entry to the handler.
*/
template <typename Handler>
void async_resolve(const endpoint_type& e, Handler handler)
{
return this->service.async_resolve(this->implementation, e, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_RESOLVER_HPP

File diff suppressed because it is too large Load Diff

View File

@ -1,824 +0,0 @@
//
// basic_socket_acceptor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BASIC_SOCKET_ACCEPTOR_HPP
#define ASIO_BASIC_SOCKET_ACCEPTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/basic_socket.hpp"
#include "asio/error.hpp"
#include "asio/socket_acceptor_service.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides the ability to accept new connections.
/**
* The basic_socket_acceptor class template is used for accepting new socket
* connections.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Example
* Opening a socket acceptor with the SO_REUSEADDR option enabled:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port);
* acceptor.open(endpoint.protocol());
* acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
* acceptor.bind(endpoint);
* acceptor.listen();
* @endcode
*/
template <typename Protocol,
typename SocketAcceptorService = socket_acceptor_service<Protocol> >
class basic_socket_acceptor
: public basic_io_object<SocketAcceptorService>,
public socket_base
{
public:
/// The native representation of an acceptor.
typedef typename SocketAcceptorService::native_type native_type;
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct an acceptor without opening it.
/**
* This constructor creates an acceptor without opening it to listen for new
* connections. The open() function must be called before the acceptor can
* accept new socket connections.
*
* @param io_service The io_service object that the acceptor will use to
* dispatch handlers for any asynchronous operations performed on the
* acceptor.
*/
explicit basic_socket_acceptor(asio::io_service& io_service)
: basic_io_object<SocketAcceptorService>(io_service)
{
}
/// Construct an open acceptor.
/**
* This constructor creates an acceptor and automatically opens it.
*
* @param io_service The io_service object that the acceptor will use to
* dispatch handlers for any asynchronous operations performed on the
* acceptor.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket_acceptor(asio::io_service& io_service,
const protocol_type& protocol)
: basic_io_object<SocketAcceptorService>(io_service)
{
asio::error_code ec;
this->service.open(this->implementation, protocol, ec);
asio::detail::throw_error(ec);
}
/// Construct an acceptor opened on the given endpoint.
/**
* This constructor creates an acceptor and automatically opens it to listen
* for new connections on the specified endpoint.
*
* @param io_service The io_service object that the acceptor will use to
* dispatch handlers for any asynchronous operations performed on the
* acceptor.
*
* @param endpoint An endpoint on the local machine on which the acceptor
* will listen for new connections.
*
* @param reuse_addr Whether the constructor should set the socket option
* socket_base::reuse_address.
*
* @throws asio::system_error Thrown on failure.
*
* @note This constructor is equivalent to the following code:
* @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(asio::io_service& io_service,
const endpoint_type& endpoint, bool reuse_addr = true)
: basic_io_object<SocketAcceptorService>(io_service)
{
asio::error_code ec;
this->service.open(this->implementation, endpoint.protocol(), ec);
asio::detail::throw_error(ec);
if (reuse_addr)
{
this->service.set_option(this->implementation,
socket_base::reuse_address(true), ec);
asio::detail::throw_error(ec);
}
this->service.bind(this->implementation, endpoint, ec);
asio::detail::throw_error(ec);
this->service.listen(this->implementation,
socket_base::max_connections, ec);
asio::detail::throw_error(ec);
}
/// Construct a basic_socket_acceptor on an existing native acceptor.
/**
* This constructor creates an acceptor object to hold an existing native
* acceptor.
*
* @param io_service The io_service object that the acceptor will use to
* dispatch handlers for any asynchronous operations performed on the
* acceptor.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_acceptor A native acceptor.
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket_acceptor(asio::io_service& io_service,
const protocol_type& protocol, const native_type& native_acceptor)
: basic_io_object<SocketAcceptorService>(io_service)
{
asio::error_code ec;
this->service.assign(this->implementation, protocol, native_acceptor, ec);
asio::detail::throw_error(ec);
}
/// Open the acceptor using the specified protocol.
/**
* This function opens the socket acceptor so that it will use the specified
* protocol.
*
* @param protocol An object specifying which protocol is to be used.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* acceptor.open(asio::ip::tcp::v4());
* @endcode
*/
void open(const protocol_type& protocol = protocol_type())
{
asio::error_code ec;
this->service.open(this->implementation, protocol, ec);
asio::detail::throw_error(ec);
}
/// Open the acceptor using the specified protocol.
/**
* This function opens the socket acceptor so that it will use the specified
* protocol.
*
* @param protocol An object specifying which protocol is to be used.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* asio::error_code ec;
* acceptor.open(asio::ip::tcp::v4(), ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code open(const protocol_type& protocol,
asio::error_code& ec)
{
return this->service.open(this->implementation, protocol, ec);
}
/// Assigns an existing native acceptor to the acceptor.
/*
* This function opens the acceptor to hold an existing native acceptor.
*
* @param protocol An object specifying which protocol is to be used.
*
* @param native_acceptor A native acceptor.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const protocol_type& protocol, const native_type& native_acceptor)
{
asio::error_code ec;
this->service.assign(this->implementation, protocol, native_acceptor, ec);
asio::detail::throw_error(ec);
}
/// Assigns an existing native acceptor to the acceptor.
/*
* This function opens the acceptor to hold an existing native acceptor.
*
* @param protocol An object specifying which protocol is to be used.
*
* @param native_acceptor A native acceptor.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code assign(const protocol_type& protocol,
const native_type& native_acceptor, asio::error_code& ec)
{
return this->service.assign(this->implementation,
protocol, native_acceptor, ec);
}
/// Determine whether the acceptor is open.
bool is_open() const
{
return this->service.is_open(this->implementation);
}
/// Bind the acceptor to the given local endpoint.
/**
* This function binds the socket acceptor to the specified endpoint on the
* local machine.
*
* @param endpoint An endpoint on the local machine to which the socket
* acceptor will be bound.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* acceptor.open(asio::ip::tcp::v4());
* acceptor.bind(asio::ip::tcp::endpoint(12345));
* @endcode
*/
void bind(const endpoint_type& endpoint)
{
asio::error_code ec;
this->service.bind(this->implementation, endpoint, ec);
asio::detail::throw_error(ec);
}
/// Bind the acceptor to the given local endpoint.
/**
* This function binds the socket acceptor to the specified endpoint on the
* local machine.
*
* @param endpoint An endpoint on the local machine to which the socket
* acceptor will be bound.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* acceptor.open(asio::ip::tcp::v4());
* asio::error_code ec;
* acceptor.bind(asio::ip::tcp::endpoint(12345), ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code bind(const endpoint_type& endpoint,
asio::error_code& ec)
{
return this->service.bind(this->implementation, endpoint, ec);
}
/// Place the acceptor into the state where it will listen for new
/// connections.
/**
* 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.
*
* @throws asio::system_error Thrown on failure.
*/
void listen(int backlog = socket_base::max_connections)
{
asio::error_code ec;
this->service.listen(this->implementation, backlog, ec);
asio::detail::throw_error(ec);
}
/// Place the acceptor into the state where it will listen for new
/// connections.
/**
* 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.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::error_code ec;
* acceptor.listen(asio::socket_base::max_connections, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code listen(int backlog, asio::error_code& ec)
{
return this->service.listen(this->implementation, backlog, ec);
}
/// Close the acceptor.
/**
* This function is used to close the acceptor. Any asynchronous accept
* operations will be cancelled immediately.
*
* A subsequent call to open() is required before the acceptor can again be
* used to again perform socket accept operations.
*
* @throws asio::system_error Thrown on failure.
*/
void close()
{
asio::error_code ec;
this->service.close(this->implementation, ec);
asio::detail::throw_error(ec);
}
/// Close the acceptor.
/**
* This function is used to close the acceptor. Any asynchronous accept
* operations will be cancelled immediately.
*
* A subsequent call to open() is required before the acceptor can again be
* used to again perform socket accept operations.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::error_code ec;
* acceptor.close(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code close(asio::error_code& ec)
{
return this->service.close(this->implementation, ec);
}
/// Get the native acceptor representation.
/**
* This function may be used to obtain the underlying representation of the
* acceptor. This is intended to allow access to native acceptor functionality
* that is not otherwise provided.
*/
native_type native()
{
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 asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
this->service.cancel(this->implementation, ec);
asio::detail::throw_error(ec);
}
/// 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 asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code cancel(asio::error_code& ec)
{
return this->service.cancel(this->implementation, ec);
}
/// Set an option on the acceptor.
/**
* This function is used to set an option on the acceptor.
*
* @param option The new option value to be set on the acceptor.
*
* @throws asio::system_error Thrown on failure.
*
* @sa SettableSocketOption @n
* asio::socket_base::reuse_address
* asio::socket_base::enable_connection_aborted
*
* @par Example
* Setting the SOL_SOCKET/SO_REUSEADDR option:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::acceptor::reuse_address option(true);
* acceptor.set_option(option);
* @endcode
*/
template <typename SettableSocketOption>
void set_option(const SettableSocketOption& option)
{
asio::error_code ec;
this->service.set_option(this->implementation, option, ec);
asio::detail::throw_error(ec);
}
/// Set an option on the acceptor.
/**
* This function is used to set an option on the acceptor.
*
* @param option The new option value to be set on the acceptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa SettableSocketOption @n
* asio::socket_base::reuse_address
* asio::socket_base::enable_connection_aborted
*
* @par Example
* Setting the SOL_SOCKET/SO_REUSEADDR option:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::acceptor::reuse_address option(true);
* asio::error_code ec;
* acceptor.set_option(option, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
template <typename SettableSocketOption>
asio::error_code set_option(const SettableSocketOption& option,
asio::error_code& ec)
{
return this->service.set_option(this->implementation, option, ec);
}
/// Get an option from the acceptor.
/**
* This function is used to get the current value of an option on the
* acceptor.
*
* @param option The option value to be obtained from the acceptor.
*
* @throws asio::system_error Thrown on failure.
*
* @sa GettableSocketOption @n
* asio::socket_base::reuse_address
*
* @par Example
* Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::acceptor::reuse_address option;
* acceptor.get_option(option);
* bool is_set = option.get();
* @endcode
*/
template <typename GettableSocketOption>
void get_option(GettableSocketOption& option)
{
asio::error_code ec;
this->service.get_option(this->implementation, option, ec);
asio::detail::throw_error(ec);
}
/// Get an option from the acceptor.
/**
* This function is used to get the current value of an option on the
* acceptor.
*
* @param option The option value to be obtained from the acceptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa GettableSocketOption @n
* asio::socket_base::reuse_address
*
* @par Example
* Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::acceptor::reuse_address option;
* asio::error_code ec;
* acceptor.get_option(option, ec);
* if (ec)
* {
* // An error occurred.
* }
* bool is_set = option.get();
* @endcode
*/
template <typename GettableSocketOption>
asio::error_code get_option(GettableSocketOption& option,
asio::error_code& ec)
{
return this->service.get_option(this->implementation, option, ec);
}
/// Get the local endpoint of the acceptor.
/**
* This function is used to obtain the locally bound endpoint of the acceptor.
*
* @returns An object that represents the local endpoint of the acceptor.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint();
* @endcode
*/
endpoint_type local_endpoint() const
{
asio::error_code ec;
endpoint_type ep = this->service.local_endpoint(this->implementation, ec);
asio::detail::throw_error(ec);
return ep;
}
/// Get the local endpoint of the acceptor.
/**
* This function is used to obtain the locally bound endpoint of the acceptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns An object that represents the local endpoint of the acceptor.
* Returns a default-constructed endpoint object if an error occurred and the
* error handler did not throw an exception.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::error_code ec;
* asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
endpoint_type local_endpoint(asio::error_code& ec) const
{
return this->service.local_endpoint(this->implementation, ec);
}
/// Accept a new connection.
/**
* This function is used to accept a new connection from a peer into the
* given socket. The function call will block until a new connection has been
* accepted successfully or an error occurs.
*
* @param peer The socket into which the new connection will be accepted.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::socket socket(io_service);
* acceptor.accept(socket);
* @endcode
*/
template <typename SocketService>
void accept(basic_socket<protocol_type, SocketService>& peer)
{
asio::error_code ec;
this->service.accept(this->implementation, peer, 0, ec);
asio::detail::throw_error(ec);
}
/// Accept a new connection.
/**
* This function is used to accept a new connection from a peer into the
* given socket. The function call will block until a new connection has been
* accepted successfully or an error occurs.
*
* @param peer The socket into which the new connection will be accepted.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::soocket socket(io_service);
* asio::error_code ec;
* acceptor.accept(socket, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
template <typename SocketService>
asio::error_code accept(
basic_socket<protocol_type, SocketService>& peer,
asio::error_code& ec)
{
return this->service.accept(this->implementation, peer, 0, ec);
}
/// Start an asynchronous accept.
/**
* This function is used to asynchronously accept a new connection into a
* socket. The function call always returns immediately.
*
* @param peer The socket into which the new connection will be accepted.
* Ownership of the peer object is retained by the caller, which must
* guarantee that it is valid until the handler is called.
*
* @param handler The handler to be called when the accept operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @par Example
* @code
* void accept_handler(const asio::error_code& error)
* {
* if (!error)
* {
* // Accept succeeded.
* }
* }
*
* ...
*
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::socket socket(io_service);
* acceptor.async_accept(socket, accept_handler);
* @endcode
*/
template <typename SocketService, typename AcceptHandler>
void async_accept(basic_socket<protocol_type, SocketService>& peer,
AcceptHandler handler)
{
this->service.async_accept(this->implementation, peer, 0, handler);
}
/// Accept a new connection and obtain the endpoint of the peer
/**
* This function is used to accept a new connection from a peer into the
* given socket, and additionally provide the endpoint of the remote peer.
* The function call will block until a new connection has been accepted
* successfully or an error occurs.
*
* @param peer The socket into which the new connection will be accepted.
*
* @param peer_endpoint An endpoint object which will receive the endpoint of
* the remote peer.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::socket socket(io_service);
* asio::ip::tcp::endpoint endpoint;
* acceptor.accept(socket, endpoint);
* @endcode
*/
template <typename SocketService>
void accept(basic_socket<protocol_type, SocketService>& peer,
endpoint_type& peer_endpoint)
{
asio::error_code ec;
this->service.accept(this->implementation, peer, &peer_endpoint, ec);
asio::detail::throw_error(ec);
}
/// Accept a new connection and obtain the endpoint of the peer
/**
* This function is used to accept a new connection from a peer into the
* given socket, and additionally provide the endpoint of the remote peer.
* The function call will block until a new connection has been accepted
* successfully or an error occurs.
*
* @param peer The socket into which the new connection will be accepted.
*
* @param peer_endpoint An endpoint object which will receive the endpoint of
* the remote peer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::socket socket(io_service);
* asio::ip::tcp::endpoint endpoint;
* asio::error_code ec;
* acceptor.accept(socket, endpoint, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
template <typename SocketService>
asio::error_code accept(
basic_socket<protocol_type, SocketService>& peer,
endpoint_type& peer_endpoint, asio::error_code& ec)
{
return this->service.accept(this->implementation, peer, &peer_endpoint, ec);
}
/// Start an asynchronous accept.
/**
* This function is used to asynchronously accept a new connection into a
* socket, and additionally obtain the endpoint of the remote peer. The
* function call always returns immediately.
*
* @param peer The socket into which the new connection will be accepted.
* Ownership of the peer object is retained by the caller, which must
* guarantee that it is valid until the handler is called.
*
* @param peer_endpoint An endpoint object into which the endpoint of the
* remote peer will be written. Ownership of the peer_endpoint object is
* retained by the caller, which must guarantee that it is valid until the
* handler is called.
*
* @param handler The handler to be called when the accept operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*/
template <typename SocketService, typename AcceptHandler>
void async_accept(basic_socket<protocol_type, SocketService>& peer,
endpoint_type& peer_endpoint, AcceptHandler handler)
{
this->service.async_accept(this->implementation,
peer, &peer_endpoint, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP

View File

@ -1,148 +0,0 @@
//
// basic_socket_iostream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BASIC_SOCKET_IOSTREAM_HPP
#define ASIO_BASIC_SOCKET_IOSTREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/utility/base_from_member.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket_streambuf.hpp"
#include "asio/stream_socket_service.hpp"
#if !defined(ASIO_SOCKET_IOSTREAM_MAX_ARITY)
#define ASIO_SOCKET_IOSTREAM_MAX_ARITY 5
#endif // !defined(ASIO_SOCKET_IOSTREAM_MAX_ARITY)
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// explicit basic_socket_iostream(T1 x1, ..., Tn xn)
// : basic_iostream<char>(&this->boost::base_from_member<
// basic_socket_streambuf<Protocol, StreamSocketService> >::member)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
// }
// This macro should only persist within this file.
#define ASIO_PRIVATE_CTR_DEF(z, n, data) \
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_socket_streambuf<Protocol, StreamSocketService> >::member) \
{ \
tie(this); \
if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \
this->setstate(std::ios_base::failbit); \
} \
/**/
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// void connect(T1 x1, ..., Tn xn)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
// }
// This macro should only persist within this file.
#define ASIO_PRIVATE_CONNECT_DEF(z, n, data) \
template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
void connect(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
{ \
if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \
this->setstate(std::ios_base::failbit); \
} \
/**/
namespace asio {
/// Iostream interface for a socket.
template <typename Protocol,
typename StreamSocketService = stream_socket_service<Protocol> >
class basic_socket_iostream
: public boost::base_from_member<
basic_socket_streambuf<Protocol, StreamSocketService> >,
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_socket_streambuf<Protocol, StreamSocketService> >::member)
{
tie(this);
}
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
* This constructor automatically establishes a connection based on the
* supplied resolver query parameters. The arguments are used to construct
* a resolver query object.
*/
template <typename T1, ..., typename TN>
explicit basic_socket_iostream(T1 t1, ..., TN tn);
#else
BOOST_PP_REPEAT_FROM_TO(
1, BOOST_PP_INC(ASIO_SOCKET_IOSTREAM_MAX_ARITY),
ASIO_PRIVATE_CTR_DEF, _ )
#endif
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
* This function automatically establishes a connection based on the supplied
* resolver query parameters. The arguments are used to construct a resolver
* query object.
*/
template <typename T1, ..., typename TN>
void connect(T1 t1, ..., TN tn);
#else
BOOST_PP_REPEAT_FROM_TO(
1, BOOST_PP_INC(ASIO_SOCKET_IOSTREAM_MAX_ARITY),
ASIO_PRIVATE_CONNECT_DEF, _ )
#endif
/// Close the connection.
void close()
{
if (rdbuf()->close() == 0)
this->setstate(std::ios_base::failbit);
}
/// Return a pointer to the underlying streambuf.
basic_socket_streambuf<Protocol, StreamSocketService>* rdbuf() const
{
return const_cast<basic_socket_streambuf<Protocol, StreamSocketService>*>(
&this->boost::base_from_member<
basic_socket_streambuf<Protocol, StreamSocketService> >::member);
}
};
} // namespace asio
#undef ASIO_PRIVATE_CTR_DEF
#undef ASIO_PRIVATE_CONNECT_DEF
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP

View File

@ -1,284 +0,0 @@
//
// basic_socket_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BASIC_SOCKET_STREAMBUF_HPP
#define ASIO_BASIC_SOCKET_STREAMBUF_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <streambuf>
#include <boost/array.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/utility/base_from_member.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/io_service.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/detail/throw_error.hpp"
#if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
#define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
#endif // !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// basic_socket_streambuf<Protocol, StreamSocketService>* connect(
// T1 x1, ..., Tn xn)
// {
// init_buffers();
// asio::error_code ec;
// this->basic_socket<Protocol, StreamSocketService>::close(ec);
// typedef typename Protocol::resolver_query resolver_query;
// resolver_query query(x1, ..., xn);
// resolve_and_connect(query, ec);
// return !ec ? this : 0;
// }
// This macro should only persist within this file.
#define ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \
template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
basic_socket_streambuf<Protocol, StreamSocketService>* connect( \
BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
{ \
init_buffers(); \
asio::error_code ec; \
this->basic_socket<Protocol, StreamSocketService>::close(ec); \
typedef typename Protocol::resolver_query resolver_query; \
resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \
resolve_and_connect(query, ec); \
return !ec ? this : 0; \
} \
/**/
namespace asio {
/// Iostream streambuf for a socket.
template <typename Protocol,
typename StreamSocketService = stream_socket_service<Protocol> >
class basic_socket_streambuf
: public std::streambuf,
private boost::base_from_member<io_service>,
public basic_socket<Protocol, StreamSocketService>
{
public:
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct a basic_socket_streambuf without establishing a connection.
basic_socket_streambuf()
: basic_socket<Protocol, StreamSocketService>(
boost::base_from_member<asio::io_service>::member),
unbuffered_(false)
{
init_buffers();
}
/// Destructor flushes buffered data.
virtual ~basic_socket_streambuf()
{
if (pptr() != pbase())
overflow(traits_type::eof());
}
/// Establish a connection.
/**
* This function establishes a connection to the specified endpoint.
*
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf<Protocol, StreamSocketService>* connect(
const endpoint_type& endpoint)
{
init_buffers();
asio::error_code ec;
this->basic_socket<Protocol, StreamSocketService>::close(ec);
this->basic_socket<Protocol, StreamSocketService>::connect(endpoint, ec);
return !ec ? this : 0;
}
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection.
/**
* This function automatically establishes a connection based on the supplied
* resolver query parameters. The arguments are used to construct a resolver
* query object.
*
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
template <typename T1, ..., typename TN>
basic_socket_streambuf<Protocol, StreamSocketService>* connect(
T1 t1, ..., TN tn);
#else
BOOST_PP_REPEAT_FROM_TO(
1, BOOST_PP_INC(ASIO_SOCKET_STREAMBUF_MAX_ARITY),
ASIO_PRIVATE_CONNECT_DEF, _ )
#endif
/// Close the connection.
/**
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf<Protocol, StreamSocketService>* close()
{
asio::error_code ec;
sync();
this->basic_socket<Protocol, StreamSocketService>::close(ec);
if (!ec)
init_buffers();
return !ec ? this : 0;
}
protected:
int_type underflow()
{
if (gptr() == egptr())
{
asio::error_code ec;
std::size_t bytes_transferred = this->service.receive(
this->implementation,
asio::buffer(asio::buffer(get_buffer_) + putback_max),
0, ec);
if (ec)
return traits_type::eof();
setg(get_buffer_.begin(), get_buffer_.begin() + putback_max,
get_buffer_.begin() + putback_max + bytes_transferred);
return traits_type::to_int_type(*gptr());
}
else
{
return traits_type::eof();
}
}
int_type overflow(int_type c)
{
if (unbuffered_)
{
if (traits_type::eq_int_type(c, traits_type::eof()))
{
// Nothing to do.
return traits_type::not_eof(c);
}
else
{
// Send the single character immediately.
asio::error_code ec;
char_type ch = traits_type::to_char_type(c);
this->service.send(this->implementation,
asio::buffer(&ch, sizeof(char_type)), 0, ec);
if (ec)
return traits_type::eof();
return c;
}
}
else
{
// Send all data in the output buffer.
asio::const_buffer buffer =
asio::buffer(pbase(), pptr() - pbase());
while (asio::buffer_size(buffer) > 0)
{
asio::error_code ec;
std::size_t bytes_transferred = this->service.send(
this->implementation, asio::buffer(buffer),
0, ec);
if (ec)
return traits_type::eof();
buffer = buffer + bytes_transferred;
}
setp(put_buffer_.begin(), put_buffer_.end());
// If the new character is eof then our work here is done.
if (traits_type::eq_int_type(c, traits_type::eof()))
return traits_type::not_eof(c);
// Add the new character to the output buffer.
*pptr() = traits_type::to_char_type(c);
pbump(1);
return c;
}
}
int sync()
{
return overflow(traits_type::eof());
}
std::streambuf* setbuf(char_type* s, std::streamsize n)
{
if (pptr() == pbase() && s == 0 && n == 0)
{
unbuffered_ = true;
setp(0, 0);
return this;
}
return 0;
}
private:
void init_buffers()
{
setg(get_buffer_.begin(),
get_buffer_.begin() + putback_max,
get_buffer_.begin() + putback_max);
if (unbuffered_)
setp(0, 0);
else
setp(put_buffer_.begin(), put_buffer_.end());
}
void resolve_and_connect(const typename Protocol::resolver_query& query,
asio::error_code& ec)
{
typedef typename Protocol::resolver resolver_type;
typedef typename Protocol::resolver_iterator iterator_type;
resolver_type resolver(
boost::base_from_member<asio::io_service>::member);
iterator_type i = resolver.resolve(query, ec);
if (!ec)
{
iterator_type end;
ec = asio::error::host_not_found;
while (ec && i != end)
{
this->basic_socket<Protocol, StreamSocketService>::close();
this->basic_socket<Protocol, StreamSocketService>::connect(*i, ec);
++i;
}
}
}
enum { putback_max = 8 };
enum { buffer_size = 512 };
boost::array<char, buffer_size> get_buffer_;
boost::array<char, buffer_size> put_buffer_;
bool unbuffered_;
};
} // namespace asio
#undef ASIO_PRIVATE_CONNECT_DEF
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP

View File

@ -1,718 +0,0 @@
//
// basic_stream_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BASIC_STREAM_SOCKET_HPP
#define ASIO_BASIC_STREAM_SOCKET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/error.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides stream-oriented socket functionality.
/**
* The basic_stream_socket class template provides asynchronous and blocking
* stream-oriented socket functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Protocol,
typename StreamSocketService = stream_socket_service<Protocol> >
class basic_stream_socket
: public basic_socket<Protocol, StreamSocketService>
{
public:
/// The native representation of a socket.
typedef typename StreamSocketService::native_type native_type;
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct a basic_stream_socket without opening it.
/**
* This constructor creates a stream socket without opening it. The socket
* needs to be opened and then connected or accepted before data can be sent
* or received on it.
*
* @param io_service The io_service object that the stream socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_stream_socket(asio::io_service& io_service)
: basic_socket<Protocol, StreamSocketService>(io_service)
{
}
/// Construct and open a basic_stream_socket.
/**
* This constructor creates and opens a stream socket. The socket needs to be
* connected or accepted before data can be sent or received on it.
*
* @param io_service The io_service object that the stream socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_service& io_service,
const protocol_type& protocol)
: basic_socket<Protocol, StreamSocketService>(io_service, protocol)
{
}
/// Construct a basic_stream_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a stream socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_service The io_service object that the stream socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the stream
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_service& io_service,
const endpoint_type& endpoint)
: basic_socket<Protocol, StreamSocketService>(io_service, endpoint)
{
}
/// Construct a basic_stream_socket on an existing native socket.
/**
* This constructor creates a stream socket object to hold an existing native
* socket.
*
* @param io_service The io_service object that the stream socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_service& io_service,
const protocol_type& protocol, const native_type& native_socket)
: basic_socket<Protocol, StreamSocketService>(
io_service, protocol, native_socket)
{
}
/// Send some data on the socket.
/**
* This function is used to send data on the stream socket. The function
* call will block until one or more bytes of the data has been sent
* successfully, or an until error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref write function if you need to ensure that all data
* is written before the blocking operation completes.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.send(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.send(
this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send some data on the socket.
/**
* This function is used to send data on the stream socket. The function
* call will block until one or more bytes of the data has been sent
* successfully, or an until error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref write function if you need to ensure that all data
* is written before the blocking operation completes.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.send(asio::buffer(data, size), 0);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.send(
this->implementation, buffers, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send some data on the socket.
/**
* This function is used to send data on the stream socket. The function
* call will block until one or more bytes of the data has been sent
* successfully, or an until error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes sent. Returns 0 if an error occurred.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref write function if you need to ensure that all data
* is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->service.send(this->implementation, buffers, flags, ec);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send data on the stream socket.
* The function call always returns immediately.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the handler is called.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_send(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(const ConstBufferSequence& buffers, WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, 0, handler);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send data on the stream socket.
* The function call always returns immediately.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the handler is called.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_send(asio::buffer(data, size), 0, handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, flags, handler);
}
/// Receive some data on the socket.
/**
* This function is used to receive data on the stream socket. The function
* call will block until one or more bytes of data has been received
* successfully, or until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.receive(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.receive(this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive some data on the socket.
/**
* This function is used to receive data on the stream socket. The function
* call will block until one or more bytes of data has been received
* successfully, or until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.receive(asio::buffer(data, size), 0);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.receive(
this->implementation, buffers, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the stream socket. The function
* call will block until one or more bytes of data has been received
* successfully, or until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes received. Returns 0 if an error occurred.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->service.receive(this->implementation, buffers, flags, ec);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive data from the stream
* socket. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref async_read function if you need to ensure
* that the requested amount of data is received before the asynchronous
* operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(const MutableBufferSequence& buffers, ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, 0, handler);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive data from the stream
* socket. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref async_read function if you need to ensure
* that the requested amount of data is received before the asynchronous
* operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(asio::buffer(data, size), 0, handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, flags, handler);
}
/// Write some data to the socket.
/**
* This function is used to write data to the stream socket. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the socket.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* socket.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.send(this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Write some data to the socket.
/**
* This function is used to write data to the stream socket. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the socket.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return this->service.send(this->implementation, buffers, 0, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the stream socket.
* The function call always returns immediately.
*
* @param buffers One or more data buffers to be written to the socket.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_write_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(const ConstBufferSequence& buffers,
WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, 0, handler);
}
/// Read some data from the socket.
/**
* This function is used to read data from the stream socket. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* socket.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.receive(this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Read some data from the socket.
/**
* This function is used to read data from the stream socket. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return this->service.receive(this->implementation, buffers, 0, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the stream socket.
* The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_read_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(const MutableBufferSequence& buffers,
ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, 0, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_STREAM_SOCKET_HPP

View File

@ -1,200 +0,0 @@
//
// basic_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BASIC_STREAMBUF_HPP
#define ASIO_BASIC_STREAMBUF_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <algorithm>
#include <limits>
#include <memory>
#include <stdexcept>
#include <streambuf>
#include <vector>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Automatically resizable buffer class based on std::streambuf.
template <typename Allocator = std::allocator<char> >
class basic_streambuf
: public std::streambuf,
private noncopyable
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The type used to represent the get area as a list of buffers.
typedef implementation_defined const_buffers_type;
/// The type used to represent the put area as a list of buffers.
typedef implementation_defined mutable_buffers_type;
#else
typedef asio::const_buffers_1 const_buffers_type;
typedef asio::mutable_buffers_1 mutable_buffers_type;
#endif
/// Construct a buffer with a specified maximum size.
explicit basic_streambuf(
std::size_t max_size = (std::numeric_limits<std::size_t>::max)(),
const Allocator& allocator = Allocator())
: max_size_(max_size),
buffer_(allocator)
{
std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta);
buffer_.resize((std::max<std::size_t>)(pend, 1));
setg(&buffer_[0], &buffer_[0], &buffer_[0]);
setp(&buffer_[0], &buffer_[0] + pend);
}
/// Return the size of the get area in characters.
std::size_t size() const
{
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
{
return asio::buffer(asio::const_buffer(gptr(),
(pptr() - gptr()) * sizeof(char_type)));
}
/// Get a list of buffers that represents the put area, with the given size.
mutable_buffers_type prepare(std::size_t size)
{
reserve(size);
return asio::buffer(asio::mutable_buffer(
pptr(), size * sizeof(char_type)));
}
/// Move the start of the put area by the specified number of characters.
void commit(std::size_t n)
{
if (pptr() + n > epptr())
n = epptr() - pptr();
pbump(static_cast<int>(n));
}
/// Move the start of the get area by the specified number of characters.
void consume(std::size_t n)
{
while (n > 0)
{
sbumpc();
--n;
}
}
protected:
enum { buffer_delta = 128 };
int_type underflow()
{
if (gptr() < pptr())
{
setg(&buffer_[0], gptr(), pptr());
return traits_type::to_int_type(*gptr());
}
else
{
return traits_type::eof();
}
}
int_type overflow(int_type c)
{
if (!traits_type::eq_int_type(c, traits_type::eof()))
{
if (pptr() == epptr())
{
std::size_t buffer_size = pptr() - gptr();
if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta)
{
reserve(max_size_ - buffer_size);
}
else
{
reserve(buffer_delta);
}
}
*pptr() = traits_type::to_char_type(c);
pbump(1);
return c;
}
return traits_type::not_eof(c);
}
void reserve(std::size_t n)
{
// Get current stream positions as offsets.
std::size_t gnext = gptr() - &buffer_[0];
std::size_t gend = egptr() - &buffer_[0];
std::size_t pnext = pptr() - &buffer_[0];
std::size_t pend = epptr() - &buffer_[0];
// Check if there is already enough space in the put area.
if (n <= pend - pnext)
{
return;
}
// Shift existing contents of get area to start of buffer.
if (gnext > 0)
{
std::rotate(&buffer_[0], &buffer_[0] + gnext, &buffer_[0] + pend);
gend -= gnext;
pnext -= gnext;
}
// Ensure buffer is large enough to hold at least the specified size.
if (n > pend - pnext)
{
if (n <= max_size_ && pnext <= max_size_ - n)
{
buffer_.resize((std::max<std::size_t>)(pnext + n, 1));
}
else
{
throw std::length_error("asio::streambuf too long");
}
}
// Update stream positions.
setg(&buffer_[0], &buffer_[0], &buffer_[0] + gend);
setp(&buffer_[0] + pnext, &buffer_[0] + pnext + n);
}
private:
std::size_t max_size_;
std::vector<char_type, Allocator> buffer_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_STREAMBUF_HPP

View File

@ -1,803 +0,0 @@
//
// buffer.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BUFFER_HPP
#define ASIO_BUFFER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/array.hpp>
#include <boost/type_traits/is_const.hpp>
#include <string>
#include <vector>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_MSVC)
# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)
# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
# define ASIO_ENABLE_BUFFER_DEBUGGING
# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
# endif // defined(_HAS_ITERATOR_DEBUGGING)
#endif // defined(BOOST_MSVC)
#if defined(__GNUC__)
# if defined(_GLIBCXX_DEBUG)
# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
# define ASIO_ENABLE_BUFFER_DEBUGGING
# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
# endif // defined(_GLIBCXX_DEBUG)
#endif // defined(__GNUC__)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
# include "asio/detail/push_options.hpp"
# include <boost/function.hpp>
# include "asio/detail/pop_options.hpp"
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
namespace asio {
class mutable_buffer;
class const_buffer;
namespace detail {
void* buffer_cast_helper(const mutable_buffer&);
const void* buffer_cast_helper(const const_buffer&);
std::size_t buffer_size_helper(const mutable_buffer&);
std::size_t buffer_size_helper(const const_buffer&);
} // namespace detail
/// Holds a buffer that can be modified.
/**
* The mutable_buffer class provides a safe representation of a buffer that can
* be modified. It does not own the underlying data, and so is cheap to copy or
* assign.
*/
class mutable_buffer
{
public:
/// Construct an empty buffer.
mutable_buffer()
: data_(0),
size_(0)
{
}
/// Construct a buffer to represent a given memory range.
mutable_buffer(void* data, std::size_t size)
: data_(data),
size_(size)
{
}
#if defined(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 // ASIO_ENABLE_BUFFER_DEBUGGING
private:
friend void* asio::detail::buffer_cast_helper(
const mutable_buffer& b);
friend std::size_t asio::detail::buffer_size_helper(
const mutable_buffer& b);
void* data_;
std::size_t size_;
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
boost::function<void()> debug_check_;
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
};
namespace detail {
inline void* buffer_cast_helper(const mutable_buffer& b)
{
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
if (b.size_ && b.debug_check_)
b.debug_check_();
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
return b.data_;
}
inline std::size_t buffer_size_helper(const mutable_buffer& b)
{
return b.size_;
}
} // namespace detail
/// Cast a non-modifiable buffer to a specified pointer to POD type.
/**
* @relates mutable_buffer
*/
template <typename PointerToPodType>
inline PointerToPodType buffer_cast(const mutable_buffer& b)
{
return static_cast<PointerToPodType>(detail::buffer_cast_helper(b));
}
/// Get the number of bytes in a non-modifiable buffer.
/**
* @relates mutable_buffer
*/
inline std::size_t buffer_size(const mutable_buffer& b)
{
return detail::buffer_size_helper(b);
}
/// Create a new modifiable buffer that is offset from the start of another.
/**
* @relates mutable_buffer
*/
inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start)
{
if (start > buffer_size(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
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
);
}
/// Create a new modifiable buffer that is offset from the start of another.
/**
* @relates mutable_buffer
*/
inline mutable_buffer operator+(std::size_t start, const mutable_buffer& b)
{
if (start > buffer_size(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
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
);
}
/// Adapts a single modifiable buffer so that it meets the requirements of the
/// MutableBufferSequence concept.
class mutable_buffers_1
: public mutable_buffer
{
public:
/// The type for each element in the list of buffers.
typedef mutable_buffer value_type;
/// A random-access iterator type that may be used to read elements.
typedef const mutable_buffer* const_iterator;
/// Construct to represent a single modifiable buffer.
explicit mutable_buffers_1(const mutable_buffer& b)
: mutable_buffer(b)
{
}
/// Get a random-access iterator to the first element.
const_iterator begin() const
{
return this;
}
/// Get a random-access iterator for one past the last element.
const_iterator end() const
{
return begin() + 1;
}
};
/// Holds a buffer that cannot be modified.
/**
* The const_buffer class provides a safe representation of a buffer that cannot
* be modified. It does not own the underlying data, and so is cheap to copy or
* assign.
*/
class const_buffer
{
public:
/// Construct an empty buffer.
const_buffer()
: data_(0),
size_(0)
{
}
/// Construct a buffer to represent a given memory range.
const_buffer(const void* data, std::size_t size)
: data_(data),
size_(size)
{
}
/// Construct a non-modifiable buffer from a modifiable one.
const_buffer(const mutable_buffer& b)
: data_(asio::detail::buffer_cast_helper(b)),
size_(asio::detail::buffer_size_helper(b))
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, debug_check_(b.get_debug_check())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
{
}
#if defined(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 // ASIO_ENABLE_BUFFER_DEBUGGING
private:
friend const void* asio::detail::buffer_cast_helper(
const const_buffer& b);
friend std::size_t asio::detail::buffer_size_helper(
const const_buffer& b);
const void* data_;
std::size_t size_;
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
boost::function<void()> debug_check_;
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
};
namespace detail {
inline const void* buffer_cast_helper(const const_buffer& b)
{
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
if (b.size_ && b.debug_check_)
b.debug_check_();
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
return b.data_;
}
inline std::size_t buffer_size_helper(const const_buffer& b)
{
return b.size_;
}
} // namespace detail
/// Cast a non-modifiable buffer to a specified pointer to POD type.
/**
* @relates const_buffer
*/
template <typename PointerToPodType>
inline PointerToPodType buffer_cast(const const_buffer& b)
{
return static_cast<PointerToPodType>(detail::buffer_cast_helper(b));
}
/// Get the number of bytes in a non-modifiable buffer.
/**
* @relates const_buffer
*/
inline std::size_t buffer_size(const const_buffer& b)
{
return detail::buffer_size_helper(b);
}
/// Create a new non-modifiable buffer that is offset from the start of another.
/**
* @relates const_buffer
*/
inline const_buffer operator+(const const_buffer& b, std::size_t start)
{
if (start > buffer_size(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
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
);
}
/// Create a new non-modifiable buffer that is offset from the start of another.
/**
* @relates const_buffer
*/
inline const_buffer operator+(std::size_t start, const const_buffer& b)
{
if (start > buffer_size(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
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
);
}
/// Adapts a single non-modifiable buffer so that it meets the requirements of
/// the ConstBufferSequence concept.
class const_buffers_1
: public const_buffer
{
public:
/// The type for each element in the list of buffers.
typedef const_buffer value_type;
/// A random-access iterator type that may be used to read elements.
typedef const const_buffer* const_iterator;
/// Construct to represent a single non-modifiable buffer.
explicit const_buffers_1(const const_buffer& b)
: const_buffer(b)
{
}
/// Get a random-access iterator to the first element.
const_iterator begin() const
{
return this;
}
/// Get a random-access iterator for one past the last element.
const_iterator end() const
{
return begin() + 1;
}
};
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
namespace detail {
template <typename Iterator>
class buffer_debug_check
{
public:
buffer_debug_check(Iterator iter)
: iter_(iter)
{
}
~buffer_debug_check()
{
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
// MSVC's string iterator checking may crash in a std::string::iterator
// object's destructor when the iterator points to an already-destroyed
// std::string object, unless the iterator is cleared first.
iter_ = Iterator();
#endif // BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
}
void operator()()
{
*iter_;
}
private:
Iterator iter_;
};
} // namespace detail
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
/** @defgroup buffer asio::buffer
*
* @brief The asio::buffer function is used to create a buffer object to
* represent raw memory, an array of POD elements, or a vector of POD elements.
*
* The simplest use case involves reading or writing a single buffer of a
* specified size:
*
* @code sock.write(asio::buffer(data, size)); @endcode
*
* In the above example, the return value of asio::buffer meets the
* requirements of the ConstBufferSequence concept so that it may be directly
* passed to the socket's write function. A buffer created for modifiable
* memory also meets the requirements of the MutableBufferSequence concept.
*
* An individual buffer may be created from a builtin array, std::vector or
* boost::array of POD elements. This helps prevent buffer overruns by
* automatically determining the size of the buffer:
*
* @code char d1[128];
* size_t bytes_transferred = sock.read(asio::buffer(d1));
*
* std::vector<char> d2(128);
* bytes_transferred = sock.read(asio::buffer(d2));
*
* boost::array<char, 128> d3;
* bytes_transferred = sock.read(asio::buffer(d3)); @endcode
*
* To read or write using multiple buffers (i.e. scatter-gather I/O), multiple
* buffer objects may be assigned into a container that supports the
* MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts:
*
* @code
* char d1[128];
* std::vector<char> d2(128);
* boost::array<char, 128> d3;
*
* boost::array<mutable_buffer, 3> bufs1 = {
* asio::buffer(d1),
* asio::buffer(d2),
* asio::buffer(d3) };
* bytes_transferred = sock.read(bufs1);
*
* std::vector<const_buffer> bufs2;
* bufs2.push_back(asio::buffer(d1));
* bufs2.push_back(asio::buffer(d2));
* bufs2.push_back(asio::buffer(d3));
* bytes_transferred = sock.write(bufs2); @endcode
*/
/*@{*/
/// Create a new modifiable buffer from an existing buffer.
inline mutable_buffers_1 buffer(const mutable_buffer& b)
{
return mutable_buffers_1(b);
}
/// Create a new modifiable buffer from an existing buffer.
inline mutable_buffers_1 buffer(const mutable_buffer& b,
std::size_t max_size_in_bytes)
{
return mutable_buffers_1(
mutable_buffer(buffer_cast<void*>(b),
buffer_size(b) < max_size_in_bytes
? buffer_size(b) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer from an existing buffer.
inline const_buffers_1 buffer(const const_buffer& b)
{
return const_buffers_1(b);
}
/// Create a new non-modifiable buffer from an existing buffer.
inline const_buffers_1 buffer(const const_buffer& b,
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(buffer_cast<const void*>(b),
buffer_size(b) < max_size_in_bytes
? buffer_size(b) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new modifiable buffer that represents the given memory range.
inline mutable_buffers_1 buffer(void* data, std::size_t size_in_bytes)
{
return mutable_buffers_1(mutable_buffer(data, size_in_bytes));
}
/// Create a new non-modifiable buffer that represents the given memory range.
inline const_buffers_1 buffer(const void* data,
std::size_t size_in_bytes)
{
return const_buffers_1(const_buffer(data, size_in_bytes));
}
/// Create a new modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(PodType (&data)[N])
{
return mutable_buffers_1(mutable_buffer(data, N * sizeof(PodType)));
}
/// Create a new modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(PodType (&data)[N],
std::size_t max_size_in_bytes)
{
return mutable_buffers_1(
mutable_buffer(data,
N * sizeof(PodType) < max_size_in_bytes
? N * sizeof(PodType) : max_size_in_bytes));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const PodType (&data)[N])
{
return const_buffers_1(const_buffer(data, N * sizeof(PodType)));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const PodType (&data)[N],
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(data,
N * sizeof(PodType) < max_size_in_bytes
? N * sizeof(PodType) : max_size_in_bytes));
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \
|| BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
// Borland C++ and Sun Studio think the overloads:
//
// unspecified buffer(boost::array<PodType, N>& array ...);
//
// and
//
// unspecified buffer(boost::array<const PodType, N>& array ...);
//
// are ambiguous. This will be worked around by using a buffer_types traits
// class that contains typedefs for the appropriate buffer and container
// classes, based on whether PodType is const or non-const.
namespace detail {
template <bool IsConst>
struct buffer_types_base;
template <>
struct buffer_types_base<false>
{
typedef mutable_buffer buffer_type;
typedef mutable_buffers_1 container_type;
};
template <>
struct buffer_types_base<true>
{
typedef const_buffer buffer_type;
typedef const_buffers_1 container_type;
};
template <typename PodType>
struct buffer_types
: public buffer_types_base<boost::is_const<PodType>::value>
{
};
} // namespace detail
template <typename PodType, std::size_t N>
inline typename detail::buffer_types<PodType>::container_type
buffer(boost::array<PodType, N>& data)
{
typedef typename asio::detail::buffer_types<PodType>::buffer_type
buffer_type;
typedef typename asio::detail::buffer_types<PodType>::container_type
container_type;
return container_type(
buffer_type(data.c_array(), data.size() * sizeof(PodType)));
}
template <typename PodType, std::size_t N>
inline typename detail::buffer_types<PodType>::container_type
buffer(boost::array<PodType, N>& data, std::size_t max_size_in_bytes)
{
typedef typename asio::detail::buffer_types<PodType>::buffer_type
buffer_type;
typedef typename asio::detail::buffer_types<PodType>::container_type
container_type;
return container_type(
buffer_type(data.c_array(),
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes));
}
#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
// || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
/// Create a new modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(boost::array<PodType, N>& data)
{
return mutable_buffers_1(
mutable_buffer(data.c_array(), data.size() * sizeof(PodType)));
}
/// Create a new modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(boost::array<PodType, N>& data,
std::size_t max_size_in_bytes)
{
return mutable_buffers_1(
mutable_buffer(data.c_array(),
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(boost::array<const PodType, N>& data)
{
return const_buffers_1(
const_buffer(data.data(), data.size() * sizeof(PodType)));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(boost::array<const PodType, N>& data,
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(data.data(),
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes));
}
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
// || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const boost::array<PodType, N>& data)
{
return const_buffers_1(
const_buffer(data.data(), data.size() * sizeof(PodType)));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const boost::array<PodType, N>& data,
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(data.data(),
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes));
}
/// Create a new modifiable buffer that represents the given POD vector.
/**
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
template <typename PodType, typename Allocator>
inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data)
{
return mutable_buffers_1(
mutable_buffer(&data[0], data.size() * sizeof(PodType)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::iterator
>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new modifiable buffer that represents the given POD vector.
/**
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
template <typename PodType, typename Allocator>
inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data,
std::size_t max_size_in_bytes)
{
return mutable_buffers_1(
mutable_buffer(&data[0],
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::iterator
>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer that represents the given POD vector.
/**
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
template <typename PodType, typename Allocator>
inline const_buffers_1 buffer(
const std::vector<PodType, Allocator>& data)
{
return const_buffers_1(
const_buffer(&data[0], data.size() * sizeof(PodType)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::const_iterator
>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer that represents the given POD vector.
/**
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
template <typename PodType, typename Allocator>
inline const_buffers_1 buffer(
const std::vector<PodType, Allocator>& data, std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(&data[0],
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::const_iterator
>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer that represents the given string.
/**
* @note The buffer is invalidated by any non-const operation called on the
* given string object.
*/
inline const_buffers_1 buffer(const std::string& data)
{
return const_buffers_1(const_buffer(data.data(), data.size()
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<std::string::const_iterator>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer that represents the given string.
/**
* @note The buffer is invalidated by any non-const operation called on the
* given string object.
*/
inline const_buffers_1 buffer(const std::string& data,
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(data.data(),
data.size() < max_size_in_bytes
? data.size() : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<std::string::const_iterator>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/*@}*/
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFER_HPP

View File

@ -1,414 +0,0 @@
//
// buffered_read_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BUFFERED_READ_STREAM_HPP
#define ASIO_BUFFERED_READ_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <cstring>
#include <boost/config.hpp>
#include <boost/type_traits.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_resize_guard.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Adds buffering to the read-related operations of a stream.
/**
* The buffered_read_stream class template can be used to add buffering to the
* synchronous and asynchronous read operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, Sync_Read_Stream, SyncWriteStream.
*/
template <typename Stream>
class buffered_read_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef typename boost::remove_reference<Stream>::type next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
#if defined(GENERATING_DOCUMENTATION)
/// The default buffer size.
static const std::size_t default_buffer_size = implementation_defined;
#else
BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
#endif
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_read_stream(Arg& a)
: next_layer_(a),
storage_(default_buffer_size)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
buffered_read_stream(Arg& a, std::size_t buffer_size)
: next_layer_(a),
storage_(buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return next_layer_;
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return next_layer_.lowest_layer();
}
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object.
asio::io_service& io_service()
{
return next_layer_.get_io_service();
}
/// Get the io_service associated with the object.
asio::io_service& get_io_service()
{
return next_layer_.get_io_service();
}
/// Close the stream.
void close()
{
next_layer_.close();
}
/// Close the stream.
asio::error_code close(asio::error_code& ec)
{
return next_layer_.close(ec);
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
return next_layer_.write_some(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return next_layer_.write_some(buffers, ec);
}
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(const ConstBufferSequence& buffers,
WriteHandler handler)
{
next_layer_.async_write_some(buffers, handler);
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation. Throws an exception on failure.
std::size_t fill()
{
detail::buffer_resize_guard<detail::buffered_stream_storage>
resize_guard(storage_);
std::size_t previous_size = storage_.size();
storage_.resize(storage_.capacity());
storage_.resize(previous_size + next_layer_.read_some(buffer(
storage_.data() + previous_size,
storage_.size() - previous_size)));
resize_guard.commit();
return storage_.size() - previous_size;
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation, or 0 if an error occurred.
std::size_t fill(asio::error_code& ec)
{
detail::buffer_resize_guard<detail::buffered_stream_storage>
resize_guard(storage_);
std::size_t previous_size = storage_.size();
storage_.resize(storage_.capacity());
storage_.resize(previous_size + next_layer_.read_some(buffer(
storage_.data() + previous_size,
storage_.size() - previous_size),
ec));
resize_guard.commit();
return storage_.size() - previous_size;
}
template <typename ReadHandler>
class fill_handler
{
public:
fill_handler(asio::io_service& io_service,
detail::buffered_stream_storage& storage,
std::size_t previous_size, ReadHandler handler)
: io_service_(io_service),
storage_(storage),
previous_size_(previous_size),
handler_(handler)
{
}
void operator()(const asio::error_code& ec,
std::size_t bytes_transferred)
{
storage_.resize(previous_size_ + bytes_transferred);
io_service_.dispatch(detail::bind_handler(
handler_, ec, bytes_transferred));
}
private:
asio::io_service& io_service_;
detail::buffered_stream_storage& storage_;
std::size_t previous_size_;
ReadHandler handler_;
};
/// Start an asynchronous fill.
template <typename ReadHandler>
void async_fill(ReadHandler handler)
{
std::size_t previous_size = storage_.size();
storage_.resize(storage_.capacity());
next_layer_.async_read_some(
buffer(
storage_.data() + previous_size,
storage_.size() - previous_size),
fill_handler<ReadHandler>(get_io_service(),
storage_, previous_size, handler));
}
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
if (storage_.empty())
fill();
return copy(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
ec = asio::error_code();
if (storage_.empty() && !fill(ec))
return 0;
return copy(buffers);
}
template <typename MutableBufferSequence, typename ReadHandler>
class read_some_handler
{
public:
read_some_handler(asio::io_service& io_service,
detail::buffered_stream_storage& storage,
const MutableBufferSequence& buffers, ReadHandler handler)
: io_service_(io_service),
storage_(storage),
buffers_(buffers),
handler_(handler)
{
}
void operator()(const asio::error_code& ec, std::size_t)
{
if (ec || storage_.empty())
{
std::size_t length = 0;
io_service_.dispatch(detail::bind_handler(handler_, ec, length));
}
else
{
using namespace std; // For memcpy.
std::size_t bytes_avail = storage_.size();
std::size_t bytes_copied = 0;
typename MutableBufferSequence::const_iterator iter = buffers_.begin();
typename MutableBufferSequence::const_iterator end = buffers_.end();
for (; iter != end && bytes_avail > 0; ++iter)
{
std::size_t max_length = buffer_size(*iter);
std::size_t length = (max_length < bytes_avail)
? max_length : bytes_avail;
memcpy(buffer_cast<void*>(*iter),
storage_.data() + bytes_copied, length);
bytes_copied += length;
bytes_avail -= length;
}
storage_.consume(bytes_copied);
io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied));
}
}
private:
asio::io_service& io_service_;
detail::buffered_stream_storage& storage_;
MutableBufferSequence buffers_;
ReadHandler handler_;
};
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(const MutableBufferSequence& buffers,
ReadHandler handler)
{
if (storage_.empty())
{
async_fill(read_some_handler<MutableBufferSequence, ReadHandler>(
get_io_service(), storage_, buffers, handler));
}
else
{
std::size_t length = copy(buffers);
get_io_service().post(detail::bind_handler(
handler, asio::error_code(), length));
}
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
if (storage_.empty())
fill();
return peek_copy(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
ec = asio::error_code();
if (storage_.empty() && !fill(ec))
return 0;
return peek_copy(buffers);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return storage_.size();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(asio::error_code& ec)
{
ec = asio::error_code();
return storage_.size();
}
private:
/// Copy data out of the internal buffer to the specified target buffer.
/// Returns the number of bytes copied.
template <typename MutableBufferSequence>
std::size_t copy(const MutableBufferSequence& buffers)
{
using namespace std; // For memcpy.
std::size_t bytes_avail = storage_.size();
std::size_t bytes_copied = 0;
typename MutableBufferSequence::const_iterator iter = buffers.begin();
typename MutableBufferSequence::const_iterator end = buffers.end();
for (; iter != end && bytes_avail > 0; ++iter)
{
std::size_t max_length = buffer_size(*iter);
std::size_t length = (max_length < bytes_avail)
? max_length : bytes_avail;
memcpy(buffer_cast<void*>(*iter), storage_.data() + bytes_copied, length);
bytes_copied += length;
bytes_avail -= length;
}
storage_.consume(bytes_copied);
return bytes_copied;
}
/// Copy data from the internal buffer to the specified target buffer, without
/// removing the data from the internal buffer. Returns the number of bytes
/// copied.
template <typename MutableBufferSequence>
std::size_t peek_copy(const MutableBufferSequence& buffers)
{
using namespace std; // For memcpy.
std::size_t bytes_avail = storage_.size();
std::size_t bytes_copied = 0;
typename MutableBufferSequence::const_iterator iter = buffers.begin();
typename MutableBufferSequence::const_iterator end = buffers.end();
for (; iter != end && bytes_avail > 0; ++iter)
{
std::size_t max_length = buffer_size(*iter);
std::size_t length = (max_length < bytes_avail)
? max_length : bytes_avail;
memcpy(buffer_cast<void*>(*iter), storage_.data() + bytes_copied, length);
bytes_copied += length;
bytes_avail -= length;
}
return bytes_copied;
}
/// The next layer.
Stream next_layer_;
// The data in the buffer.
detail::buffered_stream_storage storage_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_READ_STREAM_HPP

View File

@ -1,29 +0,0 @@
//
// buffered_read_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BUFFERED_READ_STREAM_FWD_HPP
#define ASIO_BUFFERED_READ_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
class buffered_read_stream;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP

View File

@ -1,250 +0,0 @@
//
// buffered_stream.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BUFFERED_STREAM_HPP
#define ASIO_BUFFERED_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffered_read_stream.hpp"
#include "asio/buffered_write_stream.hpp"
#include "asio/buffered_stream_fwd.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Adds buffering to the read- and write-related operations of a stream.
/**
* The buffered_stream class template can be used to add buffering to the
* synchronous and asynchronous read and write operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef typename boost::remove_reference<Stream>::type next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_stream(Arg& a)
: inner_stream_impl_(a),
stream_impl_(inner_stream_impl_)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_stream(Arg& a, std::size_t read_buffer_size,
std::size_t write_buffer_size)
: inner_stream_impl_(a, write_buffer_size),
stream_impl_(inner_stream_impl_, read_buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return stream_impl_.next_layer().next_layer();
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return stream_impl_.lowest_layer();
}
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object.
asio::io_service& io_service()
{
return stream_impl_.get_io_service();
}
/// Get the io_service associated with the object.
asio::io_service& get_io_service()
{
return stream_impl_.get_io_service();
}
/// Close the stream.
void close()
{
stream_impl_.close();
}
/// Close the stream.
asio::error_code close(asio::error_code& ec)
{
return stream_impl_.close(ec);
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation. Throws an
/// exception on failure.
std::size_t flush()
{
return stream_impl_.next_layer().flush();
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation, or 0 if an
/// error occurred.
std::size_t flush(asio::error_code& ec)
{
return stream_impl_.next_layer().flush(ec);
}
/// Start an asynchronous flush.
template <typename WriteHandler>
void async_flush(WriteHandler handler)
{
return stream_impl_.next_layer().async_flush(handler);
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
return stream_impl_.write_some(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return stream_impl_.write_some(buffers, ec);
}
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(const ConstBufferSequence& buffers,
WriteHandler handler)
{
stream_impl_.async_write_some(buffers, handler);
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation. Throws an exception on failure.
std::size_t fill()
{
return stream_impl_.fill();
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation, or 0 if an error occurred.
std::size_t fill(asio::error_code& ec)
{
return stream_impl_.fill(ec);
}
/// Start an asynchronous fill.
template <typename ReadHandler>
void async_fill(ReadHandler handler)
{
stream_impl_.async_fill(handler);
}
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
return stream_impl_.read_some(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return stream_impl_.read_some(buffers, ec);
}
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(const MutableBufferSequence& buffers,
ReadHandler handler)
{
stream_impl_.async_read_some(buffers, handler);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
return stream_impl_.peek(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return stream_impl_.peek(buffers, ec);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return stream_impl_.in_avail();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(asio::error_code& ec)
{
return stream_impl_.in_avail(ec);
}
private:
// The buffered write stream.
typedef buffered_write_stream<Stream> write_stream_type;
write_stream_type inner_stream_impl_;
// The buffered read stream.
typedef buffered_read_stream<write_stream_type&> read_stream_type;
read_stream_type stream_impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_STREAM_HPP

View File

@ -1,29 +0,0 @@
//
// buffered_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BUFFERED_STREAM_FWD_HPP
#define ASIO_BUFFERED_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
class buffered_stream;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_STREAM_FWD_HPP

View File

@ -1,368 +0,0 @@
//
// buffered_write_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BUFFERED_WRITE_STREAM_HPP
#define ASIO_BUFFERED_WRITE_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <cstring>
#include <boost/config.hpp>
#include <boost/type_traits.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/completion_condition.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/write.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Adds buffering to the write-related operations of a stream.
/**
* The buffered_write_stream class template can be used to add buffering to the
* synchronous and asynchronous write operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_write_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef typename boost::remove_reference<Stream>::type next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
#if defined(GENERATING_DOCUMENTATION)
/// The default buffer size.
static const std::size_t default_buffer_size = implementation_defined;
#else
BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
#endif
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_write_stream(Arg& a)
: next_layer_(a),
storage_(default_buffer_size)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
buffered_write_stream(Arg& a, std::size_t buffer_size)
: next_layer_(a),
storage_(buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return next_layer_;
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return next_layer_.lowest_layer();
}
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object.
asio::io_service& io_service()
{
return next_layer_.get_io_service();
}
/// Get the io_service associated with the object.
asio::io_service& get_io_service()
{
return next_layer_.get_io_service();
}
/// Close the stream.
void close()
{
next_layer_.close();
}
/// Close the stream.
asio::error_code close(asio::error_code& ec)
{
return next_layer_.close(ec);
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation. Throws an
/// exception on failure.
std::size_t flush()
{
std::size_t bytes_written = write(next_layer_,
buffer(storage_.data(), storage_.size()));
storage_.consume(bytes_written);
return bytes_written;
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation, or 0 if an
/// error occurred.
std::size_t flush(asio::error_code& ec)
{
std::size_t bytes_written = write(next_layer_,
buffer(storage_.data(), storage_.size()),
transfer_all(), ec);
storage_.consume(bytes_written);
return bytes_written;
}
template <typename WriteHandler>
class flush_handler
{
public:
flush_handler(asio::io_service& io_service,
detail::buffered_stream_storage& storage, WriteHandler handler)
: io_service_(io_service),
storage_(storage),
handler_(handler)
{
}
void operator()(const asio::error_code& ec,
std::size_t bytes_written)
{
storage_.consume(bytes_written);
io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_written));
}
private:
asio::io_service& io_service_;
detail::buffered_stream_storage& storage_;
WriteHandler handler_;
};
/// Start an asynchronous flush.
template <typename WriteHandler>
void async_flush(WriteHandler handler)
{
async_write(next_layer_, buffer(storage_.data(), storage_.size()),
flush_handler<WriteHandler>(get_io_service(), storage_, handler));
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
if (storage_.size() == storage_.capacity())
flush();
return copy(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred and the error handler did not throw.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
ec = asio::error_code();
if (storage_.size() == storage_.capacity() && !flush(ec))
return 0;
return copy(buffers);
}
template <typename ConstBufferSequence, typename WriteHandler>
class write_some_handler
{
public:
write_some_handler(asio::io_service& io_service,
detail::buffered_stream_storage& storage,
const ConstBufferSequence& buffers, WriteHandler handler)
: io_service_(io_service),
storage_(storage),
buffers_(buffers),
handler_(handler)
{
}
void operator()(const asio::error_code& ec, std::size_t)
{
if (ec)
{
std::size_t length = 0;
io_service_.dispatch(detail::bind_handler(handler_, ec, length));
}
else
{
using namespace std; // For memcpy.
std::size_t orig_size = storage_.size();
std::size_t space_avail = storage_.capacity() - orig_size;
std::size_t bytes_copied = 0;
typename ConstBufferSequence::const_iterator iter = buffers_.begin();
typename ConstBufferSequence::const_iterator end = buffers_.end();
for (; iter != end && space_avail > 0; ++iter)
{
std::size_t bytes_avail = buffer_size(*iter);
std::size_t length = (bytes_avail < space_avail)
? bytes_avail : space_avail;
storage_.resize(orig_size + bytes_copied + length);
memcpy(storage_.data() + orig_size + bytes_copied,
buffer_cast<const void*>(*iter), length);
bytes_copied += length;
space_avail -= length;
}
io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied));
}
}
private:
asio::io_service& io_service_;
detail::buffered_stream_storage& storage_;
ConstBufferSequence buffers_;
WriteHandler handler_;
};
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(const ConstBufferSequence& buffers,
WriteHandler handler)
{
if (storage_.size() == storage_.capacity())
{
async_flush(write_some_handler<ConstBufferSequence, WriteHandler>(
get_io_service(), storage_, buffers, handler));
}
else
{
std::size_t bytes_copied = copy(buffers);
get_io_service().post(detail::bind_handler(
handler, asio::error_code(), bytes_copied));
}
}
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
return next_layer_.read_some(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return next_layer_.read_some(buffers, ec);
}
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(const MutableBufferSequence& buffers,
ReadHandler handler)
{
next_layer_.async_read_some(buffers, handler);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
return next_layer_.peek(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return next_layer_.peek(buffers, ec);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return next_layer_.in_avail();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(asio::error_code& ec)
{
return next_layer_.in_avail(ec);
}
private:
/// Copy data into the internal buffer from the specified source buffer.
/// Returns the number of bytes copied.
template <typename ConstBufferSequence>
std::size_t copy(const ConstBufferSequence& buffers)
{
using namespace std; // For memcpy.
std::size_t orig_size = storage_.size();
std::size_t space_avail = storage_.capacity() - orig_size;
std::size_t bytes_copied = 0;
typename ConstBufferSequence::const_iterator iter = buffers.begin();
typename ConstBufferSequence::const_iterator end = buffers.end();
for (; iter != end && space_avail > 0; ++iter)
{
std::size_t bytes_avail = buffer_size(*iter);
std::size_t length = (bytes_avail < space_avail)
? bytes_avail : space_avail;
storage_.resize(orig_size + bytes_copied + length);
memcpy(storage_.data() + orig_size + bytes_copied,
buffer_cast<const void*>(*iter), length);
bytes_copied += length;
space_avail -= length;
}
return bytes_copied;
}
/// The next layer.
Stream next_layer_;
// The data in the buffer.
detail::buffered_stream_storage storage_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_WRITE_STREAM_HPP

View File

@ -1,29 +0,0 @@
//
// buffered_write_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
#define ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
class buffered_write_stream;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP

View File

@ -1,145 +0,0 @@
//
// completion_condition.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_COMPLETION_CONDITION_HPP
#define ASIO_COMPLETION_CONDITION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
class transfer_all_t
{
public:
typedef bool result_type;
template <typename Error>
bool operator()(const Error& err, std::size_t)
{
return !!err;
}
};
class transfer_at_least_t
{
public:
typedef bool result_type;
explicit transfer_at_least_t(std::size_t minimum)
: minimum_(minimum)
{
}
template <typename Error>
bool operator()(const Error& err, std::size_t bytes_transferred)
{
return !!err || bytes_transferred >= minimum_;
}
private:
std::size_t minimum_;
};
} // namespace detail
/**
* @defgroup completion_condition Completion Condition Function Objects
*
* Function objects used for determining when a read or write operation should
* complete.
*/
/*@{*/
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until all of the data has been transferred,
/// or until an error occurs.
/**
* This function is used to create an object, of unspecified type, that meets
* CompletionCondition requirements.
*
* @par Example
* Reading until a buffer is full:
* @code
* boost::array<char, 128> buf;
* asio::error_code ec;
* std::size_t n = asio::read(
* sock, asio::buffer(buf),
* asio::transfer_all(), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* // n == 128
* }
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_all();
#else
inline detail::transfer_all_t transfer_all()
{
return detail::transfer_all_t();
}
#endif
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until a minimum number of bytes has been
/// transferred, or until an error occurs.
/**
* This function is used to create an object, of unspecified type, that meets
* CompletionCondition requirements.
*
* @par Example
* Reading until a buffer is full or contains at least 64 bytes:
* @code
* boost::array<char, 128> buf;
* asio::error_code ec;
* std::size_t n = asio::read(
* sock, asio::buffer(buf),
* asio::transfer_at_least(64), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* // n >= 64 && n <= 128
* }
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_at_least(std::size_t minimum);
#else
inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum)
{
return detail::transfer_at_least_t(minimum);
}
#endif
/*@}*/
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_COMPLETION_CONDITION_HPP

View File

@ -1,323 +0,0 @@
//
// datagram_socket_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DATAGRAM_SOCKET_SERVICE_HPP
#define ASIO_DATAGRAM_SOCKET_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/epoll_reactor.hpp"
#include "asio/detail/kqueue_reactor.hpp"
#include "asio/detail/select_reactor.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/reactive_socket_service.hpp"
#include "asio/detail/win_iocp_socket_service.hpp"
namespace asio {
/// Default service implementation for a datagram socket.
template <typename Protocol>
class datagram_socket_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_service::service
#else
: public asio::detail::service_base<datagram_socket_service<Protocol> >
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_service::id id;
#endif
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
private:
// The type of the platform-specific implementation.
#if defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_socket_service<Protocol> service_impl_type;
#elif defined(ASIO_HAS_EPOLL)
typedef detail::reactive_socket_service<
Protocol, detail::epoll_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::reactive_socket_service<
Protocol, detail::kqueue_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_DEV_POLL)
typedef detail::reactive_socket_service<
Protocol, detail::dev_poll_reactor<false> > service_impl_type;
#else
typedef detail::reactive_socket_service<
Protocol, detail::select_reactor<false> > service_impl_type;
#endif
public:
/// The type of a datagram socket.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef typename service_impl_type::implementation_type implementation_type;
#endif
/// The native socket type.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_type;
#else
typedef typename service_impl_type::native_type native_type;
#endif
/// Construct a new datagram socket service for the specified io_service.
explicit datagram_socket_service(asio::io_service& io_service)
: asio::detail::service_base<
datagram_socket_service<Protocol> >(io_service),
service_impl_(asio::use_service<service_impl_type>(io_service))
{
}
/// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
}
/// Construct a new datagram socket implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}
/// Destroy a datagram socket implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}
// Open a new datagram socket implementation.
asio::error_code open(implementation_type& impl,
const protocol_type& protocol, asio::error_code& ec)
{
if (protocol.type() == SOCK_DGRAM)
service_impl_.open(impl, protocol, ec);
else
ec = asio::error::invalid_argument;
return ec;
}
/// Assign an existing native socket to a datagram socket.
asio::error_code assign(implementation_type& impl,
const protocol_type& protocol, const native_type& native_socket,
asio::error_code& ec)
{
return service_impl_.assign(impl, protocol, native_socket, ec);
}
/// Determine whether the socket is open.
bool is_open(const implementation_type& impl) const
{
return service_impl_.is_open(impl);
}
/// Close a datagram socket implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.close(impl, ec);
}
/// Get the native socket implementation.
native_type native(implementation_type& impl)
{
return service_impl_.native(impl);
}
/// Cancel all asynchronous operations associated with the socket.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}
/// Determine whether the socket is at the out-of-band data mark.
bool at_mark(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.at_mark(impl, ec);
}
/// Determine the number of bytes available for reading.
std::size_t available(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.available(impl, ec);
}
// Bind the datagram socket to the specified local endpoint.
asio::error_code bind(implementation_type& impl,
const endpoint_type& endpoint, asio::error_code& ec)
{
return service_impl_.bind(impl, endpoint, ec);
}
/// Connect the datagram socket to the specified endpoint.
asio::error_code connect(implementation_type& impl,
const endpoint_type& peer_endpoint, asio::error_code& ec)
{
return service_impl_.connect(impl, peer_endpoint, ec);
}
/// Start an asynchronous connect.
template <typename ConnectHandler>
void async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint, ConnectHandler handler)
{
service_impl_.async_connect(impl, peer_endpoint, handler);
}
/// Set a socket option.
template <typename SettableSocketOption>
asio::error_code set_option(implementation_type& impl,
const SettableSocketOption& option, asio::error_code& ec)
{
return service_impl_.set_option(impl, option, ec);
}
/// Get a socket option.
template <typename GettableSocketOption>
asio::error_code get_option(const implementation_type& impl,
GettableSocketOption& option, asio::error_code& ec) const
{
return service_impl_.get_option(impl, option, ec);
}
/// Perform an IO control command on the socket.
template <typename IoControlCommand>
asio::error_code io_control(implementation_type& impl,
IoControlCommand& command, asio::error_code& ec)
{
return service_impl_.io_control(impl, command, ec);
}
/// Get the local endpoint.
endpoint_type local_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.local_endpoint(impl, ec);
}
/// Get the remote endpoint.
endpoint_type remote_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.remote_endpoint(impl, ec);
}
/// Disable sends or receives on the socket.
asio::error_code shutdown(implementation_type& impl,
socket_base::shutdown_type what, asio::error_code& ec)
{
return service_impl_.shutdown(impl, what, ec);
}
/// Send the given data to the peer.
template <typename ConstBufferSequence>
std::size_t send(implementation_type& impl,
const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.send(impl, buffers, flags, ec);
}
/// Start an asynchronous send.
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
socket_base::message_flags flags, WriteHandler handler)
{
service_impl_.async_send(impl, buffers, flags, handler);
}
/// Send a datagram to the specified endpoint.
template <typename ConstBufferSequence>
std::size_t send_to(implementation_type& impl,
const ConstBufferSequence& buffers, const endpoint_type& destination,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.send_to(impl, buffers, destination, flags, ec);
}
/// Start an asynchronous send.
template <typename ConstBufferSequence, typename WriteHandler>
void async_send_to(implementation_type& impl,
const ConstBufferSequence& buffers, const endpoint_type& destination,
socket_base::message_flags flags, WriteHandler handler)
{
service_impl_.async_send_to(impl, buffers, destination, flags, handler);
}
/// Receive some data from the peer.
template <typename MutableBufferSequence>
std::size_t receive(implementation_type& impl,
const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.receive(impl, buffers, flags, ec);
}
/// Start an asynchronous receive.
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(implementation_type& impl,
const MutableBufferSequence& buffers,
socket_base::message_flags flags, ReadHandler handler)
{
service_impl_.async_receive(impl, buffers, flags, handler);
}
/// Receive a datagram with the endpoint of the sender.
template <typename MutableBufferSequence>
std::size_t receive_from(implementation_type& impl,
const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.receive_from(impl, buffers, sender_endpoint, flags,
ec);
}
/// Start an asynchronous receive that will get the endpoint of the sender.
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive_from(implementation_type& impl,
const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
socket_base::message_flags flags, ReadHandler handler)
{
service_impl_.async_receive_from(impl, buffers, sender_endpoint, flags,
handler);
}
private:
// The service that provides the platform-specific implementation.
service_impl_type& service_impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DATAGRAM_SOCKET_SERVICE_HPP

View File

@ -1,37 +0,0 @@
//
// deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DEADLINE_TIMER_HPP
#define ASIO_DEADLINE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
#include "asio/detail/push_options.hpp"
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_deadline_timer.hpp"
namespace asio {
/// Typedef for the typical usage of timer.
typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DEADLINE_TIMER_HPP

View File

@ -1,168 +0,0 @@
//
// deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DEADLINE_TIMER_SERVICE_HPP
#define ASIO_DEADLINE_TIMER_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/io_service.hpp"
#include "asio/time_traits.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/detail/epoll_reactor.hpp"
#include "asio/detail/kqueue_reactor.hpp"
#include "asio/detail/select_reactor.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/win_iocp_io_service.hpp"
namespace asio {
/// Default service implementation for a timer.
template <typename TimeType,
typename TimeTraits = asio::time_traits<TimeType> >
class deadline_timer_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_service::service
#else
: public asio::detail::service_base<
deadline_timer_service<TimeType, TimeTraits> >
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_service::id id;
#endif
/// The time traits type.
typedef TimeTraits traits_type;
/// The time type.
typedef typename traits_type::time_type time_type;
/// The duration type.
typedef typename traits_type::duration_type duration_type;
private:
// The type of the platform-specific implementation.
#if defined(ASIO_HAS_IOCP)
typedef detail::deadline_timer_service<
traits_type, detail::win_iocp_io_service> service_impl_type;
#elif defined(ASIO_HAS_EPOLL)
typedef detail::deadline_timer_service<
traits_type, detail::epoll_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::deadline_timer_service<
traits_type, detail::kqueue_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_DEV_POLL)
typedef detail::deadline_timer_service<
traits_type, detail::dev_poll_reactor<false> > service_impl_type;
#else
typedef detail::deadline_timer_service<
traits_type, detail::select_reactor<false> > service_impl_type;
#endif
public:
/// The implementation type of the deadline timer.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef typename service_impl_type::implementation_type implementation_type;
#endif
/// Construct a new timer service for the specified io_service.
explicit deadline_timer_service(asio::io_service& io_service)
: asio::detail::service_base<
deadline_timer_service<TimeType, TimeTraits> >(io_service),
service_impl_(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);
}
/// Cancel any asynchronous wait operations associated with the timer.
std::size_t cancel(implementation_type& impl, asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}
/// Get the expiry time for the timer as an absolute time.
time_type expires_at(const implementation_type& impl) const
{
return service_impl_.expires_at(impl);
}
/// Set the expiry time for the timer as an absolute time.
std::size_t expires_at(implementation_type& impl,
const time_type& expiry_time, asio::error_code& ec)
{
return service_impl_.expires_at(impl, expiry_time, ec);
}
/// Get the expiry time for the timer relative to now.
duration_type expires_from_now(const implementation_type& impl) const
{
return service_impl_.expires_from_now(impl);
}
/// Set the expiry time for the timer relative to now.
std::size_t expires_from_now(implementation_type& impl,
const duration_type& expiry_time, asio::error_code& ec)
{
return service_impl_.expires_from_now(impl, expiry_time, ec);
}
// Perform a blocking wait on the timer.
void wait(implementation_type& impl, asio::error_code& ec)
{
service_impl_.wait(impl, ec);
}
// Start an asynchronous wait on the timer.
template <typename WaitHandler>
void async_wait(implementation_type& impl, WaitHandler handler)
{
service_impl_.async_wait(impl, handler);
}
private:
// The service that provides the platform-specific implementation.
service_impl_type& service_impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DEADLINE_TIMER_SERVICE_HPP

View File

@ -1,349 +0,0 @@
//
// bind_handler.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_BIND_HANDLER_HPP
#define ASIO_DETAIL_BIND_HANDLER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
namespace asio {
namespace detail {
template <typename Handler, typename Arg1>
class binder1
{
public:
binder1(const Handler& handler, const Arg1& arg1)
: handler_(handler),
arg1_(arg1)
{
}
void operator()()
{
handler_(arg1_);
}
void operator()() const
{
handler_(arg1_);
}
//private:
Handler handler_;
Arg1 arg1_;
};
template <typename Handler, typename Arg1>
inline void* asio_handler_allocate(std::size_t size,
binder1<Handler, Arg1>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder1<Handler, Arg1>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1>
inline void asio_handler_invoke(const Function& function,
binder1<Handler, Arg1>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1>
inline binder1<Handler, Arg1> bind_handler(const Handler& handler,
const Arg1& arg1)
{
return binder1<Handler, Arg1>(handler, arg1);
}
template <typename Handler, typename Arg1, typename Arg2>
class binder2
{
public:
binder2(const Handler& handler, const Arg1& arg1, const Arg2& arg2)
: handler_(handler),
arg1_(arg1),
arg2_(arg2)
{
}
void operator()()
{
handler_(arg1_, arg2_);
}
void operator()() const
{
handler_(arg1_, arg2_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
};
template <typename Handler, typename Arg1, typename Arg2>
inline void* asio_handler_allocate(std::size_t size,
binder2<Handler, Arg1, Arg2>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder2<Handler, Arg1, Arg2>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_invoke(const Function& function,
binder2<Handler, Arg1, Arg2>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2>
inline binder2<Handler, Arg1, Arg2> bind_handler(const Handler& handler,
const Arg1& arg1, const Arg2& arg2)
{
return binder2<Handler, Arg1, Arg2>(handler, arg1, arg2);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
class binder3
{
public:
binder3(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3)
: handler_(handler),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3)
{
}
void operator()()
{
handler_(arg1_, arg2_, arg3_);
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void* asio_handler_allocate(std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->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)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline binder3<Handler, Arg1, Arg2, Arg3> bind_handler(const Handler& handler,
const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
{
return binder3<Handler, Arg1, Arg2, Arg3>(handler, arg1, arg2, arg3);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
class binder4
{
public:
binder4(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4)
: handler_(handler),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4)
{
}
void operator()()
{
handler_(arg1_, arg2_, arg3_, arg4_);
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
inline void* asio_handler_allocate(std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->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)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
inline binder4<Handler, Arg1, Arg2, Arg3, Arg4> bind_handler(
const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4)
{
return binder4<Handler, Arg1, Arg2, Arg3, Arg4>(handler, arg1, arg2, arg3,
arg4);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
class binder5
{
public:
binder5(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
: handler_(handler),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4),
arg5_(arg5)
{
}
void operator()()
{
handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
Arg5 arg5_;
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
inline void* asio_handler_allocate(std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->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)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
inline binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> bind_handler(
const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
{
return binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>(handler, arg1, arg2,
arg3, arg4, arg5);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_BIND_HANDLER_HPP

View File

@ -1,70 +0,0 @@
//
// buffer_resize_guard.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
#define ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <limits>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
// Helper class to manage buffer resizing in an exception safe way.
template <typename Buffer>
class buffer_resize_guard
{
public:
// Constructor.
buffer_resize_guard(Buffer& buffer)
: buffer_(buffer),
old_size_(buffer.size())
{
}
// Destructor rolls back the buffer resize unless commit was called.
~buffer_resize_guard()
{
if (old_size_
!= std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
{
buffer_.resize(old_size_);
}
}
// Commit the resize transaction.
void commit()
{
old_size_
= std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION();
}
private:
// The buffer being managed.
Buffer& buffer_;
// The size of the buffer at the time the guard was constructed.
size_t old_size_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP

View File

@ -1,127 +0,0 @@
//
// buffered_stream_storage.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
#define ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <vector>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
class buffered_stream_storage
{
public:
// The type of the bytes stored in the buffer.
typedef unsigned char byte_type;
// The type used for offsets into the buffer.
typedef std::size_t size_type;
// Constructor.
explicit buffered_stream_storage(std::size_t capacity)
: begin_offset_(0),
end_offset_(0),
buffer_(capacity)
{
}
/// Clear the buffer.
void clear()
{
begin_offset_ = 0;
end_offset_ = 0;
}
// Return a pointer to the beginning of the unread data.
byte_type* data()
{
return &buffer_[0] + begin_offset_;
}
// Return a pointer to the beginning of the unread data.
const byte_type* data() const
{
return &buffer_[0] + begin_offset_;
}
// Is there no unread data in the buffer.
bool empty() const
{
return begin_offset_ == end_offset_;
}
// Return the amount of unread data the is in the buffer.
size_type size() const
{
return end_offset_ - begin_offset_;
}
// Resize the buffer to the specified length.
void resize(size_type length)
{
assert(length <= capacity());
if (begin_offset_ + length <= capacity())
{
end_offset_ = begin_offset_ + length;
}
else
{
using namespace std; // For memmove.
memmove(&buffer_[0], &buffer_[0] + begin_offset_, size());
end_offset_ = length;
begin_offset_ = 0;
}
}
// Return the maximum size for data in the buffer.
size_type capacity() const
{
return buffer_.size();
}
// Consume multiple bytes from the beginning of the buffer.
void consume(size_type count)
{
assert(begin_offset_ + count <= end_offset_);
begin_offset_ += count;
if (empty())
clear();
}
private:
// The offset to the beginning of the unread data.
size_type begin_offset_;
// The offset to the end of the unread data.
size_type end_offset_;
// The data in the buffer.
std::vector<byte_type> buffer_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP

View File

@ -1,90 +0,0 @@
//
// call_stack.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_CALL_STACK_HPP
#define ASIO_DETAIL_CALL_STACK_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/tss_ptr.hpp"
namespace asio {
namespace detail {
// Helper class to determine whether or not the current thread is inside an
// invocation of io_service::run() for a specified io_service object.
template <typename Owner>
class call_stack
{
public:
// Context class automatically pushes an owner on to the stack.
class context
: private noncopyable
{
public:
// Push the owner on to the stack.
explicit context(Owner* d)
: owner_(d),
next_(call_stack<Owner>::top_)
{
call_stack<Owner>::top_ = this;
}
// Pop the owner from the stack.
~context()
{
call_stack<Owner>::top_ = next_;
}
private:
friend class call_stack<Owner>;
// The owner associated with the context.
Owner* owner_;
// The next element in the stack.
context* next_;
};
friend class context;
// Determine whether the specified owner is on the stack.
static bool contains(Owner* d)
{
context* elem = top_;
while (elem)
{
if (elem->owner_ == d)
return true;
elem = elem->next_;
}
return false;
}
private:
// The top of the stack of calls for the current thread.
static tss_ptr<context> top_;
};
template <typename Owner>
tss_ptr<typename call_stack<Owner>::context>
call_stack<Owner>::top_;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_CALL_STACK_HPP

View File

@ -1,151 +0,0 @@
//
// const_buffers_iterator.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP
#define ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
namespace asio {
namespace detail {
// A proxy iterator for a sub-range in a list of buffers.
template <typename ConstBufferSequence>
class const_buffers_iterator
: public boost::iterator_facade<const_buffers_iterator<ConstBufferSequence>,
const char, boost::bidirectional_traversal_tag>
{
public:
// Default constructor creates an iterator in an undefined state.
const_buffers_iterator()
{
}
// Create an iterator for the specified position.
const_buffers_iterator(const ConstBufferSequence& buffers,
std::size_t position)
: begin_(buffers.begin()),
current_(buffers.begin()),
end_(buffers.end()),
position_(0)
{
while (current_ != end_)
{
current_buffer_ = *current_;
std::size_t buffer_size = asio::buffer_size(current_buffer_);
if (position - position_ < buffer_size)
{
current_buffer_position_ = position - position_;
position_ = position;
return;
}
position_ += buffer_size;
++current_;
}
current_buffer_ = asio::const_buffer();
current_buffer_position_ = 0;
}
std::size_t position() const
{
return position_;
}
private:
friend class boost::iterator_core_access;
void increment()
{
if (current_ == end_)
return;
++position_;
++current_buffer_position_;
if (current_buffer_position_ != asio::buffer_size(current_buffer_))
return;
++current_;
current_buffer_position_ = 0;
while (current_ != end_)
{
current_buffer_ = *current_;
if (asio::buffer_size(current_buffer_) > 0)
return;
++current_;
}
}
void decrement()
{
if (position_ == 0)
return;
--position_;
if (current_buffer_position_ != 0)
{
--current_buffer_position_;
return;
}
typename ConstBufferSequence::const_iterator iter = current_;
while (iter != begin_)
{
--iter;
asio::const_buffer buffer = *iter;
std::size_t buffer_size = asio::buffer_size(buffer);
if (buffer_size > 0)
{
current_ = iter;
current_buffer_ = buffer;
current_buffer_position_ = buffer_size - 1;
return;
}
}
}
bool equal(const const_buffers_iterator& other) const
{
return position_ == other.position_;
}
const char& dereference() const
{
return asio::buffer_cast<const char*>(
current_buffer_)[current_buffer_position_];
}
asio::const_buffer current_buffer_;
std::size_t current_buffer_position_;
typename ConstBufferSequence::const_iterator begin_;
typename ConstBufferSequence::const_iterator current_;
typename ConstBufferSequence::const_iterator end_;
std::size_t position_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP

View File

@ -1,205 +0,0 @@
//
// consuming_buffers.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_CONSUMING_BUFFERS_HPP
#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <algorithm>
#include <cstddef>
#include <boost/config.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
// A proxy iterator for a sub-range in a list of buffers.
template <typename Buffer, typename Buffer_Iterator>
class consuming_buffers_iterator
: public boost::iterator_facade<
consuming_buffers_iterator<Buffer, Buffer_Iterator>,
const Buffer, boost::forward_traversal_tag>
{
public:
// Default constructor creates an end iterator.
consuming_buffers_iterator()
: at_end_(true)
{
}
// Construct with a buffer for the first entry and an iterator
// range for the remaining entries.
consuming_buffers_iterator(bool at_end, const Buffer& first,
Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder)
: at_end_(at_end),
first_(buffer(first, max_size)),
begin_remainder_(begin_remainder),
end_remainder_(end_remainder),
offset_(0)
{
}
private:
friend class boost::iterator_core_access;
enum { max_size = 65536 };
void increment()
{
if (!at_end_)
{
if (begin_remainder_ == end_remainder_
|| offset_ + buffer_size(first_) >= max_size)
{
at_end_ = true;
}
else
{
offset_ += buffer_size(first_);
first_ = buffer(*begin_remainder_++, max_size - offset_);
}
}
}
bool equal(const consuming_buffers_iterator& other) const
{
if (at_end_ && other.at_end_)
return true;
return !at_end_ && !other.at_end_
&& buffer_cast<const void*>(first_)
== buffer_cast<const void*>(other.first_)
&& buffer_size(first_) == buffer_size(other.first_)
&& begin_remainder_ == other.begin_remainder_
&& end_remainder_ == other.end_remainder_;
}
const Buffer& dereference() const
{
return first_;
}
bool at_end_;
Buffer first_;
Buffer_Iterator begin_remainder_;
Buffer_Iterator end_remainder_;
std::size_t offset_;
};
// A proxy for a sub-range in a list of buffers.
template <typename Buffer, typename Buffers>
class consuming_buffers
{
public:
// The type for each element in the list of buffers.
typedef Buffer value_type;
// A forward-only iterator type that may be used to read elements.
typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator>
const_iterator;
// Construct to represent the entire list of buffers.
consuming_buffers(const Buffers& buffers)
: buffers_(buffers),
at_end_(buffers_.begin() == buffers_.end()),
first_(*buffers_.begin()),
begin_remainder_(buffers_.begin())
{
if (!at_end_)
++begin_remainder_;
}
// Copy constructor.
consuming_buffers(const consuming_buffers& other)
: buffers_(other.buffers_),
at_end_(other.at_end_),
first_(other.first_),
begin_remainder_(buffers_.begin())
{
typename Buffers::const_iterator first = other.buffers_.begin();
typename Buffers::const_iterator second = other.begin_remainder_;
std::advance(begin_remainder_, std::distance(first, second));
}
// Assignment operator.
consuming_buffers& operator=(const consuming_buffers& other)
{
buffers_ = other.buffers_;
at_end_ = other.at_end_;
first_ = other.first_;
begin_remainder_ = buffers_.begin();
typename Buffers::const_iterator first = other.buffers_.begin();
typename Buffers::const_iterator second = other.begin_remainder_;
std::advance(begin_remainder_, std::distance(first, second));
return *this;
}
// Get a forward-only iterator to the first element.
const_iterator begin() const
{
return const_iterator(at_end_, first_, begin_remainder_, buffers_.end());
}
// Get a forward-only iterator for one past the last element.
const_iterator end() const
{
return const_iterator();
}
// Consume the specified number of bytes from the buffers.
void consume(std::size_t size)
{
// Remove buffers from the start until the specified size is reached.
while (size > 0 && !at_end_)
{
if (buffer_size(first_) <= size)
{
size -= buffer_size(first_);
if (begin_remainder_ == buffers_.end())
at_end_ = true;
else
first_ = *begin_remainder_++;
}
else
{
first_ = first_ + size;
size = 0;
}
}
// Remove any more empty buffers at the start.
while (!at_end_ && buffer_size(first_) == 0)
{
if (begin_remainder_ == buffers_.end())
at_end_ = true;
else
first_ = *begin_remainder_++;
}
}
private:
Buffers buffers_;
bool at_end_;
Buffer first_;
typename Buffers::const_iterator begin_remainder_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP

View File

@ -1,199 +0,0 @@
//
// deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
#define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
namespace asio {
namespace detail {
template <typename Time_Traits, typename Timer_Scheduler>
class deadline_timer_service
: public asio::detail::service_base<
deadline_timer_service<Time_Traits, Timer_Scheduler> >
{
public:
// The time type.
typedef typename Time_Traits::time_type time_type;
// The duration type.
typedef typename Time_Traits::duration_type duration_type;
// The implementation type of the timer. This type is dependent on the
// underlying implementation of the timer service.
struct implementation_type
: private asio::detail::noncopyable
{
time_type expiry;
bool might_have_pending_waits;
};
// Constructor.
deadline_timer_service(asio::io_service& io_service)
: asio::detail::service_base<
deadline_timer_service<Time_Traits, Timer_Scheduler> >(io_service),
scheduler_(asio::use_service<Timer_Scheduler>(io_service))
{
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()
{
}
// Construct a new timer implementation.
void construct(implementation_type& impl)
{
impl.expiry = time_type();
impl.might_have_pending_waits = false;
}
// Destroy a timer implementation.
void destroy(implementation_type& impl)
{
asio::error_code ec;
cancel(impl, ec);
}
// Cancel any asynchronous wait operations associated with the timer.
std::size_t cancel(implementation_type& impl, asio::error_code& ec)
{
if (!impl.might_have_pending_waits)
{
ec = asio::error_code();
return 0;
}
std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl);
impl.might_have_pending_waits = false;
ec = asio::error_code();
return count;
}
// Get the expiry time for the timer as an absolute time.
time_type expires_at(const implementation_type& impl) const
{
return impl.expiry;
}
// Set the expiry time for the timer as an absolute time.
std::size_t expires_at(implementation_type& impl,
const time_type& expiry_time, asio::error_code& ec)
{
std::size_t count = cancel(impl, ec);
impl.expiry = expiry_time;
ec = asio::error_code();
return count;
}
// Get the expiry time for the timer relative to now.
duration_type expires_from_now(const implementation_type& impl) const
{
return Time_Traits::subtract(expires_at(impl), Time_Traits::now());
}
// Set the expiry time for the timer relative to now.
std::size_t expires_from_now(implementation_type& impl,
const duration_type& expiry_time, asio::error_code& ec)
{
return expires_at(impl,
Time_Traits::add(Time_Traits::now(), expiry_time), ec);
}
// Perform a blocking wait on the timer.
void wait(implementation_type& impl, asio::error_code& ec)
{
time_type now = Time_Traits::now();
while (Time_Traits::less_than(now, impl.expiry))
{
boost::posix_time::time_duration timeout =
Time_Traits::to_posix_duration(Time_Traits::subtract(impl.expiry, now));
::timeval tv;
tv.tv_sec = timeout.total_seconds();
tv.tv_usec = timeout.total_microseconds() % 1000000;
asio::error_code ec;
socket_ops::select(0, 0, 0, 0, &tv, ec);
now = Time_Traits::now();
}
ec = asio::error_code();
}
template <typename Handler>
class wait_handler
{
public:
wait_handler(asio::io_service& io_service, Handler handler)
: io_service_(io_service),
work_(io_service),
handler_(handler)
{
}
void operator()(const asio::error_code& result)
{
io_service_.post(detail::bind_handler(handler_, result));
}
private:
asio::io_service& io_service_;
asio::io_service::work work_;
Handler handler_;
};
// Start an asynchronous wait on the timer.
template <typename Handler>
void async_wait(implementation_type& impl, Handler handler)
{
impl.might_have_pending_waits = true;
scheduler_.schedule_timer(timer_queue_, impl.expiry,
wait_handler<Handler>(this->get_io_service(), handler), &impl);
}
private:
// The queue of timers.
timer_queue<Time_Traits> timer_queue_;
// The object that schedules and executes timers. Usually a reactor.
Timer_Scheduler& scheduler_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP

View File

@ -1,647 +0,0 @@
//
// dev_poll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_DEV_POLL_REACTOR_HPP
#define ASIO_DETAIL_DEV_POLL_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/dev_poll_reactor_fwd.hpp"
#if defined(ASIO_HAS_DEV_POLL)
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <vector>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/throw_exception.hpp>
#include <sys/devpoll.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/task_io_service.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
namespace asio {
namespace detail {
template <bool Own_Thread>
class dev_poll_reactor
: public asio::detail::service_base<dev_poll_reactor<Own_Thread> >
{
public:
// Constructor.
dev_poll_reactor(asio::io_service& io_service)
: asio::detail::service_base<
dev_poll_reactor<Own_Thread> >(io_service),
mutex_(),
dev_poll_fd_(do_dev_poll_create()),
wait_in_progress_(false),
interrupter_(),
read_op_queue_(),
write_op_queue_(),
except_op_queue_(),
pending_cancellations_(),
stop_thread_(false),
thread_(0),
shutdown_(false)
{
// Start the reactor's internal thread only if needed.
if (Own_Thread)
{
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&dev_poll_reactor::call_run_thread, this));
}
// Add the interrupter's descriptor to /dev/poll.
::pollfd ev = { 0 };
ev.fd = interrupter_.read_descriptor();
ev.events = POLLIN | POLLERR;
ev.revents = 0;
::write(dev_poll_fd_, &ev, sizeof(ev));
}
// Destructor.
~dev_poll_reactor()
{
shutdown_service();
::close(dev_poll_fd_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_thread_ = true;
lock.unlock();
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
}
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type descriptor)
{
return 0;
}
// Start a new read operation. The handler object will be invoked when the
// given descriptor is ready to be read, or an error has occurred.
template <typename Handler>
void start_read_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!read_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLIN | POLLERR | POLLHUP;
if (write_op_queue_.has_operation(descriptor))
ev.events |= POLLOUT;
if (except_op_queue_.has_operation(descriptor))
ev.events |= POLLPRI;
interrupter_.interrupt();
}
}
// Start a new write operation. The handler object will be invoked when the
// given descriptor is ready to be written, or an error has occurred.
template <typename Handler>
void start_write_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!write_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLOUT | POLLERR | POLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= POLLIN;
if (except_op_queue_.has_operation(descriptor))
ev.events |= POLLPRI;
interrupter_.interrupt();
}
}
// Start a new exception operation. The handler object will be invoked when
// the given descriptor has exception information, or an error has occurred.
template <typename Handler>
void start_except_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (except_op_queue_.enqueue_operation(descriptor, handler))
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLPRI | POLLERR | POLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= POLLIN;
if (write_op_queue_.has_operation(descriptor))
ev.events |= POLLOUT;
interrupter_.interrupt();
}
}
// Start new write and exception operations. The handler object will be
// invoked when the given descriptor is ready for writing or has exception
// information available, or an error has occurred.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
bool need_mod = write_op_queue_.enqueue_operation(descriptor, handler);
need_mod = except_op_queue_.enqueue_operation(descriptor, handler)
&& need_mod;
if (need_mod)
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLOUT | POLLPRI | POLLERR | POLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= POLLIN;
interrupter_.interrupt();
}
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Enqueue cancellation of all operations associated with the given
// descriptor. The handlers associated with the descriptor will be invoked
// with the operation_aborted error. This function does not acquire the
// dev_poll_reactor's mutex, and so should only be used from within a reactor
// handler.
void enqueue_cancel_ops_unlocked(socket_type descriptor)
{
pending_cancellations_.push_back(descriptor);
}
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Remove the descriptor from /dev/poll.
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLREMOVE;
interrupter_.interrupt();
// Cancel any outstanding operations associated with the descriptor.
cancel_ops_unlocked(descriptor);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
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)
{
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>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
std::size_t n = timer_queue.cancel_timer(token);
if (n > 0)
interrupter_.interrupt();
return n;
}
private:
friend class task_io_service<dev_poll_reactor<Own_Thread> >;
// Run /dev/poll once until interrupted or events are ready to be dispatched.
void run(bool block)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Dispatch any operation cancellations that were made while the select
// loop was not running.
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->dispatch_cancellations();
// Check if the thread is supposed to stop.
if (stop_thread_)
{
cleanup_operations_and_timers(lock);
return;
}
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
cleanup_operations_and_timers(lock);
return;
}
// Write the pending event registration changes to the /dev/poll descriptor.
std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
errno = 0;
int result = ::write(dev_poll_fd_,
&pending_event_changes_[0], events_size);
if (result != static_cast<int>(events_size))
{
for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
{
int descriptor = pending_event_changes_[i].fd;
asio::error_code ec = asio::error_code(
errno, asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
pending_event_changes_.clear();
pending_event_change_index_.clear();
int timeout = block ? get_timeout() : 0;
wait_in_progress_ = true;
lock.unlock();
// Block on the /dev/poll descriptor.
::pollfd events[128] = { { 0 } };
::dvpoll dp = { 0 };
dp.dp_fds = events;
dp.dp_nfds = 128;
dp.dp_timeout = timeout;
int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
lock.lock();
wait_in_progress_ = false;
// Block signals while dispatching operations.
asio::detail::signal_blocker sb;
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].fd;
if (descriptor == interrupter_.read_descriptor())
{
interrupter_.reset();
}
else
{
bool more_reads = false;
bool more_writes = false;
bool more_except = false;
asio::error_code ec;
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
more_except = except_op_queue_.dispatch_operation(descriptor, ec);
else
more_except = except_op_queue_.has_operation(descriptor);
if (events[i].events & (POLLIN | POLLERR | POLLHUP))
more_reads = read_op_queue_.dispatch_operation(descriptor, ec);
else
more_reads = read_op_queue_.has_operation(descriptor);
if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
more_writes = write_op_queue_.dispatch_operation(descriptor, ec);
else
more_writes = write_op_queue_.has_operation(descriptor);
if ((events[i].events == POLLHUP)
&& !more_except && !more_reads && !more_writes)
{
// If we have only an POLLHUP event and no operations associated
// with the descriptor then we need to delete the descriptor from
// /dev/poll. The poll operation might produce POLLHUP events even
// if they are not specifically requested, so if we do not remove the
// descriptor we can end up in a tight polling loop.
::pollfd ev = { 0 };
ev.fd = descriptor;
ev.events = POLLREMOVE;
ev.revents = 0;
::write(dev_poll_fd_, &ev, sizeof(ev));
}
else
{
::pollfd ev = { 0 };
ev.fd = descriptor;
ev.events = POLLERR | POLLHUP;
if (more_reads)
ev.events |= POLLIN;
if (more_writes)
ev.events |= POLLOUT;
if (more_except)
ev.events |= POLLPRI;
ev.revents = 0;
int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
if (result != sizeof(ev))
{
ec = asio::error_code(errno,
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
}
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
timer_queues_[i]->dispatch_timers();
timer_queues_[i]->dispatch_cancellations();
}
// Issue any pending cancellations.
for (size_t i = 0; i < pending_cancellations_.size(); ++i)
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
cleanup_operations_and_timers(lock);
}
// Run the select loop in the thread.
void run_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!stop_thread_)
{
lock.unlock();
run(true);
lock.lock();
}
}
// Entry point for the select loop thread.
static void call_run_thread(dev_poll_reactor* reactor)
{
reactor->run_thread();
}
// Interrupt the select loop.
void interrupt()
{
interrupter_.interrupt();
}
// Create the /dev/poll file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_dev_poll_create()
{
int fd = ::open("/dev/poll", O_RDWR);
if (fd == -1)
{
boost::throw_exception(
asio::system_error(
asio::error_code(errno,
asio::error::get_system_category()),
"/dev/poll"));
}
return fd;
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the /dev/poll DP_POLL operation. The timeout
// value is returned as a number of milliseconds. A return value of -1
// indicates that the poll should block indefinitely.
int get_timeout()
{
if (all_timer_queues_are_empty())
return -1;
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::minutes(5);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
int milliseconds = minimum_wait_duration.total_milliseconds();
return milliseconds > 0 ? milliseconds : 1;
}
else
{
return 0;
}
}
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the dev_poll_reactor's mutex.
void cancel_ops_unlocked(socket_type descriptor)
{
bool interrupt = read_op_queue_.cancel_operations(descriptor);
interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
if (interrupt)
interrupter_.interrupt();
}
// Clean up operations and timers. We must not hold the lock since the
// destructors may make calls back into this reactor. We make a copy of the
// vector of timer queues since the original may be modified while the lock
// is not held.
void cleanup_operations_and_timers(
asio::detail::mutex::scoped_lock& lock)
{
timer_queues_for_cleanup_ = timer_queues_;
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
timer_queues_for_cleanup_[i]->cleanup_timers();
}
// Add a pending event entry for the given descriptor.
::pollfd& add_pending_event_change(int descriptor)
{
hash_map<int, std::size_t>::iterator iter
= pending_event_change_index_.find(descriptor);
if (iter == pending_event_change_index_.end())
{
std::size_t index = pending_event_changes_.size();
pending_event_changes_.reserve(pending_event_changes_.size() + 1);
pending_event_change_index_.insert(std::make_pair(descriptor, index));
pending_event_changes_.push_back(::pollfd());
pending_event_changes_[index].fd = descriptor;
pending_event_changes_[index].revents = 0;
return pending_event_changes_[index];
}
else
{
return pending_event_changes_[iter->second];
}
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// The /dev/poll file descriptor.
int dev_poll_fd_;
// Vector of /dev/poll events waiting to be written to the descriptor.
std::vector< ::pollfd> pending_event_changes_;
// Hash map to associate a descriptor with a pending event change index.
hash_map<int, std::size_t> pending_event_change_index_;
// Whether the DP_POLL operation is currently in progress
bool wait_in_progress_;
// The interrupter is used to break a blocking DP_POLL operation.
select_interrupter interrupter_;
// The queue of read operations.
reactor_op_queue<socket_type> read_op_queue_;
// The queue of write operations.
reactor_op_queue<socket_type> write_op_queue_;
// The queue of except operations.
reactor_op_queue<socket_type> except_op_queue_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// A copy of the timer queues, used when cleaning up timers. The copy is
// stored as a class data member to avoid unnecessary memory allocation.
std::vector<timer_queue_base*> timer_queues_for_cleanup_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
// Does the reactor loop thread need to stop.
bool stop_thread_;
// The thread that is running the reactor loop.
asio::detail::thread* thread_;
// Whether the service has been shut down.
bool shutdown_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_DEV_POLL)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP

View File

@ -1,40 +0,0 @@
//
// dev_poll_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
#define ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#if !defined(ASIO_DISABLE_DEV_POLL)
#if defined(__sun) // This service is only supported on Solaris.
// Define this to indicate that /dev/poll is supported on the target platform.
#define ASIO_HAS_DEV_POLL 1
namespace asio {
namespace detail {
template <bool Own_Thread>
class dev_poll_reactor;
} // namespace detail
} // namespace asio
#endif // defined(__sun)
#endif // !defined(ASIO_DISABLE_DEV_POLL)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP

View File

@ -1,654 +0,0 @@
//
// epoll_reactor.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_EPOLL_REACTOR_HPP
#define ASIO_DETAIL_EPOLL_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/epoll_reactor_fwd.hpp"
#if defined(ASIO_HAS_EPOLL)
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <vector>
#include <sys/epoll.h>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/task_io_service.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
namespace asio {
namespace detail {
template <bool Own_Thread>
class epoll_reactor
: public asio::detail::service_base<epoll_reactor<Own_Thread> >
{
public:
// Constructor.
epoll_reactor(asio::io_service& io_service)
: asio::detail::service_base<epoll_reactor<Own_Thread> >(io_service),
mutex_(),
epoll_fd_(do_epoll_create()),
wait_in_progress_(false),
interrupter_(),
read_op_queue_(),
write_op_queue_(),
except_op_queue_(),
pending_cancellations_(),
stop_thread_(false),
thread_(0),
shutdown_(false),
need_epoll_wait_(true)
{
// Start the reactor's internal thread only if needed.
if (Own_Thread)
{
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&epoll_reactor::call_run_thread, this));
}
// Add the interrupter's descriptor to epoll.
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR;
ev.data.fd = interrupter_.read_descriptor();
epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
}
// Destructor.
~epoll_reactor()
{
shutdown_service();
close(epoll_fd_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_thread_ = true;
lock.unlock();
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
}
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type descriptor)
{
// No need to lock according to epoll documentation.
epoll_event ev = { 0, { 0 } };
ev.events = 0;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
return errno;
return 0;
}
// Start a new read operation. The handler object will be invoked when the
// given descriptor is ready to be read, or an error has occurred.
template <typename Handler>
void start_read_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!read_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLHUP;
if (write_op_queue_.has_operation(descriptor))
ev.events |= EPOLLOUT;
if (except_op_queue_.has_operation(descriptor))
ev.events |= EPOLLPRI;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno,
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start a new write operation. The handler object will be invoked when the
// given descriptor is ready to be written, or an error has occurred.
template <typename Handler>
void start_write_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!write_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= EPOLLIN;
if (except_op_queue_.has_operation(descriptor))
ev.events |= EPOLLPRI;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno,
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start a new exception operation. The handler object will be invoked when
// the given descriptor has exception information, or an error has occurred.
template <typename Handler>
void start_except_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (except_op_queue_.enqueue_operation(descriptor, handler))
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLPRI | EPOLLERR | EPOLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= EPOLLIN;
if (write_op_queue_.has_operation(descriptor))
ev.events |= EPOLLOUT;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno,
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start new write and exception operations. The handler object will be
// invoked when the given descriptor is ready for writing or has exception
// information available, or an error has occurred.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
bool need_mod = write_op_queue_.enqueue_operation(descriptor, handler);
need_mod = except_op_queue_.enqueue_operation(descriptor, handler)
&& need_mod;
if (need_mod)
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLOUT | EPOLLPRI | EPOLLERR | EPOLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= EPOLLIN;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno,
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Enqueue cancellation of all operations associated with the given
// descriptor. The handlers associated with the descriptor will be invoked
// with the operation_aborted error. This function does not acquire the
// epoll_reactor's mutex, and so should only be used from within a reactor
// handler.
void enqueue_cancel_ops_unlocked(socket_type descriptor)
{
pending_cancellations_.push_back(descriptor);
}
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Remove the descriptor from epoll.
epoll_event ev = { 0, { 0 } };
epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
// Cancel any outstanding operations associated with the descriptor.
cancel_ops_unlocked(descriptor);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
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)
{
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>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
std::size_t n = timer_queue.cancel_timer(token);
if (n > 0)
interrupter_.interrupt();
return n;
}
private:
friend class task_io_service<epoll_reactor<Own_Thread> >;
// Run epoll once until interrupted or events are ready to be dispatched.
void run(bool block)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Dispatch any operation cancellations that were made while the select
// loop was not running.
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->dispatch_cancellations();
// Check if the thread is supposed to stop.
if (stop_thread_)
{
cleanup_operations_and_timers(lock);
return;
}
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
cleanup_operations_and_timers(lock);
return;
}
int timeout = block ? get_timeout() : 0;
wait_in_progress_ = true;
lock.unlock();
// Block on the epoll descriptor.
epoll_event events[128];
int num_events = (block || need_epoll_wait_)
? epoll_wait(epoll_fd_, events, 128, timeout)
: 0;
lock.lock();
wait_in_progress_ = false;
// Block signals while dispatching operations.
asio::detail::signal_blocker sb;
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].data.fd;
if (descriptor == interrupter_.read_descriptor())
{
interrupter_.reset();
}
else
{
bool more_reads = false;
bool more_writes = false;
bool more_except = false;
asio::error_code ec;
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
if (events[i].events & (EPOLLPRI | EPOLLERR | EPOLLHUP))
more_except = except_op_queue_.dispatch_operation(descriptor, ec);
else
more_except = except_op_queue_.has_operation(descriptor);
if (events[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP))
more_reads = read_op_queue_.dispatch_operation(descriptor, ec);
else
more_reads = read_op_queue_.has_operation(descriptor);
if (events[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP))
more_writes = write_op_queue_.dispatch_operation(descriptor, ec);
else
more_writes = write_op_queue_.has_operation(descriptor);
if ((events[i].events == EPOLLHUP)
&& !more_except && !more_reads && !more_writes)
{
// If we have only an EPOLLHUP event and no operations associated
// with the descriptor then we need to delete the descriptor from
// epoll. The epoll_wait system call will produce EPOLLHUP events
// even if they are not specifically requested, so if we do not
// remove the descriptor we can end up in a tight loop of repeated
// calls to epoll_wait.
epoll_event ev = { 0, { 0 } };
epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
}
else
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLERR | EPOLLHUP;
if (more_reads)
ev.events |= EPOLLIN;
if (more_writes)
ev.events |= EPOLLOUT;
if (more_except)
ev.events |= EPOLLPRI;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
ec = asio::error_code(errno,
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
}
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
timer_queues_[i]->dispatch_timers();
timer_queues_[i]->dispatch_cancellations();
}
// Issue any pending cancellations.
for (size_t i = 0; i < pending_cancellations_.size(); ++i)
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
// Determine whether epoll_wait should be called when the reactor next runs.
need_epoll_wait_ = !read_op_queue_.empty()
|| !write_op_queue_.empty() || !except_op_queue_.empty();
cleanup_operations_and_timers(lock);
}
// Run the select loop in the thread.
void run_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!stop_thread_)
{
lock.unlock();
run(true);
lock.lock();
}
}
// Entry point for the select loop thread.
static void call_run_thread(epoll_reactor* reactor)
{
reactor->run_thread();
}
// Interrupt the select loop.
void interrupt()
{
interrupter_.interrupt();
}
// The hint to pass to epoll_create to size its data structures.
enum { epoll_size = 20000 };
// Create the epoll file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_epoll_create()
{
int fd = epoll_create(epoll_size);
if (fd == -1)
{
boost::throw_exception(
asio::system_error(
asio::error_code(errno,
asio::error::get_system_category()),
"epoll"));
}
return fd;
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the epoll_wait call. The timeout value is
// returned as a number of milliseconds. A return value of -1 indicates
// that epoll_wait should block indefinitely.
int get_timeout()
{
if (all_timer_queues_are_empty())
return -1;
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::minutes(5);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
int milliseconds = minimum_wait_duration.total_milliseconds();
return milliseconds > 0 ? milliseconds : 1;
}
else
{
return 0;
}
}
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the epoll_reactor's mutex.
void cancel_ops_unlocked(socket_type descriptor)
{
bool interrupt = read_op_queue_.cancel_operations(descriptor);
interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
if (interrupt)
interrupter_.interrupt();
}
// Clean up operations and timers. We must not hold the lock since the
// destructors may make calls back into this reactor. We make a copy of the
// vector of timer queues since the original may be modified while the lock
// is not held.
void cleanup_operations_and_timers(
asio::detail::mutex::scoped_lock& lock)
{
timer_queues_for_cleanup_ = timer_queues_;
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
timer_queues_for_cleanup_[i]->cleanup_timers();
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// The epoll file descriptor.
int epoll_fd_;
// Whether the epoll_wait call is currently in progress
bool wait_in_progress_;
// The interrupter is used to break a blocking epoll_wait call.
select_interrupter interrupter_;
// The queue of read operations.
reactor_op_queue<socket_type> read_op_queue_;
// The queue of write operations.
reactor_op_queue<socket_type> write_op_queue_;
// The queue of except operations.
reactor_op_queue<socket_type> except_op_queue_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// A copy of the timer queues, used when cleaning up timers. The copy is
// stored as a class data member to avoid unnecessary memory allocation.
std::vector<timer_queue_base*> timer_queues_for_cleanup_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
// Does the reactor loop thread need to stop.
bool stop_thread_;
// The thread that is running the reactor loop.
asio::detail::thread* thread_;
// Whether the service has been shut down.
bool shutdown_;
// Whether we need to call epoll_wait the next time the reactor is run.
bool need_epoll_wait_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_EPOLL)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP

View File

@ -1,47 +0,0 @@
//
// epoll_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
#define ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#if !defined(ASIO_DISABLE_EPOLL)
#if defined(__linux__) // This service is only supported on Linux.
#include "asio/detail/push_options.hpp"
#include <linux/version.h>
#include "asio/detail/pop_options.hpp"
#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45.
// Define this to indicate that epoll is supported on the target platform.
#define ASIO_HAS_EPOLL 1
namespace asio {
namespace detail {
template <bool Own_Thread>
class epoll_reactor;
} // namespace detail
} // namespace asio
#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45)
#endif // defined(__linux__)
#endif // !defined(ASIO_DISABLE_EPOLL)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP

View File

@ -1,50 +0,0 @@
//
// event.hpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_EVENT_HPP
#define ASIO_DETAIL_EVENT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_event.hpp"
#elif defined(BOOST_WINDOWS)
# include "asio/detail/win_event.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_event.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
#if !defined(BOOST_HAS_THREADS)
typedef null_event event;
#elif defined(BOOST_WINDOWS)
typedef win_event event;
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_event event;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_EVENT_HPP

View File

@ -1,41 +0,0 @@
//
// fd_set_adapter.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_FD_SET_ADAPTER_HPP
#define ASIO_DETAIL_FD_SET_ADAPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/posix_fd_set_adapter.hpp"
#include "asio/detail/win_fd_set_adapter.hpp"
namespace asio {
namespace detail {
#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
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP

View File

@ -1,256 +0,0 @@
//
// handler_alloc_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
#define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/detail/workaround.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/handler_alloc_hook.hpp"
#include "asio/detail/noncopyable.hpp"
// Calls to asio_handler_allocate and asio_handler_deallocate must be made from
// a namespace that does not contain any overloads of these functions. The
// asio_handler_alloc_helpers namespace is defined here for that purpose.
namespace asio_handler_alloc_helpers {
template <typename Handler>
inline void* allocate(std::size_t s, Handler* h)
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
return ::operator new(s);
#else
using namespace asio;
return asio_handler_allocate(s, h);
#endif
}
template <typename Handler>
inline void deallocate(void* p, std::size_t s, Handler* h)
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
::operator delete(p);
#else
using namespace asio;
asio_handler_deallocate(p, s, h);
#endif
}
} // namespace asio_handler_alloc_helpers
namespace asio {
namespace detail {
// Traits for handler allocation.
template <typename Handler, typename Object>
struct handler_alloc_traits
{
typedef Handler handler_type;
typedef Object value_type;
typedef Object* pointer_type;
BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object));
};
template <typename Alloc_Traits>
class handler_ptr;
// Helper class to provide RAII on uninitialised handler memory.
template <typename Alloc_Traits>
class raw_handler_ptr
: private noncopyable
{
public:
typedef typename Alloc_Traits::handler_type handler_type;
typedef typename Alloc_Traits::value_type value_type;
typedef typename Alloc_Traits::pointer_type pointer_type;
BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
// Constructor allocates the memory.
raw_handler_ptr(handler_type& handler)
: handler_(handler),
pointer_(static_cast<pointer_type>(
asio_handler_alloc_helpers::allocate(value_size, &handler_)))
{
}
// Destructor automatically deallocates memory, unless it has been stolen by
// a handler_ptr object.
~raw_handler_ptr()
{
if (pointer_)
asio_handler_alloc_helpers::deallocate(
pointer_, value_size, &handler_);
}
private:
friend class handler_ptr<Alloc_Traits>;
handler_type& handler_;
pointer_type pointer_;
};
// Helper class to provide RAII on uninitialised handler memory.
template <typename Alloc_Traits>
class handler_ptr
: private noncopyable
{
public:
typedef typename Alloc_Traits::handler_type handler_type;
typedef typename Alloc_Traits::value_type value_type;
typedef typename Alloc_Traits::pointer_type pointer_type;
BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
typedef raw_handler_ptr<Alloc_Traits> raw_ptr_type;
// Take ownership of existing memory.
handler_ptr(handler_type& handler, pointer_type pointer)
: handler_(handler),
pointer_(pointer)
{
}
// Construct object in raw memory and take ownership if construction succeeds.
handler_ptr(raw_ptr_type& raw_ptr)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type)
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5, Arg6& a6)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6, typename Arg7>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5, Arg6& a6, Arg7& a7)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6, typename Arg7, typename Arg8>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(
a1, a2, a3, a4, a5, a6, a7, a8))
{
raw_ptr.pointer_ = 0;
}
// Destructor automatically deallocates memory, unless it has been released.
~handler_ptr()
{
reset();
}
// Get the memory.
pointer_type get() const
{
return pointer_;
}
// Release ownership of the memory.
pointer_type release()
{
pointer_type tmp = pointer_;
pointer_ = 0;
return tmp;
}
// Explicitly destroy and deallocate the memory.
void reset()
{
if (pointer_)
{
pointer_->value_type::~value_type();
asio_handler_alloc_helpers::deallocate(
pointer_, value_size, &handler_);
pointer_ = 0;
}
}
private:
handler_type& handler_;
pointer_type pointer_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP

View File

@ -1,47 +0,0 @@
//
// handler_invoke_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
#define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/detail/workaround.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/handler_invoke_hook.hpp"
// 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 asio_handler_invoke_helpers {
template <typename Function, typename Context>
inline void invoke(const Function& function, Context* context)
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
Function tmp(function);
tmp();
#else
using namespace asio;
asio_handler_invoke(function, context);
#endif
}
} // namespace asio_handler_invoke_helpers
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP

View File

@ -1,219 +0,0 @@
//
// handler_queue.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_HANDLER_QUEUE_HPP
#define ASIO_DETAIL_HANDLER_QUEUE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class handler_queue
: private noncopyable
{
public:
// Base class for handlers in the queue.
class handler
: private noncopyable
{
public:
void invoke()
{
invoke_func_(this);
}
void destroy()
{
destroy_func_(this);
}
protected:
typedef void (*invoke_func_type)(handler*);
typedef void (*destroy_func_type)(handler*);
handler(invoke_func_type invoke_func,
destroy_func_type destroy_func)
: next_(0),
invoke_func_(invoke_func),
destroy_func_(destroy_func)
{
}
~handler()
{
}
private:
friend class handler_queue;
handler* next_;
invoke_func_type invoke_func_;
destroy_func_type destroy_func_;
};
// Smart point to manager handler lifetimes.
class scoped_ptr
: private noncopyable
{
public:
explicit scoped_ptr(handler* h)
: handler_(h)
{
}
~scoped_ptr()
{
if (handler_)
handler_->destroy();
}
handler* get() const
{
return handler_;
}
handler* release()
{
handler* tmp = handler_;
handler_ = 0;
return tmp;
}
private:
handler* handler_;
};
// Constructor.
handler_queue()
: front_(0),
back_(0)
{
}
// Wrap a handler to be pushed into the queue.
template <typename Handler>
static handler* wrap(Handler h)
{
// Allocate and construct an object to wrap the handler.
typedef handler_wrapper<Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(h);
handler_ptr<alloc_traits> ptr(raw_ptr, h);
return ptr.release();
}
// Get the handler at the front of the queue.
handler* front()
{
return front_;
}
// Pop a handler from the front of the queue.
void pop()
{
if (front_)
{
handler* tmp = front_;
front_ = front_->next_;
if (front_ == 0)
back_ = 0;
tmp->next_= 0;
}
}
// Push a handler on to the back of the queue.
void push(handler* h)
{
h->next_ = 0;
if (back_)
{
back_->next_ = h;
back_ = h;
}
else
{
front_ = back_ = h;
}
}
// Whether the queue is empty.
bool empty() const
{
return front_ == 0;
}
private:
// Template wrapper for handlers.
template <typename Handler>
class handler_wrapper
: public handler
{
public:
handler_wrapper(Handler h)
: handler(
&handler_wrapper<Handler>::do_call,
&handler_wrapper<Handler>::do_destroy),
handler_(h)
{
}
static void do_call(handler* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made.
Handler handler(h->handler_);
// Free the memory associated with the handler.
ptr.reset();
// Make the upcall.
asio_handler_invoke_helpers::invoke(handler, &handler);
}
static void do_destroy(handler* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
}
private:
Handler handler_;
};
// The front of the queue.
handler* front_;
// The back of the queue.
handler* back_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_HANDLER_QUEUE_HPP

View File

@ -1,209 +0,0 @@
//
// hash_map.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_HASH_MAP_HPP
#define ASIO_DETAIL_HASH_MAP_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cassert>
#include <list>
#include <utility>
#include <boost/functional/hash.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
template <typename T>
inline std::size_t calculate_hash_value(const T& t)
{
return boost::hash_value(t);
}
#if defined(_WIN64)
inline std::size_t calculate_hash_value(SOCKET s)
{
return static_cast<std::size_t>(s);
}
#endif // defined(_WIN64)
template <typename K, typename V>
class hash_map
: private noncopyable
{
public:
// The type of a value in the map.
typedef std::pair<K, V> value_type;
// The type of a non-const iterator over the hash map.
typedef typename std::list<value_type>::iterator iterator;
// The type of a const iterator over the hash map.
typedef typename std::list<value_type>::const_iterator const_iterator;
// Constructor.
hash_map()
{
// Initialise all buckets to empty.
for (size_t i = 0; i < num_buckets; ++i)
buckets_[i].first = buckets_[i].last = values_.end();
}
// Get an iterator for the beginning of the map.
iterator begin()
{
return values_.begin();
}
// Get an iterator for the beginning of the map.
const_iterator begin() const
{
return values_.begin();
}
// Get an iterator for the end of the map.
iterator end()
{
return values_.end();
}
// Get an iterator for the end of the map.
const_iterator end() const
{
return values_.end();
}
// Check whether the map is empty.
bool empty() const
{
return values_.empty();
}
// Find an entry in the map.
iterator find(const K& k)
{
size_t bucket = calculate_hash_value(k) % num_buckets;
iterator it = buckets_[bucket].first;
if (it == values_.end())
return values_.end();
iterator end = buckets_[bucket].last;
++end;
while (it != end)
{
if (it->first == k)
return it;
++it;
}
return values_.end();
}
// Find an entry in the map.
const_iterator find(const K& k) const
{
size_t bucket = calculate_hash_value(k) % num_buckets;
const_iterator it = buckets_[bucket].first;
if (it == values_.end())
return it;
const_iterator end = buckets_[bucket].last;
++end;
while (it != end)
{
if (it->first == k)
return it;
++it;
}
return values_.end();
}
// Insert a new entry into the map.
std::pair<iterator, bool> insert(const value_type& v)
{
size_t bucket = calculate_hash_value(v.first) % num_buckets;
iterator it = buckets_[bucket].first;
if (it == values_.end())
{
buckets_[bucket].first = buckets_[bucket].last =
values_.insert(values_.end(), v);
return std::pair<iterator, bool>(buckets_[bucket].last, true);
}
iterator end = buckets_[bucket].last;
++end;
while (it != end)
{
if (it->first == v.first)
return std::pair<iterator, bool>(it, false);
++it;
}
buckets_[bucket].last = values_.insert(end, v);
return std::pair<iterator, bool>(buckets_[bucket].last, true);
}
// Erase an entry from the map.
void erase(iterator it)
{
assert(it != values_.end());
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)
buckets_[bucket].first = buckets_[bucket].last = values_.end();
else if (is_first)
++buckets_[bucket].first;
else if (is_last)
--buckets_[bucket].last;
values_.erase(it);
}
// Remove all entries from the map.
void clear()
{
// Clear the values.
values_.clear();
// Initialise all buckets to empty.
for (size_t i = 0; i < num_buckets; ++i)
buckets_[i].first = buckets_[i].last = values_.end();
}
private:
// The list of all values in the hash map.
std::list<value_type> values_;
// The type for a bucket in the hash table.
struct bucket_type
{
iterator first;
iterator last;
};
// The number of buckets in the hash.
enum { num_buckets = 1021 };
// The buckets in the hash.
bucket_type buckets_[num_buckets];
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_HASH_MAP_HPP

View File

@ -1,137 +0,0 @@
//
// io_control.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_IO_CONTROL_HPP
#define ASIO_DETAIL_IO_CONTROL_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
namespace io_control {
// IO control command for non-blocking I/O.
class non_blocking_io
{
public:
// Default constructor.
non_blocking_io()
: value_(0)
{
}
// Construct with a specific command value.
non_blocking_io(bool value)
: value_(value ? 1 : 0)
{
}
// Get the name of the IO control command.
int name() const
{
return FIONBIO;
}
// Set the value of the I/O control command.
void set(bool value)
{
value_ = value ? 1 : 0;
}
// Get the current value of the I/O control command.
bool get() const
{
return value_ != 0;
}
// Get the address of the command data.
detail::ioctl_arg_type* data()
{
return &value_;
}
// Get the address of the command data.
const detail::ioctl_arg_type* data() const
{
return &value_;
}
private:
detail::ioctl_arg_type value_;
};
// I/O control command for getting number of bytes available.
class bytes_readable
{
public:
// Default constructor.
bytes_readable()
: value_(0)
{
}
// Construct with a specific command 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 FIONREAD;
}
// 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 I/O control command.
std::size_t get() const
{
return static_cast<std::size_t>(value_);
}
// Get the address of the command data.
detail::ioctl_arg_type* data()
{
return &value_;
}
// Get the address of the command data.
const detail::ioctl_arg_type* data() const
{
return &value_;
}
private:
detail::ioctl_arg_type value_;
};
} // namespace io_control
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IO_CONTROL_HPP

View File

@ -1,652 +0,0 @@
//
// kqueue_reactor.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze 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 ASIO_DETAIL_KQUEUE_REACTOR_HPP
#define ASIO_DETAIL_KQUEUE_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/kqueue_reactor_fwd.hpp"
#if defined(ASIO_HAS_KQUEUE)
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <vector>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/task_io_service.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
// Older versions of Mac OS X may not define EV_OOBAND.
#if !defined(EV_OOBAND)
# define EV_OOBAND EV_FLAG1
#endif // !defined(EV_OOBAND)
namespace asio {
namespace detail {
template <bool Own_Thread>
class kqueue_reactor
: public asio::detail::service_base<kqueue_reactor<Own_Thread> >
{
public:
// Constructor.
kqueue_reactor(asio::io_service& io_service)
: asio::detail::service_base<
kqueue_reactor<Own_Thread> >(io_service),
mutex_(),
kqueue_fd_(do_kqueue_create()),
wait_in_progress_(false),
interrupter_(),
read_op_queue_(),
write_op_queue_(),
except_op_queue_(),
pending_cancellations_(),
stop_thread_(false),
thread_(0),
shutdown_(false),
need_kqueue_wait_(true)
{
// Start the reactor's internal thread only if needed.
if (Own_Thread)
{
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&kqueue_reactor::call_run_thread, this));
}
// Add the interrupter's descriptor to the kqueue.
struct kevent event;
EV_SET(&event, interrupter_.read_descriptor(),
EVFILT_READ, EV_ADD, 0, 0, 0);
::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
}
// Destructor.
~kqueue_reactor()
{
shutdown_service();
close(kqueue_fd_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_thread_ = true;
lock.unlock();
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
}
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type)
{
return 0;
}
// Start a new read operation. The handler object will be invoked when the
// given descriptor is ready to be read, or an error has occurred.
template <typename Handler>
void start_read_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!read_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start a new write operation. The handler object will be invoked when the
// given descriptor is ready to be written, or an error has occurred.
template <typename Handler>
void start_write_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!write_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start a new exception operation. The handler object will be invoked when
// the given descriptor has exception information, or an error has occurred.
template <typename Handler>
void start_except_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (except_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
if (read_op_queue_.has_operation(descriptor))
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
else
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start new write and exception operations. The handler object will be
// invoked when the given descriptor is ready for writing or has exception
// information available, or an error has occurred.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
if (except_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
if (read_op_queue_.has_operation(descriptor))
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
else
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Enqueue cancellation of all operations associated with the given
// descriptor. The handlers associated with the descriptor will be invoked
// with the operation_aborted error. This function does not acquire the
// kqueue_reactor's mutex, and so should only be used from within a reactor
// handler.
void enqueue_cancel_ops_unlocked(socket_type descriptor)
{
pending_cancellations_.push_back(descriptor);
}
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Remove the descriptor from kqueue.
struct kevent event[2];
EV_SET(&event[0], descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
EV_SET(&event[1], descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
::kevent(kqueue_fd_, event, 2, 0, 0, 0);
// Cancel any outstanding operations associated with the descriptor.
cancel_ops_unlocked(descriptor);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
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)
{
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>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
std::size_t n = timer_queue.cancel_timer(token);
if (n > 0)
interrupter_.interrupt();
return n;
}
private:
friend class task_io_service<kqueue_reactor<Own_Thread> >;
// Run the kqueue loop.
void run(bool block)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Dispatch any operation cancellations that were made while the select
// loop was not running.
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->dispatch_cancellations();
// Check if the thread is supposed to stop.
if (stop_thread_)
{
cleanup_operations_and_timers(lock);
return;
}
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
cleanup_operations_and_timers(lock);
return;
}
// Determine how long to block while waiting for events.
timespec timeout_buf = { 0, 0 };
timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
wait_in_progress_ = true;
lock.unlock();
// Block on the kqueue descriptor.
struct kevent events[128];
int num_events = (block || need_kqueue_wait_)
? kevent(kqueue_fd_, 0, 0, events, 128, timeout)
: 0;
lock.lock();
wait_in_progress_ = false;
// Block signals while dispatching operations.
asio::detail::signal_blocker sb;
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].ident;
if (descriptor == interrupter_.read_descriptor())
{
interrupter_.reset();
}
else if (events[i].filter == EVFILT_READ)
{
// Dispatch operations associated with the descriptor.
bool more_reads = false;
bool more_except = false;
if (events[i].flags & EV_ERROR)
{
asio::error_code error(
events[i].data, asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, error);
read_op_queue_.dispatch_all_operations(descriptor, error);
}
else if (events[i].flags & EV_OOBAND)
{
asio::error_code error;
more_except = except_op_queue_.dispatch_operation(descriptor, error);
if (events[i].data > 0)
more_reads = read_op_queue_.dispatch_operation(descriptor, error);
else
more_reads = read_op_queue_.has_operation(descriptor);
}
else
{
asio::error_code error;
more_reads = read_op_queue_.dispatch_operation(descriptor, error);
more_except = except_op_queue_.has_operation(descriptor);
}
// Update the descriptor in the kqueue.
struct kevent event;
if (more_reads)
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
else if (more_except)
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
else
EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code error(errno,
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, error);
read_op_queue_.dispatch_all_operations(descriptor, error);
}
}
else if (events[i].filter == EVFILT_WRITE)
{
// Dispatch operations associated with the descriptor.
bool more_writes = false;
if (events[i].flags & EV_ERROR)
{
asio::error_code error(
events[i].data, asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, error);
}
else
{
asio::error_code error;
more_writes = write_op_queue_.dispatch_operation(descriptor, error);
}
// Update the descriptor in the kqueue.
struct kevent event;
if (more_writes)
EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
else
EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code error(errno,
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, error);
}
}
}
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
timer_queues_[i]->dispatch_timers();
timer_queues_[i]->dispatch_cancellations();
}
// Issue any pending cancellations.
for (std::size_t i = 0; i < pending_cancellations_.size(); ++i)
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
// Determine whether kqueue needs to be called next time the reactor is run.
need_kqueue_wait_ = !read_op_queue_.empty()
|| !write_op_queue_.empty() || !except_op_queue_.empty();
cleanup_operations_and_timers(lock);
}
// Run the select loop in the thread.
void run_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!stop_thread_)
{
lock.unlock();
run(true);
lock.lock();
}
}
// Entry point for the select loop thread.
static void call_run_thread(kqueue_reactor* reactor)
{
reactor->run_thread();
}
// Interrupt the select loop.
void interrupt()
{
interrupter_.interrupt();
}
// Create the kqueue file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_kqueue_create()
{
int fd = kqueue();
if (fd == -1)
{
boost::throw_exception(
asio::system_error(
asio::error_code(errno,
asio::error::get_system_category()),
"kqueue"));
}
return fd;
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the kevent call.
timespec* get_timeout(timespec& ts)
{
if (all_timer_queues_are_empty())
return 0;
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::minutes(5);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
ts.tv_sec = minimum_wait_duration.total_seconds();
ts.tv_nsec = minimum_wait_duration.total_nanoseconds() % 1000000000;
}
else
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
return &ts;
}
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the kqueue_reactor's mutex.
void cancel_ops_unlocked(socket_type descriptor)
{
bool interrupt = read_op_queue_.cancel_operations(descriptor);
interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
if (interrupt)
interrupter_.interrupt();
}
// Clean up operations and timers. We must not hold the lock since the
// destructors may make calls back into this reactor. We make a copy of the
// vector of timer queues since the original may be modified while the lock
// is not held.
void cleanup_operations_and_timers(
asio::detail::mutex::scoped_lock& lock)
{
timer_queues_for_cleanup_ = timer_queues_;
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
timer_queues_for_cleanup_[i]->cleanup_timers();
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// The kqueue file descriptor.
int kqueue_fd_;
// Whether the kqueue wait call is currently in progress
bool wait_in_progress_;
// The interrupter is used to break a blocking kevent call.
select_interrupter interrupter_;
// The queue of read operations.
reactor_op_queue<socket_type> read_op_queue_;
// The queue of write operations.
reactor_op_queue<socket_type> write_op_queue_;
// The queue of except operations.
reactor_op_queue<socket_type> except_op_queue_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// A copy of the timer queues, used when cleaning up timers. The copy is
// stored as a class data member to avoid unnecessary memory allocation.
std::vector<timer_queue_base*> timer_queues_for_cleanup_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
// Does the reactor loop thread need to stop.
bool stop_thread_;
// The thread that is running the reactor loop.
asio::detail::thread* thread_;
// Whether the service has been shut down.
bool shutdown_;
// Whether we need to call kqueue the next time the reactor is run.
bool need_kqueue_wait_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_KQUEUE)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP

View File

@ -1,41 +0,0 @@
//
// kqueue_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze 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 ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
#define ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#if !defined(ASIO_DISABLE_KQUEUE)
#if defined(__MACH__) && defined(__APPLE__)
// Define this to indicate that epoll is supported on the target platform.
#define ASIO_HAS_KQUEUE 1
namespace asio {
namespace detail {
template <bool Own_Thread>
class kqueue_reactor;
} // namespace detail
} // namespace asio
#endif // defined(__MACH__) && defined(__APPLE__)
#endif // !defined(ASIO_DISABLE_KQUEUE)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP

View File

@ -1,59 +0,0 @@
//
// local_free_on_block_exit.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
#define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
class local_free_on_block_exit
: private noncopyable
{
public:
// Constructor blocks all signals for the calling thread.
explicit local_free_on_block_exit(void* p)
: p_(p)
{
}
// Destructor restores the previous signal mask.
~local_free_on_block_exit()
{
::LocalFree(p_);
}
private:
void* p_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP

View File

@ -1,50 +0,0 @@
//
// mutex.hpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_MUTEX_HPP
#define ASIO_DETAIL_MUTEX_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_mutex.hpp"
#elif defined(BOOST_WINDOWS)
# include "asio/detail/win_mutex.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_mutex.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
#if !defined(BOOST_HAS_THREADS)
typedef null_mutex mutex;
#elif defined(BOOST_WINDOWS)
typedef win_mutex mutex;
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_mutex mutex;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_MUTEX_HPP

View File

@ -1,55 +0,0 @@
//
// noncopyable.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_NONCOPYABLE_HPP
#define ASIO_DETAIL_NONCOPYABLE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <boost/noncopyable.hpp>
#include <boost/detail/workaround.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// Redefine the noncopyable class for Borland C++ since that compiler does not
// apply the empty base optimisation unless the base class contains a dummy
// char data member.
class noncopyable
{
protected:
noncopyable() {}
~noncopyable() {}
private:
noncopyable(const noncopyable&);
const noncopyable& operator=(const noncopyable&);
char dummy_;
};
#else
using boost::noncopyable;
#endif
} // namespace detail
using asio::detail::noncopyable;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NONCOPYABLE_HPP

View File

@ -1,71 +0,0 @@
//
// null_event.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_NULL_EVENT_HPP
#define ASIO_DETAIL_NULL_EVENT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class null_event
: private noncopyable
{
public:
// Constructor.
null_event()
{
}
// Destructor.
~null_event()
{
}
// Signal the event.
template <typename Lock>
void signal(Lock&)
{
}
// Reset the event.
template <typename Lock>
void clear(Lock&)
{
}
// Wait for the event to become signalled.
template <typename Lock>
void wait(Lock&)
{
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_EVENT_HPP

View File

@ -1,66 +0,0 @@
//
// null_mutex.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_NULL_MUTEX_HPP
#define ASIO_DETAIL_NULL_MUTEX_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/scoped_lock.hpp"
namespace asio {
namespace detail {
class null_mutex
: private noncopyable
{
public:
typedef asio::detail::scoped_lock<null_mutex> scoped_lock;
// Constructor.
null_mutex()
{
}
// Destructor.
~null_mutex()
{
}
// Lock the mutex.
void lock()
{
}
// Unlock the mutex.
void unlock()
{
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_MUTEX_HPP

View File

@ -1,63 +0,0 @@
//
// null_signal_blocker.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
#define ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class null_signal_blocker
: private noncopyable
{
public:
// Constructor blocks all signals for the calling thread.
null_signal_blocker()
{
}
// Destructor restores the previous signal mask.
~null_signal_blocker()
{
}
// Block all signals for the calling thread.
void block()
{
}
// Restore the previous signal mask.
void unblock()
{
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP

View File

@ -1,68 +0,0 @@
//
// null_thread.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_NULL_THREAD_HPP
#define ASIO_DETAIL_NULL_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class null_thread
: private noncopyable
{
public:
// Constructor.
template <typename Function>
null_thread(Function f)
{
asio::system_error e(
asio::error::operation_not_supported, "thread");
boost::throw_exception(e);
}
// Destructor.
~null_thread()
{
}
// Wait for the thread to exit.
void join()
{
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_THREAD_HPP

View File

@ -1,70 +0,0 @@
//
// null_tss_ptr.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_NULL_TSS_PTR_HPP
#define ASIO_DETAIL_NULL_TSS_PTR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
template <typename T>
class null_tss_ptr
: private noncopyable
{
public:
// Constructor.
null_tss_ptr()
: value_(0)
{
}
// Destructor.
~null_tss_ptr()
{
}
// Get the value.
operator T*() const
{
return value_;
}
// Set the value.
void operator=(T* value)
{
value_ = value;
}
private:
T* value_;
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_TSS_PTR_HPP

View File

@ -1,335 +0,0 @@
//
// old_win_sdk_compat.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
#define ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Guess whether we are building against on old Platform SDK.
#if !defined(IN6ADDR_ANY_INIT)
#define ASIO_HAS_OLD_WIN_SDK 1
#endif // !defined(IN6ADDR_ANY_INIT)
#if defined(ASIO_HAS_OLD_WIN_SDK)
// Emulation of types that are missing from old Platform SDKs.
//
// N.B. this emulation is also used if building for a Windows 2000 target with
// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support
// in that case.
namespace asio {
namespace detail {
enum
{
sockaddr_storage_maxsize = 128, // Maximum size.
sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment.
sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)),
sockaddr_storage_pad2size = (sockaddr_storage_maxsize -
(sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize))
};
struct sockaddr_storage_emulation
{
short ss_family;
char __ss_pad1[sockaddr_storage_pad1size];
__int64 __ss_align;
char __ss_pad2[sockaddr_storage_pad2size];
};
struct in6_addr_emulation
{
union
{
u_char Byte[16];
u_short Word[8];
} u;
};
#if !defined(s6_addr)
# define _S6_un u
# define _S6_u8 Byte
# define s6_addr _S6_un._S6_u8
#endif // !defined(s6_addr)
struct sockaddr_in6_emulation
{
short sin6_family;
u_short sin6_port;
u_long sin6_flowinfo;
in6_addr_emulation sin6_addr;
u_long sin6_scope_id;
};
struct ipv6_mreq_emulation
{
in6_addr_emulation ipv6mr_multiaddr;
unsigned int ipv6mr_interface;
};
#if !defined(IN6ADDR_ANY_INIT)
# define IN6ADDR_ANY_INIT { 0 }
#endif
#if !defined(IN6ADDR_LOOPBACK_INIT)
# define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
#endif
struct addrinfo_emulation
{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char* ai_canonname;
sockaddr* ai_addr;
addrinfo_emulation* ai_next;
};
#if !defined(AI_PASSIVE)
# define AI_PASSIVE 0x1
#endif
#if !defined(AI_CANONNAME)
# define AI_CANONNAME 0x2
#endif
#if !defined(AI_NUMERICHOST)
# define AI_NUMERICHOST 0x4
#endif
#if !defined(EAI_AGAIN)
# define EAI_AGAIN WSATRY_AGAIN
#endif
#if !defined(EAI_BADFLAGS)
# define EAI_BADFLAGS WSAEINVAL
#endif
#if !defined(EAI_FAIL)
# define EAI_FAIL WSANO_RECOVERY
#endif
#if !defined(EAI_FAMILY)
# define EAI_FAMILY WSAEAFNOSUPPORT
#endif
#if !defined(EAI_MEMORY)
# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY
#endif
#if !defined(EAI_NODATA)
# define EAI_NODATA WSANO_DATA
#endif
#if !defined(EAI_NONAME)
# define EAI_NONAME WSAHOST_NOT_FOUND
#endif
#if !defined(EAI_SERVICE)
# define EAI_SERVICE WSATYPE_NOT_FOUND
#endif
#if !defined(EAI_SOCKTYPE)
# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT
#endif
#if !defined(NI_NOFQDN)
# define NI_NOFQDN 0x01
#endif
#if !defined(NI_NUMERICHOST)
# define NI_NUMERICHOST 0x02
#endif
#if !defined(NI_NAMEREQD)
# define NI_NAMEREQD 0x04
#endif
#if !defined(NI_NUMERICSERV)
# define NI_NUMERICSERV 0x08
#endif
#if !defined(NI_DGRAM)
# define NI_DGRAM 0x10
#endif
#if !defined(IPPROTO_IPV6)
# define IPPROTO_IPV6 41
#endif
#if !defined(IPV6_UNICAST_HOPS)
# define IPV6_UNICAST_HOPS 4
#endif
#if !defined(IPV6_MULTICAST_IF)
# define IPV6_MULTICAST_IF 9
#endif
#if !defined(IPV6_MULTICAST_HOPS)
# define IPV6_MULTICAST_HOPS 10
#endif
#if !defined(IPV6_MULTICAST_LOOP)
# define IPV6_MULTICAST_LOOP 11
#endif
#if !defined(IPV6_JOIN_GROUP)
# define IPV6_JOIN_GROUP 12
#endif
#if !defined(IPV6_LEAVE_GROUP)
# define IPV6_LEAVE_GROUP 13
#endif
inline int IN6_IS_ADDR_UNSPECIFIED(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0)
&& (a->s6_addr[1] == 0)
&& (a->s6_addr[2] == 0)
&& (a->s6_addr[3] == 0)
&& (a->s6_addr[4] == 0)
&& (a->s6_addr[5] == 0)
&& (a->s6_addr[6] == 0)
&& (a->s6_addr[7] == 0)
&& (a->s6_addr[8] == 0)
&& (a->s6_addr[9] == 0)
&& (a->s6_addr[10] == 0)
&& (a->s6_addr[11] == 0)
&& (a->s6_addr[12] == 0)
&& (a->s6_addr[13] == 0)
&& (a->s6_addr[14] == 0)
&& (a->s6_addr[15] == 0));
}
inline int IN6_IS_ADDR_LOOPBACK(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0)
&& (a->s6_addr[1] == 0)
&& (a->s6_addr[2] == 0)
&& (a->s6_addr[3] == 0)
&& (a->s6_addr[4] == 0)
&& (a->s6_addr[5] == 0)
&& (a->s6_addr[6] == 0)
&& (a->s6_addr[7] == 0)
&& (a->s6_addr[8] == 0)
&& (a->s6_addr[9] == 0)
&& (a->s6_addr[10] == 0)
&& (a->s6_addr[11] == 0)
&& (a->s6_addr[12] == 0)
&& (a->s6_addr[13] == 0)
&& (a->s6_addr[14] == 0)
&& (a->s6_addr[15] == 1));
}
inline int IN6_IS_ADDR_MULTICAST(const in6_addr_emulation* a)
{
return (a->s6_addr[0] == 0xff);
}
inline int IN6_IS_ADDR_LINKLOCAL(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0x80));
}
inline int IN6_IS_ADDR_SITELOCAL(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0xc0));
}
inline int IN6_IS_ADDR_V4MAPPED(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0)
&& (a->s6_addr[1] == 0)
&& (a->s6_addr[2] == 0)
&& (a->s6_addr[3] == 0)
&& (a->s6_addr[4] == 0)
&& (a->s6_addr[5] == 0)
&& (a->s6_addr[6] == 0)
&& (a->s6_addr[7] == 0)
&& (a->s6_addr[8] == 0)
&& (a->s6_addr[9] == 0)
&& (a->s6_addr[10] == 0xff)
&& (a->s6_addr[11] == 0xff));
}
inline int IN6_IS_ADDR_V4COMPAT(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0)
&& (a->s6_addr[1] == 0)
&& (a->s6_addr[2] == 0)
&& (a->s6_addr[3] == 0)
&& (a->s6_addr[4] == 0)
&& (a->s6_addr[5] == 0)
&& (a->s6_addr[6] == 0)
&& (a->s6_addr[7] == 0)
&& (a->s6_addr[8] == 0)
&& (a->s6_addr[9] == 0)
&& (a->s6_addr[10] == 0xff)
&& (a->s6_addr[11] == 0xff)
&& !((a->s6_addr[12] == 0)
&& (a->s6_addr[13] == 0)
&& (a->s6_addr[14] == 0)
&& ((a->s6_addr[15] == 0) || (a->s6_addr[15] == 1))));
}
inline int IN6_IS_ADDR_MC_NODELOCAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 1);
}
inline int IN6_IS_ADDR_MC_LINKLOCAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 2);
}
inline int IN6_IS_ADDR_MC_SITELOCAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 5);
}
inline int IN6_IS_ADDR_MC_ORGLOCAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 8);
}
inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 0xe);
}
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_OLD_WIN_SDK)
// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY.
#if !defined(IPV6_V6ONLY)
# define IPV6_V6ONLY 27
#endif
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP

View File

@ -1,114 +0,0 @@
//
// pipe_select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
#define ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/push_options.hpp"
#include <fcntl.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
class pipe_select_interrupter
{
public:
// Constructor.
pipe_select_interrupter()
{
int pipe_fds[2];
if (pipe(pipe_fds) == 0)
{
read_descriptor_ = pipe_fds[0];
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
write_descriptor_ = pipe_fds[1];
::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
}
else
{
asio::error_code ec(errno,
asio::error::get_system_category());
asio::system_error e(ec, "pipe_select_interrupter");
boost::throw_exception(e);
}
}
// Destructor.
~pipe_select_interrupter()
{
if (read_descriptor_ != -1)
::close(read_descriptor_);
if (write_descriptor_ != -1)
::close(write_descriptor_);
}
// Interrupt the select call.
void interrupt()
{
char byte = 0;
::write(write_descriptor_, &byte, 1);
}
// Reset the select interrupt. Returns true if the call was interrupted.
bool reset()
{
char data[1024];
int bytes_read = ::read(read_descriptor_, data, sizeof(data));
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = ::read(read_descriptor_, data, sizeof(data));
return was_interrupted;
}
// Get the read descriptor to be passed to select.
int read_descriptor() const
{
return read_descriptor_;
}
private:
// The read end of a connection used to interrupt the select call. This file
// descriptor is passed to select such that when it is time to stop, a single
// byte will be written on the other end of the connection and this
// descriptor will become readable.
int read_descriptor_;
// The write end of a connection used to interrupt the select call. A single
// byte may be written to this to wake up the select which is waiting for the
// other end to become readable.
int write_descriptor_;
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP

View File

@ -1,88 +0,0 @@
//
// pop_options.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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)
//
// No header guard
#if defined(__COMO__)
// Comeau C++
#elif defined(__DMC__)
// Digital Mars C++
#elif defined(__INTEL_COMPILER) || defined(__ICL) \
|| defined(__ICC) || defined(__ECC)
// Intel C++
#elif defined(__GNUC__)
// GNU C++
# if defined(__MINGW32__) || defined(__CYGWIN__)
# pragma pack (pop)
# endif
#elif defined(__KCC)
// Kai C++
#elif defined(__sgi)
// SGI MIPSpro C++
#elif defined(__DECCXX)
// Compaq Tru64 Unix cxx
#elif defined(__ghs)
// Greenhills C++
#elif defined(__BORLANDC__)
// Borland C++
# pragma option pop
# pragma nopushoptwarn
# pragma nopackwarning
#elif defined(__MWERKS__)
// Metrowerks CodeWarrior
#elif defined(__SUNPRO_CC)
// Sun Workshop Compiler C++
#elif defined(__HP_aCC)
// HP aCC
#elif defined(__MRC__) || defined(__SC__)
// MPW MrCpp or SCpp
#elif defined(__IBMCPP__)
// IBM Visual Age
#elif defined(_MSC_VER)
// Microsoft Visual C++
//
// Must remain the last #elif since some other vendors (Metrowerks, for example)
// also #define _MSC_VER
# pragma warning (pop)
# pragma pack (pop)
#endif

View File

@ -1,104 +0,0 @@
//
// posix_event.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_POSIX_EVENT_HPP
#define ASIO_DETAIL_POSIX_EVENT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include <pthread.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class posix_event
: private noncopyable
{
public:
// Constructor.
posix_event()
: signalled_(false)
{
int error = ::pthread_cond_init(&cond_, 0);
if (error != 0)
{
asio::system_error e(
asio::error_code(error,
asio::error::get_system_category()),
"event");
boost::throw_exception(e);
}
}
// Destructor.
~posix_event()
{
::pthread_cond_destroy(&cond_);
}
// Signal the event.
template <typename Lock>
void signal(Lock& lock)
{
BOOST_ASSERT(lock.locked());
(void)lock;
signalled_ = true;
::pthread_cond_signal(&cond_); // Ignore EINVAL.
}
// Reset the event.
template <typename Lock>
void clear(Lock& lock)
{
BOOST_ASSERT(lock.locked());
(void)lock;
signalled_ = false;
}
// Wait for the event to become signalled.
template <typename Lock>
void wait(Lock& lock)
{
BOOST_ASSERT(lock.locked());
while (!signalled_)
::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL.
}
private:
::pthread_cond_t cond_;
bool signalled_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_EVENT_HPP

View File

@ -1,77 +0,0 @@
//
// posix_fd_set_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
#define ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/socket_types.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
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)
{
using namespace std; // Needed for memset on Solaris.
FD_ZERO(&fd_set_);
}
bool set(socket_type descriptor)
{
if (descriptor < (socket_type)FD_SETSIZE)
{
if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_)
max_descriptor_ = descriptor;
FD_SET(descriptor, &fd_set_);
return true;
}
return false;
}
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:
mutable fd_set fd_set_;
socket_type max_descriptor_;
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP

View File

@ -1,107 +0,0 @@
//
// posix_mutex.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_POSIX_MUTEX_HPP
#define ASIO_DETAIL_POSIX_MUTEX_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <pthread.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/scoped_lock.hpp"
namespace asio {
namespace detail {
class posix_event;
class posix_mutex
: private noncopyable
{
public:
typedef asio::detail::scoped_lock<posix_mutex> scoped_lock;
// Constructor.
posix_mutex()
{
int error = ::pthread_mutex_init(&mutex_, 0);
if (error != 0)
{
asio::system_error e(
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}
}
// Destructor.
~posix_mutex()
{
::pthread_mutex_destroy(&mutex_);
}
// Lock the mutex.
void lock()
{
int error = ::pthread_mutex_lock(&mutex_);
if (error != 0)
{
asio::system_error e(
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}
}
// Unlock the mutex.
void unlock()
{
int error = ::pthread_mutex_unlock(&mutex_);
if (error != 0)
{
asio::system_error e(
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}
}
private:
friend class posix_event;
::pthread_mutex_t mutex_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_MUTEX_HPP

View File

@ -1,90 +0,0 @@
//
// posix_signal_blocker.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
#define ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <csignal>
#include <pthread.h>
#include <signal.h>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class posix_signal_blocker
: private noncopyable
{
public:
// Constructor blocks all signals for the calling thread.
posix_signal_blocker()
: blocked_(false)
{
sigset_t new_mask;
sigfillset(&new_mask);
blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
}
// Destructor restores the previous signal mask.
~posix_signal_blocker()
{
if (blocked_)
pthread_sigmask(SIG_SETMASK, &old_mask_, 0);
}
// Block all signals for the calling thread.
void block()
{
if (!blocked_)
{
sigset_t new_mask;
sigfillset(&new_mask);
blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
}
}
// Restore the previous signal mask.
void unblock()
{
if (blocked_)
blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0);
}
private:
// Have signals been blocked.
bool blocked_;
// The previous signal mask.
sigset_t old_mask_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP

View File

@ -1,129 +0,0 @@
//
// posix_thread.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_POSIX_THREAD_HPP
#define ASIO_DETAIL_POSIX_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <memory>
#include <boost/throw_exception.hpp>
#include <pthread.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
extern "C" void* asio_detail_posix_thread_function(void* arg);
class posix_thread
: private noncopyable
{
public:
// Constructor.
template <typename Function>
posix_thread(Function f)
: joined_(false)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
int error = ::pthread_create(&thread_, 0,
asio_detail_posix_thread_function, arg.get());
if (error != 0)
{
asio::system_error e(
asio::error_code(error,
asio::error::get_system_category()),
"thread");
boost::throw_exception(e);
}
arg.release();
}
// Destructor.
~posix_thread()
{
if (!joined_)
::pthread_detach(thread_);
}
// Wait for the thread to exit.
void join()
{
if (!joined_)
{
::pthread_join(thread_, 0);
joined_ = true;
}
}
private:
friend void* asio_detail_posix_thread_function(void* arg);
class func_base
{
public:
virtual ~func_base() {}
virtual void run() = 0;
};
template <typename Function>
class func
: public func_base
{
public:
func(Function f)
: f_(f)
{
}
virtual void run()
{
f_();
}
private:
Function f_;
};
::pthread_t thread_;
bool joined_;
};
inline void* asio_detail_posix_thread_function(void* arg)
{
std::auto_ptr<posix_thread::func_base> f(
static_cast<posix_thread::func_base*>(arg));
f->run();
return 0;
}
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_THREAD_HPP

View File

@ -1,88 +0,0 @@
//
// posix_tss_ptr.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_POSIX_TSS_PTR_HPP
#define ASIO_DETAIL_POSIX_TSS_PTR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <pthread.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
template <typename T>
class posix_tss_ptr
: private noncopyable
{
public:
// Constructor.
posix_tss_ptr()
{
int error = ::pthread_key_create(&tss_key_, 0);
if (error != 0)
{
asio::system_error e(
asio::error_code(error,
asio::error::get_system_category()),
"tss");
boost::throw_exception(e);
}
}
// Destructor.
~posix_tss_ptr()
{
::pthread_key_delete(tss_key_);
}
// Get the value.
operator T*() const
{
return static_cast<T*>(::pthread_getspecific(tss_key_));
}
// Set the value.
void operator=(T* value)
{
::pthread_setspecific(tss_key_, value);
}
private:
// Thread-specific storage to allow unlocked access to determine whether a
// thread is a member of the pool.
pthread_key_t tss_key_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP

View File

@ -1,112 +0,0 @@
//
// push_options.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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)
//
// No header guard
#if defined(__COMO__)
// Comeau C++
#elif defined(__DMC__)
// Digital Mars C++
#elif defined(__INTEL_COMPILER) || defined(__ICL) \
|| defined(__ICC) || defined(__ECC)
// Intel C++
#elif defined(__GNUC__)
// GNU C++
# if defined(__MINGW32__) || defined(__CYGWIN__)
# pragma pack (push, 8)
# endif
#elif defined(__KCC)
// Kai C++
#elif defined(__sgi)
// SGI MIPSpro C++
#elif defined(__DECCXX)
// Compaq Tru64 Unix cxx
#elif defined(__ghs)
// Greenhills C++
#elif defined(__BORLANDC__)
// Borland C++
# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi-
# pragma nopushoptwarn
# pragma nopackwarning
# if !defined(__MT__)
# error Multithreaded RTL must be selected.
# endif // !defined(__MT__)
#elif defined(__MWERKS__)
// Metrowerks CodeWarrior
#elif defined(__SUNPRO_CC)
// Sun Workshop Compiler C++
#elif defined(__HP_aCC)
// HP aCC
#elif defined(__MRC__) || defined(__SC__)
// MPW MrCpp or SCpp
#elif defined(__IBMCPP__)
// IBM Visual Age
#elif defined(_MSC_VER)
// Microsoft Visual C++
//
// Must remain the last #elif since some other vendors (Metrowerks, for example)
// also #define _MSC_VER
# pragma warning (disable:4103)
# pragma warning (push)
# pragma warning (disable:4244)
# pragma warning (disable:4355)
# pragma warning (disable:4675)
# if defined(_M_IX86) && defined(_Wp64)
// The /Wp64 option is broken. If you want to check 64 bit portability, use a
// 64 bit compiler!
# pragma warning (disable:4311)
# pragma warning (disable:4312)
# endif // defined(_M_IX86) && defined(_Wp64)
# pragma pack (push, 8)
// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler
// has a tendency to incorrectly optimise away some calls to member template
// functions, even though those functions contain code that should not be
// optimised away! Therefore we will always disable this optimisation option
// for the MSVC6 compiler.
# if (_MSC_VER < 1300)
# pragma optimize ("g", off)
# endif
# if !defined(_MT)
# error Multithreaded RTL must be selected.
# endif // !defined(_MT)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,389 +0,0 @@
//
// reactor_op_queue.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
#define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <memory>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
template <typename Descriptor>
class reactor_op_queue
: private noncopyable
{
public:
// Constructor.
reactor_op_queue()
: operations_(),
cancelled_operations_(0),
cleanup_operations_(0)
{
}
// Add a new operation to the queue. Returns true if this is the only
// operation for the given descriptor, in which case the reactor's event
// demultiplexing function call may need to be interrupted and restarted.
template <typename Handler>
bool enqueue_operation(Descriptor descriptor, Handler handler)
{
op_base* new_op = new op<Handler>(descriptor, handler);
typedef typename operation_map::iterator iterator;
typedef typename operation_map::value_type value_type;
std::pair<iterator, bool> entry =
operations_.insert(value_type(descriptor, new_op));
if (entry.second)
return true;
op_base* current_op = entry.first->second;
while (current_op->next_)
current_op = current_op->next_;
current_op->next_ = new_op;
return false;
}
// Cancel all operations associated with the descriptor. Any operations
// pending for the descriptor will be notified that they have been cancelled
// next time dispatch_cancellations is called. Returns true if any operations
// were cancelled, in which case the reactor's event demultiplexing function
// may need to be interrupted and restarted.
bool cancel_operations(Descriptor descriptor)
{
typename operation_map::iterator i = operations_.find(descriptor);
if (i != operations_.end())
{
op_base* last_op = i->second;
while (last_op->next_)
last_op = last_op->next_;
last_op->next_ = cancelled_operations_;
cancelled_operations_ = i->second;
operations_.erase(i);
return true;
}
return false;
}
// Whether there are no operations in the queue.
bool empty() const
{
return operations_.empty();
}
// Determine whether there are any operations associated with the descriptor.
bool has_operation(Descriptor descriptor) const
{
return operations_.find(descriptor) != operations_.end();
}
// Dispatch the first operation corresponding to the descriptor. Returns true
// if there are more operations queued for the descriptor.
bool dispatch_operation(Descriptor descriptor,
const asio::error_code& result)
{
typename operation_map::iterator i = operations_.find(descriptor);
if (i != operations_.end())
{
op_base* this_op = i->second;
i->second = this_op->next_;
this_op->next_ = cleanup_operations_;
cleanup_operations_ = this_op;
bool done = this_op->invoke(result);
if (done)
{
// Operation has finished.
if (i->second)
{
return true;
}
else
{
operations_.erase(i);
return false;
}
}
else
{
// Operation wants to be called again. Leave it at the front of the
// queue for this descriptor, and remove from the cleanup list.
cleanup_operations_ = this_op->next_;
this_op->next_ = i->second;
i->second = this_op;
return true;
}
}
return false;
}
// Dispatch all operations corresponding to the descriptor.
void dispatch_all_operations(Descriptor descriptor,
const asio::error_code& result)
{
typename operation_map::iterator i = operations_.find(descriptor);
if (i != operations_.end())
{
while (i->second)
{
op_base* this_op = i->second;
i->second = this_op->next_;
this_op->next_ = cleanup_operations_;
cleanup_operations_ = this_op;
bool done = this_op->invoke(result);
if (!done)
{
// Operation has not finished yet, so leave at front of queue, and
// remove from the cleanup list.
cleanup_operations_ = this_op->next_;
this_op->next_ = i->second;
i->second = this_op;
return;
}
}
operations_.erase(i);
}
}
// Fill a descriptor set with the descriptors corresponding to each active
// operation.
template <typename Descriptor_Set>
void get_descriptors(Descriptor_Set& descriptors)
{
typename operation_map::iterator i = operations_.begin();
while (i != operations_.end())
{
Descriptor descriptor = i->first;
++i;
if (!descriptors.set(descriptor))
{
asio::error_code ec(error::fd_set_failure);
dispatch_all_operations(descriptor, ec);
}
}
}
// Dispatch the operations corresponding to the ready file descriptors
// contained in the given descriptor set.
template <typename Descriptor_Set>
void dispatch_descriptors(const Descriptor_Set& descriptors,
const asio::error_code& result)
{
typename operation_map::iterator i = operations_.begin();
while (i != operations_.end())
{
typename operation_map::iterator op_iter = i++;
if (descriptors.is_set(op_iter->first))
{
op_base* this_op = op_iter->second;
op_iter->second = this_op->next_;
this_op->next_ = cleanup_operations_;
cleanup_operations_ = this_op;
bool done = this_op->invoke(result);
if (done)
{
if (!op_iter->second)
operations_.erase(op_iter);
}
else
{
// Operation has not finished yet, so leave at front of queue, and
// remove from the cleanup list.
cleanup_operations_ = this_op->next_;
this_op->next_ = op_iter->second;
op_iter->second = this_op;
}
}
}
}
// Dispatch any pending cancels for operations.
void dispatch_cancellations()
{
while (cancelled_operations_)
{
op_base* this_op = cancelled_operations_;
cancelled_operations_ = this_op->next_;
this_op->next_ = cleanup_operations_;
cleanup_operations_ = this_op;
this_op->invoke(asio::error::operation_aborted);
}
}
// Destroy operations that are waiting to be cleaned up.
void cleanup_operations()
{
while (cleanup_operations_)
{
op_base* next_op = cleanup_operations_->next_;
cleanup_operations_->next_ = 0;
cleanup_operations_->destroy();
cleanup_operations_ = next_op;
}
}
// Destroy all operations owned by the queue.
void destroy_operations()
{
while (cancelled_operations_)
{
op_base* next_op = cancelled_operations_->next_;
cancelled_operations_->next_ = 0;
cancelled_operations_->destroy();
cancelled_operations_ = next_op;
}
while (cleanup_operations_)
{
op_base* next_op = cleanup_operations_->next_;
cleanup_operations_->next_ = 0;
cleanup_operations_->destroy();
cleanup_operations_ = next_op;
}
typename operation_map::iterator i = operations_.begin();
while (i != operations_.end())
{
typename operation_map::iterator op_iter = i++;
op_base* curr_op = op_iter->second;
operations_.erase(op_iter);
while (curr_op)
{
op_base* next_op = curr_op->next_;
curr_op->next_ = 0;
curr_op->destroy();
curr_op = next_op;
}
}
}
private:
// Base class for reactor operations. A function pointer is used instead of
// virtual functions to avoid the associated overhead.
class op_base
{
public:
// Get the descriptor associated with the operation.
Descriptor descriptor() const
{
return descriptor_;
}
// Perform the operation.
bool invoke(const asio::error_code& result)
{
return invoke_func_(this, result);
}
// Destroy the operation.
void destroy()
{
return destroy_func_(this);
}
protected:
typedef bool (*invoke_func_type)(op_base*,
const asio::error_code&);
typedef void (*destroy_func_type)(op_base*);
// Construct an operation for the given descriptor.
op_base(invoke_func_type invoke_func,
destroy_func_type destroy_func, Descriptor descriptor)
: invoke_func_(invoke_func),
destroy_func_(destroy_func),
descriptor_(descriptor),
next_(0)
{
}
// Prevent deletion through this type.
~op_base()
{
}
private:
friend class reactor_op_queue<Descriptor>;
// The function to be called to dispatch the handler.
invoke_func_type invoke_func_;
// The function to be called to delete the handler.
destroy_func_type destroy_func_;
// The descriptor associated with the operation.
Descriptor descriptor_;
// The next operation for the same file descriptor.
op_base* next_;
};
// Adaptor class template for using handlers in operations.
template <typename Handler>
class op
: public op_base
{
public:
// Constructor.
op(Descriptor descriptor, Handler handler)
: op_base(&op<Handler>::invoke_handler,
&op<Handler>::destroy_handler, descriptor),
handler_(handler)
{
}
// Invoke the handler.
static bool invoke_handler(op_base* base,
const asio::error_code& result)
{
return static_cast<op<Handler>*>(base)->handler_(result);
}
// Delete the handler.
static void destroy_handler(op_base* base)
{
delete static_cast<op<Handler>*>(base);
}
private:
Handler handler_;
};
// The type for a map of operations.
typedef hash_map<Descriptor, op_base*> operation_map;
// The operations that are currently executing asynchronously.
operation_map operations_;
// The list of operations that have been cancelled.
op_base* cancelled_operations_;
// The list of operations to be destroyed.
op_base* cleanup_operations_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP

View File

@ -1,357 +0,0 @@
//
// resolver_service.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_RESOLVER_SERVICE_HPP
#define ASIO_DETAIL_RESOLVER_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstring>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/thread.hpp"
namespace asio {
namespace detail {
template <typename Protocol>
class resolver_service
: public asio::detail::service_base<resolver_service<Protocol> >
{
private:
// Helper class to perform exception-safe cleanup of addrinfo objects.
class auto_addrinfo
: private asio::detail::noncopyable
{
public:
explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
: ai_(ai)
{
}
~auto_addrinfo()
{
if (ai_)
socket_ops::freeaddrinfo(ai_);
}
operator asio::detail::addrinfo_type*()
{
return ai_;
}
private:
asio::detail::addrinfo_type* ai_;
};
public:
// The implementation type of the resolver. The shared pointer is used as a
// cancellation token to indicate to the background thread that the operation
// has been cancelled.
typedef boost::shared_ptr<void> implementation_type;
struct noop_deleter { void operator()(void*) {} };
// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
// The query type.
typedef typename Protocol::resolver_query query_type;
// The iterator type.
typedef typename Protocol::resolver_iterator iterator_type;
// Constructor.
resolver_service(asio::io_service& io_service)
: asio::detail::service_base<
resolver_service<Protocol> >(io_service),
mutex_(),
work_io_service_(new asio::io_service),
work_(new asio::io_service::work(*work_io_service_)),
work_thread_(0)
{
}
// Destructor.
~resolver_service()
{
shutdown_service();
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
work_.reset();
if (work_io_service_)
{
work_io_service_->stop();
if (work_thread_)
{
work_thread_->join();
work_thread_.reset();
}
work_io_service_.reset();
}
}
// Construct a new resolver implementation.
void construct(implementation_type& impl)
{
impl.reset(static_cast<void*>(0), noop_deleter());
}
// Destroy a resolver implementation.
void destroy(implementation_type&)
{
}
// Cancel pending asynchronous operations.
void cancel(implementation_type& impl)
{
impl.reset(static_cast<void*>(0), noop_deleter());
}
// Resolve a query to a list of entries.
iterator_type resolve(implementation_type&, const query_type& query,
asio::error_code& ec)
{
asio::detail::addrinfo_type* address_info = 0;
std::string host_name = query.host_name();
std::string service_name = query.service_name();
asio::detail::addrinfo_type hints = query.hints();
socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
service_name.c_str(), &hints, &address_info, ec);
auto_addrinfo auto_address_info(address_info);
if (ec)
return iterator_type();
return iterator_type::create(address_info, host_name, service_name);
}
template <typename Handler>
class resolve_query_handler
{
public:
resolve_query_handler(implementation_type impl, const query_type& query,
asio::io_service& io_service, Handler handler)
: impl_(impl),
query_(query),
io_service_(io_service),
work_(io_service),
handler_(handler)
{
}
void operator()()
{
// Check if the operation has been cancelled.
if (impl_.expired())
{
iterator_type iterator;
io_service_.post(asio::detail::bind_handler(handler_,
asio::error::operation_aborted, iterator));
return;
}
// Perform the blocking host resolution operation.
asio::detail::addrinfo_type* address_info = 0;
std::string host_name = query_.host_name();
std::string service_name = query_.service_name();
asio::detail::addrinfo_type hints = query_.hints();
asio::error_code ec;
socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
service_name.c_str(), &hints, &address_info, ec);
auto_addrinfo auto_address_info(address_info);
// Invoke the handler and pass the result.
iterator_type iterator;
if (!ec)
iterator = iterator_type::create(address_info, host_name, service_name);
io_service_.post(asio::detail::bind_handler(
handler_, ec, iterator));
}
private:
boost::weak_ptr<void> impl_;
query_type query_;
asio::io_service& io_service_;
asio::io_service::work work_;
Handler handler_;
};
// Asynchronously resolve a query to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl, const query_type& query,
Handler handler)
{
if (work_io_service_)
{
start_work_thread();
work_io_service_->post(
resolve_query_handler<Handler>(
impl, query, this->get_io_service(), handler));
}
}
// Resolve an endpoint to a list of entries.
iterator_type resolve(implementation_type&,
const endpoint_type& endpoint, asio::error_code& ec)
{
// First try resolving with the service name. If that fails try resolving
// but allow the service to be returned as a number.
char host_name[NI_MAXHOST];
char service_name[NI_MAXSERV];
int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
if (ec)
{
flags |= NI_NUMERICSERV;
socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
}
if (ec)
return iterator_type();
return iterator_type::create(endpoint, host_name, service_name);
}
template <typename Handler>
class resolve_endpoint_handler
{
public:
resolve_endpoint_handler(implementation_type impl,
const endpoint_type& endpoint, asio::io_service& io_service,
Handler handler)
: impl_(impl),
endpoint_(endpoint),
io_service_(io_service),
work_(io_service),
handler_(handler)
{
}
void operator()()
{
// Check if the operation has been cancelled.
if (impl_.expired())
{
iterator_type iterator;
io_service_.post(asio::detail::bind_handler(handler_,
asio::error::operation_aborted, iterator));
return;
}
// First try resolving with the service name. If that fails try resolving
// but allow the service to be returned as a number.
char host_name[NI_MAXHOST];
char service_name[NI_MAXSERV];
int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
asio::error_code ec;
socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
if (ec)
{
flags |= NI_NUMERICSERV;
socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
}
// Invoke the handler and pass the result.
iterator_type iterator;
if (!ec)
iterator = iterator_type::create(endpoint_, host_name, service_name);
io_service_.post(asio::detail::bind_handler(
handler_, ec, iterator));
}
private:
boost::weak_ptr<void> impl_;
endpoint_type endpoint_;
asio::io_service& io_service_;
asio::io_service::work work_;
Handler handler_;
};
// Asynchronously resolve an endpoint to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
Handler handler)
{
if (work_io_service_)
{
start_work_thread();
work_io_service_->post(
resolve_endpoint_handler<Handler>(
impl, endpoint, this->get_io_service(), handler));
}
}
private:
// Helper class to run the work io_service in a thread.
class work_io_service_runner
{
public:
work_io_service_runner(asio::io_service& io_service)
: io_service_(io_service) {}
void operator()() { io_service_.run(); }
private:
asio::io_service& io_service_;
};
// Start the work thread if it's not already running.
void start_work_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (work_thread_ == 0)
{
work_thread_.reset(new asio::detail::thread(
work_io_service_runner(*work_io_service_)));
}
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// Private io_service used for performing asynchronous host resolution.
boost::scoped_ptr<asio::io_service> work_io_service_;
// Work for the private io_service to perform.
boost::scoped_ptr<asio::io_service::work> work_;
// Thread used for running the work io_service's run loop.
boost::scoped_ptr<asio::detail::thread> work_thread_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP

View File

@ -1,91 +0,0 @@
//
// scoped_lock.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SCOPED_LOCK_HPP
#define ASIO_DETAIL_SCOPED_LOCK_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
// Helper class to lock and unlock a mutex automatically.
template <typename Mutex>
class scoped_lock
: private noncopyable
{
public:
// Constructor acquires the lock.
scoped_lock(Mutex& m)
: mutex_(m)
{
mutex_.lock();
locked_ = true;
}
// Destructor releases the lock.
~scoped_lock()
{
if (locked_)
mutex_.unlock();
}
// Explicitly acquire the lock.
void lock()
{
if (!locked_)
{
mutex_.lock();
locked_ = true;
}
}
// Explicitly release the lock.
void unlock()
{
if (locked_)
{
mutex_.unlock();
locked_ = false;
}
}
// Test whether the lock is held.
bool locked() const
{
return locked_;
}
// Get the underlying mutex.
Mutex& mutex()
{
return mutex_;
}
private:
// The underlying mutex.
Mutex& mutex_;
// Whether the mutex is currently locked or unlocked.
bool locked_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SCOPED_LOCK_HPP

View File

@ -1,41 +0,0 @@
//
// select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SELECT_INTERRUPTER_HPP
#define ASIO_DETAIL_SELECT_INTERRUPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/pipe_select_interrupter.hpp"
#include "asio/detail/socket_select_interrupter.hpp"
namespace asio {
namespace detail {
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef socket_select_interrupter select_interrupter;
#else
typedef pipe_select_interrupter select_interrupter;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP

View File

@ -1,469 +0,0 @@
//
// select_reactor.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SELECT_REACTOR_HPP
#define ASIO_DETAIL_SELECT_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <vector>
#include "asio/detail/pop_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/fd_set_adapter.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/select_reactor_fwd.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/task_io_service.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/timer_queue.hpp"
namespace asio {
namespace detail {
template <bool Own_Thread>
class select_reactor
: public asio::detail::service_base<select_reactor<Own_Thread> >
{
public:
// Constructor.
select_reactor(asio::io_service& io_service)
: asio::detail::service_base<
select_reactor<Own_Thread> >(io_service),
mutex_(),
select_in_progress_(false),
interrupter_(),
read_op_queue_(),
write_op_queue_(),
except_op_queue_(),
pending_cancellations_(),
stop_thread_(false),
thread_(0),
shutdown_(false)
{
if (Own_Thread)
{
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&select_reactor::call_run_thread, this));
}
}
// Destructor.
~select_reactor()
{
shutdown_service();
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_thread_ = true;
lock.unlock();
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
}
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type descriptor)
{
return 0;
}
// Start a new read operation. The handler object will be invoked when the
// given descriptor is ready to be read, or an error has occurred.
template <typename Handler>
void start_read_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (read_op_queue_.enqueue_operation(descriptor, handler))
interrupter_.interrupt();
}
// Start a new write operation. The handler object will be invoked when the
// given descriptor is ready to be written, or an error has occurred.
template <typename Handler>
void start_write_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (write_op_queue_.enqueue_operation(descriptor, handler))
interrupter_.interrupt();
}
// Start a new exception operation. The handler object will be invoked when
// the given descriptor has exception information, or an error has occurred.
template <typename Handler>
void start_except_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (except_op_queue_.enqueue_operation(descriptor, handler))
interrupter_.interrupt();
}
// Start new write and exception operations. The handler object will be
// invoked when the given descriptor is ready for writing or has exception
// information available, or an error has occurred.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
{
bool interrupt = write_op_queue_.enqueue_operation(descriptor, handler);
interrupt = except_op_queue_.enqueue_operation(descriptor, handler)
|| interrupt;
if (interrupt)
interrupter_.interrupt();
}
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Enqueue cancellation of all operations associated with the given
// descriptor. The handlers associated with the descriptor will be invoked
// with the operation_aborted error. This function does not acquire the
// select_reactor's mutex, and so should only be used from within a reactor
// handler.
void enqueue_cancel_ops_unlocked(socket_type descriptor)
{
pending_cancellations_.push_back(descriptor);
}
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
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)
{
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>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
std::size_t n = timer_queue.cancel_timer(token);
if (n > 0)
interrupter_.interrupt();
return n;
}
private:
friend class task_io_service<select_reactor<Own_Thread> >;
// Run select once until interrupted or events are ready to be dispatched.
void run(bool block)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Dispatch any operation cancellations that were made while the select
// loop was not running.
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->dispatch_cancellations();
// Check if the thread is supposed to stop.
if (stop_thread_)
{
cleanup_operations_and_timers(lock);
return;
}
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
cleanup_operations_and_timers(lock);
return;
}
// Set up the descriptor sets.
fd_set_adapter read_fds;
read_fds.set(interrupter_.read_descriptor());
read_op_queue_.get_descriptors(read_fds);
fd_set_adapter write_fds;
write_op_queue_.get_descriptors(write_fds);
fd_set_adapter except_fds;
except_op_queue_.get_descriptors(except_fds);
socket_type max_fd = read_fds.max_descriptor();
if (write_fds.max_descriptor() > max_fd)
max_fd = write_fds.max_descriptor();
if (except_fds.max_descriptor() > max_fd)
max_fd = except_fds.max_descriptor();
// Block on the select call without holding the lock so that new
// operations can be started while the call is executing.
timeval tv_buf = { 0, 0 };
timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
select_in_progress_ = true;
lock.unlock();
asio::error_code ec;
int retval = socket_ops::select(static_cast<int>(max_fd + 1),
read_fds, write_fds, except_fds, tv, ec);
lock.lock();
select_in_progress_ = false;
// Block signals while dispatching operations.
asio::detail::signal_blocker sb;
// Reset the interrupter.
if (retval > 0 && read_fds.is_set(interrupter_.read_descriptor()))
interrupter_.reset();
// Dispatch all ready operations.
if (retval > 0)
{
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
except_op_queue_.dispatch_descriptors(except_fds,
asio::error_code());
read_op_queue_.dispatch_descriptors(read_fds,
asio::error_code());
write_op_queue_.dispatch_descriptors(write_fds,
asio::error_code());
except_op_queue_.dispatch_cancellations();
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
}
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
timer_queues_[i]->dispatch_timers();
timer_queues_[i]->dispatch_cancellations();
}
// Issue any pending cancellations.
for (size_t i = 0; i < pending_cancellations_.size(); ++i)
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
cleanup_operations_and_timers(lock);
}
// Run the select loop in the thread.
void run_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!stop_thread_)
{
lock.unlock();
run(true);
lock.lock();
}
}
// Entry point for the select loop thread.
static void call_run_thread(select_reactor* reactor)
{
reactor->run_thread();
}
// Interrupt the select loop.
void interrupt()
{
interrupter_.interrupt();
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the select call.
timeval* get_timeout(timeval& tv)
{
if (all_timer_queues_are_empty())
return 0;
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::minutes(5);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
tv.tv_sec = minimum_wait_duration.total_seconds();
tv.tv_usec = minimum_wait_duration.total_microseconds() % 1000000;
}
else
{
tv.tv_sec = 0;
tv.tv_usec = 0;
}
return &tv;
}
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the select_reactor's mutex.
void cancel_ops_unlocked(socket_type descriptor)
{
bool interrupt = read_op_queue_.cancel_operations(descriptor);
interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
if (interrupt)
interrupter_.interrupt();
}
// Clean up operations and timers. We must not hold the lock since the
// destructors may make calls back into this reactor. We make a copy of the
// vector of timer queues since the original may be modified while the lock
// is not held.
void cleanup_operations_and_timers(
asio::detail::mutex::scoped_lock& lock)
{
timer_queues_for_cleanup_ = timer_queues_;
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
timer_queues_for_cleanup_[i]->cleanup_timers();
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// Whether the select loop is currently running or not.
bool select_in_progress_;
// The interrupter is used to break a blocking select call.
select_interrupter interrupter_;
// The queue of read operations.
reactor_op_queue<socket_type> read_op_queue_;
// The queue of write operations.
reactor_op_queue<socket_type> write_op_queue_;
// The queue of exception operations.
reactor_op_queue<socket_type> except_op_queue_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// A copy of the timer queues, used when cleaning up timers. The copy is
// stored as a class data member to avoid unnecessary memory allocation.
std::vector<timer_queue_base*> timer_queues_for_cleanup_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
// Does the reactor loop thread need to stop.
bool stop_thread_;
// The thread that is running the reactor loop.
asio::detail::thread* thread_;
// Whether the service has been shut down.
bool shutdown_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SELECT_REACTOR_HPP

View File

@ -1,31 +0,0 @@
//
// select_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
#define ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <bool Own_Thread>
class select_reactor;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SELECT_REACTOR_FWD_HPP

View File

@ -1,49 +0,0 @@
//
// service_base.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SERVICE_BASE_HPP
#define ASIO_DETAIL_SERVICE_BASE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/service_id.hpp"
namespace asio {
namespace detail {
// Special service base class to keep classes header-file only.
template <typename Type>
class service_base
: public asio::io_service::service
{
public:
static asio::detail::service_id<Type> id;
// Constructor.
service_base(asio::io_service& io_service)
: asio::io_service::service(io_service)
{
}
};
template <typename Type>
asio::detail::service_id<Type> service_base<Type>::id;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SERVICE_BASE_HPP

View File

@ -1,37 +0,0 @@
//
// service_id.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SERVICE_ID_HPP
#define ASIO_DETAIL_SERVICE_ID_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/io_service.hpp"
namespace asio {
namespace detail {
// Special derived service id type to keep classes header-file only.
template <typename Type>
class service_id
: public asio::io_service::id
{
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SERVICE_ID_HPP

View File

@ -1,200 +0,0 @@
//
// service_registry.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SERVICE_REGISTRY_HPP
#define ASIO_DETAIL_SERVICE_REGISTRY_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <memory>
#include <typeinfo>
#include "asio/detail/pop_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_id.hpp"
namespace asio {
namespace detail {
class service_registry
: private noncopyable
{
public:
// Constructor.
service_registry(asio::io_service& o)
: owner_(o),
first_service_(0)
{
}
// Destructor.
~service_registry()
{
// Shutdown all services. This must be done in a separate loop before the
// services are destroyed since the destructors of user-defined handler
// objects may try to access other service objects.
asio::io_service::service* service = first_service_;
while (service)
{
service->shutdown_service();
service = service->next_;
}
// Destroy all services.
while (first_service_)
{
asio::io_service::service* next_service = first_service_->next_;
delete first_service_;
first_service_ = next_service;
}
}
// Get the service object corresponding to the specified service type. Will
// create a new service object automatically if no such object already
// exists. Ownership of the service object is not transferred to the caller.
template <typename Service>
Service& use_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
// First see if there is an existing service object for the given type.
asio::io_service::service* service = first_service_;
while (service)
{
if (service_id_matches(*service, Service::id))
return *static_cast<Service*>(service);
service = service->next_;
}
// Create a new service object. The service registry's mutex is not locked
// at this time to allow for nested calls into this function from the new
// service's constructor.
lock.unlock();
std::auto_ptr<Service> new_service(new Service(owner_));
init_service_id(*new_service, Service::id);
Service& new_service_ref = *new_service;
lock.lock();
// Check that nobody else created another service object of the same type
// while the lock was released.
service = first_service_;
while (service)
{
if (service_id_matches(*service, Service::id))
return *static_cast<Service*>(service);
service = service->next_;
}
// Service was successfully initialised, pass ownership to registry.
new_service->next_ = first_service_;
first_service_ = new_service.release();
return new_service_ref;
}
// Add a service object. Returns false on error, in which case ownership of
// the object is retained by the caller.
template <typename Service>
bool add_service(Service* new_service)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Check if there is an existing service object for the given type.
asio::io_service::service* service = first_service_;
while (service)
{
if (service_id_matches(*service, Service::id))
return false;
service = service->next_;
}
// Take ownership of the service object.
init_service_id(*new_service, Service::id);
new_service->next_ = first_service_;
first_service_ = new_service;
return true;
}
// Check whether a service object of the specified type already exists.
template <typename Service>
bool has_service() const
{
asio::detail::mutex::scoped_lock lock(mutex_);
asio::io_service::service* service = first_service_;
while (service)
{
if (service_id_matches(*service, Service::id))
return true;
service = service->next_;
}
return false;
}
private:
// Set a service's id.
void init_service_id(asio::io_service::service& service,
const asio::io_service::id& id)
{
service.type_info_ = 0;
service.id_ = &id;
}
// Set a service's id.
template <typename Service>
void init_service_id(asio::io_service::service& service,
const asio::detail::service_id<Service>& /*id*/)
{
service.type_info_ = &typeid(Service);
service.id_ = 0;
}
// Check if a service matches the given id.
static bool service_id_matches(
const asio::io_service::service& service,
const asio::io_service::id& id)
{
return service.id_ == &id;
}
// Check if a service matches the given id.
template <typename Service>
static bool service_id_matches(
const asio::io_service::service& service,
const asio::detail::service_id<Service>& /*id*/)
{
return service.type_info_ != 0 && *service.type_info_ == typeid(Service);
}
// Mutex to protect access to internal data.
mutable asio::detail::mutex mutex_;
// The owner of this service registry and the services it contains.
asio::io_service& owner_;
// The first service in the list of contained services.
asio::io_service::service* first_service_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP

View File

@ -1,30 +0,0 @@
//
// service_registry_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
#define ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class service_registry;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP

View File

@ -1,50 +0,0 @@
//
// signal_blocker.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SIGNAL_BLOCKER_HPP
#define ASIO_DETAIL_SIGNAL_BLOCKER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_signal_blocker.hpp"
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# include "asio/detail/win_signal_blocker.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_signal_blocker.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
#if !defined(BOOST_HAS_THREADS)
typedef null_signal_blocker signal_blocker;
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef win_signal_blocker signal_blocker;
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_signal_blocker signal_blocker;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP

View File

@ -1,51 +0,0 @@
//
// signal_init.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SIGNAL_INIT_HPP
#define ASIO_DETAIL_SIGNAL_INIT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/push_options.hpp"
#include <csignal>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
template <int Signal = SIGPIPE>
class signal_init
{
public:
// Constructor.
signal_init()
{
std::signal(Signal, SIG_IGN);
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SIGNAL_INIT_HPP

View File

@ -1,95 +0,0 @@
//
// socket_holder.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SOCKET_HOLDER_HPP
#define ASIO_DETAIL_SOCKET_HOLDER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_ops.hpp"
namespace asio {
namespace detail {
// Implement the resource acquisition is initialisation idiom for sockets.
class socket_holder
: private noncopyable
{
public:
// Construct as an uninitialised socket.
socket_holder()
: socket_(invalid_socket)
{
}
// Construct to take ownership of the specified socket.
explicit socket_holder(socket_type s)
: socket_(s)
{
}
// Destructor.
~socket_holder()
{
if (socket_ != invalid_socket)
{
asio::error_code ec;
socket_ops::close(socket_, ec);
}
}
// Get the underlying socket.
socket_type get() const
{
return socket_;
}
// Reset to an uninitialised socket.
void reset()
{
if (socket_ != invalid_socket)
{
asio::error_code ec;
socket_ops::close(socket_, ec);
socket_ = invalid_socket;
}
}
// Reset to take ownership of the specified socket.
void reset(socket_type s)
{
reset();
socket_ = s;
}
// Release ownership of the socket.
socket_type release()
{
socket_type tmp = socket_;
socket_ = invalid_socket;
return tmp;
}
private:
// The underlying socket.
socket_type socket_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SOCKET_HOLDER_HPP

File diff suppressed because it is too large Load Diff

View File

@ -1,309 +0,0 @@
//
// socket_option.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SOCKET_OPTION_HPP
#define ASIO_DETAIL_SOCKET_OPTION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <stdexcept>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
namespace socket_option {
// Helper template for implementing boolean-based options.
template <int Level, int Name>
class boolean
{
public:
// Default constructor.
boolean()
: value_(0)
{
}
// Construct with a specific option value.
explicit boolean(bool v)
: value_(v ? 1 : 0)
{
}
// Set the current value of the boolean.
boolean& operator=(bool v)
{
value_ = v ? 1 : 0;
return *this;
}
// Get the current value of the boolean.
bool value() const
{
return !!value_;
}
// Convert to bool.
operator bool() const
{
return !!value_;
}
// Test for false.
bool operator!() const
{
return !value_;
}
// Get the level of the socket option.
template <typename Protocol>
int level(const Protocol&) const
{
return Level;
}
// Get the name of the socket option.
template <typename Protocol>
int name(const Protocol&) const
{
return Name;
}
// Get the address of the boolean data.
template <typename Protocol>
int* data(const Protocol&)
{
return &value_;
}
// Get the address of the boolean data.
template <typename Protocol>
const int* data(const Protocol&) const
{
return &value_;
}
// Get the size of the boolean data.
template <typename Protocol>
std::size_t size(const Protocol&) const
{
return sizeof(value_);
}
// Set the size of the boolean data.
template <typename Protocol>
void resize(const Protocol&, std::size_t s)
{
// On some platforms (e.g. Windows Vista), the getsockopt function will
// return the size of a boolean socket option as one byte, even though a
// four byte integer was passed in.
switch (s)
{
case sizeof(char):
value_ = *reinterpret_cast<char*>(&value_) ? 1 : 0;
break;
case sizeof(value_):
break;
default:
throw std::length_error("boolean socket option resize");
}
}
private:
int value_;
};
// Helper template for implementing integer options.
template <int Level, int Name>
class integer
{
public:
// Default constructor.
integer()
: value_(0)
{
}
// Construct with a specific option value.
explicit integer(int v)
: value_(v)
{
}
// Set the value of the int option.
integer& operator=(int v)
{
value_ = v;
return *this;
}
// Get the current value of the int option.
int value() const
{
return value_;
}
// Get the level of the socket option.
template <typename Protocol>
int level(const Protocol&) const
{
return Level;
}
// Get the name of the socket option.
template <typename Protocol>
int name(const Protocol&) const
{
return Name;
}
// Get the address of the int data.
template <typename Protocol>
int* data(const Protocol&)
{
return &value_;
}
// Get the address of the int data.
template <typename Protocol>
const int* data(const Protocol&) const
{
return &value_;
}
// Get the size of the int data.
template <typename Protocol>
std::size_t size(const Protocol&) const
{
return sizeof(value_);
}
// Set the size of the int data.
template <typename Protocol>
void resize(const Protocol&, std::size_t s)
{
if (s != sizeof(value_))
throw std::length_error("integer socket option resize");
}
private:
int value_;
};
// Helper template for implementing linger options.
template <int Level, int Name>
class linger
{
public:
// Default constructor.
linger()
{
value_.l_onoff = 0;
value_.l_linger = 0;
}
// Construct with specific option values.
linger(bool e, int t)
{
enabled(e);
timeout(t);
}
// Set the value for whether linger is enabled.
void enabled(bool value)
{
value_.l_onoff = value ? 1 : 0;
}
// Get the value for whether linger is enabled.
bool enabled() const
{
return value_.l_onoff != 0;
}
// Set the value for the linger timeout.
void timeout(int value)
{
#if defined(WIN32)
value_.l_linger = static_cast<u_short>(value);
#else
value_.l_linger = value;
#endif
}
// Get the value for the linger timeout.
int timeout() const
{
return static_cast<int>(value_.l_linger);
}
// Get the level of the socket option.
template <typename Protocol>
int level(const Protocol&) const
{
return Level;
}
// Get the name of the socket option.
template <typename Protocol>
int name(const Protocol&) const
{
return Name;
}
// Get the address of the linger data.
template <typename Protocol>
::linger* data(const Protocol&)
{
return &value_;
}
// Get the address of the linger data.
template <typename Protocol>
const ::linger* data(const Protocol&) const
{
return &value_;
}
// Get the size of the linger data.
template <typename Protocol>
std::size_t size(const Protocol&) const
{
return sizeof(value_);
}
// Set the size of the int data.
template <typename Protocol>
void resize(const Protocol&, std::size_t s)
{
if (s != sizeof(value_))
throw std::length_error("linger socket option resize");
}
private:
::linger value_;
};
} // namespace socket_option
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SOCKET_OPTION_HPP

View File

@ -1,187 +0,0 @@
//
// socket_select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
#define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstdlib>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/socket_holder.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
class socket_select_interrupter
{
public:
// Constructor.
socket_select_interrupter()
{
asio::error_code ec;
socket_holder acceptor(socket_ops::socket(
AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
if (acceptor.get() == invalid_socket)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
int opt = 1;
socket_ops::setsockopt(acceptor.get(),
SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
using namespace std; // For memset.
sockaddr_in4_type addr;
std::size_t addr_len = sizeof(addr);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = 0;
if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
addr_len, ec) == socket_error_retval)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
&addr_len, ec) == socket_error_retval)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
if (socket_ops::listen(acceptor.get(),
SOMAXCONN, ec) == socket_error_retval)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
socket_holder client(socket_ops::socket(
AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
if (client.get() == invalid_socket)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
addr_len, ec) == socket_error_retval)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
if (server.get() == invalid_socket)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
ioctl_arg_type non_blocking = 1;
if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
opt = 1;
socket_ops::setsockopt(client.get(),
IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
non_blocking = 1;
if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
opt = 1;
socket_ops::setsockopt(server.get(),
IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
read_descriptor_ = server.release();
write_descriptor_ = client.release();
}
// Destructor.
~socket_select_interrupter()
{
asio::error_code ec;
if (read_descriptor_ != invalid_socket)
socket_ops::close(read_descriptor_, ec);
if (write_descriptor_ != invalid_socket)
socket_ops::close(write_descriptor_, ec);
}
// Interrupt the select call.
void interrupt()
{
char byte = 0;
socket_ops::buf b;
socket_ops::init_buf(b, &byte, 1);
asio::error_code ec;
socket_ops::send(write_descriptor_, &b, 1, 0, ec);
}
// Reset the select interrupt. Returns true if the call was interrupted.
bool reset()
{
char data[1024];
socket_ops::buf b;
socket_ops::init_buf(b, data, sizeof(data));
asio::error_code ec;
int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
return was_interrupted;
}
// Get the read descriptor to be passed to select.
socket_type read_descriptor() const
{
return read_descriptor_;
}
private:
// The read end of a connection used to interrupt the select call. This file
// descriptor is passed to select such that when it is time to stop, a single
// byte will be written on the other end of the connection and this
// descriptor will become readable.
socket_type read_descriptor_;
// The write end of a connection used to interrupt the select call. A single
// byte may be written to this to wake up the select which is waiting for the
// other end to become readable.
socket_type write_descriptor_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP

View File

@ -1,199 +0,0 @@
//
// socket_types.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_SOCKET_TYPES_HPP
#define ASIO_DETAIL_SOCKET_TYPES_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "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")
# pragma message("Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)")
# else // defined(_MSC_VER) || defined(__BORLANDC__)
# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately
# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)
# endif // defined(_MSC_VER) || defined(__BORLANDC__)
# define _WIN32_WINNT 0x0501
# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
# if defined(_MSC_VER)
# if defined(_WIN32) && !defined(WIN32)
# if !defined(_WINSOCK2API_)
# define WIN32 // Needed for correct types in winsock2.h
# else // !defined(_WINSOCK2API_)
# error Please define the macro WIN32 in your compiler options
# endif // !defined(_WINSOCK2API_)
# endif // defined(_WIN32) && !defined(WIN32)
# endif // defined(_MSC_VER)
# if defined(__BORLANDC__)
# include <stdlib.h> // Needed for __errno
# if defined(__WIN32__) && !defined(WIN32)
# if !defined(_WINSOCK2API_)
# define WIN32 // Needed for correct types in winsock2.h
# else // !defined(_WINSOCK2API_)
# error Please define the macro WIN32 in your compiler options
# endif // !defined(_WINSOCK2API_)
# endif // defined(__WIN32__) && !defined(WIN32)
# if !defined(_WSPIAPI_H_)
# define _WSPIAPI_H_
# define ASIO_WSPIAPI_H_DEFINED
# endif // !defined(_WSPIAPI_H_)
# endif // defined(__BORLANDC__)
# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif // !defined(WIN32_LEAN_AND_MEAN)
# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
# if defined(__CYGWIN__)
# if !defined(__USE_W32_SOCKETS)
# error You must add -D__USE_W32_SOCKETS to your compiler options.
# endif // !defined(__USE_W32_SOCKETS)
# if !defined(NOMINMAX)
# define NOMINMAX 1
# endif // !defined(NOMINMAX)
# endif // defined(__CYGWIN__)
# include <winsock2.h>
# include <ws2tcpip.h>
# include <mswsock.h>
# if defined(ASIO_WSPIAPI_H_DEFINED)
# undef _WSPIAPI_H_
# undef ASIO_WSPIAPI_H_DEFINED
# endif // defined(ASIO_WSPIAPI_H_DEFINED)
# if !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
# if defined(UNDER_CE)
# pragma comment(lib, "ws2.lib")
# elif defined(_MSC_VER) || defined(__BORLANDC__)
# pragma comment(lib, "ws2_32.lib")
# pragma comment(lib, "mswsock.lib")
# endif // defined(_MSC_VER) || defined(__BORLANDC__)
# endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
# include "asio/detail/old_win_sdk_compat.hpp"
#else
# include <sys/ioctl.h>
# include <sys/poll.h>
# include <sys/types.h>
# if defined(__hpux) && !defined(__HP_aCC)
# include <sys/time.h>
# else
# include <sys/select.h>
# endif
# include <sys/socket.h>
# include <sys/uio.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <net/if.h>
# include <limits.h>
# if defined(__sun)
# include <sys/filio.h>
# include <sys/sockio.h>
# endif
#endif
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef SOCKET socket_type;
const SOCKET invalid_socket = INVALID_SOCKET;
const int socket_error_retval = SOCKET_ERROR;
const int max_addr_v4_str_len = 256;
const int max_addr_v6_str_len = 256;
typedef sockaddr socket_addr_type;
typedef in_addr in4_addr_type;
typedef ip_mreq in4_mreq_type;
typedef sockaddr_in sockaddr_in4_type;
# if defined(ASIO_HAS_OLD_WIN_SDK)
typedef in6_addr_emulation in6_addr_type;
typedef ipv6_mreq_emulation in6_mreq_type;
typedef sockaddr_in6_emulation sockaddr_in6_type;
typedef sockaddr_storage_emulation sockaddr_storage_type;
typedef addrinfo_emulation addrinfo_type;
# else
typedef in6_addr in6_addr_type;
typedef ipv6_mreq in6_mreq_type;
typedef sockaddr_in6 sockaddr_in6_type;
typedef sockaddr_storage sockaddr_storage_type;
typedef addrinfo addrinfo_type;
# endif
typedef unsigned long ioctl_arg_type;
typedef u_long u_long_type;
typedef u_short u_short_type;
const int shutdown_receive = SD_RECEIVE;
const int shutdown_send = SD_SEND;
const int shutdown_both = SD_BOTH;
const int message_peek = MSG_PEEK;
const int message_out_of_band = MSG_OOB;
const int message_do_not_route = MSG_DONTROUTE;
# if defined (_WIN32_WINNT)
const int max_iov_len = 64;
# else
const int max_iov_len = 16;
# endif
#else
typedef int socket_type;
const int invalid_socket = -1;
const int socket_error_retval = -1;
const int max_addr_v4_str_len = INET_ADDRSTRLEN;
const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE;
typedef sockaddr socket_addr_type;
typedef in_addr in4_addr_type;
# if defined(__hpux)
// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined.
struct in4_mreq_type
{
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
# else
typedef ip_mreq in4_mreq_type;
# endif
typedef sockaddr_in sockaddr_in4_type;
typedef in6_addr in6_addr_type;
typedef ipv6_mreq in6_mreq_type;
typedef sockaddr_in6 sockaddr_in6_type;
typedef sockaddr_storage sockaddr_storage_type;
typedef addrinfo addrinfo_type;
typedef int ioctl_arg_type;
typedef uint32_t u_long_type;
typedef uint16_t u_short_type;
const int shutdown_receive = SHUT_RD;
const int shutdown_send = SHUT_WR;
const int shutdown_both = SHUT_RDWR;
const int message_peek = MSG_PEEK;
const int message_out_of_band = MSG_OOB;
const int message_do_not_route = MSG_DONTROUTE;
const int max_iov_len = IOV_MAX;
#endif
const int custom_socket_option_level = 0xA5100000;
const int enable_connection_aborted_option = 1;
const int always_fail_option = 2;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SOCKET_TYPES_HPP

View File

@ -1,525 +0,0 @@
//
// strand_service.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_STRAND_SERVICE_HPP
#define ASIO_DETAIL_STRAND_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/aligned_storage.hpp>
#include <boost/assert.hpp>
#include <boost/intrusive_ptr.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/call_stack.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_base.hpp"
namespace asio {
namespace detail {
// Default service implementation for a strand.
class strand_service
: public asio::detail::service_base<strand_service>
{
public:
class handler_base;
class invoke_current_handler;
class post_next_waiter_on_exit;
// The underlying implementation of a strand.
class strand_impl
{
#if defined (__BORLANDC__)
public:
#else
private:
#endif
void add_ref()
{
asio::detail::mutex::scoped_lock lock(mutex_);
++ref_count_;
}
void release()
{
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.
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.
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.
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_;
// The start of the list of waiting handlers for the strand.
handler_base* first_waiter_;
// The end of the list of waiting handlers for the strand.
handler_base* last_waiter_;
// Storage for posted handlers.
typedef boost::aligned_storage<128> handler_storage_type;
#if defined(__BORLANDC__)
boost::aligned_storage<128> handler_storage_;
#else
handler_storage_type handler_storage_;
#endif
// Pointers to adjacent socket implementations in linked list.
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
{
public:
typedef void (*invoke_func_type)(handler_base*,
strand_service&, implementation_type&);
typedef void (*destroy_func_type)(handler_base*);
handler_base(invoke_func_type invoke_func, destroy_func_type destroy_func)
: next_(0),
invoke_func_(invoke_func),
destroy_func_(destroy_func)
{
}
void invoke(strand_service& service_impl, implementation_type& impl)
{
invoke_func_(this, service_impl, impl);
}
void destroy()
{
destroy_func_(this);
}
protected:
~handler_base()
{
}
private:
friend class strand_service;
friend class strand_impl;
friend class post_next_waiter_on_exit;
handler_base* next_;
invoke_func_type invoke_func_;
destroy_func_type destroy_func_;
};
// Helper class to allow handlers to be dispatched.
class invoke_current_handler
{
public:
invoke_current_handler(strand_service& service_impl,
const implementation_type& impl)
: service_impl_(service_impl),
impl_(impl)
{
}
void operator()()
{
impl_->current_handler_->invoke(service_impl_, impl_);
}
friend void* asio_handler_allocate(std::size_t size,
invoke_current_handler* this_handler)
{
return this_handler->do_handler_allocate(size);
}
friend void asio_handler_deallocate(void*, std::size_t,
invoke_current_handler*)
{
}
void* do_handler_allocate(std::size_t size)
{
#if defined(__BORLANDC__)
BOOST_ASSERT(size <= boost::aligned_storage<128>::size);
#else
BOOST_ASSERT(size <= strand_impl::handler_storage_type::size);
#endif
(void)size;
return impl_->handler_storage_.address();
}
// The asio_handler_invoke hook is not defined here since the default one
// provides the correct behaviour, and including it here breaks MSVC 7.1
// in some situations.
private:
strand_service& service_impl_;
implementation_type impl_;
};
// Helper class to automatically enqueue next waiter on block exit.
class post_next_waiter_on_exit
{
public:
post_next_waiter_on_exit(strand_service& service_impl,
implementation_type& impl)
: service_impl_(service_impl),
impl_(impl),
cancelled_(false)
{
}
~post_next_waiter_on_exit()
{
if (!cancelled_)
{
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;
lock.unlock();
service_impl_.get_io_service().post(
invoke_current_handler(service_impl_, impl_));
}
}
}
void cancel()
{
cancelled_ = true;
}
private:
strand_service& service_impl_;
implementation_type& impl_;
bool cancelled_;
};
// Class template for a waiter.
template <typename Handler>
class handler_wrapper
: public handler_base
{
public:
handler_wrapper(Handler handler)
: handler_base(&handler_wrapper<Handler>::do_invoke,
&handler_wrapper<Handler>::do_destroy),
handler_(handler)
{
}
static void do_invoke(handler_base* base,
strand_service& service_impl, implementation_type& impl)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
post_next_waiter_on_exit p1(service_impl, impl);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made.
Handler handler(h->handler_);
// A handler object must still be valid when the next waiter is posted
// since destroying the last handler might cause the strand object to be
// destroyed. Therefore we create a second post_next_waiter_on_exit object
// that will be destroyed before the handler object.
p1.cancel();
post_next_waiter_on_exit p2(service_impl, impl);
// Free the memory associated with the handler.
ptr.reset();
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl.get());
// Make the upcall.
asio_handler_invoke_helpers::invoke(handler, &handler);
}
static void do_destroy(handler_base* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
}
private:
Handler handler_;
};
// Construct a new strand service for the specified io_service.
explicit strand_service(asio::io_service& io_service)
: asio::detail::service_base<strand_service>(io_service),
mutex_(),
impl_list_(0)
{
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
// Construct a list of all handlers to be destroyed.
asio::detail::mutex::scoped_lock lock(mutex_);
strand_impl* impl = impl_list_;
handler_base* first_handler = 0;
while (impl)
{
if (impl->current_handler_)
{
impl->current_handler_->next_ = first_handler;
first_handler = impl->current_handler_;
impl->current_handler_ = 0;
}
if (impl->first_waiter_)
{
impl->last_waiter_->next_ = first_handler;
first_handler = impl->first_waiter_;
impl->first_waiter_ = 0;
impl->last_waiter_ = 0;
}
impl = impl->next_;
}
// Destroy all handlers without holding the lock.
lock.unlock();
while (first_handler)
{
handler_base* next = first_handler->next_;
first_handler->destroy();
first_handler = next;
}
}
// Construct a new strand implementation.
void construct(implementation_type& impl)
{
impl = implementation_type(new strand_impl(*this));
}
// Destroy a strand implementation.
void destroy(implementation_type& impl)
{
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<strand_impl>::contains(impl.get()))
{
asio_handler_invoke_helpers::invoke(handler, &handler);
}
else
{
// Allocate and construct an object to wrap the handler.
typedef handler_wrapper<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, handler);
asio::detail::mutex::scoped_lock lock(impl->mutex_);
if (impl->current_handler_ == 0)
{
// This handler now has the lock, so can be dispatched immediately.
impl->current_handler_ = ptr.release();
lock.unlock();
this->get_io_service().dispatch(invoke_current_handler(*this, impl));
}
else
{
// 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_)
{
impl->last_waiter_->next_ = ptr.get();
impl->last_waiter_ = impl->last_waiter_->next_;
}
else
{
impl->first_waiter_ = ptr.get();
impl->last_waiter_ = ptr.get();
}
ptr.release();
}
}
}
// Request the io_service to invoke the given handler and return immediately.
template <typename Handler>
void post(implementation_type& impl, Handler handler)
{
// Allocate and construct an object to wrap the handler.
typedef handler_wrapper<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, handler);
asio::detail::mutex::scoped_lock lock(impl->mutex_);
if (impl->current_handler_ == 0)
{
// This handler now has the lock, so can be dispatched immediately.
impl->current_handler_ = ptr.release();
lock.unlock();
this->get_io_service().post(invoke_current_handler(*this, impl));
}
else
{
// 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_)
{
impl->last_waiter_->next_ = ptr.get();
impl->last_waiter_ = impl->last_waiter_->next_;
}
else
{
impl->first_waiter_ = ptr.get();
impl->last_waiter_ = ptr.get();
}
ptr.release();
}
}
private:
// Mutex to protect access to the linked list of implementations.
asio::detail::mutex mutex_;
// The head of a linked list of all implementations.
strand_impl* impl_list_;
};
} // namespace detail
} // namespace asio
#if defined(__BORLANDC__)
namespace boost {
inline void intrusive_ptr_add_ref(
asio::detail::strand_service::strand_impl* p)
{
p->add_ref();
}
inline void intrusive_ptr_release(
asio::detail::strand_service::strand_impl* p)
{
p->release();
}
} // namespace boost
#endif // defined(__BORLANDC__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_STRAND_SERVICE_HPP

View File

@ -1,419 +0,0 @@
//
// task_io_service.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_TASK_IO_SERVICE_HPP
#define ASIO_DETAIL_TASK_IO_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/error_code.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/call_stack.hpp"
#include "asio/detail/event.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/handler_queue.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/task_io_service_fwd.hpp"
namespace asio {
namespace detail {
template <typename Task>
class task_io_service
: public asio::detail::service_base<task_io_service<Task> >
{
public:
// Constructor.
task_io_service(asio::io_service& io_service)
: asio::detail::service_base<task_io_service<Task> >(io_service),
mutex_(),
task_(use_service<Task>(io_service)),
task_interrupted_(true),
outstanding_work_(0),
stopped_(false),
shutdown_(false),
first_idle_thread_(0)
{
handler_queue_.push(&task_handler_);
}
void init(size_t /*concurrency_hint*/)
{
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
// Destroy handler objects.
while (!handler_queue_.empty())
{
handler_queue::handler* h = handler_queue_.front();
handler_queue_.pop();
if (h != &task_handler_)
h->destroy();
}
// Reset handler queue to initial state.
handler_queue_.push(&task_handler_);
}
// Run the event loop until interrupted or no more work.
size_t run(asio::error_code& ec)
{
typename call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
this_idle_thread.next = 0;
asio::detail::mutex::scoped_lock lock(mutex_);
size_t n = 0;
while (do_one(lock, &this_idle_thread, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
// Run until interrupted or one operation is performed.
size_t run_one(asio::error_code& ec)
{
typename call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
this_idle_thread.next = 0;
asio::detail::mutex::scoped_lock lock(mutex_);
return do_one(lock, &this_idle_thread, ec);
}
// Poll for operations without blocking.
size_t poll(asio::error_code& ec)
{
typename call_stack<task_io_service>::context ctx(this);
asio::detail::mutex::scoped_lock lock(mutex_);
size_t n = 0;
while (do_one(lock, 0, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
// Poll for one operation without blocking.
size_t poll_one(asio::error_code& ec)
{
typename call_stack<task_io_service>::context ctx(this);
asio::detail::mutex::scoped_lock lock(mutex_);
return do_one(lock, 0, ec);
}
// Interrupt the event processing loop.
void stop()
{
asio::detail::mutex::scoped_lock lock(mutex_);
stop_all_threads(lock);
}
// Reset in preparation for a subsequent run invocation.
void reset()
{
asio::detail::mutex::scoped_lock lock(mutex_);
stopped_ = false;
}
// Notify that some work has started.
void work_started()
{
asio::detail::mutex::scoped_lock lock(mutex_);
++outstanding_work_;
}
// Notify that some work has finished.
void work_finished()
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (--outstanding_work_ == 0)
stop_all_threads(lock);
}
// Request invocation of the given handler.
template <typename Handler>
void dispatch(Handler handler)
{
if (call_stack<task_io_service>::contains(this))
asio_handler_invoke_helpers::invoke(handler, &handler);
else
post(handler);
}
// Request invocation of the given handler and return immediately.
template <typename Handler>
void post(Handler handler)
{
// Allocate and construct an operation to wrap the handler.
handler_queue::scoped_ptr ptr(handler_queue::wrap(handler));
asio::detail::mutex::scoped_lock lock(mutex_);
// If the service has been shut down we silently discard the handler.
if (shutdown_)
return;
// Add the handler to the end of the queue.
handler_queue_.push(ptr.get());
ptr.release();
// An undelivered handler is treated as unfinished work.
++outstanding_work_;
// Wake up a thread to execute the handler.
if (!interrupt_one_idle_thread(lock))
{
if (!task_interrupted_)
{
task_interrupted_ = true;
task_.interrupt();
}
}
}
private:
struct idle_thread_info;
size_t do_one(asio::detail::mutex::scoped_lock& lock,
idle_thread_info* this_idle_thread, asio::error_code& ec)
{
if (outstanding_work_ == 0 && !stopped_)
{
stop_all_threads(lock);
ec = asio::error_code();
return 0;
}
bool polling = !this_idle_thread;
bool task_has_run = false;
while (!stopped_)
{
if (!handler_queue_.empty())
{
// Prepare to execute first handler from queue.
handler_queue::handler* h = handler_queue_.front();
handler_queue_.pop();
if (h == &task_handler_)
{
bool more_handlers = (!handler_queue_.empty());
task_interrupted_ = more_handlers || polling;
// If the task has already run and we're polling then we're done.
if (task_has_run && polling)
{
task_interrupted_ = true;
handler_queue_.push(&task_handler_);
ec = asio::error_code();
return 0;
}
task_has_run = true;
lock.unlock();
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
{
lock.unlock();
handler_cleanup c(lock, *this);
// Invoke the handler. May throw an exception.
h->invoke(); // invoke() deletes the handler object
ec = asio::error_code();
return 1;
}
}
else if (this_idle_thread)
{
// Nothing to run right now, so just wait for work to do.
this_idle_thread->next = first_idle_thread_;
first_idle_thread_ = this_idle_thread;
this_idle_thread->wakeup_event.clear(lock);
this_idle_thread->wakeup_event.wait(lock);
}
else
{
ec = asio::error_code();
return 0;
}
}
ec = asio::error_code();
return 0;
}
// Stop the task and all idle threads.
void stop_all_threads(
asio::detail::mutex::scoped_lock& lock)
{
stopped_ = true;
interrupt_all_idle_threads(lock);
if (!task_interrupted_)
{
task_interrupted_ = true;
task_.interrupt();
}
}
// Interrupt a single idle thread. Returns true if a thread was interrupted,
// false if no running thread could be found to interrupt.
bool interrupt_one_idle_thread(
asio::detail::mutex::scoped_lock& lock)
{
if (first_idle_thread_)
{
idle_thread_info* idle_thread = first_idle_thread_;
first_idle_thread_ = idle_thread->next;
idle_thread->next = 0;
idle_thread->wakeup_event.signal(lock);
return true;
}
return false;
}
// Interrupt all idle threads.
void interrupt_all_idle_threads(
asio::detail::mutex::scoped_lock& lock)
{
while (first_idle_thread_)
{
idle_thread_info* idle_thread = first_idle_thread_;
first_idle_thread_ = idle_thread->next;
idle_thread->next = 0;
idle_thread->wakeup_event.signal(lock);
}
}
// Helper class to perform task-related operations on block exit.
class task_cleanup;
friend class task_cleanup;
class task_cleanup
{
public:
task_cleanup(asio::detail::mutex::scoped_lock& lock,
task_io_service& task_io_svc)
: lock_(lock),
task_io_service_(task_io_svc)
{
}
~task_cleanup()
{
// Reinsert the task at the end of the handler queue.
lock_.lock();
task_io_service_.task_interrupted_ = true;
task_io_service_.handler_queue_.push(&task_io_service_.task_handler_);
}
private:
asio::detail::mutex::scoped_lock& lock_;
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(asio::detail::mutex::scoped_lock& lock,
task_io_service& task_io_svc)
: lock_(lock),
task_io_service_(task_io_svc)
{
}
~handler_cleanup()
{
lock_.lock();
if (--task_io_service_.outstanding_work_ == 0)
task_io_service_.stop_all_threads(lock_);
}
private:
asio::detail::mutex::scoped_lock& lock_;
task_io_service& task_io_service_;
};
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// The task to be run by this service.
Task& task_;
// Handler object to represent the position of the task in the queue.
class task_handler
: public handler_queue::handler
{
public:
task_handler()
: handler_queue::handler(0, 0)
{
}
} task_handler_;
// Whether the task has been interrupted.
bool task_interrupted_;
// The count of unfinished work.
int outstanding_work_;
// The queue of handlers that are ready to be delivered.
handler_queue handler_queue_;
// Flag to indicate that the dispatcher has been stopped.
bool stopped_;
// Flag to indicate that the dispatcher has been shut down.
bool shutdown_;
// Structure containing information about an idle thread.
struct idle_thread_info
{
event wakeup_event;
idle_thread_info* next;
};
// The number of threads that are currently idle.
idle_thread_info* first_idle_thread_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TASK_IO_SERVICE_HPP

View File

@ -1,31 +0,0 @@
//
// task_io_service_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
#define ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Task>
class task_io_service;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP

View File

@ -1,58 +0,0 @@
//
// thread.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_THREAD_HPP
#define ASIO_DETAIL_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_thread.hpp"
#elif defined(BOOST_WINDOWS)
# if defined(UNDER_CE)
# include "asio/detail/wince_thread.hpp"
# else
# include "asio/detail/win_thread.hpp"
# endif
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_thread.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
#if !defined(BOOST_HAS_THREADS)
typedef null_thread thread;
#elif defined(BOOST_WINDOWS)
# if defined(UNDER_CE)
typedef wince_thread thread;
# else
typedef win_thread thread;
# endif
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_thread thread;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_THREAD_HPP

View File

@ -1,44 +0,0 @@
//
// throw_error.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_THROW_ERROR_HPP
#define ASIO_DETAIL_THROW_ERROR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error_code.hpp"
#include "asio/system_error.hpp"
namespace asio {
namespace detail {
inline void throw_error(const asio::error_code& err)
{
if (err)
{
asio::system_error e(err);
boost::throw_exception(e);
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_THROW_ERROR_HPP

View File

@ -1,395 +0,0 @@
//
// timer_queue.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_TIMER_QUEUE_HPP
#define ASIO_DETAIL_TIMER_QUEUE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <functional>
#include <limits>
#include <memory>
#include <vector>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/timer_queue_base.hpp"
namespace asio {
namespace detail {
template <typename Time_Traits>
class timer_queue
: public timer_queue_base
{
public:
// The time type.
typedef typename Time_Traits::time_type time_type;
// The duration type.
typedef typename Time_Traits::duration_type duration_type;
// Constructor.
timer_queue()
: timers_(),
heap_(),
cancelled_timers_(0),
cleanup_timers_(0)
{
}
// Add a new timer to the queue. Returns true if this is the timer that is
// earliest in the queue, in which case the reactor's event demultiplexing
// function call may need to be interrupted and restarted.
template <typename Handler>
bool enqueue_timer(const time_type& time, Handler handler, void* token)
{
// Ensure that there is space for the timer in the heap. We reserve here so
// that the push_back below will not throw due to a reallocation failure.
heap_.reserve(heap_.size() + 1);
// Create a new timer object.
std::auto_ptr<timer<Handler> > new_timer(
new timer<Handler>(time, handler, token));
// Insert the new timer into the hash.
typedef typename hash_map<void*, timer_base*>::iterator iterator;
typedef typename hash_map<void*, timer_base*>::value_type value_type;
std::pair<iterator, bool> result =
timers_.insert(value_type(token, new_timer.get()));
if (!result.second)
{
result.first->second->prev_ = new_timer.get();
new_timer->next_ = result.first->second;
result.first->second = new_timer.get();
}
// Put the timer at the correct position in the heap.
new_timer->heap_index_ = heap_.size();
heap_.push_back(new_timer.get());
up_heap(heap_.size() - 1);
bool is_first = (heap_[0] == new_timer.get());
// Ownership of the timer is transferred to the timer queue.
new_timer.release();
return is_first;
}
// Whether there are no timers in the queue.
virtual bool empty() const
{
return heap_.empty();
}
// Get the time for the timer that is earliest in the queue.
virtual boost::posix_time::time_duration wait_duration() const
{
return Time_Traits::to_posix_duration(
Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
}
// Dispatch the timers that are earlier than the specified time.
virtual void dispatch_timers()
{
const time_type now = Time_Traits::now();
while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
{
timer_base* t = heap_[0];
remove_timer(t);
t->prev_ = 0;
t->next_ = cleanup_timers_;
cleanup_timers_ = t;
t->invoke(asio::error_code());
}
}
// Cancel the timers with the given token. Any timers pending for the token
// will be notified that they have been cancelled next time
// dispatch_cancellations is called. Returns the number of timers that were
// cancelled.
std::size_t cancel_timer(void* timer_token)
{
std::size_t num_cancelled = 0;
typedef typename hash_map<void*, timer_base*>::iterator iterator;
iterator it = timers_.find(timer_token);
if (it != timers_.end())
{
timer_base* t = it->second;
while (t)
{
timer_base* next = t->next_;
remove_timer(t);
t->prev_ = 0;
t->next_ = cancelled_timers_;
cancelled_timers_ = t;
t = next;
++num_cancelled;
}
}
return num_cancelled;
}
// Dispatch any pending cancels for timers.
virtual void dispatch_cancellations()
{
while (cancelled_timers_)
{
timer_base* this_timer = cancelled_timers_;
cancelled_timers_ = this_timer->next_;
this_timer->next_ = cleanup_timers_;
cleanup_timers_ = this_timer;
this_timer->invoke(asio::error::operation_aborted);
}
}
// Destroy timers that are waiting to be cleaned up.
virtual void cleanup_timers()
{
destroy_timer_list(cleanup_timers_);
}
// Destroy all timers.
virtual void destroy_timers()
{
typename hash_map<void*, timer_base*>::iterator i = timers_.begin();
typename hash_map<void*, timer_base*>::iterator end = timers_.end();
while (i != end)
{
timer_base* t = i->second;
typename hash_map<void*, timer_base*>::iterator old_i = i++;
timers_.erase(old_i);
destroy_timer_list(t);
}
heap_.clear();
timers_.clear();
destroy_timer_list(cancelled_timers_);
destroy_timer_list(cleanup_timers_);
}
private:
// Base class for timer operations. Function pointers are used instead of
// virtual functions to avoid the associated overhead.
class timer_base
{
public:
// Perform the timer operation and then destroy.
void invoke(const asio::error_code& result)
{
invoke_func_(this, result);
}
// Destroy the timer operation.
void destroy()
{
destroy_func_(this);
}
protected:
typedef void (*invoke_func_type)(timer_base*,
const asio::error_code&);
typedef void (*destroy_func_type)(timer_base*);
// Constructor.
timer_base(invoke_func_type invoke_func, destroy_func_type destroy_func,
const time_type& time, void* token)
: invoke_func_(invoke_func),
destroy_func_(destroy_func),
time_(time),
token_(token),
next_(0),
prev_(0),
heap_index_(
std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
{
}
// Prevent deletion through this type.
~timer_base()
{
}
private:
friend class timer_queue<Time_Traits>;
// The function to be called to dispatch the handler.
invoke_func_type invoke_func_;
// The function to be called to destroy the handler.
destroy_func_type destroy_func_;
// The time when the operation should fire.
time_type time_;
// The token associated with the timer.
void* token_;
// The next timer known to the queue.
timer_base* next_;
// The previous timer known to the queue.
timer_base* prev_;
// The index of the timer in the heap.
size_t heap_index_;
};
// Adaptor class template for using handlers in timers.
template <typename Handler>
class timer
: public timer_base
{
public:
// Constructor.
timer(const time_type& time, Handler handler, void* token)
: timer_base(&timer<Handler>::invoke_handler,
&timer<Handler>::destroy_handler, time, token),
handler_(handler)
{
}
// Invoke the handler and then destroy it.
static void invoke_handler(timer_base* base,
const asio::error_code& result)
{
static_cast<timer<Handler>*>(base)->handler_(result);
}
// Destroy the handler.
static void destroy_handler(timer_base* base)
{
delete static_cast<timer<Handler>*>(base);
}
private:
Handler handler_;
};
// Move the item at the given index up the heap to its correct position.
void up_heap(size_t index)
{
size_t parent = (index - 1) / 2;
while (index > 0
&& Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
{
swap_heap(index, parent);
index = parent;
parent = (index - 1) / 2;
}
}
// Move the item at the given index down the heap to its correct position.
void down_heap(size_t index)
{
size_t child = index * 2 + 1;
while (child < heap_.size())
{
size_t min_child = (child + 1 == heap_.size()
|| Time_Traits::less_than(
heap_[child]->time_, heap_[child + 1]->time_))
? child : child + 1;
if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_))
break;
swap_heap(index, min_child);
index = min_child;
child = index * 2 + 1;
}
}
// Swap two entries in the heap.
void swap_heap(size_t index1, size_t index2)
{
timer_base* tmp = heap_[index1];
heap_[index1] = heap_[index2];
heap_[index2] = tmp;
heap_[index1]->heap_index_ = index1;
heap_[index2]->heap_index_ = index2;
}
// Remove a timer from the heap and list of timers.
void remove_timer(timer_base* t)
{
// Remove the timer from the heap.
size_t index = t->heap_index_;
if (!heap_.empty() && index < heap_.size())
{
if (index == heap_.size() - 1)
{
heap_.pop_back();
}
else
{
swap_heap(index, heap_.size() - 1);
heap_.pop_back();
size_t parent = (index - 1) / 2;
if (index > 0 && Time_Traits::less_than(
heap_[index]->time_, heap_[parent]->time_))
up_heap(index);
else
down_heap(index);
}
}
// Remove the timer from the hash.
typedef typename hash_map<void*, timer_base*>::iterator iterator;
iterator it = timers_.find(t->token_);
if (it != timers_.end())
{
if (it->second == t)
it->second = t->next_;
if (t->prev_)
t->prev_->next_ = t->next_;
if (t->next_)
t->next_->prev_ = t->prev_;
if (it->second == 0)
timers_.erase(it);
}
}
// Destroy all timers in a linked list.
void destroy_timer_list(timer_base*& t)
{
while (t)
{
timer_base* next = t->next_;
t->next_ = 0;
t->destroy();
t = next;
}
}
// A hash of timer token to linked lists of timers.
hash_map<void*, timer_base*> timers_;
// The heap of timers, with the earliest timer at the front.
std::vector<timer_base*> heap_;
// The list of timers to be cancelled.
timer_base* cancelled_timers_;
// The list of timers to be destroyed.
timer_base* cleanup_timers_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TIMER_QUEUE_HPP

View File

@ -1,62 +0,0 @@
//
// timer_queue_base.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
#define ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
#include "asio/detail/push_options.hpp"
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class timer_queue_base
: private noncopyable
{
public:
// Destructor.
virtual ~timer_queue_base() {}
// Whether there are no timers in the queue.
virtual bool empty() const = 0;
// Get the time to wait until the next timer.
virtual boost::posix_time::time_duration wait_duration() const = 0;
// Dispatch all ready timers.
virtual void dispatch_timers() = 0;
// Dispatch any pending cancels for timers.
virtual void dispatch_cancellations() = 0;
// Destroy timers that are waiting to be cleaned up.
virtual void cleanup_timers() = 0;
// Destroy all timers.
virtual void destroy_timers() = 0;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TIMER_QUEUE_BASE_HPP

View File

@ -1,65 +0,0 @@
//
// tss_ptr.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_TSS_PTR_HPP
#define ASIO_DETAIL_TSS_PTR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_tss_ptr.hpp"
#elif defined(BOOST_WINDOWS)
# include "asio/detail/win_tss_ptr.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_tss_ptr.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
template <typename T>
class tss_ptr
#if !defined(BOOST_HAS_THREADS)
: public null_tss_ptr<T>
#elif defined(BOOST_WINDOWS)
: public win_tss_ptr<T>
#elif defined(BOOST_HAS_PTHREADS)
: public posix_tss_ptr<T>
#endif
{
public:
void operator=(T* value)
{
#if !defined(BOOST_HAS_THREADS)
null_tss_ptr<T>::operator=(value);
#elif defined(BOOST_WINDOWS)
win_tss_ptr<T>::operator=(value);
#elif defined(BOOST_HAS_PTHREADS)
posix_tss_ptr<T>::operator=(value);
#endif
}
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TSS_PTR_HPP

View File

@ -1,103 +0,0 @@
//
// win_event.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WIN_EVENT_HPP
#define ASIO_DETAIL_WIN_EVENT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS)
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
class win_event
: private noncopyable
{
public:
// Constructor.
win_event()
: event_(::CreateEvent(0, true, false, 0))
{
if (!event_)
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"event");
boost::throw_exception(e);
}
}
// Destructor.
~win_event()
{
::CloseHandle(event_);
}
// Signal the event.
template <typename Lock>
void signal(Lock& lock)
{
BOOST_ASSERT(lock.locked());
(void)lock;
::SetEvent(event_);
}
// Reset the event.
template <typename Lock>
void clear(Lock& lock)
{
BOOST_ASSERT(lock.locked());
(void)lock;
::ResetEvent(event_);
}
// Wait for the event to become signalled.
template <typename Lock>
void wait(Lock& lock)
{
BOOST_ASSERT(lock.locked());
lock.unlock();
::WaitForSingleObject(event_, INFINITE);
lock.lock();
}
private:
HANDLE event_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_EVENT_HPP

View File

@ -1,88 +0,0 @@
//
// win_fd_set_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
#define ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/socket_types.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
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;
}
bool set(socket_type descriptor)
{
for (u_int i = 0; i < fd_set_.fd_count; ++i)
if (fd_set_.fd_array[i] == descriptor)
return true;
if (fd_set_.fd_count < win_fd_set_size)
{
fd_set_.fd_array[fd_set_.fd_count++] = descriptor;
return true;
}
return false;
}
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
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP

View File

@ -1,705 +0,0 @@
//
// win_iocp_io_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
#define ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/win_iocp_io_service_fwd.hpp"
#if defined(ASIO_HAS_IOCP)
#include "asio/detail/push_options.hpp"
#include <limits>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/io_service.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/call_stack.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
#include "asio/detail/mutex.hpp"
namespace asio {
namespace detail {
class win_iocp_io_service
: public asio::detail::service_base<win_iocp_io_service>
{
public:
// Base class for all operations. A function pointer is used instead of
// virtual functions to avoid the associated overhead.
//
// This class inherits from OVERLAPPED so that we can downcast to get back to
// the operation pointer from the LPOVERLAPPED out parameter of
// GetQueuedCompletionStatus.
class operation
: public OVERLAPPED
{
public:
typedef void (*invoke_func_type)(operation*, DWORD, size_t);
typedef void (*destroy_func_type)(operation*);
operation(win_iocp_io_service& iocp_service,
invoke_func_type invoke_func, destroy_func_type destroy_func)
: outstanding_operations_(&iocp_service.outstanding_operations_),
invoke_func_(invoke_func),
destroy_func_(destroy_func)
{
Internal = 0;
InternalHigh = 0;
Offset = 0;
OffsetHigh = 0;
hEvent = 0;
::InterlockedIncrement(outstanding_operations_);
}
void do_completion(DWORD last_error, size_t bytes_transferred)
{
invoke_func_(this, last_error, bytes_transferred);
}
void destroy()
{
destroy_func_(this);
}
protected:
// Prevent deletion through this type.
~operation()
{
::InterlockedDecrement(outstanding_operations_);
}
private:
long* outstanding_operations_;
invoke_func_type invoke_func_;
destroy_func_type destroy_func_;
};
// Constructor.
win_iocp_io_service(asio::io_service& io_service)
: asio::detail::service_base<win_iocp_io_service>(io_service),
iocp_(),
outstanding_work_(0),
outstanding_operations_(0),
stopped_(0),
shutdown_(0),
timer_thread_(0),
timer_interrupt_issued_(false)
{
}
void init(size_t concurrency_hint)
{
iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
if (!iocp_.handle)
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"iocp");
boost::throw_exception(e);
}
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
::InterlockedExchange(&shutdown_, 1);
while (::InterlockedExchangeAdd(&outstanding_operations_, 0) > 0)
{
DWORD bytes_transferred = 0;
#if (WINVER < 0x0500)
DWORD completion_key = 0;
#else
DWORD_PTR completion_key = 0;
#endif
LPOVERLAPPED overlapped = 0;
::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
&completion_key, &overlapped, INFINITE);
if (overlapped)
static_cast<operation*>(overlapped)->destroy();
}
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a handle with the IO completion port.
void register_handle(HANDLE handle)
{
::CreateIoCompletionPort(handle, iocp_.handle, 0, 0);
}
// Run the event loop until stopped or no more work.
size_t run(asio::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
ec = asio::error_code();
return 0;
}
call_stack<win_iocp_io_service>::context ctx(this);
size_t n = 0;
while (do_one(true, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
// Run until stopped or one operation is performed.
size_t run_one(asio::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
ec = asio::error_code();
return 0;
}
call_stack<win_iocp_io_service>::context ctx(this);
return do_one(true, ec);
}
// Poll for operations without blocking.
size_t poll(asio::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
ec = asio::error_code();
return 0;
}
call_stack<win_iocp_io_service>::context ctx(this);
size_t n = 0;
while (do_one(false, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
// Poll for one operation without blocking.
size_t poll_one(asio::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
ec = asio::error_code();
return 0;
}
call_stack<win_iocp_io_service>::context ctx(this);
return do_one(false, ec);
}
// Stop the event processing loop.
void stop()
{
if (::InterlockedExchange(&stopped_, 1) == 0)
{
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"pqcs");
boost::throw_exception(e);
}
}
}
// Reset in preparation for a subsequent run invocation.
void reset()
{
::InterlockedExchange(&stopped_, 0);
}
// Notify that some work has started.
void work_started()
{
::InterlockedIncrement(&outstanding_work_);
}
// Notify that some work has finished.
void work_finished()
{
if (::InterlockedDecrement(&outstanding_work_) == 0)
stop();
}
// Request invocation of the given handler.
template <typename Handler>
void dispatch(Handler handler)
{
if (call_stack<win_iocp_io_service>::contains(this))
asio_handler_invoke_helpers::invoke(handler, &handler);
else
post(handler);
}
// Request invocation of the given handler and return immediately.
template <typename Handler>
void post(Handler handler)
{
// If the service has been shut down we silently discard the handler.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
return;
// Allocate and construct an operation to wrap the handler.
typedef handler_operation<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, *this, handler);
// Enqueue the operation on the I/O completion port.
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, ptr.get()))
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"pqcs");
boost::throw_exception(e);
}
// Operation has been successfully posted.
ptr.release();
}
// Request invocation of the given OVERLAPPED-derived operation.
void post_completion(operation* op, DWORD op_last_error,
DWORD bytes_transferred)
{
// Enqueue the operation on the I/O completion port.
if (!::PostQueuedCompletionStatus(iocp_.handle,
bytes_transferred, op_last_error, op))
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"pqcs");
boost::throw_exception(e);
}
}
// Add a new timer queue to the service.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(timer_mutex_);
timer_queues_.push_back(&timer_queue);
}
// Remove a timer queue from the service.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(timer_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>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
// If the service has been shut down we silently discard the timer.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
return;
asio::detail::mutex::scoped_lock lock(timer_mutex_);
if (timer_queue.enqueue_timer(time, handler, token))
{
if (!timer_interrupt_issued_)
{
timer_interrupt_issued_ = true;
lock.unlock();
::PostQueuedCompletionStatus(iocp_.handle,
0, steal_timer_dispatching, 0);
}
}
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
// If the service has been shut down we silently ignore the cancellation.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
return 0;
asio::detail::mutex::scoped_lock lock(timer_mutex_);
std::size_t n = timer_queue.cancel_timer(token);
if (n > 0 && !timer_interrupt_issued_)
{
timer_interrupt_issued_ = true;
lock.unlock();
::PostQueuedCompletionStatus(iocp_.handle,
0, steal_timer_dispatching, 0);
}
return n;
}
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, asio::error_code& ec)
{
long this_thread_id = static_cast<long>(::GetCurrentThreadId());
for (;;)
{
// Try to acquire responsibility for dispatching timers.
bool dispatching_timers = (::InterlockedCompareExchange(
&timer_thread_, this_thread_id, 0) == 0);
// Calculate timeout for GetQueuedCompletionStatus call.
DWORD timeout = max_timeout;
if (dispatching_timers)
{
asio::detail::mutex::scoped_lock lock(timer_mutex_);
timer_interrupt_issued_ = false;
timeout = get_timeout();
}
// 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 ? timeout : 0);
DWORD last_error = ::GetLastError();
// Dispatch any pending timers.
if (dispatching_timers)
{
try
{
asio::detail::mutex::scoped_lock lock(timer_mutex_);
timer_queues_copy_ = timer_queues_;
for (std::size_t i = 0; i < timer_queues_copy_.size(); ++i)
{
timer_queues_copy_[i]->dispatch_timers();
timer_queues_copy_[i]->dispatch_cancellations();
timer_queues_copy_[i]->cleanup_timers();
}
}
catch (...)
{
// Transfer responsibility for dispatching timers to another thread.
if (::InterlockedCompareExchange(&timer_thread_,
0, this_thread_id) == this_thread_id)
{
::PostQueuedCompletionStatus(iocp_.handle,
0, transfer_timer_dispatching, 0);
}
throw;
}
}
if (!ok && overlapped == 0)
{
if (block && last_error == WAIT_TIMEOUT)
{
// Relinquish responsibility for dispatching timers.
if (dispatching_timers)
{
::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
}
continue;
}
// Transfer responsibility for dispatching timers to another thread.
if (dispatching_timers && ::InterlockedCompareExchange(
&timer_thread_, 0, this_thread_id) == this_thread_id)
{
::PostQueuedCompletionStatus(iocp_.handle,
0, transfer_timer_dispatching, 0);
}
ec = asio::error_code();
return 0;
}
else if (overlapped)
{
// We may have been passed a last_error value in the completion_key.
if (last_error == 0)
{
last_error = completion_key;
}
// Transfer responsibility for dispatching timers to another thread.
if (dispatching_timers && ::InterlockedCompareExchange(
&timer_thread_, 0, this_thread_id) == this_thread_id)
{
::PostQueuedCompletionStatus(iocp_.handle,
0, transfer_timer_dispatching, 0);
}
// 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);
ec = asio::error_code();
return 1;
}
else if (completion_key == transfer_timer_dispatching)
{
// Woken up to try to acquire responsibility for dispatching timers.
::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
}
else if (completion_key == steal_timer_dispatching)
{
// Woken up to steal responsibility for dispatching timers.
::InterlockedExchange(&timer_thread_, 0);
}
else
{
// The stopped_ flag is always checked to ensure that any leftover
// interrupts from a previous run invocation are ignored.
if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
{
// Relinquish responsibility for dispatching timers.
if (dispatching_timers)
{
::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
}
// Wake up next thread that is blocked on GetQueuedCompletionStatus.
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return 0;
}
ec = asio::error_code();
return 0;
}
}
}
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the GetQueuedCompletionStatus call. The timeout
// value is returned as a number of milliseconds. We will wait no longer than
// 1000 milliseconds.
DWORD get_timeout()
{
if (all_timer_queues_are_empty())
return max_timeout;
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::milliseconds(max_timeout);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
int milliseconds = minimum_wait_duration.total_milliseconds();
return static_cast<DWORD>(milliseconds > 0 ? milliseconds : 1);
}
else
{
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(io_service, &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
{
HANDLE handle;
iocp_holder() : handle(0) {}
~iocp_holder() { if (handle) ::CloseHandle(handle); }
} iocp_;
// The count of unfinished work.
long outstanding_work_;
// The count of unfinished operations.
long outstanding_operations_;
friend class operation;
// Flag to indicate whether the event loop has been stopped.
long stopped_;
// Flag to indicate whether the service has been shut down.
long shutdown_;
enum
{
// Maximum GetQueuedCompletionStatus timeout, in milliseconds.
max_timeout = 500,
// Completion key value to indicate that responsibility for dispatching
// timers is being cooperatively transferred from one thread to another.
transfer_timer_dispatching = 1,
// Completion key value to indicate that responsibility for dispatching
// timers should be stolen from another thread.
steal_timer_dispatching = 2
};
// The thread that's currently in charge of dispatching timers.
long timer_thread_;
// Mutex for protecting access to the timer queues.
mutex timer_mutex_;
// Whether a thread has been interrupted to process a new timeout.
bool timer_interrupt_issued_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// A copy of the timer queues, used when dispatching, cancelling and cleaning
// up timers. The copy is stored as a class data member to avoid unnecessary
// memory allocation.
std::vector<timer_queue_base*> timer_queues_copy_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP

View File

@ -1,50 +0,0 @@
//
// win_iocp_io_service_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
#define ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/socket_types.hpp"
// This service is only supported on Win32 (NT4 and later).
#if !defined(ASIO_DISABLE_IOCP)
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
#if !defined(UNDER_CE)
// Define this to indicate that IOCP is supported on the target platform.
#define ASIO_HAS_IOCP 1
namespace asio {
namespace detail {
class win_iocp_io_service;
} // namespace detail
} // namespace asio
#endif // !defined(UNDER_CE)
#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#endif // !defined(ASIO_DISABLE_IOCP)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP

View File

@ -1,81 +0,0 @@
//
// win_iocp_operation.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 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 ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
#define ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/win_iocp_io_service_fwd.hpp"
#if defined(ASIO_HAS_IOCP)
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
// Base class for all IOCP operations. A function pointer is used instead of
// virtual functions to avoid the associated overhead.
//
// This class inherits from OVERLAPPED so that we can downcast to get back to
// the win_iocp_operation pointer from the LPOVERLAPPED out parameter of
// GetQueuedCompletionStatus.
struct win_iocp_operation
: public OVERLAPPED
{
typedef void (*invoke_func_type)(win_iocp_operation*, DWORD, size_t);
typedef void (*destroy_func_type)(win_iocp_operation*);
win_iocp_operation(invoke_func_type invoke_func,
destroy_func_type destroy_func)
: invoke_func_(invoke_func),
destroy_func_(destroy_func)
{
Internal = 0;
InternalHigh = 0;
Offset = 0;
OffsetHigh = 0;
hEvent = 0;
}
void do_completion(DWORD last_error, size_t bytes_transferred)
{
invoke_func_(this, last_error, bytes_transferred);
}
void destroy()
{
destroy_func_(this);
}
protected:
// Prevent deletion through this type.
~win_iocp_operation()
{
}
private:
invoke_func_type invoke_func_;
destroy_func_type destroy_func_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +0,0 @@
//
// win_local_free_on_block_exit.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 ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP
#define ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
class win_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)
: p_(p)
{
}
// Destructor restores the previous signal mask.
~win_local_free_on_block_exit()
{
::LocalFree(p_);
}
private:
void* p_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP

View File

@ -1,149 +0,0 @@
//
// win_mutex.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WIN_MUTEX_HPP
#define ASIO_DETAIL_WIN_MUTEX_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS)
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/scoped_lock.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
class win_mutex
: private noncopyable
{
public:
typedef asio::detail::scoped_lock<win_mutex> scoped_lock;
// Constructor.
win_mutex()
{
int error = do_init();
if (error != 0)
{
asio::system_error e(
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}
}
// Destructor.
~win_mutex()
{
::DeleteCriticalSection(&crit_section_);
}
// Lock the mutex.
void lock()
{
int error = do_lock();
if (error != 0)
{
asio::system_error e(
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}
}
// Unlock the mutex.
void unlock()
{
::LeaveCriticalSection(&crit_section_);
}
private:
// Initialisation must be performed in a separate function to the constructor
// since the compiler does not support the use of structured exceptions and
// C++ exceptions in the same function.
int do_init()
{
#if defined(__MINGW32__)
// Not sure if MinGW supports structured exception handling, so for now
// we'll just call the Windows API and hope.
::InitializeCriticalSection(&crit_section_);
return 0;
#else
__try
{
::InitializeCriticalSection(&crit_section_);
}
__except(GetExceptionCode() == STATUS_NO_MEMORY
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
return ERROR_OUTOFMEMORY;
}
return 0;
#endif
}
// Locking must be performed in a separate function to lock() since the
// compiler does not support the use of structured exceptions and C++
// exceptions in the same function.
int do_lock()
{
#if defined(__MINGW32__)
// Not sure if MinGW supports structured exception handling, so for now
// we'll just call the Windows API and hope.
::EnterCriticalSection(&crit_section_);
return 0;
#else
__try
{
::EnterCriticalSection(&crit_section_);
}
__except(GetExceptionCode() == STATUS_INVALID_HANDLE
|| GetExceptionCode() == STATUS_NO_MEMORY
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
if (GetExceptionCode() == STATUS_NO_MEMORY)
return ERROR_OUTOFMEMORY;
return ERROR_INVALID_HANDLE;
}
return 0;
#endif
}
::CRITICAL_SECTION crit_section_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_MUTEX_HPP

View File

@ -1,67 +0,0 @@
//
// win_signal_blocker.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP
#define ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class win_signal_blocker
: private noncopyable
{
public:
// Constructor blocks all signals for the calling thread.
win_signal_blocker()
{
// No-op.
}
// Destructor restores the previous signal mask.
~win_signal_blocker()
{
// No-op.
}
// Block all signals for the calling thread.
void block()
{
// No-op.
}
// Restore the previous signal mask.
void unblock()
{
// No-op.
}
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP

View File

@ -1,125 +0,0 @@
//
// win_thread.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WIN_THREAD_HPP
#define ASIO_DETAIL_WIN_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <memory>
#include <process.h>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
unsigned int __stdcall win_thread_function(void* arg);
class win_thread
: private noncopyable
{
public:
// Constructor.
template <typename Function>
win_thread(Function f)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
unsigned int thread_id = 0;
thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0,
win_thread_function, arg.get(), 0, &thread_id));
if (!thread_)
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"thread");
boost::throw_exception(e);
}
arg.release();
}
// Destructor.
~win_thread()
{
::CloseHandle(thread_);
}
// Wait for the thread to exit.
void join()
{
::WaitForSingleObject(thread_, INFINITE);
}
private:
friend unsigned int __stdcall win_thread_function(void* arg);
class func_base
{
public:
virtual ~func_base() {}
virtual void run() = 0;
};
template <typename Function>
class func
: public func_base
{
public:
func(Function f)
: f_(f)
{
}
virtual void run()
{
f_();
}
private:
Function f_;
};
::HANDLE thread_;
};
inline unsigned int __stdcall win_thread_function(void* arg)
{
std::auto_ptr<win_thread::func_base> func(
static_cast<win_thread::func_base*>(arg));
func->run();
return 0;
}
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_THREAD_HPP

View File

@ -1,95 +0,0 @@
//
// win_tss_ptr.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WIN_TSS_PTR_HPP
#define ASIO_DETAIL_WIN_TSS_PTR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS)
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
template <typename T>
class win_tss_ptr
: private noncopyable
{
public:
#if defined(UNDER_CE)
enum { out_of_indexes = 0xFFFFFFFF };
#else
enum { out_of_indexes = TLS_OUT_OF_INDEXES };
#endif
// Constructor.
win_tss_ptr()
{
tss_key_ = ::TlsAlloc();
if (tss_key_ == out_of_indexes)
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"tss");
boost::throw_exception(e);
}
}
// Destructor.
~win_tss_ptr()
{
::TlsFree(tss_key_);
}
// Get the value.
operator T*() const
{
return static_cast<T*>(::TlsGetValue(tss_key_));
}
// Set the value.
void operator=(T* value)
{
::TlsSetValue(tss_key_, value);
}
private:
// Thread-specific storage to allow unlocked access to determine whether a
// thread is a member of the pool.
DWORD tss_key_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_TSS_PTR_HPP

View File

@ -1,124 +0,0 @@
//
// wince_thread.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WINCE_THREAD_HPP
#define ASIO_DETAIL_WINCE_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <memory>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
DWORD WINAPI wince_thread_function(LPVOID arg);
class wince_thread
: private noncopyable
{
public:
// Constructor.
template <typename Function>
wince_thread(Function f)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
DWORD thread_id = 0;
thread_ = ::CreateThread(0, 0, wince_thread_function,
arg.get(), 0, &thread_id);
if (!thread_)
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"thread");
boost::throw_exception(e);
}
arg.release();
}
// Destructor.
~wince_thread()
{
::CloseHandle(thread_);
}
// Wait for the thread to exit.
void join()
{
::WaitForSingleObject(thread_, INFINITE);
}
private:
friend DWORD WINAPI wince_thread_function(LPVOID arg);
class func_base
{
public:
virtual ~func_base() {}
virtual void run() = 0;
};
template <typename Function>
class func
: public func_base
{
public:
func(Function f)
: f_(f)
{
}
virtual void run()
{
f_();
}
private:
Function f_;
};
::HANDLE thread_;
};
inline DWORD WINAPI wince_thread_function(LPVOID arg)
{
std::auto_ptr<wince_thread::func_base> func(
static_cast<wince_thread::func_base*>(arg));
func->run();
return 0;
}
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WINCE_THREAD_HPP

View File

@ -1,120 +0,0 @@
//
// winsock_init.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WINSOCK_INIT_HPP
#define ASIO_DETAIL_WINSOCK_INIT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/push_options.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
template <int Major = 2, int Minor = 0>
class winsock_init
: private noncopyable
{
private:
// Structure to perform the actual initialisation.
struct do_init
{
do_init()
{
WSADATA wsa_data;
result_ = ::WSAStartup(MAKEWORD(Major, Minor), &wsa_data);
}
~do_init()
{
::WSACleanup();
}
int result() const
{
return result_;
}
// Helper function to manage a do_init singleton. The static instance of the
// winsock_init object ensures that this function is always called before
// main, and therefore before any other threads can get started. The do_init
// instance must be static in this function to ensure that it gets
// initialised before any other global objects try to use it.
static boost::shared_ptr<do_init> instance()
{
static boost::shared_ptr<do_init> init(new do_init);
return init;
}
private:
int result_;
};
public:
// Constructor.
winsock_init()
: ref_(do_init::instance())
{
// Check whether winsock was successfully initialised. This check is not
// performed for the global instance since there will be nobody around to
// catch the exception.
if (this != &instance_ && ref_->result() != 0)
{
asio::system_error e(
asio::error_code(ref_->result(),
asio::error::get_system_category()),
"winsock");
boost::throw_exception(e);
}
}
// Destructor.
~winsock_init()
{
}
private:
// Instance to force initialisation of winsock at global scope.
static winsock_init instance_;
// Reference to singleton do_init object to ensure that winsock does not get
// cleaned up until the last user has finished with it.
boost::shared_ptr<do_init> ref_;
};
template <int Major, int Minor>
winsock_init<Major, Minor> winsock_init<Major, Minor>::instance_;
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WINSOCK_INIT_HPP

Some files were not shown because too many files have changed in this diff Show More