Remove asio, updating next revision
This commit is contained in:
parent
71555ebd0a
commit
c4a4121060
|
@ -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)
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
Loading…
Reference in New Issue