asio 1.1.1 sync

This commit is contained in:
Marcos Pinto 2008-07-10 02:25:28 +00:00
parent 63d36a4b70
commit 4d46faf014
77 changed files with 13277 additions and 670 deletions

View File

@ -63,6 +63,10 @@ public:
protected:
/// Construct a basic_io_object.
/**
* Performs:
* @code service.construct(implementation); @endcode
*/
explicit basic_io_object(asio::io_service& io_service)
: service(asio::use_service<IoObjectService>(io_service))
{
@ -70,15 +74,19 @@ protected:
}
/// Protected destructor to prevent deletion through this type.
/**
* Performs:
* @code service.destroy(implementation); @endcode
*/
~basic_io_object()
{
service.destroy(implementation);
}
// The backend service implementation.
/// The service associated with the I/O object.
service_type& service;
// The underlying native implementation.
/// The underlying implementation of the I/O object.
implementation_type implementation;
};

View File

@ -0,0 +1,798 @@
//
// basic_raw_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_RAW_SOCKET_HPP
#define ASIO_BASIC_RAW_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/raw_socket_service.hpp"
#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides raw-oriented socket functionality.
/**
* The basic_raw_socket class template provides asynchronous and blocking
* raw-oriented socket functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol,
typename RawSocketService = raw_socket_service<Protocol> >
class basic_raw_socket
: public basic_socket<Protocol, RawSocketService>
{
public:
/// The native representation of a socket.
typedef typename RawSocketService::native_type native_type;
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct a basic_raw_socket without opening it.
/**
* This constructor creates a raw 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 raw socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
*/
explicit basic_raw_socket(asio::io_service& io_service)
: basic_socket<Protocol, RawSocketService>(io_service)
{
}
/// Construct and open a basic_raw_socket.
/**
* This constructor creates and opens a raw socket.
*
* @param io_service The io_service object that the raw 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_raw_socket(asio::io_service& io_service,
const protocol_type& protocol)
: basic_socket<Protocol, RawSocketService>(io_service, protocol)
{
}
/// Construct a basic_raw_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a raw 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 raw 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 raw
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_raw_socket(asio::io_service& io_service,
const endpoint_type& endpoint)
: basic_socket<Protocol, RawSocketService>(io_service, endpoint)
{
}
/// Construct a basic_raw_socket on an existing native socket.
/**
* This constructor creates a raw socket object to hold an existing
* native socket.
*
* @param io_service The io_service object that the raw 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_raw_socket(asio::io_service& io_service,
const protocol_type& protocol, const native_type& native_socket)
: basic_socket<Protocol, RawSocketService>(
io_service, protocol, native_socket)
{
}
/// Send some data on a connected socket.
/**
* This function is used to send data on the raw 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 raw 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 raw 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 raw 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 raw 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 raw 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 raw 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 raw
* 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 raw 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 raw
* 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 raw data to the specified endpoint.
/**
* This function is used to send raw data 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 raw data to the specified endpoint.
/**
* This function is used to send raw data 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 raw data to the specified endpoint.
/**
* This function is used to send raw data 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 raw data 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 raw data 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 raw 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 raw
* 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 raw 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 raw
* 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 raw 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 raw
* 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 raw
* 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
* raw 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 raw
* 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
* raw 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 raw data with the endpoint of the sender.
/**
* This function is used to receive raw data. 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 data.
*
* @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 raw data with the endpoint of the sender.
/**
* This function is used to receive raw data. 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 data.
*
* @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 raw data with the endpoint of the sender.
/**
* This function is used to receive raw data. 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 data.
*
* @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 raw data. 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 data. 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 raw data. 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 data. 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_RAW_SOCKET_HPP

View File

@ -0,0 +1,608 @@
//
// basic_serial_port.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_SERIAL_PORT_HPP
#define ASIO_BASIC_SERIAL_PORT_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 <string>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/error.hpp"
#include "asio/serial_port_base.hpp"
#include "asio/serial_port_service.hpp"
#include "asio/detail/throw_error.hpp"
#if defined(ASIO_HAS_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
/// Provides serial port functionality.
/**
* The basic_serial_port class template provides functionality that is common
* to all serial ports.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename SerialPortService = serial_port_service>
class basic_serial_port
: public basic_io_object<SerialPortService>,
public serial_port_base
{
public:
/// The native representation of a serial port.
typedef typename SerialPortService::native_type native_type;
/// A basic_serial_port is always the lowest layer.
typedef basic_serial_port<SerialPortService> lowest_layer_type;
/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param io_service The io_service object that the serial port will use to
* dispatch handlers for any asynchronous operations performed on the port.
*/
explicit basic_serial_port(asio::io_service& io_service)
: basic_io_object<SerialPortService>(io_service)
{
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param io_service The io_service object that the serial port will use to
* dispatch handlers for any asynchronous operations performed on the port.
*
* @param device The platform-specific device name for this serial
* port.
*/
explicit basic_serial_port(asio::io_service& io_service,
const char* device)
: basic_io_object<SerialPortService>(io_service)
{
asio::error_code ec;
this->service.open(this->implementation, device, ec);
asio::detail::throw_error(ec);
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param io_service The io_service object that the serial port will use to
* dispatch handlers for any asynchronous operations performed on the port.
*
* @param device The platform-specific device name for this serial
* port.
*/
explicit basic_serial_port(asio::io_service& io_service,
const std::string& device)
: basic_io_object<SerialPortService>(io_service)
{
asio::error_code ec;
this->service.open(this->implementation, device, ec);
asio::detail::throw_error(ec);
}
/// Construct a basic_serial_port on an existing native serial port.
/**
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param io_service The io_service object that the serial port will use to
* dispatch handlers for any asynchronous operations performed on the port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
basic_serial_port(asio::io_service& io_service,
const native_type& native_serial_port)
: basic_io_object<SerialPortService>(io_service)
{
asio::error_code ec;
this->service.assign(this->implementation, native_serial_port, ec);
asio::detail::throw_error(ec);
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_serial_port cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Open the serial port using the specified device name.
/**
* This function opens the serial port for the specified device name.
*
* @param device The platform-specific device name.
*
* @throws asio::system_error Thrown on failure.
*/
void open(const std::string& device)
{
asio::error_code ec;
this->service.open(this->implementation, device, ec);
asio::detail::throw_error(ec);
}
/// Open the serial port using the specified device name.
/**
* This function opens the serial port using the given platform-specific
* device name.
*
* @param device The platform-specific device name.
*
* @param ec Set the indicate what error occurred, if any.
*/
asio::error_code open(const std::string& device,
asio::error_code& ec)
{
return this->service.open(this->implementation, device, ec);
}
/// Assign an existing native serial port to the serial port.
/*
* This function opens the serial port to hold an existing native serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_type& native_serial_port)
{
asio::error_code ec;
this->service.assign(this->implementation, native_serial_port, ec);
asio::detail::throw_error(ec);
}
/// Assign an existing native serial port to the serial port.
/*
* This function opens the serial port to hold an existing native serial port.
*
* @param native_serial_port A native serial port.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code assign(const native_type& native_serial_port,
asio::error_code& ec)
{
return this->service.assign(this->implementation, native_serial_port, ec);
}
/// Determine whether the serial port is open.
bool is_open() const
{
return this->service.is_open(this->implementation);
}
/// Close the serial port.
/**
* This function is used to close the serial port. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @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 serial port.
/**
* This function is used to close the serial port. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code close(asio::error_code& ec)
{
return this->service.close(this->implementation, ec);
}
/// Get the native serial port representation.
/**
* This function may be used to obtain the underlying representation of the
* serial port. This is intended to allow access to native serial port
* functionality that is not otherwise provided.
*/
native_type native()
{
return this->service.native(this->implementation);
}
/// Cancel all asynchronous operations associated with the serial port.
/**
* This function causes all outstanding asynchronous read or write 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 serial port.
/**
* This function causes all outstanding asynchronous read or write 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);
}
/// Send a break sequence to the serial port.
/**
* This function causes a break sequence of platform-specific duration to be
* sent out the serial port.
*
* @throws asio::system_error Thrown on failure.
*/
void send_break()
{
asio::error_code ec;
this->service.send_break(this->implementation, ec);
asio::detail::throw_error(ec);
}
/// Send a break sequence to the serial port.
/**
* This function causes a break sequence of platform-specific duration to be
* sent out the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code send_break(asio::error_code& ec)
{
return this->service.send_break(this->implementation, ec);
}
/// Set an option on the serial port.
/**
* This function is used to set an option on the serial port.
*
* @param option The option value to be set on the serial port.
*
* @throws asio::system_error Thrown on failure.
*
* @sa SettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename SettableSerialPortOption>
void set_option(const SettableSerialPortOption& option)
{
asio::error_code ec;
this->service.set_option(this->implementation, option, ec);
asio::detail::throw_error(ec);
}
/// Set an option on the serial port.
/**
* This function is used to set an option on the serial port.
*
* @param option The option value to be set on the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa SettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename SettableSerialPortOption>
asio::error_code set_option(const SettableSerialPortOption& option,
asio::error_code& ec)
{
return this->service.set_option(this->implementation, option, ec);
}
/// Get an option from the serial port.
/**
* This function is used to get the current value of an option on the serial
* port.
*
* @param option The option value to be obtained from the serial port.
*
* @throws asio::system_error Thrown on failure.
*
* @sa GettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename GettableSerialPortOption>
void get_option(GettableSerialPortOption& option)
{
asio::error_code ec;
this->service.get_option(this->implementation, option, ec);
asio::detail::throw_error(ec);
}
/// Get an option from the serial port.
/**
* This function is used to get the current value of an option on the serial
* port.
*
* @param option The option value to be obtained from the serial port.
*
* @param ec Set to indicate what error occured, if any.
*
* @sa GettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename GettableSerialPortOption>
asio::error_code get_option(GettableSerialPortOption& option,
asio::error_code& ec)
{
return this->service.get_option(this->implementation, option, ec);
}
/// Write some data to the serial port.
/**
* This function is used to write data to the serial port. 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 serial port.
*
* @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
* serial_port.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.write_some(this->implementation, buffers, ec);
asio::detail::throw_error(ec);
return s;
}
/// Write some data to the serial port.
/**
* This function is used to write data to the serial port. 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 serial port.
*
* @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.write_some(this->implementation, buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the serial port.
* The function call always returns immediately.
*
* @param buffers One or more data buffers to be written to the serial port.
* 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
* serial_port.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_write_some(this->implementation, buffers, handler);
}
/// Read some data from the serial port.
/**
* This function is used to read data from the serial port. 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
* serial_port.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.read_some(this->implementation, buffers, ec);
asio::detail::throw_error(ec);
return s;
}
/// Read some data from the serial port.
/**
* This function is used to read data from the serial port. 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.read_some(this->implementation, buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the serial port.
* 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
* serial_port.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_read_some(this->implementation, buffers, handler);
}
};
} // namespace asio
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SERIAL_PORT_HPP

View File

@ -514,7 +514,7 @@ public:
*
* The socket is automatically opened if it is not already open. If the
* connect fails, and the socket was automatically opened, the socket is
* returned to the closed state.
* not returned to the closed state.
*
* @param peer_endpoint The remote endpoint to which the socket will be
* connected.
@ -549,7 +549,7 @@ public:
*
* The socket is automatically opened if it is not already open. If the
* connect fails, and the socket was automatically opened, the socket is
* returned to the closed state.
* not returned to the closed state.
*
* @param peer_endpoint The remote endpoint to which the socket will be
* connected.
@ -591,7 +591,7 @@ public:
*
* The socket is automatically opened if it is not already open. If the
* connect fails, and the socket was automatically opened, the socket is
* returned to the closed state.
* not returned to the closed state.
*
* @param peer_endpoint The remote endpoint to which the socket will be
* connected. Copies will be made of the endpoint object as required.

View File

@ -100,11 +100,9 @@ public:
/// Move the start of the get area by the specified number of characters.
void consume(std::size_t n)
{
while (n > 0)
{
sbumpc();
--n;
}
if (gptr() + n > pptr())
n = pptr() - gptr();
gbump(static_cast<int>(n));
}
protected:

View File

@ -195,6 +195,12 @@ public:
/// A random-access iterator type that may be used to read elements.
typedef const mutable_buffer* const_iterator;
/// Construct to represent a given memory range.
mutable_buffers_1(void* data, std::size_t size)
: mutable_buffer(data, size)
{
}
/// Construct to represent a single modifiable buffer.
explicit mutable_buffers_1(const mutable_buffer& b)
: mutable_buffer(b)
@ -359,6 +365,12 @@ public:
/// A random-access iterator type that may be used to read elements.
typedef const const_buffer* const_iterator;
/// Construct to represent a given memory range.
const_buffers_1(const void* data, std::size_t size)
: const_buffer(data, size)
{
}
/// Construct to represent a single non-modifiable buffer.
explicit const_buffers_1(const const_buffer& b)
: const_buffer(b)
@ -378,6 +390,33 @@ public:
}
};
/// An implementation of both the ConstBufferSequence and MutableBufferSequence
/// concepts to represent a null buffer sequence.
class null_buffers
{
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;
/// Get a random-access iterator to the first element.
const_iterator begin() const
{
return &buf_;
}
/// Get a random-access iterator for one past the last element.
const_iterator end() const
{
return &buf_;
}
private:
mutable_buffer buf_;
};
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
namespace detail {
@ -415,12 +454,22 @@ private:
/** @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.
* represent raw memory, an array of POD elements, a vector of POD elements,
* or a std::string.
*
* A buffer object represents a contiguous region of memory as a 2-tuple
* consisting of a pointer and size in bytes. A tuple of the form <tt>{void*,
* size_t}</tt> specifies a mutable (modifiable) region of memory. Similarly, a
* tuple of the form <tt>{const void*, size_t}</tt> specifies a const
* (non-modifiable) region of memory. These two forms correspond to the classes
* mutable_buffer and const_buffer, respectively. To mirror C++'s conversion
* rules, a mutable_buffer is implicitly convertible to a const_buffer, and the
* opposite conversion is not permitted.
*
* The simplest use case involves reading or writing a single buffer of a
* specified size:
*
* @code sock.write(asio::buffer(data, size)); @endcode
* @code sock.send(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
@ -432,13 +481,90 @@ private:
* automatically determining the size of the buffer:
*
* @code char d1[128];
* size_t bytes_transferred = sock.read(asio::buffer(d1));
* size_t bytes_transferred = sock.receive(asio::buffer(d1));
*
* std::vector<char> d2(128);
* bytes_transferred = sock.read(asio::buffer(d2));
* bytes_transferred = sock.receive(asio::buffer(d2));
*
* boost::array<char, 128> d3;
* bytes_transferred = sock.read(asio::buffer(d3)); @endcode
* bytes_transferred = sock.receive(asio::buffer(d3)); @endcode
*
* In all three cases above, the buffers created are exactly 128 bytes long.
* Note that a vector is @e never automatically resized when creating or using
* a buffer. The buffer size is determined using the vector's <tt>size()</tt>
* member function, and not its capacity.
*
* @par Accessing Buffer Contents
*
* The contents of a buffer may be accessed using the asio::buffer_size
* and asio::buffer_cast functions:
*
* @code asio::mutable_buffer b1 = ...;
* std::size_t s1 = asio::buffer_size(b1);
* unsigned char* p1 = asio::buffer_cast<unsigned char*>(b1);
*
* asio::const_buffer b2 = ...;
* std::size_t s2 = asio::buffer_size(b2);
* const void* p2 = asio::buffer_cast<const void*>(b2); @endcode
*
* The asio::buffer_cast function permits violations of type safety, so
* uses of it in application code should be carefully considered.
*
* @par Buffer Invalidation
*
* A buffer object does not have any ownership of the memory it refers to. It
* is the responsibility of the application to ensure the memory region remains
* valid until it is no longer required for an I/O operation. When the memory
* is no longer available, the buffer is said to have been invalidated.
*
* For the asio::buffer overloads that accept an argument of type
* std::vector, the buffer objects returned are invalidated by any vector
* operation that also invalidates all references, pointers and iterators
* referring to the elements in the sequence (C++ Std, 23.2.4)
*
* For the asio::buffer overloads that accept an argument of type
* std::string, the buffer objects returned are invalidated according to the
* rules defined for invalidation of references, pointers and iterators
* referring to elements of the sequence (C++ Std, 21.3).
*
* @par Buffer Arithmetic
*
* Buffer objects may be manipulated using simple arithmetic in a safe way
* which helps prevent buffer overruns. Consider an array initialised as
* follows:
*
* @code boost::array<char, 6> a = { 'a', 'b', 'c', 'd', 'e' }; @endcode
*
* A buffer object @c b1 created using:
*
* @code b1 = asio::buffer(a); @endcode
*
* represents the entire array, <tt>{ 'a', 'b', 'c', 'd', 'e' }</tt>. An
* optional second argument to the asio::buffer function may be used to
* limit the size, in bytes, of the buffer:
*
* @code b2 = asio::buffer(a, 3); @endcode
*
* such that @c b2 represents the data <tt>{ 'a', 'b', 'c' }</tt>. Even if the
* size argument exceeds the actual size of the array, the size of the buffer
* object created will be limited to the array size.
*
* An offset may be applied to an existing buffer to create a new one:
*
* @code b3 = b1 + 2; @endcode
*
* where @c b3 will set to represent <tt>{ 'c', 'd', 'e' }</tt>. If the offset
* exceeds the size of the existing buffer, the newly created buffer will be
* empty.
*
* Both an offset and size may be specified to create a buffer that corresponds
* to a specific range of bytes within an existing buffer:
*
* @code b4 = asio::buffer(b1 + 1, 3); @endcode
*
* so that @c b4 will refer to the bytes <tt>{ 'b', 'c', 'd' }</tt>.
*
* @par Buffers and Scatter-Gather I/O
*
* 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
@ -453,23 +579,32 @@ private:
* asio::buffer(d1),
* asio::buffer(d2),
* asio::buffer(d3) };
* bytes_transferred = sock.read(bufs1);
* bytes_transferred = sock.receive(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
* bytes_transferred = sock.send(bufs2); @endcode
*/
/*@{*/
/// Create a new modifiable buffer from an existing buffer.
/**
* @returns <tt>mutable_buffers_1(b)</tt>.
*/
inline mutable_buffers_1 buffer(const mutable_buffer& b)
{
return mutable_buffers_1(b);
}
/// Create a new modifiable buffer from an existing buffer.
/**
* @returns A mutable_buffers_1 value equivalent to:
* @code mutable_buffers_1(
* buffer_cast<void*>(b),
* min(buffer_size(b), max_size_in_bytes)); @endcode
*/
inline mutable_buffers_1 buffer(const mutable_buffer& b,
std::size_t max_size_in_bytes)
{
@ -484,12 +619,21 @@ inline mutable_buffers_1 buffer(const mutable_buffer& b,
}
/// Create a new non-modifiable buffer from an existing buffer.
/**
* @returns <tt>const_buffers_1(b)</tt>.
*/
inline const_buffers_1 buffer(const const_buffer& b)
{
return const_buffers_1(b);
}
/// Create a new non-modifiable buffer from an existing buffer.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* buffer_cast<const void*>(b),
* min(buffer_size(b), max_size_in_bytes)); @endcode
*/
inline const_buffers_1 buffer(const const_buffer& b,
std::size_t max_size_in_bytes)
{
@ -504,12 +648,18 @@ inline const_buffers_1 buffer(const const_buffer& b,
}
/// Create a new modifiable buffer that represents the given memory range.
/**
* @returns <tt>mutable_buffers_1(data, size_in_bytes)</tt>.
*/
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.
/**
* @returns <tt>const_buffers_1(data, size_in_bytes)</tt>.
*/
inline const_buffers_1 buffer(const void* data,
std::size_t size_in_bytes)
{
@ -517,6 +667,12 @@ inline const_buffers_1 buffer(const void* data,
}
/// Create a new modifiable buffer that represents the given POD array.
/**
* @returns A mutable_buffers_1 value equivalent to:
* @code mutable_buffers_1(
* static_cast<void*>(data),
* N * sizeof(PodType)); @endcode
*/
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(PodType (&data)[N])
{
@ -524,6 +680,12 @@ inline mutable_buffers_1 buffer(PodType (&data)[N])
}
/// Create a new modifiable buffer that represents the given POD array.
/**
* @returns A mutable_buffers_1 value equivalent to:
* @code mutable_buffers_1(
* static_cast<void*>(data),
* min(N * sizeof(PodType), max_size_in_bytes)); @endcode
*/
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(PodType (&data)[N],
std::size_t max_size_in_bytes)
@ -535,6 +697,12 @@ inline mutable_buffers_1 buffer(PodType (&data)[N],
}
/// Create a new non-modifiable buffer that represents the given POD array.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* static_cast<const void*>(data),
* N * sizeof(PodType)); @endcode
*/
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const PodType (&data)[N])
{
@ -542,6 +710,12 @@ inline const_buffers_1 buffer(const PodType (&data)[N])
}
/// Create a new non-modifiable buffer that represents the given POD array.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* static_cast<const void*>(data),
* min(N * sizeof(PodType), max_size_in_bytes)); @endcode
*/
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const PodType (&data)[N],
std::size_t max_size_in_bytes)
@ -624,6 +798,12 @@ buffer(boost::array<PodType, N>& data, std::size_t max_size_in_bytes)
// || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
/// Create a new modifiable buffer that represents the given POD array.
/**
* @returns A mutable_buffers_1 value equivalent to:
* @code mutable_buffers_1(
* data.data(),
* data.size() * sizeof(PodType)); @endcode
*/
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(boost::array<PodType, N>& data)
{
@ -632,6 +812,12 @@ inline mutable_buffers_1 buffer(boost::array<PodType, N>& data)
}
/// Create a new modifiable buffer that represents the given POD array.
/**
* @returns A mutable_buffers_1 value equivalent to:
* @code mutable_buffers_1(
* data.data(),
* min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
*/
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(boost::array<PodType, N>& data,
std::size_t max_size_in_bytes)
@ -643,6 +829,12 @@ inline mutable_buffers_1 buffer(boost::array<PodType, N>& data,
}
/// Create a new non-modifiable buffer that represents the given POD array.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* data.data(),
* data.size() * sizeof(PodType)); @endcode
*/
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(boost::array<const PodType, N>& data)
{
@ -651,6 +843,12 @@ inline const_buffers_1 buffer(boost::array<const PodType, N>& data)
}
/// Create a new non-modifiable buffer that represents the given POD array.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* data.data(),
* min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
*/
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)
@ -665,6 +863,12 @@ inline const_buffers_1 buffer(boost::array<const PodType, N>& data,
// || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
/// Create a new non-modifiable buffer that represents the given POD array.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* data.data(),
* data.size() * sizeof(PodType)); @endcode
*/
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const boost::array<PodType, N>& data)
{
@ -673,6 +877,12 @@ inline const_buffers_1 buffer(const boost::array<PodType, N>& data)
}
/// Create a new non-modifiable buffer that represents the given POD array.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* data.data(),
* min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
*/
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)
@ -685,6 +895,11 @@ inline const_buffers_1 buffer(const boost::array<PodType, N>& data,
/// Create a new modifiable buffer that represents the given POD vector.
/**
* @returns A mutable_buffers_1 value equivalent to:
* @code mutable_buffers_1(
* data.size() ? &data[0] : 0,
* data.size() * sizeof(PodType)); @endcode
*
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
@ -692,7 +907,7 @@ 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)
mutable_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::iterator
@ -703,6 +918,11 @@ inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data)
/// Create a new modifiable buffer that represents the given POD vector.
/**
* @returns A mutable_buffers_1 value equivalent to:
* @code mutable_buffers_1(
* data.size() ? &data[0] : 0,
* min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
*
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
@ -711,7 +931,7 @@ 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],
mutable_buffer(data.size() ? &data[0] : 0,
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
@ -724,6 +944,11 @@ inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data,
/// Create a new non-modifiable buffer that represents the given POD vector.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* data.size() ? &data[0] : 0,
* data.size() * sizeof(PodType)); @endcode
*
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
@ -732,7 +957,7 @@ inline const_buffers_1 buffer(
const std::vector<PodType, Allocator>& data)
{
return const_buffers_1(
const_buffer(&data[0], data.size() * sizeof(PodType)
const_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::const_iterator
@ -743,6 +968,11 @@ inline const_buffers_1 buffer(
/// Create a new non-modifiable buffer that represents the given POD vector.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* data.size() ? &data[0] : 0,
* min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
*
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
@ -751,7 +981,7 @@ 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],
const_buffer(data.size() ? &data[0] : 0,
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
@ -764,6 +994,8 @@ inline const_buffers_1 buffer(
/// Create a new non-modifiable buffer that represents the given string.
/**
* @returns <tt>const_buffers_1(data.data(), data.size())</tt>.
*
* @note The buffer is invalidated by any non-const operation called on the
* given string object.
*/
@ -778,6 +1010,11 @@ inline const_buffers_1 buffer(const std::string& data)
/// Create a new non-modifiable buffer that represents the given string.
/**
* @returns A const_buffers_1 value equivalent to:
* @code const_buffers_1(
* data.data(),
* min(data.size(), max_size_in_bytes)); @endcode
*
* @note The buffer is invalidated by any non-const operation called on the
* given string object.
*/

View File

@ -0,0 +1,318 @@
//
// 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_BUFFERS_ITERATOR_HPP
#define ASIO_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/assert.hpp>
#include <boost/config.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/add_const.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
namespace asio {
namespace detail
{
template <bool IsMutable>
struct buffers_iterator_types_helper;
template <>
struct buffers_iterator_types_helper<false>
{
typedef const_buffer buffer_type;
template <typename ByteType>
struct byte_type
{
typedef typename boost::add_const<ByteType>::type type;
};
};
template <>
struct buffers_iterator_types_helper<true>
{
typedef mutable_buffer buffer_type;
template <typename ByteType>
struct byte_type
{
typedef ByteType type;
};
};
template <typename BufferSequence, typename ByteType>
struct buffers_iterator_types
{
enum
{
is_mutable = boost::is_convertible<
typename BufferSequence::value_type, mutable_buffer>::value
};
typedef buffers_iterator_types_helper<is_mutable> helper;
typedef typename helper::buffer_type buffer_type;
typedef typename helper::template byte_type<ByteType>::type byte_type;
};
}
/// A random access iterator over the bytes in a buffer sequence.
template <typename BufferSequence, typename ByteType = char>
class buffers_iterator
: public boost::iterator_facade<
buffers_iterator<BufferSequence, ByteType>,
typename detail::buffers_iterator_types<
BufferSequence, ByteType>::byte_type,
boost::random_access_traversal_tag>
{
private:
typedef typename detail::buffers_iterator_types<
BufferSequence, ByteType>::buffer_type buffer_type;
typedef typename detail::buffers_iterator_types<
BufferSequence, ByteType>::byte_type byte_type;
public:
/// Default constructor. Creates an iterator in an undefined state.
buffers_iterator()
: current_buffer_(),
current_buffer_position_(0),
begin_(),
current_(),
end_(),
position_(0)
{
}
/// Construct an iterator representing the beginning of the buffers' data.
static buffers_iterator begin(const BufferSequence& buffers)
{
buffers_iterator new_iter;
new_iter.begin_ = buffers.begin();
new_iter.current_ = buffers.begin();
new_iter.end_ = buffers.end();
while (new_iter.current_ != new_iter.end_)
{
new_iter.current_buffer_ = *new_iter.current_;
if (asio::buffer_size(new_iter.current_buffer_) > 0)
break;
++new_iter.current_;
}
return new_iter;
}
/// Construct an iterator representing the end of the buffers' data.
static buffers_iterator end(const BufferSequence& buffers)
{
buffers_iterator new_iter;
new_iter.begin_ = buffers.begin();
new_iter.current_ = buffers.begin();
new_iter.end_ = buffers.end();
while (new_iter.current_ != new_iter.end_)
{
buffer_type buffer = *new_iter.current_;
new_iter.position_ += asio::buffer_size(buffer);
++new_iter.current_;
}
return new_iter;
}
private:
friend class boost::iterator_core_access;
// Dereference the iterator.
byte_type& dereference() const
{
return buffer_cast<byte_type*>(current_buffer_)[current_buffer_position_];
}
// Compare two iterators for equality.
bool equal(const buffers_iterator& other) const
{
return position_ == other.position_;
}
// Increment the iterator.
void increment()
{
BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
++position_;
// Check if the increment can be satisfied by the current buffer.
++current_buffer_position_;
if (current_buffer_position_ != asio::buffer_size(current_buffer_))
return;
// Find the next non-empty buffer.
++current_;
current_buffer_position_ = 0;
while (current_ != end_)
{
current_buffer_ = *current_;
if (asio::buffer_size(current_buffer_) > 0)
return;
++current_;
}
}
// Decrement the iterator.
void decrement()
{
BOOST_ASSERT(position_ > 0 && "iterator out of bounds");
--position_;
// Check if the decrement can be satisfied by the current buffer.
if (current_buffer_position_ != 0)
{
--current_buffer_position_;
return;
}
// Find the previous non-empty buffer.
typename BufferSequence::const_iterator iter = current_;
while (iter != begin_)
{
--iter;
buffer_type 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;
}
}
}
// Advance the iterator by the specified distance.
void advance(std::ptrdiff_t n)
{
if (n > 0)
{
BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
for (;;)
{
std::ptrdiff_t current_buffer_balance
= asio::buffer_size(current_buffer_)
- current_buffer_position_;
// Check if the advance can be satisfied by the current buffer.
if (current_buffer_balance > n)
{
position_ += n;
current_buffer_position_ += n;
return;
}
// Update position.
n -= current_buffer_balance;
position_ += current_buffer_balance;
// Move to next buffer. If it is empty then it will be skipped on the
// next iteration of this loop.
if (++current_ == end_)
{
BOOST_ASSERT(n == 0 && "iterator out of bounds");
current_buffer_ = buffer_type();
current_buffer_position_ = 0;
return;
}
current_buffer_ = *current_;
current_buffer_position_ = 0;
}
}
else if (n < 0)
{
std::size_t abs_n = -n;
BOOST_ASSERT(position_ >= abs_n && "iterator out of bounds");
for (;;)
{
// Check if the advance can be satisfied by the current buffer.
if (current_buffer_position_ >= abs_n)
{
position_ -= abs_n;
current_buffer_position_ -= abs_n;
return;
}
// Update position.
abs_n -= current_buffer_position_;
position_ -= current_buffer_position_;
// Check if we've reached the beginning of the buffers.
if (current_ == begin_)
{
BOOST_ASSERT(abs_n == 0 && "iterator out of bounds");
current_buffer_position_ = 0;
return;
}
// Find the previous non-empty buffer.
typename BufferSequence::const_iterator iter = current_;
while (iter != begin_)
{
--iter;
buffer_type 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;
break;
}
}
}
}
}
// Determine the distance between two iterators.
std::ptrdiff_t distance_to(const buffers_iterator& other) const
{
return other.position_ - position_;
}
buffer_type current_buffer_;
std::size_t current_buffer_position_;
typename BufferSequence::const_iterator begin_;
typename BufferSequence::const_iterator current_;
typename BufferSequence::const_iterator end_;
std::size_t position_;
};
/// Construct an iterator representing the beginning of the buffers' data.
template <typename BufferSequence>
inline buffers_iterator<BufferSequence> buffers_begin(
const BufferSequence& buffers)
{
return buffers_iterator<BufferSequence>::begin(buffers);
}
/// Construct an iterator representing the end of the buffers' data.
template <typename BufferSequence>
inline buffers_iterator<BufferSequence> buffers_end(
const BufferSequence& buffers)
{
return buffers_iterator<BufferSequence>::end(buffers);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERS_ITERATOR_HPP

View File

@ -24,6 +24,8 @@
#include <boost/iterator/iterator_facade.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
namespace asio {
namespace detail {
@ -197,6 +199,24 @@ private:
typename Buffers::const_iterator begin_remainder_;
};
// Specialisation for null_buffers to ensure that the null_buffers type is
// always passed through to the underlying read or write operation.
template <typename Buffer>
class consuming_buffers<Buffer, asio::null_buffers>
: public asio::null_buffers
{
public:
consuming_buffers(const asio::null_buffers&)
{
// No-op.
}
void consume(std::size_t)
{
// No-op.
}
};
} // namespace detail
} // namespace asio

View File

@ -26,6 +26,7 @@
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/handler_base_from_member.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_ops.hpp"
@ -153,25 +154,25 @@ public:
}
template <typename Handler>
class wait_handler
class wait_handler :
public handler_base_from_member<Handler>
{
public:
wait_handler(asio::io_service& io_service, Handler handler)
: io_service_(io_service),
work_(io_service),
handler_(handler)
: handler_base_from_member<Handler>(handler),
io_service_(io_service),
work_(io_service)
{
}
void operator()(const asio::error_code& result)
{
io_service_.post(detail::bind_handler(handler_, result));
io_service_.post(detail::bind_handler(this->handler_, result));
}
private:
asio::io_service& io_service_;
asio::io_service::work work_;
Handler handler_;
};
// Start an asynchronous wait on the timer.

View File

@ -0,0 +1,138 @@
//
// descriptor_ops.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_DESCRIPTOR_OPS_HPP
#define ASIO_DETAIL_DESCRIPTOR_OPS_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 <cerrno>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/detail/socket_types.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
namespace asio {
namespace detail {
namespace descriptor_ops {
inline void clear_error(asio::error_code& ec)
{
errno = 0;
ec = asio::error_code();
}
template <typename ReturnType>
inline ReturnType error_wrapper(ReturnType return_value,
asio::error_code& ec)
{
ec = asio::error_code(errno,
asio::error::get_system_category());
return return_value;
}
inline int open(const char* path, int flags, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::open(path, flags), ec);
}
inline int close(int d, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::close(d), ec);
}
typedef iovec buf;
inline void init_buf(buf& b, void* data, size_t size)
{
b.iov_base = data;
b.iov_len = size;
}
inline void init_buf(buf& b, const void* data, size_t size)
{
b.iov_base = const_cast<void*>(data);
b.iov_len = size;
}
inline int scatter_read(int d, buf* bufs, size_t count,
asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
}
inline int gather_write(int d, const buf* bufs, size_t count,
asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
}
inline int ioctl(int d, long cmd, ioctl_arg_type* arg,
asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::ioctl(d, cmd, arg), ec);
}
inline int fcntl(int d, long cmd, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::fcntl(d, cmd), ec);
}
inline int fcntl(int d, long cmd, long arg, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::fcntl(d, cmd, arg), ec);
}
inline int poll_read(int d, asio::error_code& ec)
{
clear_error(ec);
pollfd fds;
fds.fd = d;
fds.events = POLLIN;
fds.revents = 0;
clear_error(ec);
return error_wrapper(::poll(&fds, 1, -1), ec);
}
inline int poll_write(int d, asio::error_code& ec)
{
clear_error(ec);
pollfd fds;
fds.fd = d;
fds.events = POLLOUT;
fds.revents = 0;
clear_error(ec);
return error_wrapper(::poll(&fds, 1, -1), ec);
}
} // namespace descriptor_ops
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP

View File

@ -53,6 +53,11 @@ class dev_poll_reactor
: public asio::detail::service_base<dev_poll_reactor<Own_Thread> >
{
public:
// Per-descriptor data.
struct per_descriptor_data
{
};
// Constructor.
dev_poll_reactor(asio::io_service& io_service)
: asio::detail::service_base<
@ -115,11 +120,11 @@ public:
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)
int register_descriptor(socket_type, per_descriptor_data&)
{
return 0;
}
@ -127,16 +132,27 @@ public:
// 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)
void start_read_op(socket_type descriptor, per_descriptor_data&,
Handler handler, bool allow_speculative_read = true)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!read_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (allow_speculative_read)
{
if (!read_op_queue_.has_operation(descriptor))
{
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
}
}
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
@ -153,16 +169,27 @@ public:
// 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)
void start_write_op(socket_type descriptor, per_descriptor_data&,
Handler handler, bool allow_speculative_write = true)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!write_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (allow_speculative_write)
{
if (!write_op_queue_.has_operation(descriptor))
{
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
}
}
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
@ -179,7 +206,8 @@ public:
// 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)
void start_except_op(socket_type descriptor,
per_descriptor_data&, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
@ -198,26 +226,25 @@ public:
}
}
// Start new write and exception operations. The handler object will be
// invoked when the given descriptor is ready for writing or has exception
// Start a new write operation. The handler object will be invoked when the
// information available, or an error has occurred.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
void start_connect_op(socket_type descriptor,
per_descriptor_data&, 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)
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLOUT | POLLPRI | POLLERR | POLLHUP;
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();
}
}
@ -225,25 +252,15 @@ public:
// 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)
void cancel_ops(socket_type descriptor, per_descriptor_data&)
{
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)
void close_descriptor(socket_type descriptor, per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
@ -313,16 +330,16 @@ private:
// 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();
read_op_queue_.perform_cancellations();
write_op_queue_.perform_cancellations();
except_op_queue_.perform_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);
complete_operations_and_timers(lock);
return;
}
@ -331,7 +348,7 @@ private:
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
cleanup_operations_and_timers(lock);
complete_operations_and_timers(lock);
return;
}
@ -347,9 +364,9 @@ private:
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);
read_op_queue_.perform_all_operations(descriptor, ec);
write_op_queue_.perform_all_operations(descriptor, ec);
except_op_queue_.perform_all_operations(descriptor, ec);
}
}
pending_event_changes_.clear();
@ -370,7 +387,7 @@ private:
lock.lock();
wait_in_progress_ = false;
// Block signals while dispatching operations.
// Block signals while performing operations.
asio::detail::signal_blocker sb;
// Dispatch the waiting events.
@ -391,17 +408,17 @@ private:
// 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);
more_except = except_op_queue_.perform_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);
more_reads = read_op_queue_.perform_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);
more_writes = write_op_queue_.perform_operation(descriptor, ec);
else
more_writes = write_op_queue_.has_operation(descriptor);
@ -436,16 +453,16 @@ private:
{
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_.perform_all_operations(descriptor, ec);
write_op_queue_.perform_all_operations(descriptor, ec);
except_op_queue_.perform_all_operations(descriptor, ec);
}
}
}
}
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
read_op_queue_.perform_cancellations();
write_op_queue_.perform_cancellations();
except_op_queue_.perform_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
timer_queues_[i]->dispatch_timers();
@ -457,7 +474,7 @@ private:
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
cleanup_operations_and_timers(lock);
complete_operations_and_timers(lock);
}
// Run the select loop in the thread.
@ -557,16 +574,16 @@ private:
// 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(
void complete_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();
read_op_queue_.complete_operations();
write_op_queue_.complete_operations();
except_op_queue_.complete_operations();
for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
timer_queues_for_cleanup_[i]->cleanup_timers();
timer_queues_for_cleanup_[i]->complete_timers();
}
// Add a pending event entry for the given descriptor.

View File

@ -53,6 +53,13 @@ class epoll_reactor
: public asio::detail::service_base<epoll_reactor<Own_Thread> >
{
public:
// Per-descriptor data.
struct per_descriptor_data
{
bool allow_speculative_read;
bool allow_speculative_write;
};
// Constructor.
epoll_reactor(asio::io_service& io_service)
: asio::detail::service_base<epoll_reactor<Own_Thread> >(io_service),
@ -118,10 +125,14 @@ public:
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type descriptor)
int register_descriptor(socket_type descriptor,
per_descriptor_data& descriptor_data)
{
// No need to lock according to epoll documentation.
descriptor_data.allow_speculative_read = true;
descriptor_data.allow_speculative_write = true;
epoll_event ev = { 0, { 0 } };
ev.events = 0;
ev.data.fd = descriptor;
@ -134,16 +145,47 @@ public:
// 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)
void start_read_op(socket_type descriptor,
per_descriptor_data& descriptor_data,
Handler handler, bool allow_speculative_read = true)
{
if (allow_speculative_read && descriptor_data.allow_speculative_read)
{
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
// We only get one shot at a speculative read in this function.
allow_speculative_read = false;
}
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!read_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
if (!allow_speculative_read)
need_epoll_wait_ = true;
else if (!read_op_queue_.has_operation(descriptor))
{
// Speculative reads are ok as there are no queued read operations.
descriptor_data.allow_speculative_read = true;
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
}
// Speculative reads are not ok as there will be queued read operations.
descriptor_data.allow_speculative_read = false;
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
@ -162,7 +204,7 @@ public:
{
asio::error_code ec(errno,
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
read_op_queue_.perform_all_operations(descriptor, ec);
}
}
}
@ -170,16 +212,47 @@ public:
// 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)
void start_write_op(socket_type descriptor,
per_descriptor_data& descriptor_data,
Handler handler, bool allow_speculative_write = true)
{
if (allow_speculative_write && descriptor_data.allow_speculative_write)
{
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
// We only get one shot at a speculative write in this function.
allow_speculative_write = false;
}
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!write_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
if (!allow_speculative_write)
need_epoll_wait_ = true;
else if (!write_op_queue_.has_operation(descriptor))
{
// Speculative writes are ok as there are no queued write operations.
descriptor_data.allow_speculative_write = true;
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
}
// Speculative writes are not ok as there will be queued write operations.
descriptor_data.allow_speculative_write = false;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
@ -198,7 +271,7 @@ public:
{
asio::error_code ec(errno,
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.perform_all_operations(descriptor, ec);
}
}
}
@ -206,7 +279,8 @@ public:
// 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)
void start_except_op(socket_type descriptor,
per_descriptor_data&, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
@ -230,31 +304,34 @@ public:
{
asio::error_code ec(errno,
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.perform_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.
// Start a new write operation. The handler object will be invoked when the
// given descriptor is ready for writing or an error has occurred. Speculative
// writes are not allowed.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
void start_connect_op(socket_type descriptor,
per_descriptor_data& descriptor_data, 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)
// Speculative writes are not ok as there will be queued write operations.
descriptor_data.allow_speculative_write = false;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLOUT | EPOLLPRI | EPOLLERR | EPOLLHUP;
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);
@ -264,8 +341,7 @@ public:
{
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);
write_op_queue_.perform_all_operations(descriptor, ec);
}
}
}
@ -273,25 +349,15 @@ public:
// 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)
void cancel_ops(socket_type descriptor, per_descriptor_data&)
{
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)
void close_descriptor(socket_type descriptor, per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
@ -360,16 +426,16 @@ private:
// 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();
read_op_queue_.perform_cancellations();
write_op_queue_.perform_cancellations();
except_op_queue_.perform_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);
complete_operations_and_timers(lock);
return;
}
@ -378,7 +444,7 @@ private:
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
cleanup_operations_and_timers(lock);
complete_operations_and_timers(lock);
return;
}
@ -395,7 +461,7 @@ private:
lock.lock();
wait_in_progress_ = false;
// Block signals while dispatching operations.
// Block signals while performing operations.
asio::detail::signal_blocker sb;
// Dispatch the waiting events.
@ -416,17 +482,17 @@ private:
// 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);
more_except = except_op_queue_.perform_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);
more_reads = read_op_queue_.perform_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);
more_writes = write_op_queue_.perform_operation(descriptor, ec);
else
more_writes = write_op_queue_.has_operation(descriptor);
@ -460,16 +526,16 @@ private:
{
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_.perform_all_operations(descriptor, ec);
write_op_queue_.perform_all_operations(descriptor, ec);
except_op_queue_.perform_all_operations(descriptor, ec);
}
}
}
}
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
read_op_queue_.perform_cancellations();
write_op_queue_.perform_cancellations();
except_op_queue_.perform_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
timer_queues_[i]->dispatch_timers();
@ -485,7 +551,7 @@ private:
need_epoll_wait_ = !read_op_queue_.empty()
|| !write_op_queue_.empty() || !except_op_queue_.empty();
cleanup_operations_and_timers(lock);
complete_operations_and_timers(lock);
}
// Run the select loop in the thread.
@ -588,16 +654,16 @@ private:
// 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(
void complete_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();
read_op_queue_.complete_operations();
write_op_queue_.complete_operations();
except_op_queue_.complete_operations();
for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
timer_queues_for_cleanup_[i]->cleanup_timers();
timer_queues_for_cleanup_[i]->complete_timers();
}
// Mutex to protect access to internal data.

View File

@ -0,0 +1,76 @@
//
// handler_base_from_member.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_BASE_FROM_MEMBER_HPP
#define ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_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 {
// Base class for classes that need a handler data member. Forwards the custom
// allocation and invocation hooks to the contained handler.
template <typename Handler>
class handler_base_from_member
{
public:
handler_base_from_member(Handler handler)
: handler_(handler)
{
}
//protected:
Handler handler_;
protected:
// Protected destructor to prevent deletion through this type.
~handler_base_from_member()
{
}
};
template <typename Handler>
inline void* asio_handler_allocate(std::size_t size,
handler_base_from_member<Handler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
handler_base_from_member<Handler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename Handler>
inline void asio_handler_invoke(const Function& function,
handler_base_from_member<Handler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP

View File

@ -198,6 +198,16 @@ private:
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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(h->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
private:

View File

@ -43,6 +43,7 @@ inline std::size_t calculate_hash_value(SOCKET s)
}
#endif // defined(_WIN64)
// Note: assumes K and V are POD types.
template <typename K, typename V>
class hash_map
: private noncopyable
@ -139,7 +140,7 @@ public:
if (it == values_.end())
{
buckets_[bucket].first = buckets_[bucket].last =
values_.insert(values_.end(), v);
values_insert(values_.end(), v);
return std::pair<iterator, bool>(buckets_[bucket].last, true);
}
iterator end = buckets_[bucket].last;
@ -150,7 +151,7 @@ public:
return std::pair<iterator, bool>(it, false);
++it;
}
buckets_[bucket].last = values_.insert(end, v);
buckets_[bucket].last = values_insert(end, v);
return std::pair<iterator, bool>(buckets_[bucket].last, true);
}
@ -169,7 +170,7 @@ public:
else if (is_last)
--buckets_[bucket].last;
values_.erase(it);
values_erase(it);
}
// Remove all entries from the map.
@ -184,9 +185,36 @@ public:
}
private:
// Insert an element into the values list by splicing from the spares list,
// if a spare is available, and otherwise by inserting a new element.
iterator values_insert(iterator it, const value_type& v)
{
if (spares_.empty())
{
return values_.insert(it, v);
}
else
{
spares_.front() = v;
values_.splice(it, spares_, spares_.begin());
return --it;
}
}
// Erase an element from the values list by splicing it to the spares list.
void values_erase(iterator it)
{
*it = value_type();
spares_.splice(spares_.begin(), values_, it);
}
// The list of all values in the hash map.
std::list<value_type> values_;
// The list of spare nodes waiting to be recycled. Assumes that POD types only
// are stored in the hash map.
std::list<value_type> spares_;
// The type for a bucket in the hash table.
struct bucket_type
{

View File

@ -0,0 +1,291 @@
//
// indirect_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_INDIRECT_HANDLER_QUEUE_HPP
#define ASIO_DETAIL_INDIRECT_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"
#if defined(_MSC_VER) && (_MSC_VER >= 1310)
extern "C" void _ReadWriteBarrier();
# pragma intrinsic(_ReadWriteBarrier)
#endif // defined(_MSC_VER) && (_MSC_VER >= 1310)
namespace asio {
namespace detail {
class indirect_handler_queue
: private noncopyable
{
public:
class handler;
// Element for a node in the queue.
class node
{
public:
node()
: version_(0),
handler_(0),
next_(0)
{
}
private:
friend class indirect_handler_queue;
unsigned long version_;
handler* handler_;
node* next_;
};
// 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)
: node_(new node),
invoke_func_(invoke_func),
destroy_func_(destroy_func)
{
}
~handler()
{
if (node_)
delete node_;
}
private:
friend class indirect_handler_queue;
node* node_;
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.
indirect_handler_queue()
: front_(new node),
back_(front_),
next_version_(1)
{
}
// Destructor.
~indirect_handler_queue()
{
while (front_)
{
node* tmp = front_;
front_ = front_->next_;
delete tmp;
}
}
// 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();
}
// Determine whether the queue has something ready to pop.
bool poppable()
{
return front_->next_ != 0;
}
// The version number at the front of the queue.
unsigned long front_version()
{
return front_->version_;
}
// The version number at the back of the queue.
unsigned long back_version()
{
return back_->version_;
}
// Pop a handler from the front of the queue.
handler* pop()
{
node* n = front_;
node* new_front = n->next_;
if (new_front)
{
handler* h = new_front->handler_;
h->node_ = n;
new_front->handler_ = 0;
front_ = new_front;
return h;
}
return 0;
}
// Push a handler on to the back of the queue.
void push(handler* h)
{
node* n = h->node_;
h->node_ = 0;
n->version_ = next_version_;
next_version_ += 2;
n->handler_ = h;
n->next_ = 0;
memory_barrier();
back_->next_ = n;
back_ = n;
}
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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(h->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
private:
Handler handler_;
};
// Helper function to create a memory barrier.
static void memory_barrier()
{
#if defined(_GLIBCXX_WRITE_MEM_BARRIER)
_GLIBCXX_WRITE_MEM_BARRIER;
#elif defined(_MSC_VER) && (_MSC_VER >= 1310)
_ReadWriteBarrier();
#else
# error memory barrier required
#endif
}
// The front of the queue.
node* front_;
// The back of the queue.
node* back_;
// The next version counter to be assigned to a node.
unsigned long next_version_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP

View File

@ -60,6 +60,13 @@ class kqueue_reactor
: public asio::detail::service_base<kqueue_reactor<Own_Thread> >
{
public:
// Per-descriptor data.
struct per_descriptor_data
{
bool allow_speculative_read;
bool allow_speculative_write;
};
// Constructor.
kqueue_reactor(asio::io_service& io_service)
: asio::detail::service_base<
@ -126,24 +133,58 @@ public:
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type)
int register_descriptor(socket_type, per_descriptor_data& descriptor_data)
{
descriptor_data.allow_speculative_read = true;
descriptor_data.allow_speculative_write = true;
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)
void start_read_op(socket_type descriptor,
per_descriptor_data& descriptor_data, Handler handler,
bool allow_speculative_read = true)
{
if (allow_speculative_read && descriptor_data.allow_speculative_read)
{
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
// We only get one shot at a speculative read in this function.
allow_speculative_read = false;
}
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!read_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
if (!allow_speculative_read)
need_kqueue_wait_ = true;
else if (!read_op_queue_.has_operation(descriptor))
{
// Speculative reads are ok as there are no queued read operations.
descriptor_data.allow_speculative_read = true;
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
}
// Speculative reads are not ok as there will be queued read operations.
descriptor_data.allow_speculative_read = false;
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
@ -153,7 +194,7 @@ public:
{
asio::error_code ec(errno,
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
read_op_queue_.perform_all_operations(descriptor, ec);
}
}
}
@ -161,16 +202,47 @@ public:
// 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)
void start_write_op(socket_type descriptor,
per_descriptor_data& descriptor_data, Handler handler,
bool allow_speculative_write = true)
{
if (allow_speculative_write && descriptor_data.allow_speculative_write)
{
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
// We only get one shot at a speculative write in this function.
allow_speculative_write = false;
}
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!write_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
if (!allow_speculative_write)
need_kqueue_wait_ = true;
else if (!write_op_queue_.has_operation(descriptor))
{
// Speculative writes are ok as there are no queued write operations.
descriptor_data.allow_speculative_write = true;
asio::error_code ec;
std::size_t bytes_transferred = 0;
if (handler.perform(ec, bytes_transferred))
{
handler.complete(ec, bytes_transferred);
return;
}
}
// Speculative writes are not ok as there will be queued write operations.
descriptor_data.allow_speculative_write = false;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
@ -180,7 +252,7 @@ public:
{
asio::error_code ec(errno,
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.perform_all_operations(descriptor, ec);
}
}
}
@ -188,7 +260,8 @@ public:
// 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)
void start_except_op(socket_type descriptor,
per_descriptor_data&, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
@ -206,22 +279,25 @@ public:
{
asio::error_code ec(errno,
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.perform_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.
// 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_and_except_ops(socket_type descriptor, Handler handler)
void start_connect_op(socket_type descriptor,
per_descriptor_data& descriptor_data, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
// Speculative writes are not ok as there will be queued write operations.
descriptor_data.allow_speculative_write = false;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
@ -230,23 +306,7 @@ public:
{
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);
write_op_queue_.perform_all_operations(descriptor, ec);
}
}
}
@ -254,25 +314,15 @@ public:
// 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)
void cancel_ops(socket_type descriptor, per_descriptor_data&)
{
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)
void close_descriptor(socket_type descriptor, per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
@ -343,16 +393,16 @@ private:
// 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();
read_op_queue_.perform_cancellations();
write_op_queue_.perform_cancellations();
except_op_queue_.perform_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);
complete_operations_and_timers(lock);
return;
}
@ -361,7 +411,7 @@ private:
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
cleanup_operations_and_timers(lock);
complete_operations_and_timers(lock);
return;
}
@ -381,7 +431,7 @@ private:
lock.lock();
wait_in_progress_ = false;
// Block signals while dispatching operations.
// Block signals while performing operations.
asio::detail::signal_blocker sb;
// Dispatch the waiting events.
@ -401,22 +451,22 @@ private:
{
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);
except_op_queue_.perform_all_operations(descriptor, error);
read_op_queue_.perform_all_operations(descriptor, error);
}
else if (events[i].flags & EV_OOBAND)
{
asio::error_code error;
more_except = except_op_queue_.dispatch_operation(descriptor, error);
more_except = except_op_queue_.perform_operation(descriptor, error);
if (events[i].data > 0)
more_reads = read_op_queue_.dispatch_operation(descriptor, error);
more_reads = read_op_queue_.perform_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_reads = read_op_queue_.perform_operation(descriptor, error);
more_except = except_op_queue_.has_operation(descriptor);
}
@ -432,8 +482,8 @@ private:
{
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);
except_op_queue_.perform_all_operations(descriptor, error);
read_op_queue_.perform_all_operations(descriptor, error);
}
}
else if (events[i].filter == EVFILT_WRITE)
@ -444,12 +494,12 @@ private:
{
asio::error_code error(
events[i].data, asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, error);
write_op_queue_.perform_all_operations(descriptor, error);
}
else
{
asio::error_code error;
more_writes = write_op_queue_.dispatch_operation(descriptor, error);
more_writes = write_op_queue_.perform_operation(descriptor, error);
}
// Update the descriptor in the kqueue.
@ -462,14 +512,14 @@ private:
{
asio::error_code error(errno,
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, error);
write_op_queue_.perform_all_operations(descriptor, error);
}
}
}
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
read_op_queue_.perform_cancellations();
write_op_queue_.perform_cancellations();
except_op_queue_.perform_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
timer_queues_[i]->dispatch_timers();
@ -485,7 +535,7 @@ private:
need_kqueue_wait_ = !read_op_queue_.empty()
|| !write_op_queue_.empty() || !except_op_queue_.empty();
cleanup_operations_and_timers(lock);
complete_operations_and_timers(lock);
}
// Run the select loop in the thread.
@ -586,16 +636,16 @@ private:
// 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(
void complete_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();
read_op_queue_.complete_operations();
write_op_queue_.complete_operations();
except_op_queue_.complete_operations();
for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
timer_queues_for_cleanup_[i]->cleanup_timers();
timer_queues_for_cleanup_[i]->complete_timers();
}
// Mutex to protect access to internal data.

View File

@ -38,9 +38,12 @@ class null_thread
: private noncopyable
{
public:
// The purpose of the thread.
enum purpose { internal, external };
// Constructor.
template <typename Function>
null_thread(Function f)
null_thread(Function f, purpose = internal)
{
asio::system_error e(
asio::error::operation_not_supported, "thread");

View File

@ -328,6 +328,11 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
# define IPV6_V6ONLY 27
#endif
// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6.
#if !defined(IPPROTO_ICMPV6)
# define IPPROTO_ICMPV6 58
#endif
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"

View File

@ -42,9 +42,12 @@ class posix_thread
: private noncopyable
{
public:
// The purpose of the thread.
enum purpose { internal, external };
// Constructor.
template <typename Function>
posix_thread(Function f)
posix_thread(Function f, purpose = internal)
: joined_(false)
{
std::auto_ptr<func_base> arg(new func<Function>(f));

View File

@ -87,8 +87,10 @@
# pragma warning (disable:4103)
# pragma warning (push)
# pragma warning (disable:4127)
# pragma warning (disable:4244)
# pragma warning (disable:4355)
# pragma warning (disable:4512)
# 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

View File

@ -0,0 +1,709 @@
//
// reactive_descriptor_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_REACTIVE_DESCRIPTOR_SERVICE_HPP
#define ASIO_DETAIL_REACTIVE_DESCRIPTOR_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/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/handler_base_from_member.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/descriptor_ops.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
namespace asio {
namespace detail {
template <typename Reactor>
class reactive_descriptor_service
: public asio::detail::service_base<
reactive_descriptor_service<Reactor> >
{
public:
// The native type of a descriptor.
typedef int native_type;
// The implementation type of the descriptor.
class implementation_type
: private asio::detail::noncopyable
{
public:
// Default constructor.
implementation_type()
: descriptor_(-1),
flags_(0)
{
}
private:
// Only this service will have access to the internal values.
friend class reactive_descriptor_service<Reactor>;
// The native descriptor representation.
int descriptor_;
enum
{
user_set_non_blocking = 1, // The user wants a non-blocking descriptor.
internal_non_blocking = 2 // The descriptor has been set non-blocking.
};
// Flags indicating the current state of the descriptor.
unsigned char flags_;
// Per-descriptor data used by the reactor.
typename Reactor::per_descriptor_data reactor_data_;
};
// The maximum number of buffers to support in a single operation.
enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
// Constructor.
reactive_descriptor_service(asio::io_service& io_service)
: asio::detail::service_base<
reactive_descriptor_service<Reactor> >(io_service),
reactor_(asio::use_service<Reactor>(io_service))
{
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
}
// Construct a new descriptor implementation.
void construct(implementation_type& impl)
{
impl.descriptor_ = -1;
impl.flags_ = 0;
}
// Destroy a descriptor implementation.
void destroy(implementation_type& impl)
{
if (impl.descriptor_ != -1)
{
reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
if (impl.flags_ & implementation_type::internal_non_blocking)
{
ioctl_arg_type non_blocking = 0;
asio::error_code ignored_ec;
descriptor_ops::ioctl(impl.descriptor_,
FIONBIO, &non_blocking, ignored_ec);
impl.flags_ &= ~implementation_type::internal_non_blocking;
}
asio::error_code ignored_ec;
descriptor_ops::close(impl.descriptor_, ignored_ec);
impl.descriptor_ = -1;
}
}
// Assign a native descriptor to a descriptor implementation.
asio::error_code assign(implementation_type& impl,
const native_type& native_descriptor, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
if (int err = reactor_.register_descriptor(
native_descriptor, impl.reactor_data_))
{
ec = asio::error_code(err,
asio::error::get_system_category());
return ec;
}
impl.descriptor_ = native_descriptor;
impl.flags_ = 0;
ec = asio::error_code();
return ec;
}
// Determine whether the descriptor is open.
bool is_open(const implementation_type& impl) const
{
return impl.descriptor_ != -1;
}
// Destroy a descriptor implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
if (is_open(impl))
{
reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
if (impl.flags_ & implementation_type::internal_non_blocking)
{
ioctl_arg_type non_blocking = 0;
asio::error_code ignored_ec;
descriptor_ops::ioctl(impl.descriptor_,
FIONBIO, &non_blocking, ignored_ec);
impl.flags_ &= ~implementation_type::internal_non_blocking;
}
if (descriptor_ops::close(impl.descriptor_, ec) == -1)
return ec;
impl.descriptor_ = -1;
}
ec = asio::error_code();
return ec;
}
// Get the native descriptor representation.
native_type native(const implementation_type& impl) const
{
return impl.descriptor_;
}
// Cancel all operations associated with the descriptor.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return ec;
}
reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
ec = asio::error_code();
return ec;
}
// Perform an IO control command on the descriptor.
template <typename IO_Control_Command>
asio::error_code io_control(implementation_type& impl,
IO_Control_Command& command, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return ec;
}
if (command.name() == static_cast<int>(FIONBIO))
{
if (command.get())
impl.flags_ |= implementation_type::user_set_non_blocking;
else
impl.flags_ &= ~implementation_type::user_set_non_blocking;
ec = asio::error_code();
}
else
{
descriptor_ops::ioctl(impl.descriptor_, command.name(),
static_cast<ioctl_arg_type*>(command.data()), ec);
}
return ec;
}
// Write some data to the descriptor.
template <typename ConstBufferSequence>
size_t write_some(implementation_type& impl,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Copy buffers into array.
descriptor_ops::buf bufs[max_buffers];
typename ConstBufferSequence::const_iterator iter = buffers.begin();
typename ConstBufferSequence::const_iterator end = buffers.end();
size_t i = 0;
size_t total_buffer_size = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::const_buffer buffer(*iter);
descriptor_ops::init_buf(bufs[i],
asio::buffer_cast<const void*>(buffer),
asio::buffer_size(buffer));
total_buffer_size += asio::buffer_size(buffer);
}
// A request to read_some 0 bytes on a stream is a no-op.
if (total_buffer_size == 0)
{
ec = asio::error_code();
return 0;
}
// Make descriptor non-blocking if user wants non-blocking.
if (impl.flags_ & implementation_type::user_set_non_blocking)
{
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
ioctl_arg_type non_blocking = 1;
if (descriptor_ops::ioctl(impl.descriptor_,
FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Send the data.
for (;;)
{
// Try to complete the operation without blocking.
int bytes_sent = descriptor_ops::gather_write(
impl.descriptor_, bufs, i, ec);
// Check if operation succeeded.
if (bytes_sent >= 0)
return bytes_sent;
// Operation failed.
if ((impl.flags_ & implementation_type::user_set_non_blocking)
|| (ec != asio::error::would_block
&& ec != asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0)
return 0;
}
}
// Wait until data can be written without blocking.
size_t write_some(implementation_type& impl,
const null_buffers&, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for descriptor to become ready.
descriptor_ops::poll_write(impl.descriptor_, ec);
return 0;
}
template <typename ConstBufferSequence, typename Handler>
class write_operation :
public handler_base_from_member<Handler>
{
public:
write_operation(int descriptor, asio::io_service& io_service,
const ConstBufferSequence& buffers, Handler handler)
: handler_base_from_member<Handler>(handler),
descriptor_(descriptor),
io_service_(io_service),
work_(io_service),
buffers_(buffers)
{
}
bool perform(asio::error_code& ec,
std::size_t& bytes_transferred)
{
// Check whether the operation was successful.
if (ec)
{
bytes_transferred = 0;
return true;
}
// Copy buffers into array.
descriptor_ops::buf bufs[max_buffers];
typename ConstBufferSequence::const_iterator iter = buffers_.begin();
typename ConstBufferSequence::const_iterator end = buffers_.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::const_buffer buffer(*iter);
descriptor_ops::init_buf(bufs[i],
asio::buffer_cast<const void*>(buffer),
asio::buffer_size(buffer));
}
// Write the data.
int bytes = descriptor_ops::gather_write(descriptor_, bufs, i, ec);
// Check if we need to run the operation again.
if (ec == asio::error::would_block
|| ec == asio::error::try_again)
return false;
bytes_transferred = (bytes < 0 ? 0 : bytes);
return true;
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
}
private:
int descriptor_;
asio::io_service& io_service_;
asio::io_service::work work_;
ConstBufferSequence buffers_;
};
// Start an asynchronous write. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
// Determine total size of buffers.
typename ConstBufferSequence::const_iterator iter = buffers.begin();
typename ConstBufferSequence::const_iterator end = buffers.end();
size_t i = 0;
size_t total_buffer_size = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::const_buffer buffer(*iter);
total_buffer_size += asio::buffer_size(buffer);
}
// A request to read_some 0 bytes on a stream is a no-op.
if (total_buffer_size == 0)
{
this->get_io_service().post(bind_handler(handler,
asio::error_code(), 0));
return;
}
// Make descriptor non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
ioctl_arg_type non_blocking = 1;
asio::error_code ec;
if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
{
this->get_io_service().post(bind_handler(handler, ec, 0));
return;
}
impl.flags_ |= implementation_type::internal_non_blocking;
}
reactor_.start_write_op(impl.descriptor_, impl.reactor_data_,
write_operation<ConstBufferSequence, Handler>(
impl.descriptor_, this->get_io_service(), buffers, handler));
}
}
template <typename Handler>
class null_buffers_operation :
public handler_base_from_member<Handler>
{
public:
null_buffers_operation(asio::io_service& io_service, Handler handler)
: handler_base_from_member<Handler>(handler),
work_(io_service)
{
}
bool perform(asio::error_code&,
std::size_t& bytes_transferred)
{
bytes_transferred = 0;
return true;
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
work_.get_io_service().post(bind_handler(
this->handler_, ec, bytes_transferred));
}
private:
asio::io_service::work work_;
};
// Start an asynchronous wait until data can be written without blocking.
template <typename Handler>
void async_write_some(implementation_type& impl,
const null_buffers&, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
reactor_.start_write_op(impl.descriptor_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
// Read some data from the stream. Returns the number of bytes read.
template <typename MutableBufferSequence>
size_t read_some(implementation_type& impl,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Copy buffers into array.
descriptor_ops::buf bufs[max_buffers];
typename MutableBufferSequence::const_iterator iter = buffers.begin();
typename MutableBufferSequence::const_iterator end = buffers.end();
size_t i = 0;
size_t total_buffer_size = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::mutable_buffer buffer(*iter);
descriptor_ops::init_buf(bufs[i],
asio::buffer_cast<void*>(buffer),
asio::buffer_size(buffer));
total_buffer_size += asio::buffer_size(buffer);
}
// A request to read_some 0 bytes on a stream is a no-op.
if (total_buffer_size == 0)
{
ec = asio::error_code();
return 0;
}
// Make descriptor non-blocking if user wants non-blocking.
if (impl.flags_ & implementation_type::user_set_non_blocking)
{
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
ioctl_arg_type non_blocking = 1;
if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Read some data.
for (;;)
{
// Try to complete the operation without blocking.
int bytes_read = descriptor_ops::scatter_read(
impl.descriptor_, bufs, i, ec);
// Check if operation succeeded.
if (bytes_read > 0)
return bytes_read;
// Check for EOF.
if (bytes_read == 0)
{
ec = asio::error::eof;
return 0;
}
// Operation failed.
if ((impl.flags_ & implementation_type::user_set_non_blocking)
|| (ec != asio::error::would_block
&& ec != asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0)
return 0;
}
}
// Wait until data can be read without blocking.
size_t read_some(implementation_type& impl,
const null_buffers&, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for descriptor to become ready.
descriptor_ops::poll_read(impl.descriptor_, ec);
return 0;
}
template <typename MutableBufferSequence, typename Handler>
class read_operation :
public handler_base_from_member<Handler>
{
public:
read_operation(int descriptor, asio::io_service& io_service,
const MutableBufferSequence& buffers, Handler handler)
: handler_base_from_member<Handler>(handler),
descriptor_(descriptor),
io_service_(io_service),
work_(io_service),
buffers_(buffers)
{
}
bool perform(asio::error_code& ec,
std::size_t& bytes_transferred)
{
// Check whether the operation was successful.
if (ec)
{
bytes_transferred = 0;
return true;
}
// Copy buffers into array.
descriptor_ops::buf bufs[max_buffers];
typename MutableBufferSequence::const_iterator iter = buffers_.begin();
typename MutableBufferSequence::const_iterator end = buffers_.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::mutable_buffer buffer(*iter);
descriptor_ops::init_buf(bufs[i],
asio::buffer_cast<void*>(buffer),
asio::buffer_size(buffer));
}
// Read some data.
int bytes = descriptor_ops::scatter_read(descriptor_, bufs, i, ec);
if (bytes == 0)
ec = asio::error::eof;
// Check if we need to run the operation again.
if (ec == asio::error::would_block
|| ec == asio::error::try_again)
return false;
bytes_transferred = (bytes < 0 ? 0 : bytes);
return true;
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
}
private:
int descriptor_;
asio::io_service& io_service_;
asio::io_service::work work_;
MutableBufferSequence buffers_;
};
// Start an asynchronous read. The buffer for the data being read must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
// Determine total size of buffers.
typename MutableBufferSequence::const_iterator iter = buffers.begin();
typename MutableBufferSequence::const_iterator end = buffers.end();
size_t i = 0;
size_t total_buffer_size = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::mutable_buffer buffer(*iter);
total_buffer_size += asio::buffer_size(buffer);
}
// A request to read_some 0 bytes on a stream is a no-op.
if (total_buffer_size == 0)
{
this->get_io_service().post(bind_handler(handler,
asio::error_code(), 0));
return;
}
// Make descriptor non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
ioctl_arg_type non_blocking = 1;
asio::error_code ec;
if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
{
this->get_io_service().post(bind_handler(handler, ec, 0));
return;
}
impl.flags_ |= implementation_type::internal_non_blocking;
}
reactor_.start_read_op(impl.descriptor_, impl.reactor_data_,
read_operation<MutableBufferSequence, Handler>(
impl.descriptor_, this->get_io_service(), buffers, handler));
}
}
// Wait until data can be read without blocking.
template <typename Handler>
void async_read_some(implementation_type& impl,
const null_buffers&, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
reactor_.start_read_op(impl.descriptor_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
private:
// The selector that performs event demultiplexing for the service.
Reactor& reactor_;
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP

View File

@ -0,0 +1,267 @@
//
// reactive_serial_port_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_REACTIVE_SERIAL_PORT_SERVICE_HPP
#define ASIO_DETAIL_REACTIVE_SERIAL_PORT_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 <string>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/push_options.hpp"
#include <termios.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/descriptor_ops.hpp"
#include "asio/detail/reactive_descriptor_service.hpp"
namespace asio {
namespace detail {
// Extend reactive_descriptor_service to provide serial port support.
template <typename Reactor>
class reactive_serial_port_service
: public asio::detail::service_base<
reactive_serial_port_service<Reactor> >
{
public:
// The native type of a stream handle.
typedef typename reactive_descriptor_service<Reactor>::native_type
native_type;
// The implementation type of the stream handle.
typedef typename reactive_descriptor_service<Reactor>::implementation_type
implementation_type;
reactive_serial_port_service(asio::io_service& io_service)
: asio::detail::service_base<
reactive_serial_port_service>(io_service),
descriptor_service_(asio::use_service<
reactive_descriptor_service<Reactor> >(io_service))
{
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
}
// Construct a new handle implementation.
void construct(implementation_type& impl)
{
descriptor_service_.construct(impl);
}
// Destroy a handle implementation.
void destroy(implementation_type& impl)
{
descriptor_service_.destroy(impl);
}
// Open the serial port using the specified device name.
asio::error_code open(implementation_type& impl,
const std::string& device, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
int fd = descriptor_ops::open(device.c_str(),
O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
if (fd < 0)
return ec;
int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
if (s >= 0)
s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
if (s < 0)
{
asio::error_code ignored_ec;
descriptor_ops::close(fd, ignored_ec);
return ec;
}
// Set up default serial port options.
termios ios;
descriptor_ops::clear_error(ec);
s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
if (s >= 0)
{
#if defined(_BSD_SOURCE)
::cfmakeraw(&ios);
#else
ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
| ISTRIP | INLCR | IGNCR | ICRNL | IXON);
ios.c_oflag &= ~OPOST;
ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
ios.c_cflag &= ~(CSIZE | PARENB);
ios.c_cflag |= CS8;
#endif
ios.c_iflag |= IGNPAR;
descriptor_ops::clear_error(ec);
s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
}
if (s < 0)
{
asio::error_code ignored_ec;
descriptor_ops::close(fd, ignored_ec);
return ec;
}
// We're done. Take ownership of the serial port descriptor.
if (descriptor_service_.assign(impl, fd, ec))
{
asio::error_code ignored_ec;
descriptor_ops::close(fd, ignored_ec);
}
return ec;
}
// Assign a native handle to a handle implementation.
asio::error_code assign(implementation_type& impl,
const native_type& native_descriptor, asio::error_code& ec)
{
return descriptor_service_.assign(impl, native_descriptor, ec);
}
// Determine whether the handle is open.
bool is_open(const implementation_type& impl) const
{
return descriptor_service_.is_open(impl);
}
// Destroy a handle implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return descriptor_service_.close(impl, ec);
}
// Get the native handle representation.
native_type native(implementation_type& impl)
{
return descriptor_service_.native(impl);
}
// Cancel all operations associated with the handle.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
return descriptor_service_.cancel(impl, ec);
}
// Set an option on the serial port.
template <typename SettableSerialPortOption>
asio::error_code set_option(implementation_type& impl,
const SettableSerialPortOption& option, asio::error_code& ec)
{
termios ios;
descriptor_ops::clear_error(ec);
descriptor_ops::error_wrapper(::tcgetattr(
descriptor_service_.native(impl), &ios), ec);
if (ec)
return ec;
if (option.store(ios, ec))
return ec;
descriptor_ops::clear_error(ec);
descriptor_ops::error_wrapper(::tcsetattr(
descriptor_service_.native(impl), TCSANOW, &ios), ec);
return ec;
}
// Get an option from the serial port.
template <typename GettableSerialPortOption>
asio::error_code get_option(const implementation_type& impl,
GettableSerialPortOption& option, asio::error_code& ec) const
{
termios ios;
descriptor_ops::clear_error(ec);
descriptor_ops::error_wrapper(::tcgetattr(
descriptor_service_.native(impl), &ios), ec);
if (ec)
return ec;
return option.load(ios, ec);
}
// Send a break sequence to the serial port.
asio::error_code send_break(implementation_type& impl,
asio::error_code& ec)
{
descriptor_ops::clear_error(ec);
descriptor_ops::error_wrapper(::tcsendbreak(
descriptor_service_.native(impl), 0), ec);
return ec;
}
// Write the given data. Returns the number of bytes sent.
template <typename ConstBufferSequence>
size_t write_some(implementation_type& impl,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return descriptor_service_.write_some(impl, buffers, ec);
}
// Start an asynchronous write. The data being written must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, Handler handler)
{
descriptor_service_.async_write_some(impl, buffers, handler);
}
// Read some data. Returns the number of bytes received.
template <typename MutableBufferSequence>
size_t read_some(implementation_type& impl,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return descriptor_service_.read_some(impl, buffers, ec);
}
// Start an asynchronous read. The buffer for the data being received must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, Handler handler)
{
descriptor_service_.async_read_some(impl, buffers, handler);
}
private:
// The handle service used for initiating asynchronous operations.
reactive_descriptor_service<Reactor>& descriptor_service_;
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP

View File

@ -26,6 +26,7 @@
#include "asio/io_service.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/handler_base_from_member.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_holder.hpp"
@ -83,6 +84,9 @@ public:
// The protocol associated with the socket.
protocol_type protocol_;
// Per-descriptor data used by the reactor.
typename Reactor::per_descriptor_data reactor_data_;
};
// The maximum number of buffers to support in a single operation.
@ -113,7 +117,7 @@ public:
{
if (impl.socket_ != invalid_socket)
{
reactor_.close_descriptor(impl.socket_);
reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
if (impl.flags_ & implementation_type::internal_non_blocking)
{
@ -155,7 +159,7 @@ public:
if (sock.get() == invalid_socket)
return ec;
if (int err = reactor_.register_descriptor(sock.get()))
if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
{
ec = asio::error_code(err,
asio::error::get_system_category());
@ -180,7 +184,8 @@ public:
return ec;
}
if (int err = reactor_.register_descriptor(native_socket))
if (int err = reactor_.register_descriptor(
native_socket, impl.reactor_data_))
{
ec = asio::error_code(err,
asio::error::get_system_category());
@ -206,7 +211,7 @@ public:
{
if (is_open(impl))
{
reactor_.close_descriptor(impl.socket_);
reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
if (impl.flags_ & implementation_type::internal_non_blocking)
{
@ -242,7 +247,7 @@ public:
return ec;
}
reactor_.cancel_ops(impl.socket_);
reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
ec = asio::error_code();
return ec;
}
@ -558,28 +563,46 @@ public:
}
}
// Wait until data can be sent without blocking.
size_t send(implementation_type& impl, const null_buffers&,
socket_base::message_flags, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for socket to become ready.
socket_ops::poll_write(impl.socket_, ec);
return 0;
}
template <typename ConstBufferSequence, typename Handler>
class send_handler
class send_operation :
public handler_base_from_member<Handler>
{
public:
send_handler(socket_type socket, asio::io_service& io_service,
send_operation(socket_type socket, asio::io_service& io_service,
const ConstBufferSequence& buffers, socket_base::message_flags flags,
Handler handler)
: socket_(socket),
: handler_base_from_member<Handler>(handler),
socket_(socket),
io_service_(io_service),
work_(io_service),
buffers_(buffers),
flags_(flags),
handler_(handler)
flags_(flags)
{
}
bool operator()(const asio::error_code& result)
bool perform(asio::error_code& ec,
std::size_t& bytes_transferred)
{
// Check whether the operation was successful.
if (result)
if (ec)
{
io_service_.post(bind_handler(handler_, result, 0));
bytes_transferred = 0;
return true;
}
@ -597,7 +620,6 @@ public:
}
// Send the data.
asio::error_code ec;
int bytes = socket_ops::send(socket_, bufs, i, flags_, ec);
// Check if we need to run the operation again.
@ -605,17 +627,22 @@ public:
|| ec == asio::error::try_again)
return false;
io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
bytes_transferred = (bytes < 0 ? 0 : bytes);
return true;
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
}
private:
socket_type socket_;
asio::io_service& io_service_;
asio::io_service::work work_;
ConstBufferSequence buffers_;
socket_base::message_flags flags_;
Handler handler_;
};
// Start an asynchronous send. The data being sent must be valid for the
@ -666,12 +693,59 @@ public:
impl.flags_ |= implementation_type::internal_non_blocking;
}
reactor_.start_write_op(impl.socket_,
send_handler<ConstBufferSequence, Handler>(
reactor_.start_write_op(impl.socket_, impl.reactor_data_,
send_operation<ConstBufferSequence, Handler>(
impl.socket_, this->get_io_service(), buffers, flags, handler));
}
}
template <typename Handler>
class null_buffers_operation :
public handler_base_from_member<Handler>
{
public:
null_buffers_operation(asio::io_service& io_service, Handler handler)
: handler_base_from_member<Handler>(handler),
work_(io_service)
{
}
bool perform(asio::error_code&,
std::size_t& bytes_transferred)
{
bytes_transferred = 0;
return true;
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
work_.get_io_service().post(bind_handler(
this->handler_, ec, bytes_transferred));
}
private:
asio::io_service::work work_;
};
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
void async_send(implementation_type& impl, const null_buffers&,
socket_base::message_flags, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
reactor_.start_write_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
// Send a datagram to the specified endpoint. Returns the number of bytes
// sent.
template <typename ConstBufferSequence>
@ -733,29 +807,48 @@ public:
}
}
// Wait until data can be sent without blocking.
size_t send_to(implementation_type& impl, const null_buffers&,
socket_base::message_flags, const endpoint_type&,
asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for socket to become ready.
socket_ops::poll_write(impl.socket_, ec);
return 0;
}
template <typename ConstBufferSequence, typename Handler>
class send_to_handler
class send_to_operation :
public handler_base_from_member<Handler>
{
public:
send_to_handler(socket_type socket, asio::io_service& io_service,
send_to_operation(socket_type socket, asio::io_service& io_service,
const ConstBufferSequence& buffers, const endpoint_type& endpoint,
socket_base::message_flags flags, Handler handler)
: socket_(socket),
: handler_base_from_member<Handler>(handler),
socket_(socket),
io_service_(io_service),
work_(io_service),
buffers_(buffers),
destination_(endpoint),
flags_(flags),
handler_(handler)
flags_(flags)
{
}
bool operator()(const asio::error_code& result)
bool perform(asio::error_code& ec,
std::size_t& bytes_transferred)
{
// Check whether the operation was successful.
if (result)
if (ec)
{
io_service_.post(bind_handler(handler_, result, 0));
bytes_transferred = 0;
return true;
}
@ -773,7 +866,6 @@ public:
}
// Send the data.
asio::error_code ec;
int bytes = socket_ops::sendto(socket_, bufs, i, flags_,
destination_.data(), destination_.size(), ec);
@ -782,10 +874,16 @@ public:
|| ec == asio::error::try_again)
return false;
io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
bytes_transferred = (bytes < 0 ? 0 : bytes);
return true;
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
}
private:
socket_type socket_;
asio::io_service& io_service_;
@ -793,7 +891,6 @@ public:
ConstBufferSequence buffers_;
endpoint_type destination_;
socket_base::message_flags flags_;
Handler handler_;
};
// Start an asynchronous send. The data being sent must be valid for the
@ -824,13 +921,31 @@ public:
impl.flags_ |= implementation_type::internal_non_blocking;
}
reactor_.start_write_op(impl.socket_,
send_to_handler<ConstBufferSequence, Handler>(
reactor_.start_write_op(impl.socket_, impl.reactor_data_,
send_to_operation<ConstBufferSequence, Handler>(
impl.socket_, this->get_io_service(), buffers,
destination, flags, handler));
}
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
void async_send_to(implementation_type& impl, const null_buffers&,
socket_base::message_flags, const endpoint_type&, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
reactor_.start_write_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
// Receive some data from the peer. Returns the number of bytes received.
template <typename MutableBufferSequence>
size_t receive(implementation_type& impl,
@ -888,7 +1003,7 @@ public:
return bytes_recvd;
// Check for EOF.
if (bytes_recvd == 0)
if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM)
{
ec = asio::error::eof;
return 0;
@ -906,28 +1021,48 @@ public:
}
}
// Wait until data can be received without blocking.
size_t receive(implementation_type& impl, const null_buffers&,
socket_base::message_flags, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for socket to become ready.
socket_ops::poll_read(impl.socket_, ec);
return 0;
}
template <typename MutableBufferSequence, typename Handler>
class receive_handler
class receive_operation :
public handler_base_from_member<Handler>
{
public:
receive_handler(socket_type socket, asio::io_service& io_service,
const MutableBufferSequence& buffers, socket_base::message_flags flags,
Handler handler)
: socket_(socket),
receive_operation(socket_type socket, int protocol_type,
asio::io_service& io_service,
const MutableBufferSequence& buffers,
socket_base::message_flags flags, Handler handler)
: handler_base_from_member<Handler>(handler),
socket_(socket),
protocol_type_(protocol_type),
io_service_(io_service),
work_(io_service),
buffers_(buffers),
flags_(flags),
handler_(handler)
flags_(flags)
{
}
bool operator()(const asio::error_code& result)
bool perform(asio::error_code& ec,
std::size_t& bytes_transferred)
{
// Check whether the operation was successful.
if (result)
if (ec)
{
io_service_.post(bind_handler(handler_, result, 0));
bytes_transferred = 0;
return true;
}
@ -945,9 +1080,8 @@ public:
}
// Receive some data.
asio::error_code ec;
int bytes = socket_ops::recv(socket_, bufs, i, flags_, ec);
if (bytes == 0)
if (bytes == 0 && protocol_type_ == SOCK_STREAM)
ec = asio::error::eof;
// Check if we need to run the operation again.
@ -955,17 +1089,23 @@ public:
|| ec == asio::error::try_again)
return false;
io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
bytes_transferred = (bytes < 0 ? 0 : bytes);
return true;
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
}
private:
socket_type socket_;
int protocol_type_;
asio::io_service& io_service_;
asio::io_service::work work_;
MutableBufferSequence buffers_;
socket_base::message_flags flags_;
Handler handler_;
};
// Start an asynchronous receive. The buffer for the data being received
@ -1019,19 +1159,44 @@ public:
if (flags & socket_base::message_out_of_band)
{
reactor_.start_except_op(impl.socket_,
receive_handler<MutableBufferSequence, Handler>(
impl.socket_, this->get_io_service(), buffers, flags, handler));
reactor_.start_except_op(impl.socket_, impl.reactor_data_,
receive_operation<MutableBufferSequence, Handler>(
impl.socket_, impl.protocol_.type(),
this->get_io_service(), buffers, flags, handler));
}
else
{
reactor_.start_read_op(impl.socket_,
receive_handler<MutableBufferSequence, Handler>(
impl.socket_, this->get_io_service(), buffers, flags, handler));
reactor_.start_read_op(impl.socket_, impl.reactor_data_,
receive_operation<MutableBufferSequence, Handler>(
impl.socket_, impl.protocol_.type(),
this->get_io_service(), buffers, flags, handler));
}
}
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive(implementation_type& impl, const null_buffers&,
socket_base::message_flags flags, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else if (flags & socket_base::message_out_of_band)
{
reactor_.start_except_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler));
}
else
{
reactor_.start_read_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
// Receive a datagram with the endpoint of the sender. Returns the number of
// bytes received.
template <typename MutableBufferSequence>
@ -1087,7 +1252,7 @@ public:
}
// Check for EOF.
if (bytes_recvd == 0)
if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM)
{
ec = asio::error::eof;
return 0;
@ -1105,30 +1270,53 @@ public:
}
}
// Wait until data can be received without blocking.
size_t receive_from(implementation_type& impl, const null_buffers&,
endpoint_type& sender_endpoint, socket_base::message_flags,
asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for socket to become ready.
socket_ops::poll_read(impl.socket_, ec);
// Reset endpoint since it can be given no sensible value at this time.
sender_endpoint = endpoint_type();
return 0;
}
template <typename MutableBufferSequence, typename Handler>
class receive_from_handler
class receive_from_operation :
public handler_base_from_member<Handler>
{
public:
receive_from_handler(socket_type socket,
receive_from_operation(socket_type socket, int protocol_type,
asio::io_service& io_service,
const MutableBufferSequence& buffers, endpoint_type& endpoint,
socket_base::message_flags flags, Handler handler)
: socket_(socket),
: handler_base_from_member<Handler>(handler),
socket_(socket),
protocol_type_(protocol_type),
io_service_(io_service),
work_(io_service),
buffers_(buffers),
sender_endpoint_(endpoint),
flags_(flags),
handler_(handler)
flags_(flags)
{
}
bool operator()(const asio::error_code& result)
bool perform(asio::error_code& ec,
std::size_t& bytes_transferred)
{
// Check whether the operation was successful.
if (result)
if (ec)
{
io_service_.post(bind_handler(handler_, result, 0));
bytes_transferred = 0;
return true;
}
@ -1147,10 +1335,9 @@ public:
// Receive some data.
std::size_t addr_len = sender_endpoint_.capacity();
asio::error_code ec;
int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_,
sender_endpoint_.data(), &addr_len, ec);
if (bytes == 0)
if (bytes == 0 && protocol_type_ == SOCK_STREAM)
ec = asio::error::eof;
// Check if we need to run the operation again.
@ -1159,18 +1346,24 @@ public:
return false;
sender_endpoint_.resize(addr_len);
io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
bytes_transferred = (bytes < 0 ? 0 : bytes);
return true;
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
}
private:
socket_type socket_;
int protocol_type_;
asio::io_service& io_service_;
asio::io_service::work work_;
MutableBufferSequence buffers_;
endpoint_type& sender_endpoint_;
socket_base::message_flags flags_;
Handler handler_;
};
// Start an asynchronous receive. The buffer for the data being received and
@ -1201,10 +1394,40 @@ public:
impl.flags_ |= implementation_type::internal_non_blocking;
}
reactor_.start_read_op(impl.socket_,
receive_from_handler<MutableBufferSequence, Handler>(
impl.socket_, this->get_io_service(), buffers,
sender_endpoint, flags, handler));
reactor_.start_read_op(impl.socket_, impl.reactor_data_,
receive_from_operation<MutableBufferSequence, Handler>(
impl.socket_, impl.protocol_.type(), this->get_io_service(),
buffers, sender_endpoint, flags, handler));
}
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive_from(implementation_type& impl,
const null_buffers&, endpoint_type& sender_endpoint,
socket_base::message_flags flags, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
// Reset endpoint since it can be given no sensible value at this time.
sender_endpoint = endpoint_type();
if (flags & socket_base::message_out_of_band)
{
reactor_.start_except_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler));
}
else
{
reactor_.start_read_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
}
@ -1299,35 +1522,32 @@ public:
}
template <typename Socket, typename Handler>
class accept_handler
class accept_operation :
public handler_base_from_member<Handler>
{
public:
accept_handler(socket_type socket, asio::io_service& io_service,
accept_operation(socket_type socket, asio::io_service& io_service,
Socket& peer, const protocol_type& protocol,
endpoint_type* peer_endpoint, bool enable_connection_aborted,
Handler handler)
: socket_(socket),
: handler_base_from_member<Handler>(handler),
socket_(socket),
io_service_(io_service),
work_(io_service),
peer_(peer),
protocol_(protocol),
peer_endpoint_(peer_endpoint),
enable_connection_aborted_(enable_connection_aborted),
handler_(handler)
enable_connection_aborted_(enable_connection_aborted)
{
}
bool operator()(const asio::error_code& result)
bool perform(asio::error_code& ec, std::size_t&)
{
// Check whether the operation was successful.
if (result)
{
io_service_.post(bind_handler(handler_, result));
if (ec)
return true;
}
// Accept the waiting connection.
asio::error_code ec;
socket_holder new_socket;
std::size_t addr_len = 0;
if (peer_endpoint_)
@ -1363,10 +1583,14 @@ public:
new_socket.release();
}
io_service_.post(bind_handler(handler_, ec));
return true;
}
void complete(const asio::error_code& ec, std::size_t)
{
io_service_.post(bind_handler(this->handler_, ec));
}
private:
socket_type socket_;
asio::io_service& io_service_;
@ -1375,7 +1599,6 @@ public:
protocol_type protocol_;
endpoint_type* peer_endpoint_;
bool enable_connection_aborted_;
Handler handler_;
};
// Start an asynchronous accept. The peer and peer_endpoint objects
@ -1409,8 +1632,8 @@ public:
impl.flags_ |= implementation_type::internal_non_blocking;
}
reactor_.start_read_op(impl.socket_,
accept_handler<Socket, Handler>(
reactor_.start_read_op(impl.socket_, impl.reactor_data_,
accept_operation<Socket, Handler>(
impl.socket_, this->get_io_service(),
peer, impl.protocol_, peer_endpoint,
(impl.flags_ & implementation_type::enable_connection_aborted) != 0,
@ -1444,70 +1667,52 @@ public:
}
template <typename Handler>
class connect_handler
class connect_operation :
public handler_base_from_member<Handler>
{
public:
connect_handler(socket_type socket, boost::shared_ptr<bool> completed,
asio::io_service& io_service, Reactor& reactor, Handler handler)
: socket_(socket),
completed_(completed),
connect_operation(socket_type socket,
asio::io_service& io_service, Handler handler)
: handler_base_from_member<Handler>(handler),
socket_(socket),
io_service_(io_service),
work_(io_service),
reactor_(reactor),
handler_(handler)
work_(io_service)
{
}
bool operator()(const asio::error_code& result)
bool perform(asio::error_code& ec, std::size_t&)
{
// Check whether a handler has already been called for the connection.
// If it has, then we don't want to do anything in this handler.
if (*completed_)
return true;
// Cancel the other reactor operation for the connection.
*completed_ = true;
reactor_.enqueue_cancel_ops_unlocked(socket_);
// Check whether the operation was successful.
if (result)
{
io_service_.post(bind_handler(handler_, result));
if (ec)
return true;
}
// Get the error code from the connect operation.
int connect_error = 0;
size_t connect_error_len = sizeof(connect_error);
asio::error_code ec;
if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR,
&connect_error, &connect_error_len, ec) == socket_error_retval)
{
io_service_.post(bind_handler(handler_, ec));
return true;
}
// If connection failed then post the handler with the error code.
// The connection failed so the handler will be posted with an error code.
if (connect_error)
{
ec = asio::error_code(connect_error,
asio::error::get_system_category());
io_service_.post(bind_handler(handler_, ec));
return true;
}
// Post the result of the successful connection operation.
io_service_.post(bind_handler(handler_, ec));
return true;
}
void complete(const asio::error_code& ec, std::size_t)
{
io_service_.post(bind_handler(this->handler_, ec));
}
private:
socket_type socket_;
boost::shared_ptr<bool> completed_;
asio::io_service& io_service_;
asio::io_service::work work_;
Reactor& reactor_;
Handler handler_;
};
// Start an asynchronous connect.
@ -1551,10 +1756,9 @@ public:
{
// The connection is happening in the background, and we need to wait
// until the socket becomes writeable.
boost::shared_ptr<bool> completed(new bool(false));
reactor_.start_write_and_except_ops(impl.socket_,
connect_handler<Handler>(impl.socket_, completed,
this->get_io_service(), reactor_, handler));
reactor_.start_connect_op(impl.socket_, impl.reactor_data_,
connect_operation<Handler>(impl.socket_,
this->get_io_service(), handler));
}
else
{

View File

@ -22,6 +22,7 @@
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/noncopyable.hpp"
@ -37,36 +38,42 @@ public:
reactor_op_queue()
: operations_(),
cancelled_operations_(0),
cleanup_operations_(0)
complete_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)
template <typename Operation>
bool enqueue_operation(Descriptor descriptor, Operation operation)
{
op_base* new_op = new op<Handler>(descriptor, handler);
// Allocate and construct an object to wrap the handler.
typedef handler_alloc_traits<Operation, op<Operation> > alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(operation);
handler_ptr<alloc_traits> ptr(raw_ptr, descriptor, operation);
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));
operations_.insert(value_type(descriptor, ptr.get()));
if (entry.second)
{
ptr.release();
return true;
}
op_base* current_op = entry.first->second;
while (current_op->next_)
current_op = current_op->next_;
current_op->next_ = new_op;
current_op->next_ = ptr.release();
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
// next time perform_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)
@ -98,9 +105,9 @@ public:
return operations_.find(descriptor) != operations_.end();
}
// Dispatch the first operation corresponding to the descriptor. Returns true
// Perform the first operation corresponding to the descriptor. Returns true
// if there are more operations queued for the descriptor.
bool dispatch_operation(Descriptor descriptor,
bool perform_operation(Descriptor descriptor,
const asio::error_code& result)
{
typename operation_map::iterator i = operations_.find(descriptor);
@ -108,9 +115,9 @@ public:
{
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);
this_op->next_ = complete_operations_;
complete_operations_ = this_op;
bool done = this_op->perform(result);
if (done)
{
// Operation has finished.
@ -127,8 +134,8 @@ public:
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_;
// queue for this descriptor, and remove from the completed list.
complete_operations_ = this_op->next_;
this_op->next_ = i->second;
i->second = this_op;
return true;
@ -137,8 +144,8 @@ public:
return false;
}
// Dispatch all operations corresponding to the descriptor.
void dispatch_all_operations(Descriptor descriptor,
// Perform all operations corresponding to the descriptor.
void perform_all_operations(Descriptor descriptor,
const asio::error_code& result)
{
typename operation_map::iterator i = operations_.find(descriptor);
@ -148,14 +155,14 @@ public:
{
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);
this_op->next_ = complete_operations_;
complete_operations_ = this_op;
bool done = this_op->perform(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_;
// remove from the completed list.
complete_operations_ = this_op->next_;
this_op->next_ = i->second;
i->second = this_op;
return;
@ -178,15 +185,15 @@ public:
if (!descriptors.set(descriptor))
{
asio::error_code ec(error::fd_set_failure);
dispatch_all_operations(descriptor, ec);
perform_all_operations(descriptor, ec);
}
}
}
// Dispatch the operations corresponding to the ready file descriptors
// Perform 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,
void perform_operations_for_descriptors(const Descriptor_Set& descriptors,
const asio::error_code& result)
{
typename operation_map::iterator i = operations_.begin();
@ -197,9 +204,9 @@ public:
{
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);
this_op->next_ = complete_operations_;
complete_operations_ = this_op;
bool done = this_op->perform(result);
if (done)
{
if (!op_iter->second)
@ -208,8 +215,8 @@ public:
else
{
// Operation has not finished yet, so leave at front of queue, and
// remove from the cleanup list.
cleanup_operations_ = this_op->next_;
// remove from the completed list.
complete_operations_ = this_op->next_;
this_op->next_ = op_iter->second;
op_iter->second = this_op;
}
@ -217,28 +224,28 @@ public:
}
}
// Dispatch any pending cancels for operations.
void dispatch_cancellations()
// Perform any pending cancels for operations.
void perform_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);
this_op->next_ = complete_operations_;
complete_operations_ = this_op;
this_op->perform(asio::error::operation_aborted);
}
}
// Destroy operations that are waiting to be cleaned up.
void cleanup_operations()
// Complete all operations that are waiting to be completed.
void complete_operations()
{
while (cleanup_operations_)
while (complete_operations_)
{
op_base* next_op = cleanup_operations_->next_;
cleanup_operations_->next_ = 0;
cleanup_operations_->destroy();
cleanup_operations_ = next_op;
op_base* next_op = complete_operations_->next_;
complete_operations_->next_ = 0;
complete_operations_->complete();
complete_operations_ = next_op;
}
}
@ -253,12 +260,12 @@ public:
cancelled_operations_ = next_op;
}
while (cleanup_operations_)
while (complete_operations_)
{
op_base* next_op = cleanup_operations_->next_;
cleanup_operations_->next_ = 0;
cleanup_operations_->destroy();
cleanup_operations_ = next_op;
op_base* next_op = complete_operations_->next_;
complete_operations_->next_ = 0;
complete_operations_->destroy();
complete_operations_ = next_op;
}
typename operation_map::iterator i = operations_.begin();
@ -290,28 +297,40 @@ private:
}
// Perform the operation.
bool invoke(const asio::error_code& result)
bool perform(const asio::error_code& result)
{
return invoke_func_(this, result);
result_ = result;
return perform_func_(this, result_, bytes_transferred_);
}
// Destroy the operation and post the handler.
void complete()
{
complete_func_(this, result_, bytes_transferred_);
}
// Destroy the operation.
void destroy()
{
return destroy_func_(this);
destroy_func_(this);
}
protected:
typedef bool (*invoke_func_type)(op_base*,
const asio::error_code&);
typedef bool (*perform_func_type)(op_base*,
asio::error_code&, std::size_t&);
typedef void (*complete_func_type)(op_base*,
const asio::error_code&, std::size_t);
typedef void (*destroy_func_type)(op_base*);
// Construct an operation for the given descriptor.
op_base(invoke_func_type invoke_func,
op_base(perform_func_type perform_func, complete_func_type complete_func,
destroy_func_type destroy_func, Descriptor descriptor)
: invoke_func_(invoke_func),
: perform_func_(perform_func),
complete_func_(complete_func),
destroy_func_(destroy_func),
descriptor_(descriptor),
result_(),
bytes_transferred_(0),
next_(0)
{
}
@ -324,48 +343,94 @@ private:
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 perform the operation.
perform_func_type perform_func_;
// The function to be called to delete the handler.
// The function to be called to delete the operation and post the handler.
complete_func_type complete_func_;
// The function to be called to delete the operation.
destroy_func_type destroy_func_;
// The descriptor associated with the operation.
Descriptor descriptor_;
// The result of the operation.
asio::error_code result_;
// The number of bytes transferred in the operation.
std::size_t bytes_transferred_;
// The next operation for the same file descriptor.
op_base* next_;
};
// Adaptor class template for using handlers in operations.
template <typename Handler>
// Adaptor class template for operations.
template <typename Operation>
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)
op(Descriptor descriptor, Operation operation)
: op_base(&op<Operation>::do_perform, &op<Operation>::do_complete,
&op<Operation>::do_destroy, descriptor),
operation_(operation)
{
}
// Invoke the handler.
static bool invoke_handler(op_base* base,
const asio::error_code& result)
// Perform the operation.
static bool do_perform(op_base* base,
asio::error_code& result, std::size_t& bytes_transferred)
{
return static_cast<op<Handler>*>(base)->handler_(result);
return static_cast<op<Operation>*>(base)->operation_.perform(
result, bytes_transferred);
}
// Delete the handler.
static void destroy_handler(op_base* base)
// Destroy the operation and post the handler.
static void do_complete(op_base* base,
const asio::error_code& result, std::size_t bytes_transferred)
{
delete static_cast<op<Handler>*>(base);
// Take ownership of the operation object.
typedef op<Operation> this_type;
this_type* this_op(static_cast<this_type*>(base));
typedef handler_alloc_traits<Operation, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(this_op->operation_, this_op);
// Make a copy of the error_code and the operation so that the memory can
// be deallocated before the upcall is made.
asio::error_code ec(result);
Operation operation(this_op->operation_);
// Free the memory associated with the operation.
ptr.reset();
// Make the upcall.
operation.complete(ec, bytes_transferred);
}
// Destroy the operation.
static void do_destroy(op_base* base)
{
// Take ownership of the operation object.
typedef op<Operation> this_type;
this_type* this_op(static_cast<this_type*>(base));
typedef handler_alloc_traits<Operation, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(this_op->operation_, this_op);
// A sub-object of the operation may be the true owner of the memory
// associated with the operation. Consequently, a local copy of the
// operation is required to ensure that any owning sub-object remains
// valid until after we have deallocated the memory here.
Operation operation(this_op->operation_);
(void)operation;
// Free the memory associated with the operation.
ptr.reset();
}
private:
Handler handler_;
Operation operation_;
};
// The type for a map of operations.
@ -377,8 +442,8 @@ private:
// The list of operations that have been cancelled.
op_base* cancelled_operations_;
// The list of operations to be destroyed.
op_base* cleanup_operations_;
// The list of operations waiting to be completed.
op_base* complete_operations_;
};
} // namespace detail

View File

@ -23,6 +23,7 @@
#include <cstddef>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
#include "asio/detail/pop_options.hpp"
@ -50,6 +51,11 @@ class select_reactor
: public asio::detail::service_base<select_reactor<Own_Thread> >
{
public:
// Per-descriptor data.
struct per_descriptor_data
{
};
// Constructor.
select_reactor(asio::io_service& io_service)
: asio::detail::service_base<
@ -106,7 +112,7 @@ public:
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type descriptor)
int register_descriptor(socket_type, per_descriptor_data&)
{
return 0;
}
@ -114,7 +120,8 @@ public:
// 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)
void start_read_op(socket_type descriptor, per_descriptor_data&,
Handler handler, bool /*allow_speculative_read*/ = true)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
@ -125,7 +132,8 @@ public:
// 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)
void start_write_op(socket_type descriptor, per_descriptor_data&,
Handler handler, bool /*allow_speculative_write*/ = true)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
@ -136,7 +144,8 @@ public:
// 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)
void start_except_op(socket_type descriptor,
per_descriptor_data&, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
@ -144,18 +153,74 @@ public:
interrupter_.interrupt();
}
// Wrapper for connect handlers to enable the handler object to be placed
// in both the write and the except operation queues, but ensure that only
// one of the handlers is called.
template <typename Handler>
class connect_handler_wrapper
{
public:
connect_handler_wrapper(socket_type descriptor,
boost::shared_ptr<bool> completed,
select_reactor<Own_Thread>& reactor, Handler handler)
: descriptor_(descriptor),
completed_(completed),
reactor_(reactor),
handler_(handler)
{
}
bool perform(asio::error_code& ec,
std::size_t& bytes_transferred)
{
// Check whether one of the handlers has already been called. If it has,
// then we don't want to do anything in this handler.
if (*completed_)
{
completed_.reset(); // Indicate that this handler should not complete.
return true;
}
// Cancel the other reactor operation for the connection.
*completed_ = true;
reactor_.enqueue_cancel_ops_unlocked(descriptor_);
// Call the contained handler.
return handler_.perform(ec, bytes_transferred);
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
if (completed_.get())
handler_.complete(ec, bytes_transferred);
}
private:
socket_type descriptor_;
boost::shared_ptr<bool> completed_;
select_reactor<Own_Thread>& reactor_;
Handler handler_;
};
// 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.
// information available, or an error has occurred. The handler will be called
// only once.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
void start_connect_op(socket_type descriptor,
per_descriptor_data&, 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;
boost::shared_ptr<bool> completed(new bool(false));
connect_handler_wrapper<Handler> wrapped_handler(
descriptor, completed, *this, handler);
bool interrupt = write_op_queue_.enqueue_operation(
descriptor, wrapped_handler);
interrupt = except_op_queue_.enqueue_operation(
descriptor, wrapped_handler) || interrupt;
if (interrupt)
interrupter_.interrupt();
}
@ -164,7 +229,7 @@ public:
// 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)
void cancel_ops(socket_type descriptor, per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
@ -173,8 +238,8 @@ public:
// 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.
// select_reactor's mutex, and so should only be used when the reactor lock is
// already held.
void enqueue_cancel_ops_unlocked(socket_type descriptor)
{
pending_cancellations_.push_back(descriptor);
@ -182,7 +247,7 @@ public:
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor)
void close_descriptor(socket_type descriptor, per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
@ -245,16 +310,16 @@ private:
// 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();
read_op_queue_.perform_cancellations();
write_op_queue_.perform_cancellations();
except_op_queue_.perform_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);
complete_operations_and_timers(lock);
return;
}
@ -263,7 +328,7 @@ private:
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
cleanup_operations_and_timers(lock);
complete_operations_and_timers(lock);
return;
}
@ -305,15 +370,15 @@ private:
{
// 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();
except_op_queue_.perform_operations_for_descriptors(
except_fds, asio::error_code());
read_op_queue_.perform_operations_for_descriptors(
read_fds, asio::error_code());
write_op_queue_.perform_operations_for_descriptors(
write_fds, asio::error_code());
except_op_queue_.perform_cancellations();
read_op_queue_.perform_cancellations();
write_op_queue_.perform_cancellations();
}
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
@ -326,7 +391,7 @@ private:
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
cleanup_operations_and_timers(lock);
complete_operations_and_timers(lock);
}
// Run the select loop in the thread.
@ -411,16 +476,16 @@ private:
// 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(
void complete_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();
read_op_queue_.complete_operations();
write_op_queue_.complete_operations();
except_op_queue_.complete_operations();
for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
timer_queues_for_cleanup_[i]->cleanup_timers();
timer_queues_for_cleanup_[i]->complete_timers();
}
// Mutex to protect access to internal data.

View File

@ -27,6 +27,12 @@
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_id.hpp"
#if defined(BOOST_NO_TYPEID)
# if !defined(ASIO_NO_TYPEID)
# define ASIO_NO_TYPEID
# endif // !defined(ASIO_NO_TYPEID)
#endif // defined(BOOST_NO_TYPEID)
namespace asio {
namespace detail {
@ -156,6 +162,7 @@ private:
service.id_ = &id;
}
#if !defined(ASIO_NO_TYPEID)
// Set a service's id.
template <typename Service>
void init_service_id(asio::io_service::service& service,
@ -164,6 +171,7 @@ private:
service.type_info_ = &typeid(Service);
service.id_ = 0;
}
#endif // !defined(ASIO_NO_TYPEID)
// Check if a service matches the given id.
static bool service_id_matches(
@ -173,6 +181,7 @@ private:
return service.id_ == &id;
}
#if !defined(ASIO_NO_TYPEID)
// Check if a service matches the given id.
template <typename Service>
static bool service_id_matches(
@ -181,6 +190,7 @@ private:
{
return service.type_info_ != 0 && *service.type_info_ == typeid(Service);
}
#endif // !defined(ASIO_NO_TYPEID)
// Mutex to protect access to internal data.
mutable asio::detail::mutex mutex_;

View File

@ -175,6 +175,22 @@ inline int connect(socket_type s, const socket_addr_type* addr,
return result;
}
inline int socketpair(int af, int type, int protocol,
socket_type sv[2], asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
(void)(af);
(void)(type);
(void)(protocol);
(void)(sv);
ec = asio::error::operation_not_supported;
return -1;
#else
clear_error(ec);
return error_wrapper(::socketpair(af, type, protocol, sv), ec);
#endif
}
inline int listen(socket_type s, int backlog, asio::error_code& ec)
{
clear_error(ec);

View File

@ -99,6 +99,7 @@
# endif
# include <sys/socket.h>
# include <sys/uio.h>
# include <sys/un.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
@ -175,6 +176,7 @@ 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 sockaddr_un sockaddr_un_type;
typedef addrinfo addrinfo_type;
typedef int ioctl_arg_type;
typedef uint32_t u_long_type;

View File

@ -20,6 +20,7 @@
#include "asio/detail/push_options.hpp"
#include <boost/aligned_storage.hpp>
#include <boost/assert.hpp>
#include <boost/detail/atomic_count.hpp>
#include <boost/intrusive_ptr.hpp>
#include "asio/detail/pop_options.hpp"
@ -54,19 +55,13 @@ public:
#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();
if (--ref_count_ == 0)
delete this;
}
}
private:
@ -147,7 +142,7 @@ public:
strand_impl* prev_;
// The reference count on the strand implementation.
size_t ref_count_;
boost::detail::atomic_count ref_count_;
#if !defined(__BORLANDC__)
friend void intrusive_ptr_add_ref(strand_impl* p)
@ -345,6 +340,16 @@ public:
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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(h->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
private:

View File

@ -15,6 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#if defined(ASIO_ENABLE_TWO_LOCK_QUEUE)
#include "asio/detail/task_io_service_2lock.hpp"
#else // defined(ASIO_ENABLE_TWO_LOCK_QUEUE)
#include "asio/detail/push_options.hpp"
#include "asio/error_code.hpp"
@ -416,4 +420,6 @@ private:
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_ENABLE_TWO_LOCK_QUEUE)
#endif // ASIO_DETAIL_TASK_IO_SERVICE_HPP

View File

@ -0,0 +1,462 @@
//
// task_io_service_2lock.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_2LOCK_HPP
#define ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_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/indirect_handler_queue.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/task_io_service_fwd.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/detail/atomic_count.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
// An alternative task_io_service implementation based on a two-lock queue.
template <typename Task>
class task_io_service
: public asio::detail::service_base<task_io_service<Task> >
{
public:
typedef indirect_handler_queue handler_queue;
// Constructor.
task_io_service(asio::io_service& io_service)
: asio::detail::service_base<task_io_service<Task> >(io_service),
front_mutex_(),
back_mutex_(),
task_(use_service<Task>(io_service)),
outstanding_work_(0),
front_stopped_(false),
back_stopped_(false),
back_shutdown_(false),
back_first_idle_thread_(0),
back_task_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 back_lock(back_mutex_);
back_shutdown_ = true;
back_lock.unlock();
// Destroy handler objects.
while (handler_queue::handler* h = 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)
{
if (outstanding_work_ == 0)
{
stop();
ec = asio::error_code();
return 0;
}
typename call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
this_idle_thread.next = 0;
size_t n = 0;
while (do_one(&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)
{
if (outstanding_work_ == 0)
{
stop();
ec = asio::error_code();
return 0;
}
typename call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
this_idle_thread.next = 0;
return do_one(&this_idle_thread, ec);
}
// Poll for operations without blocking.
size_t poll(asio::error_code& ec)
{
if (outstanding_work_ == 0)
{
stop();
ec = asio::error_code();
return 0;
}
typename call_stack<task_io_service>::context ctx(this);
size_t n = 0;
while (do_one(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)
{
if (outstanding_work_ == 0)
{
stop();
ec = asio::error_code();
return 0;
}
typename call_stack<task_io_service>::context ctx(this);
return do_one(0, ec);
}
// Interrupt the event processing loop.
void stop()
{
asio::detail::mutex::scoped_lock front_lock(front_mutex_);
front_stopped_ = true;
front_lock.unlock();
asio::detail::mutex::scoped_lock back_lock(back_mutex_);
back_stopped_ = true;
interrupt_all_idle_threads(back_lock);
}
// Reset in preparation for a subsequent run invocation.
void reset()
{
asio::detail::mutex::scoped_lock front_lock(front_mutex_);
front_stopped_ = false;
front_lock.unlock();
asio::detail::mutex::scoped_lock back_lock(back_mutex_);
back_stopped_ = false;
}
// Notify that some work has started.
void work_started()
{
++outstanding_work_;
}
// Notify that some work has finished.
void work_finished()
{
if (--outstanding_work_ == 0)
stop();
}
// 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 back_lock(back_mutex_);
// If the service has been shut down we silently discard the handler.
if (back_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.
interrupt_one_idle_thread(back_lock);
}
private:
struct idle_thread_info;
size_t do_one(idle_thread_info* this_idle_thread,
asio::error_code& ec)
{
bool task_has_run = false;
for (;;)
{
// The front lock must be held before we can pop items from the queue.
asio::detail::mutex::scoped_lock front_lock(front_mutex_);
if (front_stopped_)
{
ec = asio::error_code();
return 0;
}
if (handler_queue::handler* h = handler_queue_.pop())
{
if (h == &task_handler_)
{
bool more_handlers = handler_queue_.poppable();
unsigned long front_version = handler_queue_.front_version();
front_lock.unlock();
// The task is always added to the back of the queue when we exit
// this block.
task_cleanup c(*this);
// If we're polling and the task has already run then we're done.
bool polling = !this_idle_thread;
if (task_has_run && polling)
{
ec = asio::error_code();
return 0;
}
// If we're considering going idle we need to check whether the queue
// is still empty. If it is, add the thread to the list of idle
// threads.
if (!more_handlers && !polling)
{
asio::detail::mutex::scoped_lock back_lock(back_mutex_);
if (back_stopped_)
{
ec = asio::error_code();
return 0;
}
else if (front_version == handler_queue_.back_version())
{
back_task_thread_ = this_idle_thread;
}
else
{
more_handlers = true;
}
}
// Run the task. May throw an exception. Only block if the handler
// queue is empty and we're not polling, otherwise we want to return
// as soon as possible.
task_has_run = true;
task_.run(!more_handlers && !polling);
}
else
{
front_lock.unlock();
handler_cleanup c(*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)
{
unsigned long front_version = handler_queue_.front_version();
front_lock.unlock();
// If we're considering going idle we need to check whether the queue
// is still empty. If it is, add the thread to the list of idle
// threads.
asio::detail::mutex::scoped_lock back_lock(back_mutex_);
if (back_stopped_)
{
ec = asio::error_code();
return 0;
}
else if (front_version == handler_queue_.back_version())
{
this_idle_thread->next = back_first_idle_thread_;
back_first_idle_thread_ = this_idle_thread;
this_idle_thread->wakeup_event.clear(back_lock);
this_idle_thread->wakeup_event.wait(back_lock);
}
}
else
{
ec = asio::error_code();
return 0;
}
}
}
// Interrupt a single idle thread.
void interrupt_one_idle_thread(
asio::detail::mutex::scoped_lock& back_lock)
{
if (back_first_idle_thread_)
{
idle_thread_info* idle_thread = back_first_idle_thread_;
back_first_idle_thread_ = idle_thread->next;
idle_thread->next = 0;
idle_thread->wakeup_event.signal(back_lock);
}
else if (back_task_thread_)
{
back_task_thread_ = 0;
task_.interrupt();
}
}
// Interrupt all idle threads.
void interrupt_all_idle_threads(
asio::detail::mutex::scoped_lock& back_lock)
{
while (back_first_idle_thread_)
{
idle_thread_info* idle_thread = back_first_idle_thread_;
back_first_idle_thread_ = idle_thread->next;
idle_thread->next = 0;
idle_thread->wakeup_event.signal(back_lock);
}
if (back_task_thread_)
{
back_task_thread_ = 0;
task_.interrupt();
}
}
// Helper class to perform task-related operations on block exit.
class task_cleanup;
friend class task_cleanup;
class task_cleanup
{
public:
task_cleanup(task_io_service& task_io_svc)
: task_io_service_(task_io_svc)
{
}
~task_cleanup()
{
// Reinsert the task at the end of the handler queue.
asio::detail::mutex::scoped_lock back_lock(
task_io_service_.back_mutex_);
task_io_service_.back_task_thread_ = 0;
task_io_service_.handler_queue_.push(&task_io_service_.task_handler_);
}
private:
task_io_service& task_io_service_;
};
// Helper class to perform handler-related operations on block exit.
class handler_cleanup
{
public:
handler_cleanup(task_io_service& task_io_svc)
: task_io_service_(task_io_svc)
{
}
~handler_cleanup()
{
task_io_service_.work_finished();
}
private:
task_io_service& task_io_service_;
};
// Mutexes to protect access to internal data.
asio::detail::mutex front_mutex_;
asio::detail::mutex back_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_;
// The count of unfinished work.
boost::detail::atomic_count 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 front_stopped_;
bool back_stopped_;
// Flag to indicate that the dispatcher has been shut down.
bool back_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* back_first_idle_thread_;
// The thread that is currently blocked on the task.
idle_thread_info* back_task_thread_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP

View File

@ -27,6 +27,7 @@
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/timer_queue_base.hpp"
@ -50,7 +51,7 @@ public:
: timers_(),
heap_(),
cancelled_timers_(0),
cleanup_timers_(0)
complete_timers_(0)
{
}
@ -101,6 +102,8 @@ public:
// Get the time for the timer that is earliest in the queue.
virtual boost::posix_time::time_duration wait_duration() const
{
if (heap_.empty())
return boost::posix_time::pos_infin;
return Time_Traits::to_posix_duration(
Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
}
@ -113,10 +116,10 @@ public:
{
timer_base* t = heap_[0];
remove_timer(t);
t->result_ = asio::error_code();
t->prev_ = 0;
t->next_ = cleanup_timers_;
cleanup_timers_ = t;
t->invoke(asio::error_code());
t->next_ = complete_timers_;
complete_timers_ = t;
}
}
@ -152,17 +155,23 @@ public:
while (cancelled_timers_)
{
timer_base* this_timer = cancelled_timers_;
this_timer->result_ = asio::error::operation_aborted;
cancelled_timers_ = this_timer->next_;
this_timer->next_ = cleanup_timers_;
cleanup_timers_ = this_timer;
this_timer->invoke(asio::error::operation_aborted);
this_timer->next_ = complete_timers_;
complete_timers_ = this_timer;
}
}
// Destroy timers that are waiting to be cleaned up.
virtual void cleanup_timers()
// Complete any timers that are waiting to be completed.
virtual void complete_timers()
{
destroy_timer_list(cleanup_timers_);
while (complete_timers_)
{
timer_base* this_timer = complete_timers_;
complete_timers_ = this_timer->next_;
this_timer->next_ = 0;
this_timer->complete();
}
}
// Destroy all timers.
@ -180,7 +189,7 @@ public:
heap_.clear();
timers_.clear();
destroy_timer_list(cancelled_timers_);
destroy_timer_list(cleanup_timers_);
destroy_timer_list(complete_timers_);
}
private:
@ -189,27 +198,27 @@ private:
class timer_base
{
public:
// Perform the timer operation and then destroy.
void invoke(const asio::error_code& result)
// Delete the timer and post the handler.
void complete()
{
invoke_func_(this, result);
complete_func_(this, result_);
}
// Destroy the timer operation.
// Delete the timer.
void destroy()
{
destroy_func_(this);
}
protected:
typedef void (*invoke_func_type)(timer_base*,
typedef void (*complete_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,
timer_base(complete_func_type complete_func, destroy_func_type destroy_func,
const time_type& time, void* token)
: invoke_func_(invoke_func),
: complete_func_(complete_func),
destroy_func_(destroy_func),
time_(time),
token_(token),
@ -228,13 +237,16 @@ private:
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 delete the timer and post the handler.
complete_func_type complete_func_;
// The function to be called to destroy the handler.
// The function to be called to delete the timer.
destroy_func_type destroy_func_;
// The time when the operation should fire.
// The result of the timer operation.
asio::error_code result_;
// The time when the timer should fire.
time_type time_;
// The token associated with the timer.
@ -258,23 +270,52 @@ private:
public:
// Constructor.
timer(const time_type& time, Handler handler, void* token)
: timer_base(&timer<Handler>::invoke_handler,
: timer_base(&timer<Handler>::complete_handler,
&timer<Handler>::destroy_handler, time, token),
handler_(handler)
{
}
// Invoke the handler and then destroy it.
static void invoke_handler(timer_base* base,
// Delete the timer and post the handler.
static void complete_handler(timer_base* base,
const asio::error_code& result)
{
static_cast<timer<Handler>*>(base)->handler_(result);
// Take ownership of the timer object.
typedef timer<Handler> this_type;
this_type* this_timer(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
// Make a copy of the error_code and the handler so that the memory can
// be deallocated before the upcall is made.
asio::error_code ec(result);
Handler handler(this_timer->handler_);
// Free the memory associated with the handler.
ptr.reset();
// Make the upcall.
handler(ec);
}
// Destroy the handler.
// Delete the timer.
static void destroy_handler(timer_base* base)
{
delete static_cast<timer<Handler>*>(base);
// Take ownership of the timer object.
typedef timer<Handler> this_type;
this_type* this_timer(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(this_timer->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
private:
@ -383,8 +424,8 @@ private:
// The list of timers to be cancelled.
timer_base* cancelled_timers_;
// The list of timers to be destroyed.
timer_base* cleanup_timers_;
// The list of timers waiting to be completed.
timer_base* complete_timers_;
};
} // namespace detail

View File

@ -47,8 +47,8 @@ public:
// 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;
// Complete all timers that are waiting to be completed.
virtual void complete_timers() = 0;
// Destroy all timers.
virtual void destroy_timers() = 0;

View File

@ -0,0 +1,832 @@
//
// win_iocp_handle_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_HANDLE_SERVICE_HPP
#define ASIO_DETAIL_WIN_IOCP_HANDLE_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 <boost/cstdint.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/win_iocp_io_service.hpp"
namespace asio {
namespace detail {
class win_iocp_handle_service
: public asio::detail::service_base<win_iocp_handle_service>
{
public:
// Base class for all operations.
typedef win_iocp_io_service::operation operation;
// The native type of a stream handle.
typedef HANDLE native_type;
// The implementation type of the stream handle.
class implementation_type
{
public:
// Default constructor.
implementation_type()
: handle_(INVALID_HANDLE_VALUE),
safe_cancellation_thread_id_(0),
next_(0),
prev_(0)
{
}
private:
// Only this service will have access to the internal values.
friend class win_iocp_handle_service;
// The native stream handle representation.
native_type handle_;
// The ID of the thread from which it is safe to cancel asynchronous
// operations. 0 means no asynchronous operations have been started yet.
// ~0 means asynchronous operations have been started from more than one
// thread, and cancellation is not supported for the handle.
DWORD safe_cancellation_thread_id_;
// Pointers to adjacent handle implementations in linked list.
implementation_type* next_;
implementation_type* prev_;
};
win_iocp_handle_service(asio::io_service& io_service)
: asio::detail::service_base<win_iocp_handle_service>(io_service),
iocp_service_(asio::use_service<win_iocp_io_service>(io_service)),
mutex_(),
impl_list_(0)
{
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
// Close all implementations, causing all operations to complete.
asio::detail::mutex::scoped_lock lock(mutex_);
implementation_type* impl = impl_list_;
while (impl)
{
close_for_destruction(*impl);
impl = impl->next_;
}
}
// Construct a new handle implementation.
void construct(implementation_type& impl)
{
impl.handle_ = INVALID_HANDLE_VALUE;
impl.safe_cancellation_thread_id_ = 0;
// Insert implementation into linked list of all implementations.
asio::detail::mutex::scoped_lock lock(mutex_);
impl.next_ = impl_list_;
impl.prev_ = 0;
if (impl_list_)
impl_list_->prev_ = &impl;
impl_list_ = &impl;
}
// Destroy a handle implementation.
void destroy(implementation_type& impl)
{
close_for_destruction(impl);
// Remove implementation from linked list of all implementations.
asio::detail::mutex::scoped_lock lock(mutex_);
if (impl_list_ == &impl)
impl_list_ = impl.next_;
if (impl.prev_)
impl.prev_->next_ = impl.next_;
if (impl.next_)
impl.next_->prev_= impl.prev_;
impl.next_ = 0;
impl.prev_ = 0;
}
// Assign a native handle to a handle implementation.
asio::error_code assign(implementation_type& impl,
const native_type& native_handle, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
if (iocp_service_.register_handle(native_handle, ec))
return ec;
impl.handle_ = native_handle;
ec = asio::error_code();
return ec;
}
// Determine whether the handle is open.
bool is_open(const implementation_type& impl) const
{
return impl.handle_ != INVALID_HANDLE_VALUE;
}
// Destroy a handle implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
if (is_open(impl))
{
if (!::CloseHandle(impl.handle_))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
impl.handle_ = INVALID_HANDLE_VALUE;
impl.safe_cancellation_thread_id_ = 0;
}
ec = asio::error_code();
return ec;
}
// Get the native handle representation.
native_type native(const implementation_type& impl) const
{
return impl.handle_;
}
// Cancel all operations associated with the handle.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
}
else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
{
// The version of Windows supports cancellation from any thread.
typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
if (!cancel_io_ex(impl.handle_, 0))
{
DWORD last_error = ::GetLastError();
if (last_error == ERROR_NOT_FOUND)
{
// ERROR_NOT_FOUND means that there were no operations to be
// cancelled. We swallow this error to match the behaviour on other
// platforms.
ec = asio::error_code();
}
else
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
}
else
{
ec = asio::error_code();
}
}
else if (impl.safe_cancellation_thread_id_ == 0)
{
// No operations have been started, so there's nothing to cancel.
ec = asio::error_code();
}
else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
{
// Asynchronous operations have been started from the current thread only,
// so it is safe to try to cancel them using CancelIo.
if (!::CancelIo(impl.handle_))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
else
{
ec = asio::error_code();
}
}
else
{
// Asynchronous operations have been started from more than one thread,
// so cancellation is not safe.
ec = asio::error::operation_not_supported;
}
return ec;
}
class overlapped_wrapper
: public OVERLAPPED
{
public:
explicit overlapped_wrapper(asio::error_code& ec)
{
Internal = 0;
InternalHigh = 0;
Offset = 0;
OffsetHigh = 0;
// Create a non-signalled manual-reset event, for GetOverlappedResult.
hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
if (hEvent)
{
// As documented in GetQueuedCompletionStatus, setting the low order
// bit of this event prevents our synchronous writes from being treated
// as completion port events.
*reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1;
}
else
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
}
~overlapped_wrapper()
{
if (hEvent)
{
::CloseHandle(hEvent);
}
}
};
// Write the given data. Returns the number of bytes written.
template <typename ConstBufferSequence>
size_t write_some(implementation_type& impl,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return write_some_at(impl, 0, buffers, ec);
}
// Write the given data at the specified offset. Returns the number of bytes
// written.
template <typename ConstBufferSequence>
size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Find first buffer of non-zero length.
asio::const_buffer buffer;
typename ConstBufferSequence::const_iterator iter = buffers.begin();
typename ConstBufferSequence::const_iterator end = buffers.end();
for (DWORD i = 0; iter != end; ++iter, ++i)
{
buffer = asio::const_buffer(*iter);
if (asio::buffer_size(buffer) != 0)
break;
}
// A request to write 0 bytes on a handle is a no-op.
if (asio::buffer_size(buffer) == 0)
{
ec = asio::error_code();
return 0;
}
overlapped_wrapper overlapped(ec);
if (ec)
{
return 0;
}
// Write the data.
overlapped.Offset = offset & 0xFFFFFFFF;
overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::WriteFile(impl.handle_,
asio::buffer_cast<LPCVOID>(buffer),
static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
if (!ok)
{
DWORD last_error = ::GetLastError();
if (last_error != ERROR_IO_PENDING)
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
return 0;
}
}
// Wait for the operation to complete.
DWORD bytes_transferred = 0;
ok = ::GetOverlappedResult(impl.handle_,
&overlapped, &bytes_transferred, TRUE);
if (!ok)
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
ec = asio::error_code();
return bytes_transferred;
}
template <typename ConstBufferSequence, typename Handler>
class write_operation
: public operation
{
public:
write_operation(win_iocp_io_service& io_service,
const ConstBufferSequence& buffers, Handler handler)
: operation(io_service,
&write_operation<ConstBufferSequence, Handler>::do_completion_impl,
&write_operation<ConstBufferSequence, Handler>::destroy_impl),
work_(io_service.get_io_service()),
buffers_(buffers),
handler_(handler)
{
}
private:
static void do_completion_impl(operation* op,
DWORD last_error, size_t bytes_transferred)
{
// Take ownership of the operation object.
typedef write_operation<ConstBufferSequence, 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);
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
// Check whether buffers are still valid.
typename ConstBufferSequence::const_iterator iter
= handler_op->buffers_.begin();
typename ConstBufferSequence::const_iterator end
= handler_op->buffers_.end();
while (iter != end)
{
asio::const_buffer buffer(*iter);
asio::buffer_cast<const char*>(buffer);
++iter;
}
#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made.
Handler handler(handler_op->handler_);
// Free the memory associated with the handler.
ptr.reset();
// Call the handler.
asio::error_code ec(last_error,
asio::error::get_system_category());
asio_handler_invoke_helpers::invoke(
bind_handler(handler, ec, bytes_transferred), &handler);
}
static void destroy_impl(operation* op)
{
// Take ownership of the operation object.
typedef write_operation<ConstBufferSequence, 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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(handler_op->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
asio::io_service::work work_;
ConstBufferSequence buffers_;
Handler handler_;
};
// Start an asynchronous write. The data being written must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, Handler handler)
{
async_write_some_at(impl, 0, buffers, handler);
}
// Start an asynchronous write at a specified offset. The data being written
// must be valid for the lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
void async_write_some_at(implementation_type& impl, boost::uint64_t offset,
const ConstBufferSequence& buffers, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
return;
}
// Update the ID of the thread from which cancellation is safe.
if (impl.safe_cancellation_thread_id_ == 0)
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
impl.safe_cancellation_thread_id_ = ~DWORD(0);
// Allocate and construct an operation to wrap the handler.
typedef write_operation<ConstBufferSequence, 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, iocp_service_, buffers, handler);
// Find first buffer of non-zero length.
asio::const_buffer buffer;
typename ConstBufferSequence::const_iterator iter = buffers.begin();
typename ConstBufferSequence::const_iterator end = buffers.end();
for (DWORD i = 0; iter != end; ++iter, ++i)
{
buffer = asio::const_buffer(*iter);
if (asio::buffer_size(buffer) != 0)
break;
}
// A request to write 0 bytes on a handle is a no-op.
if (asio::buffer_size(buffer) == 0)
{
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code error;
iocp_service_.post(bind_handler(handler, error, 0));
return;
}
// Write the data.
DWORD bytes_transferred = 0;
ptr.get()->Offset = offset & 0xFFFFFFFF;
ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::WriteFile(impl.handle_,
asio::buffer_cast<LPCVOID>(buffer),
static_cast<DWORD>(asio::buffer_size(buffer)),
&bytes_transferred, ptr.get());
DWORD last_error = ::GetLastError();
// Check if the operation completed immediately.
if (!ok && last_error != ERROR_IO_PENDING)
{
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code ec(last_error,
asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}
else
{
ptr.release();
}
}
// Read some data. Returns the number of bytes received.
template <typename MutableBufferSequence>
size_t read_some(implementation_type& impl,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return read_some_at(impl, 0, buffers, ec);
}
// Read some data at a specified offset. Returns the number of bytes received.
template <typename MutableBufferSequence>
size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Find first buffer of non-zero length.
asio::mutable_buffer buffer;
typename MutableBufferSequence::const_iterator iter = buffers.begin();
typename MutableBufferSequence::const_iterator end = buffers.end();
for (DWORD i = 0; iter != end; ++iter, ++i)
{
buffer = asio::mutable_buffer(*iter);
if (asio::buffer_size(buffer) != 0)
break;
}
// A request to read 0 bytes on a stream handle is a no-op.
if (asio::buffer_size(buffer) == 0)
{
ec = asio::error_code();
return 0;
}
overlapped_wrapper overlapped(ec);
if (ec)
{
return 0;
}
// Read some data.
overlapped.Offset = offset & 0xFFFFFFFF;
overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::ReadFile(impl.handle_,
asio::buffer_cast<LPVOID>(buffer),
static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
if (!ok)
{
DWORD last_error = ::GetLastError();
if (last_error != ERROR_IO_PENDING)
{
if (last_error == ERROR_HANDLE_EOF)
{
ec = asio::error::eof;
}
else
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
return 0;
}
}
// Wait for the operation to complete.
DWORD bytes_transferred = 0;
ok = ::GetOverlappedResult(impl.handle_,
&overlapped, &bytes_transferred, TRUE);
if (!ok)
{
DWORD last_error = ::GetLastError();
if (last_error == ERROR_HANDLE_EOF)
{
ec = asio::error::eof;
}
else
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
}
ec = asio::error_code();
return bytes_transferred;
}
template <typename MutableBufferSequence, typename Handler>
class read_operation
: public operation
{
public:
read_operation(win_iocp_io_service& io_service,
const MutableBufferSequence& buffers, Handler handler)
: operation(io_service,
&read_operation<
MutableBufferSequence, Handler>::do_completion_impl,
&read_operation<
MutableBufferSequence, Handler>::destroy_impl),
work_(io_service.get_io_service()),
buffers_(buffers),
handler_(handler)
{
}
private:
static void do_completion_impl(operation* op,
DWORD last_error, size_t bytes_transferred)
{
// Take ownership of the operation object.
typedef read_operation<MutableBufferSequence, 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);
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
// Check whether buffers are still valid.
typename MutableBufferSequence::const_iterator iter
= handler_op->buffers_.begin();
typename MutableBufferSequence::const_iterator end
= handler_op->buffers_.end();
while (iter != end)
{
asio::mutable_buffer buffer(*iter);
asio::buffer_cast<char*>(buffer);
++iter;
}
#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
// Check for the end-of-file condition.
asio::error_code ec(last_error,
asio::error::get_system_category());
if (!ec && bytes_transferred == 0 || last_error == ERROR_HANDLE_EOF)
{
ec = asio::error::eof;
}
// 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();
// Call the handler.
asio_handler_invoke_helpers::invoke(
bind_handler(handler, ec, bytes_transferred), &handler);
}
static void destroy_impl(operation* op)
{
// Take ownership of the operation object.
typedef read_operation<MutableBufferSequence, Handler> op_type;
op_type* handler_op(static_cast<op_type*>(op));
typedef asio::detail::handler_alloc_traits<
Handler, op_type> alloc_traits;
asio::detail::handler_ptr<alloc_traits> ptr(
handler_op->handler_, handler_op);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(handler_op->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
asio::io_service::work work_;
MutableBufferSequence buffers_;
Handler handler_;
};
// Start an asynchronous read. The buffer for the data being received must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, Handler handler)
{
async_read_some_at(impl, 0, buffers, handler);
}
// Start an asynchronous read at a specified offset. The buffer for the data
// being received must be valid for the lifetime of the asynchronous
// operation.
template <typename MutableBufferSequence, typename Handler>
void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
const MutableBufferSequence& buffers, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
return;
}
// Update the ID of the thread from which cancellation is safe.
if (impl.safe_cancellation_thread_id_ == 0)
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
impl.safe_cancellation_thread_id_ = ~DWORD(0);
// Allocate and construct an operation to wrap the handler.
typedef read_operation<MutableBufferSequence, 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, iocp_service_, buffers, handler);
// Find first buffer of non-zero length.
asio::mutable_buffer buffer;
typename MutableBufferSequence::const_iterator iter = buffers.begin();
typename MutableBufferSequence::const_iterator end = buffers.end();
for (DWORD i = 0; iter != end; ++iter, ++i)
{
buffer = asio::mutable_buffer(*iter);
if (asio::buffer_size(buffer) != 0)
break;
}
// A request to receive 0 bytes on a stream handle is a no-op.
if (asio::buffer_size(buffer) == 0)
{
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code error;
iocp_service_.post(bind_handler(handler, error, 0));
return;
}
// Read some data.
DWORD bytes_transferred = 0;
ptr.get()->Offset = offset & 0xFFFFFFFF;
ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::ReadFile(impl.handle_,
asio::buffer_cast<LPVOID>(buffer),
static_cast<DWORD>(asio::buffer_size(buffer)),
&bytes_transferred, ptr.get());
DWORD last_error = ::GetLastError();
if (!ok && last_error != ERROR_IO_PENDING)
{
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code ec(last_error,
asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}
else
{
ptr.release();
}
}
private:
// Prevent the use of the null_buffers type with this service.
size_t write_some(implementation_type& impl,
const null_buffers& buffers, asio::error_code& ec);
size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
const null_buffers& buffers, asio::error_code& ec);
template <typename Handler>
void async_write_some(implementation_type& impl,
const null_buffers& buffers, Handler handler);
template <typename Handler>
void async_write_some_at(implementation_type& impl, boost::uint64_t offset,
const null_buffers& buffers, Handler handler);
size_t read_some(implementation_type& impl,
const null_buffers& buffers, asio::error_code& ec);
size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
const null_buffers& buffers, asio::error_code& ec);
template <typename Handler>
void async_read_some(implementation_type& impl,
const null_buffers& buffers, Handler handler);
template <typename Handler>
void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
const null_buffers& buffers, Handler handler);
// Helper function to close a handle when the associated object is being
// destroyed.
void close_for_destruction(implementation_type& impl)
{
if (is_open(impl))
{
::CloseHandle(impl.handle_);
impl.handle_ = INVALID_HANDLE_VALUE;
impl.safe_cancellation_thread_id_ = 0;
}
}
// The IOCP service used for running asynchronous operations and dispatching
// handlers.
win_iocp_io_service& iocp_service_;
// Mutex to protect access to the linked list of implementations.
asio::detail::mutex mutex_;
// The head of a linked list of all implementations.
implementation_type* impl_list_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP

View File

@ -149,9 +149,20 @@ public:
}
// Register a handle with the IO completion port.
void register_handle(HANDLE handle)
asio::error_code register_handle(
HANDLE handle, asio::error_code& ec)
{
::CreateIoCompletionPort(handle, iocp_.handle, 0, 0);
if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
else
{
ec = asio::error_code();
}
return ec;
}
// Run the event loop until stopped or no more work.
@ -424,7 +435,7 @@ private:
{
timer_queues_copy_[i]->dispatch_timers();
timer_queues_copy_[i]->dispatch_cancellations();
timer_queues_copy_[i]->cleanup_timers();
timer_queues_copy_[i]->complete_timers();
}
}
catch (...)
@ -504,16 +515,18 @@ private:
}
else
{
// Relinquish responsibility for dispatching timers. If the io_service
// is not being stopped then the thread will get an opportunity to
// reacquire timer responsibility on the next loop iteration.
if (dispatching_timers)
{
::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
}
// 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))
{
@ -636,6 +649,16 @@ private:
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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(handler_op->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
win_iocp_io_service& io_service_;

View File

@ -0,0 +1,292 @@
//
// win_iocp_serial_port_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_SERIAL_PORT_SERVICE_HPP
#define ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_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 <string>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/win_iocp_io_service_fwd.hpp"
#if defined(ASIO_HAS_IOCP)
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/win_iocp_handle_service.hpp"
namespace asio {
namespace detail {
// Extend win_iocp_handle_service to provide serial port support.
class win_iocp_serial_port_service
: public asio::detail::service_base<win_iocp_serial_port_service>
{
public:
// The native type of a stream handle.
typedef win_iocp_handle_service::native_type native_type;
// The implementation type of the stream handle.
typedef win_iocp_handle_service::implementation_type implementation_type;
win_iocp_serial_port_service(asio::io_service& io_service)
: asio::detail::service_base<
win_iocp_serial_port_service>(io_service),
handle_service_(
asio::use_service<win_iocp_handle_service>(io_service))
{
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
}
// Construct a new handle implementation.
void construct(implementation_type& impl)
{
handle_service_.construct(impl);
}
// Destroy a handle implementation.
void destroy(implementation_type& impl)
{
handle_service_.destroy(impl);
}
// Open the serial port using the specified device name.
asio::error_code open(implementation_type& impl,
const std::string& device, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
// For convenience, add a leading \\.\ sequence if not already present.
std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
// Open a handle to the serial port.
::HANDLE handle = ::CreateFileA(name.c_str(),
GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (handle == INVALID_HANDLE_VALUE)
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
// Determine the initial serial port parameters.
using namespace std; // For memcpy.
::DCB dcb;
memset(&dcb, 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!::GetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
// Set some default serial port parameters. This implementation does not
// support changing these, so they might as well be in a known state.
dcb.fBinary = TRUE; // Win32 only supports binary mode.
dcb.fDsrSensitivity = FALSE;
dcb.fNull = FALSE; // Do not ignore NULL characters.
dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
if (!::SetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
// Set up timeouts so that the serial port will behave similarly to a
// network socket. Reads wait for at least one byte, then return with
// whatever they have. Writes return once everything is out the door.
::COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!::SetCommTimeouts(handle, &timeouts))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
// We're done. Take ownership of the serial port handle.
if (handle_service_.assign(impl, handle, ec))
::CloseHandle(handle);
return ec;
}
// Assign a native handle to a handle implementation.
asio::error_code assign(implementation_type& impl,
const native_type& native_handle, asio::error_code& ec)
{
return handle_service_.assign(impl, native_handle, ec);
}
// Determine whether the handle is open.
bool is_open(const implementation_type& impl) const
{
return handle_service_.is_open(impl);
}
// Destroy a handle implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return handle_service_.close(impl, ec);
}
// Get the native handle representation.
native_type native(implementation_type& impl)
{
return handle_service_.native(impl);
}
// Cancel all operations associated with the handle.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
return handle_service_.cancel(impl, ec);
}
// Set an option on the serial port.
template <typename SettableSerialPortOption>
asio::error_code set_option(implementation_type& impl,
const SettableSerialPortOption& option, asio::error_code& ec)
{
using namespace std; // For memcpy.
::DCB dcb;
memset(&dcb, 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!::GetCommState(handle_service_.native(impl), &dcb))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
if (option.store(dcb, ec))
return ec;
if (!::SetCommState(handle_service_.native(impl), &dcb))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
ec = asio::error_code();
return ec;
}
// Get an option from the serial port.
template <typename GettableSerialPortOption>
asio::error_code get_option(const implementation_type& impl,
GettableSerialPortOption& option, asio::error_code& ec) const
{
using namespace std; // For memcpy.
::DCB dcb;
memset(&dcb, 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!::GetCommState(handle_service_.native(impl), &dcb))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
return option.load(dcb, ec);
}
// Send a break sequence to the serial port.
asio::error_code send_break(implementation_type& impl,
asio::error_code& ec)
{
ec = asio::error::operation_not_supported;
return ec;
}
// Write the given data. Returns the number of bytes sent.
template <typename ConstBufferSequence>
size_t write_some(implementation_type& impl,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return handle_service_.write_some(impl, buffers, ec);
}
// Start an asynchronous write. The data being written must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, Handler handler)
{
handle_service_.async_write_some(impl, buffers, handler);
}
// Read some data. Returns the number of bytes received.
template <typename MutableBufferSequence>
size_t read_some(implementation_type& impl,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return handle_service_.read_some(impl, buffers, ec);
}
// Start an asynchronous read. The buffer for the data being received must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, Handler handler)
{
handle_service_.async_read_some(impl, buffers, handler);
}
private:
// The handle service used for initiating asynchronous operations.
win_iocp_handle_service& handle_service_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP

View File

@ -24,6 +24,7 @@
#include "asio/detail/push_options.hpp"
#include <cstring>
#include <boost/shared_ptr.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/weak_ptr.hpp>
#include "asio/detail/pop_options.hpp"
@ -112,6 +113,9 @@ public:
endpoint_type remote_endpoint_;
};
// The type of the reactor used for connect operations.
typedef detail::select_reactor<true> reactor_type;
// The implementation type of the socket.
class implementation_type
{
@ -155,6 +159,9 @@ public:
// The protocol associated with the socket.
protocol_type protocol_;
// Per-descriptor data used by the reactor.
reactor_type::per_descriptor_data reactor_data_;
#if defined(ASIO_ENABLE_CANCELIO)
// The ID of the thread from which it is safe to cancel asynchronous
// operations. 0 means no asynchronous operations have been started yet.
@ -168,9 +175,6 @@ public:
implementation_type* prev_;
};
// The type of the reactor used for connect operations.
typedef detail::select_reactor<true> reactor_type;
// The maximum number of buffers to support in a single operation.
enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
@ -251,7 +255,8 @@ public:
return ec;
HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
iocp_service_.register_handle(sock_as_handle);
if (iocp_service_.register_handle(sock_as_handle, ec))
return ec;
impl.socket_ = sock.release();
impl.flags_ = 0;
@ -272,7 +277,8 @@ public:
return ec;
}
iocp_service_.register_handle(native_socket.as_handle());
if (iocp_service_.register_handle(native_socket.as_handle(), ec))
return ec;
impl.socket_ = native_socket;
impl.flags_ = 0;
@ -301,7 +307,7 @@ public:
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (reactor)
reactor->close_descriptor(impl.socket_);
reactor->close_descriptor(impl.socket_, impl.reactor_data_);
if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
return ec;
@ -331,6 +337,7 @@ public:
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return ec;
}
else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
@ -699,6 +706,22 @@ public:
return bytes_transferred;
}
// Wait until data can be sent without blocking.
size_t send(implementation_type& impl, const null_buffers&,
socket_base::message_flags, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for socket to become ready.
socket_ops::poll_write(impl.socket_, ec);
return 0;
}
template <typename ConstBufferSequence, typename Handler>
class send_operation
: public operation
@ -775,6 +798,16 @@ public:
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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(handler_op->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
asio::io_service::work work_;
@ -857,6 +890,65 @@ public:
}
}
template <typename Handler>
class null_buffers_operation
{
public:
null_buffers_operation(asio::io_service& io_service, Handler handler)
: work_(io_service),
handler_(handler)
{
}
bool perform(asio::error_code&,
std::size_t& bytes_transferred)
{
bytes_transferred = 0;
return true;
}
void complete(const asio::error_code& ec,
std::size_t bytes_transferred)
{
work_.get_io_service().post(bind_handler(
handler_, ec, bytes_transferred));
}
private:
asio::io_service::work work_;
Handler handler_;
};
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
void async_send(implementation_type& impl, const null_buffers&,
socket_base::message_flags, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
// Check if the reactor was already obtained from the io_service.
reactor_type* reactor = static_cast<reactor_type*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (!reactor)
{
reactor = &(asio::use_service<reactor_type>(
this->get_io_service()));
interlocked_exchange_pointer(
reinterpret_cast<void**>(&reactor_), reactor);
}
reactor->start_write_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
// Send a datagram to the specified endpoint. Returns the number of bytes
// sent.
template <typename ConstBufferSequence>
@ -901,6 +993,23 @@ public:
return bytes_transferred;
}
// Wait until data can be sent without blocking.
size_t send_to(implementation_type& impl, const null_buffers&,
socket_base::message_flags, const endpoint_type&,
asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for socket to become ready.
socket_ops::poll_write(impl.socket_, ec);
return 0;
}
template <typename ConstBufferSequence, typename Handler>
class send_to_operation
: public operation
@ -968,6 +1077,16 @@ public:
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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(handler_op->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
asio::io_service::work work_;
@ -1037,6 +1156,36 @@ public:
}
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
void async_send_to(implementation_type& impl, const null_buffers&,
socket_base::message_flags, const endpoint_type&, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
// Check if the reactor was already obtained from the io_service.
reactor_type* reactor = static_cast<reactor_type*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (!reactor)
{
reactor = &(asio::use_service<reactor_type>(
this->get_io_service()));
interlocked_exchange_pointer(
reinterpret_cast<void**>(&reactor_), reactor);
}
reactor->start_write_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
// Receive some data from the peer. Returns the number of bytes received.
template <typename MutableBufferSequence>
size_t receive(implementation_type& impl,
@ -1086,7 +1235,7 @@ public:
asio::error::get_system_category());
return 0;
}
if (bytes_transferred == 0)
if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM)
{
ec = asio::error::eof;
return 0;
@ -1096,12 +1245,28 @@ public:
return bytes_transferred;
}
// Wait until data can be received without blocking.
size_t receive(implementation_type& impl, const null_buffers&,
socket_base::message_flags, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for socket to become ready.
socket_ops::poll_read(impl.socket_, ec);
return 0;
}
template <typename MutableBufferSequence, typename Handler>
class receive_operation
: public operation
{
public:
receive_operation(win_iocp_io_service& io_service,
receive_operation(int protocol_type, win_iocp_io_service& io_service,
weak_cancel_token_type cancel_token,
const MutableBufferSequence& buffers, Handler handler)
: operation(io_service,
@ -1109,6 +1274,7 @@ public:
MutableBufferSequence, Handler>::do_completion_impl,
&receive_operation<
MutableBufferSequence, Handler>::destroy_impl),
protocol_type_(protocol_type),
work_(io_service.get_io_service()),
cancel_token_(cancel_token),
buffers_(buffers),
@ -1156,7 +1322,9 @@ public:
}
// Check for connection closed.
else if (!ec && bytes_transferred == 0)
else if (!ec && bytes_transferred == 0
&& handler_op->protocol_type_ == SOCK_STREAM
&& !boost::is_same<MutableBufferSequence, null_buffers>::value)
{
ec = asio::error::eof;
}
@ -1180,8 +1348,19 @@ public:
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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(handler_op->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
int protocol_type_;
asio::io_service::work work_;
weak_cancel_token_type cancel_token_;
MutableBufferSequence buffers_;
@ -1214,8 +1393,9 @@ public:
typedef receive_operation<MutableBufferSequence, 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, iocp_service_,
impl.cancel_token_, buffers, handler);
int protocol_type = impl.protocol_.type();
handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
iocp_service_, impl.cancel_token_, buffers, handler);
// Copy buffers into WSABUF array.
::WSABUF bufs[max_buffers];
@ -1261,6 +1441,85 @@ public:
}
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive(implementation_type& impl, const null_buffers& buffers,
socket_base::message_flags flags, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else if (impl.protocol_.type() == SOCK_STREAM)
{
// For stream sockets on Windows, we may issue a 0-byte overlapped
// WSARecv to wait until there is data available on the socket.
#if defined(ASIO_ENABLE_CANCELIO)
// Update the ID of the thread from which cancellation is safe.
if (impl.safe_cancellation_thread_id_ == 0)
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
impl.safe_cancellation_thread_id_ = ~DWORD(0);
#endif // defined(ASIO_ENABLE_CANCELIO)
// Allocate and construct an operation to wrap the handler.
typedef receive_operation<null_buffers, Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
int protocol_type = impl.protocol_.type();
handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
iocp_service_, impl.cancel_token_, buffers, handler);
// Issue a receive operation with an empty buffer.
::WSABUF buf = { 0, 0 };
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
int result = ::WSARecv(impl.socket_, &buf, 1,
&bytes_transferred, &recv_flags, ptr.get(), 0);
DWORD last_error = ::WSAGetLastError();
if (result != 0 && last_error != WSA_IO_PENDING)
{
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code ec(last_error,
asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}
else
{
ptr.release();
}
}
else
{
// Check if the reactor was already obtained from the io_service.
reactor_type* reactor = static_cast<reactor_type*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (!reactor)
{
reactor = &(asio::use_service<reactor_type>(
this->get_io_service()));
interlocked_exchange_pointer(
reinterpret_cast<void**>(&reactor_), reactor);
}
if (flags & socket_base::message_out_of_band)
{
reactor->start_except_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler));
}
else
{
reactor->start_read_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
}
// Receive a datagram with the endpoint of the sender. Returns the number of
// bytes received.
template <typename MutableBufferSequence>
@ -1302,7 +1561,7 @@ public:
asio::error::get_system_category());
return 0;
}
if (bytes_transferred == 0)
if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM)
{
ec = asio::error::eof;
return 0;
@ -1314,12 +1573,32 @@ public:
return bytes_transferred;
}
// Wait until data can be received without blocking.
size_t receive_from(implementation_type& impl,
const null_buffers&, endpoint_type& sender_endpoint,
socket_base::message_flags, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// Wait for socket to become ready.
socket_ops::poll_read(impl.socket_, ec);
// Reset endpoint since it can be given no sensible value at this time.
sender_endpoint = endpoint_type();
return 0;
}
template <typename MutableBufferSequence, typename Handler>
class receive_from_operation
: public operation
{
public:
receive_from_operation(win_iocp_io_service& io_service,
receive_from_operation(int protocol_type, win_iocp_io_service& io_service,
endpoint_type& endpoint, const MutableBufferSequence& buffers,
Handler handler)
: operation(io_service,
@ -1327,6 +1606,7 @@ public:
MutableBufferSequence, Handler>::do_completion_impl,
&receive_from_operation<
MutableBufferSequence, Handler>::destroy_impl),
protocol_type_(protocol_type),
endpoint_(endpoint),
endpoint_size_(static_cast<int>(endpoint.capacity())),
work_(io_service.get_io_service()),
@ -1373,7 +1653,8 @@ public:
}
// Check for connection closed.
if (!ec && bytes_transferred == 0)
if (!ec && bytes_transferred == 0
&& handler_op->protocol_type_ == SOCK_STREAM)
{
ec = asio::error::eof;
}
@ -1400,8 +1681,19 @@ public:
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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(handler_op->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
int protocol_type_;
endpoint_type& endpoint_;
int endpoint_size_;
asio::io_service::work work_;
@ -1436,8 +1728,9 @@ public:
typedef receive_from_operation<MutableBufferSequence, 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, iocp_service_,
sender_endp, buffers, handler);
int protocol_type = impl.protocol_.type();
handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
iocp_service_, sender_endp, buffers, handler);
// Copy buffers into WSABUF array.
::WSABUF bufs[max_buffers];
@ -1472,6 +1765,48 @@ public:
}
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive_from(implementation_type& impl,
const null_buffers&, endpoint_type& sender_endpoint,
socket_base::message_flags flags, Handler handler)
{
if (!is_open(impl))
{
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
{
// Check if the reactor was already obtained from the io_service.
reactor_type* reactor = static_cast<reactor_type*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (!reactor)
{
reactor = &(asio::use_service<reactor_type>(
this->get_io_service()));
interlocked_exchange_pointer(
reinterpret_cast<void**>(&reactor_), reactor);
}
// Reset endpoint since it can be given no sensible value at this time.
sender_endpoint = endpoint_type();
if (flags & socket_base::message_out_of_band)
{
reactor->start_except_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler));
}
else
{
reactor->start_read_op(impl.socket_, impl.reactor_data_,
null_buffers_operation<Handler>(this->get_io_service(), handler),
false);
}
}
}
// Accept a new connection.
template <typename Socket>
asio::error_code accept(implementation_type& impl, Socket& peer,
@ -1492,7 +1827,6 @@ public:
for (;;)
{
asio::error_code ec;
socket_holder new_socket;
std::size_t addr_len = 0;
if (peer_endpoint)
@ -1570,8 +1904,7 @@ public:
}
private:
static void do_completion_impl(operation* op,
DWORD last_error, size_t bytes_transferred)
static void do_completion_impl(operation* op, DWORD last_error, size_t)
{
// Take ownership of the operation object.
typedef accept_operation<Socket, Handler> op_type;
@ -1714,6 +2047,16 @@ public:
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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(handler_op->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
win_iocp_io_service& io_service_;
@ -1832,58 +2175,38 @@ public:
}
template <typename Handler>
class connect_handler
class connect_operation
{
public:
connect_handler(socket_type socket, bool user_set_non_blocking,
boost::shared_ptr<bool> completed,
asio::io_service& io_service,
reactor_type& reactor, Handler handler)
connect_operation(socket_type socket, bool user_set_non_blocking,
asio::io_service& io_service, Handler handler)
: socket_(socket),
user_set_non_blocking_(user_set_non_blocking),
completed_(completed),
io_service_(io_service),
reactor_(reactor),
work_(io_service),
handler_(handler)
{
}
bool operator()(const asio::error_code& result)
bool perform(asio::error_code& ec,
std::size_t& bytes_transferred)
{
// Check whether a handler has already been called for the connection.
// If it has, then we don't want to do anything in this handler.
if (*completed_)
return true;
// Cancel the other reactor operation for the connection.
*completed_ = true;
reactor_.enqueue_cancel_ops_unlocked(socket_);
// Check whether the operation was successful.
if (result)
{
io_service_.post(bind_handler(handler_, result));
if (ec)
return true;
}
// Get the error code from the connect operation.
int connect_error = 0;
size_t connect_error_len = sizeof(connect_error);
asio::error_code ec;
if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR,
&connect_error, &connect_error_len, ec) == socket_error_retval)
{
io_service_.post(bind_handler(handler_, ec));
return true;
}
// If connection failed then post the handler with the error code.
if (connect_error)
{
ec = asio::error_code(connect_error,
asio::error::get_system_category());
io_service_.post(bind_handler(handler_, ec));
return true;
}
@ -1892,24 +2215,23 @@ public:
{
ioctl_arg_type non_blocking = 0;
if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec))
{
io_service_.post(bind_handler(handler_, ec));
return true;
}
}
// Post the result of the successful connection operation.
ec = asio::error_code();
io_service_.post(bind_handler(handler_, ec));
return true;
}
void complete(const asio::error_code& ec, std::size_t)
{
io_service_.post(bind_handler(handler_, ec));
}
private:
socket_type socket_;
bool user_set_non_blocking_;
boost::shared_ptr<bool> completed_;
asio::io_service& io_service_;
reactor_type& reactor_;
asio::io_service::work work_;
Handler handler_;
};
@ -1977,11 +2299,11 @@ public:
// The connection is happening in the background, and we need to wait
// until the socket becomes writeable.
boost::shared_ptr<bool> completed(new bool(false));
reactor->start_write_and_except_ops(impl.socket_,
connect_handler<Handler>(
reactor->start_connect_op(impl.socket_, impl.reactor_data_,
connect_operation<Handler>(
impl.socket_,
(impl.flags_ & implementation_type::user_set_non_blocking) != 0,
completed, this->get_io_service(), *reactor, handler));
this->get_io_service(), handler));
}
else
{
@ -2012,7 +2334,7 @@ private:
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (reactor)
reactor->close_descriptor(impl.socket_);
reactor->close_descriptor(impl.socket_, impl.reactor_data_);
// The socket destructor must not block. If the user has changed the
// linger option to block in the foreground, we will change it back to the

View File

@ -43,17 +43,53 @@ class win_thread
: private noncopyable
{
public:
// The purpose of the thread.
enum purpose { internal, external };
// Constructor.
template <typename Function>
win_thread(Function f)
win_thread(Function f, purpose p = internal)
: exit_event_(0)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
::HANDLE entry_event = 0;
if (p == internal)
{
arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
if (!entry_event)
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"thread.entry_event");
boost::throw_exception(e);
}
arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
if (!exit_event_)
{
DWORD last_error = ::GetLastError();
::CloseHandle(entry_event);
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"thread.exit_event");
boost::throw_exception(e);
}
}
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();
if (entry_event)
::CloseHandle(entry_event);
if (exit_event_)
::CloseHandle(exit_event_);
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
@ -61,18 +97,36 @@ public:
boost::throw_exception(e);
}
arg.release();
if (entry_event)
{
::WaitForSingleObject(entry_event, INFINITE);
::CloseHandle(entry_event);
}
}
// Destructor.
~win_thread()
{
::CloseHandle(thread_);
// The exit_event_ handle is deliberately allowed to leak here since it
// is an error for the owner of an internal thread not to join() it.
}
// Wait for the thread to exit.
void join()
{
::WaitForSingleObject(thread_, INFINITE);
if (exit_event_)
{
::WaitForSingleObject(exit_event_, INFINITE);
::CloseHandle(exit_event_);
::TerminateThread(thread_, 0);
}
else
{
::WaitForSingleObject(thread_, INFINITE);
}
}
private:
@ -83,6 +137,8 @@ private:
public:
virtual ~func_base() {}
virtual void run() = 0;
::HANDLE entry_event_;
::HANDLE exit_event_;
};
template <typename Function>
@ -105,13 +161,26 @@ private:
};
::HANDLE thread_;
::HANDLE exit_event_;
};
inline unsigned int __stdcall win_thread_function(void* arg)
{
std::auto_ptr<win_thread::func_base> func(
static_cast<win_thread::func_base*>(arg));
if (func->entry_event_)
::SetEvent(func->entry_event_);
func->run();
if (HANDLE exit_event = func->exit_event_)
{
func.reset();
::SetEvent(exit_event);
::Sleep(INFINITE);
}
return 0;
}

View File

@ -42,9 +42,12 @@ class wince_thread
: private noncopyable
{
public:
// The purpose of the thread.
enum purpose { internal, external };
// Constructor.
template <typename Function>
wince_thread(Function f)
wince_thread(Function f, purpose = internal)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
DWORD thread_id = 0;

View File

@ -127,22 +127,6 @@ public:
Handler handler_;
};
template <typename Dispatcher, typename Handler>
inline void* asio_handler_allocate(std::size_t size,
wrapped_handler<Dispatcher, Handler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Dispatcher, typename Handler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
wrapped_handler<Dispatcher, Handler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Handler, typename Context>
class rewrapped_handler
{
@ -168,6 +152,22 @@ public:
Context context_;
};
template <typename Dispatcher, typename Handler>
inline void* asio_handler_allocate(std::size_t size,
wrapped_handler<Dispatcher, Handler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Dispatcher, typename Handler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
wrapped_handler<Dispatcher, Handler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename Dispatcher, typename Handler>
inline void asio_handler_invoke(const Function& function,
wrapped_handler<Dispatcher, Handler>* this_handler)
@ -177,6 +177,22 @@ inline void asio_handler_invoke(const Function& function,
function, this_handler->handler_));
}
template <typename Handler, typename Context>
inline void* asio_handler_allocate(std::size_t size,
rewrapped_handler<Handler, Context>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->context_);
}
template <typename Handler, typename Context>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
rewrapped_handler<Handler, Context>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->context_);
}
template <typename Function, typename Handler, typename Context>
inline void asio_handler_invoke(const Function& function,
rewrapped_handler<Handler, Context>* this_handler)

View File

@ -105,6 +105,9 @@ enum basic_errors
/// Message too long.
message_size = ASIO_SOCKET_ERROR(EMSGSIZE),
/// The name was too long.
name_too_long = ASIO_SOCKET_ERROR(ENAMETOOLONG),
/// Network is down.
network_down = ASIO_SOCKET_ERROR(ENETDOWN),

View File

@ -35,7 +35,7 @@ namespace asio {
*
* This default implementation is simply:
* @code
* return ::operator new(bytes);
* return ::operator new(size);
* @endcode
*
* @note All temporary objects associated with a handler will be deallocated

View File

@ -0,0 +1,337 @@
//
// read_at.ipp
// ~~~~~~~~~~~
//
// 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_READ_AT_IPP
#define ASIO_READ_AT_IPP
#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 "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
#include "asio/completion_condition.hpp"
#include "asio/error.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/consuming_buffers.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
typename CompletionCondition>
std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec)
{
asio::detail::consuming_buffers<
mutable_buffer, MutableBufferSequence> tmp(buffers);
std::size_t total_transferred = 0;
while (tmp.begin() != tmp.end())
{
std::size_t bytes_transferred = d.read_some_at(
offset + total_transferred, tmp, ec);
tmp.consume(bytes_transferred);
total_transferred += bytes_transferred;
if (completion_condition(ec, total_transferred))
return total_transferred;
}
ec = asio::error_code();
return total_transferred;
}
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t bytes_transferred = read_at(
d, offset, buffers, transfer_all(), ec);
asio::detail::throw_error(ec);
return bytes_transferred;
}
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
typename CompletionCondition>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition)
{
asio::error_code ec;
std::size_t bytes_transferred = read_at(
d, offset, buffers, completion_condition, ec);
asio::detail::throw_error(ec);
return bytes_transferred;
}
template <typename SyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition>
std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, asio::error_code& ec)
{
std::size_t total_transferred = 0;
for (;;)
{
std::size_t bytes_available =
std::min<std::size_t>(512, b.max_size() - b.size());
std::size_t bytes_transferred = d.read_some_at(
offset + total_transferred, b.prepare(bytes_available), ec);
b.commit(bytes_transferred);
total_transferred += bytes_transferred;
if (b.size() == b.max_size()
|| completion_condition(ec, total_transferred))
return total_transferred;
}
}
template <typename SyncRandomAccessReadDevice, typename Allocator>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b)
{
asio::error_code ec;
std::size_t bytes_transferred = read_at(
d, offset, b, transfer_all(), ec);
asio::detail::throw_error(ec);
return bytes_transferred;
}
template <typename SyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition)
{
asio::error_code ec;
std::size_t bytes_transferred = read_at(
d, offset, b, completion_condition, ec);
asio::detail::throw_error(ec);
return bytes_transferred;
}
namespace detail
{
template <typename AsyncRandomAccessReadDevice,
typename MutableBufferSequence, typename CompletionCondition,
typename ReadHandler>
class read_at_handler
{
public:
typedef asio::detail::consuming_buffers<
mutable_buffer, MutableBufferSequence> buffers_type;
read_at_handler(AsyncRandomAccessReadDevice& stream,
boost::uint64_t offset, const buffers_type& buffers,
CompletionCondition completion_condition, ReadHandler handler)
: stream_(stream),
offset_(offset),
buffers_(buffers),
total_transferred_(0),
completion_condition_(completion_condition),
handler_(handler)
{
}
void operator()(const asio::error_code& ec,
std::size_t bytes_transferred)
{
total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred);
if (completion_condition_(ec, total_transferred_)
|| buffers_.begin() == buffers_.end())
{
handler_(ec, total_transferred_);
}
else
{
stream_.async_read_some_at(
offset_ + total_transferred_, buffers_, *this);
}
}
//private:
AsyncRandomAccessReadDevice& stream_;
boost::uint64_t offset_;
buffers_type buffers_;
std::size_t total_transferred_;
CompletionCondition completion_condition_;
ReadHandler handler_;
};
template <typename AsyncRandomAccessReadDevice,
typename MutableBufferSequence, typename CompletionCondition,
typename ReadHandler>
inline void* asio_handler_allocate(std::size_t size,
read_at_handler<AsyncRandomAccessReadDevice, MutableBufferSequence,
CompletionCondition, ReadHandler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename AsyncRandomAccessReadDevice,
typename MutableBufferSequence, typename CompletionCondition,
typename ReadHandler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
read_at_handler<AsyncRandomAccessReadDevice, MutableBufferSequence,
CompletionCondition, ReadHandler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename AsyncRandomAccessReadDevice,
typename MutableBufferSequence, typename CompletionCondition,
typename ReadHandler>
inline void asio_handler_invoke(const Function& function,
read_at_handler<AsyncRandomAccessReadDevice, MutableBufferSequence,
CompletionCondition, ReadHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
} // namespace detail
template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
typename CompletionCondition, typename ReadHandler>
inline void async_read_at(AsyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, ReadHandler handler)
{
asio::detail::consuming_buffers<
mutable_buffer, MutableBufferSequence> tmp(buffers);
d.async_read_some_at(offset, tmp,
detail::read_at_handler<AsyncRandomAccessReadDevice,
MutableBufferSequence, CompletionCondition, ReadHandler>(
d, offset, tmp, completion_condition, handler));
}
template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
typename ReadHandler>
inline void async_read_at(AsyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers,
ReadHandler handler)
{
async_read_at(d, offset, buffers, transfer_all(), handler);
}
namespace detail
{
template <typename AsyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition, typename ReadHandler>
class read_at_streambuf_handler
{
public:
read_at_streambuf_handler(AsyncRandomAccessReadDevice& stream,
boost::uint64_t offset, basic_streambuf<Allocator>& streambuf,
CompletionCondition completion_condition, ReadHandler handler)
: stream_(stream),
offset_(offset),
streambuf_(streambuf),
total_transferred_(0),
completion_condition_(completion_condition),
handler_(handler)
{
}
void operator()(const asio::error_code& ec,
std::size_t bytes_transferred)
{
total_transferred_ += bytes_transferred;
streambuf_.commit(bytes_transferred);
if (streambuf_.size() == streambuf_.max_size()
|| completion_condition_(ec, total_transferred_))
{
handler_(ec, total_transferred_);
}
else
{
std::size_t bytes_available =
std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
stream_.async_read_some_at(offset_ + total_transferred_,
streambuf_.prepare(bytes_available), *this);
}
}
//private:
AsyncRandomAccessReadDevice& stream_;
boost::uint64_t offset_;
asio::basic_streambuf<Allocator>& streambuf_;
std::size_t total_transferred_;
CompletionCondition completion_condition_;
ReadHandler handler_;
};
template <typename AsyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition, typename ReadHandler>
inline void* asio_handler_allocate(std::size_t size,
read_at_streambuf_handler<AsyncRandomAccessReadDevice, Allocator,
CompletionCondition, ReadHandler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename AsyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition, typename ReadHandler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
read_at_streambuf_handler<AsyncRandomAccessReadDevice, Allocator,
CompletionCondition, ReadHandler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename AsyncRandomAccessReadDevice,
typename Allocator, typename CompletionCondition, typename ReadHandler>
inline void asio_handler_invoke(const Function& function,
read_at_streambuf_handler<AsyncRandomAccessReadDevice, Allocator,
CompletionCondition, ReadHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
} // namespace detail
template <typename AsyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition, typename ReadHandler>
inline void async_read_at(AsyncRandomAccessReadDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, ReadHandler handler)
{
std::size_t bytes_available =
std::min<std::size_t>(512, b.max_size() - b.size());
d.async_read_some_at(offset, b.prepare(bytes_available),
detail::read_at_streambuf_handler<AsyncRandomAccessReadDevice, Allocator,
CompletionCondition, ReadHandler>(
d, offset, b, completion_condition, handler));
}
template <typename AsyncRandomAccessReadDevice, typename Allocator,
typename ReadHandler>
inline void async_read_at(AsyncRandomAccessReadDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
ReadHandler handler)
{
async_read_at(d, offset, b, transfer_all(), handler);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_READ_AT_IPP

View File

@ -25,8 +25,8 @@
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
#include "asio/buffers_iterator.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/const_buffers_iterator.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/throw_error.hpp"
@ -54,24 +54,24 @@ std::size_t read_until(SyncReadStream& s,
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::detail::const_buffers_iterator<
const_buffers_type> iterator;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = b.data();
iterator begin(buffers, next_search_start);
iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
iterator begin = iterator::begin(buffers);
iterator start = begin + next_search_start;
iterator end = iterator::end(buffers);
// Look for a match.
iterator iter = std::find(begin, end, delim);
iterator iter = std::find(start, end, delim);
if (iter != end)
{
// Found a match. We're done.
ec = asio::error_code();
return iter.position() + 1;
return iter - begin + 1;
}
else
{
// No match. Next search can start with the new data.
next_search_start = end.position();
next_search_start = end - begin;
}
// Check if buffer is full.
@ -146,33 +146,33 @@ std::size_t read_until(SyncReadStream& s,
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::detail::const_buffers_iterator<
const_buffers_type> iterator;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = b.data();
iterator begin(buffers, next_search_start);
iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
iterator begin = iterator::begin(buffers);
iterator start = begin + next_search_start;
iterator end = iterator::end(buffers);
// Look for a match.
std::pair<iterator, bool> result = asio::detail::partial_search(
begin, end, delim.begin(), delim.end());
start, end, delim.begin(), delim.end());
if (result.first != end)
{
if (result.second)
{
// Full match. We're done.
ec = asio::error_code();
return result.first.position() + delim.length();
return result.first - begin + delim.length();
}
else
{
// Partial match. Next search needs to start from beginning of match.
next_search_start = result.first.position();
next_search_start = result.first - begin;
}
}
else
{
// No match. Next search can start with the new data.
next_search_start = end.position();
next_search_start = end - begin;
}
// Check if buffer is full.
@ -212,33 +212,33 @@ std::size_t read_until(SyncReadStream& s,
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::detail::const_buffers_iterator<
const_buffers_type> iterator;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = b.data();
iterator begin(buffers, next_search_start);
iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
iterator begin = iterator::begin(buffers);
iterator start = begin + next_search_start;
iterator end = iterator::end(buffers);
// Look for a match.
boost::match_results<iterator> match_results;
if (boost::regex_search(begin, end, match_results, expr,
if (boost::regex_search(start, end, match_results, expr,
boost::match_default | boost::match_partial))
{
if (match_results[0].matched)
{
// Full match. We're done.
ec = asio::error_code();
return match_results[0].second.position();
return match_results[0].second - begin;
}
else
{
// Partial match. Next search needs to start from beginning of match.
next_search_start = match_results[0].first.position();
next_search_start = match_results[0].first - begin;
}
}
else
{
// No match. Next search can start with the new data.
next_search_start = end.position();
next_search_start = end - begin;
}
// Check if buffer is full.
@ -257,6 +257,73 @@ std::size_t read_until(SyncReadStream& s,
}
}
template <typename SyncReadStream, typename Allocator, typename MatchCondition>
std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
MatchCondition match_condition, asio::error_code& ec,
typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
{
std::size_t next_search_start = 0;
for (;;)
{
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = b.data();
iterator begin = iterator::begin(buffers);
iterator start = begin + next_search_start;
iterator end = iterator::end(buffers);
// Look for a match.
std::pair<iterator, bool> result = match_condition(start, end);
if (result.first != end)
{
if (result.second)
{
// Full match. We're done.
ec = asio::error_code();
return result.first - begin;
}
else
{
// Partial match. Next search needs to start from beginning of match.
next_search_start = result.first - begin;
}
}
else
{
// No match. Next search can start with the new data.
next_search_start = end - begin;
}
// Check if buffer is full.
if (b.size() == b.max_size())
{
ec = error::not_found;
return 0;
}
// Need more data.
std::size_t bytes_available =
std::min<std::size_t>(512, b.max_size() - b.size());
b.commit(s.read_some(b.prepare(bytes_available), ec));
if (ec)
return 0;
}
}
template <typename SyncReadStream, typename Allocator, typename MatchCondition>
inline std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
{
asio::error_code ec;
std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
asio::detail::throw_error(ec);
return bytes_transferred;
}
namespace detail
{
template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
@ -291,18 +358,18 @@ namespace detail
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::detail::const_buffers_iterator<
const_buffers_type> iterator;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = streambuf_.data();
iterator begin(buffers, next_search_start_);
iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
iterator begin = iterator::begin(buffers);
iterator start = begin + next_search_start_;
iterator end = iterator::end(buffers);
// Look for a match.
iterator iter = std::find(begin, end, delim_);
iterator iter = std::find(start, end, delim_);
if (iter != end)
{
// Found a match. We're done.
std::size_t bytes = iter.position() + 1;
std::size_t bytes = iter - begin + 1;
handler_(ec, bytes);
return;
}
@ -317,7 +384,7 @@ namespace detail
}
// Next search can start with the new data.
next_search_start_ = end.position();
next_search_start_ = end - begin;
// Start a new asynchronous read operation to obtain more data.
std::size_t bytes_available =
@ -369,11 +436,10 @@ void async_read_until(AsyncReadStream& s,
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::detail::const_buffers_iterator<
const_buffers_type> iterator;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = b.data();
iterator begin(buffers, 0);
iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
iterator begin = iterator::begin(buffers);
iterator end = iterator::end(buffers);
// Look for a match.
iterator iter = std::find(begin, end, delim);
@ -381,7 +447,7 @@ void async_read_until(AsyncReadStream& s,
{
// Found a match. We're done.
asio::error_code ec;
std::size_t bytes = iter.position() + 1;
std::size_t bytes = iter - begin + 1;
s.io_service().post(detail::bind_handler(handler, ec, bytes));
return;
}
@ -399,7 +465,7 @@ void async_read_until(AsyncReadStream& s,
std::min<std::size_t>(512, b.max_size() - b.size());
s.async_read_some(b.prepare(bytes_available),
detail::read_until_delim_handler<AsyncReadStream, Allocator, ReadHandler>(
s, b, delim, end.position(), handler));
s, b, delim, end - begin, handler));
}
namespace detail
@ -437,34 +503,34 @@ namespace detail
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::detail::const_buffers_iterator<
const_buffers_type> iterator;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = streambuf_.data();
iterator begin(buffers, next_search_start_);
iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
iterator begin = iterator::begin(buffers);
iterator start = begin + next_search_start_;
iterator end = iterator::end(buffers);
// Look for a match.
std::pair<iterator, bool> result = asio::detail::partial_search(
begin, end, delim_.begin(), delim_.end());
start, end, delim_.begin(), delim_.end());
if (result.first != end)
{
if (result.second)
{
// Full match. We're done.
std::size_t bytes = result.first.position() + delim_.length();
std::size_t bytes = result.first - begin + delim_.length();
handler_(ec, bytes);
return;
}
else
{
// Partial match. Next search needs to start from beginning of match.
next_search_start_ = result.first.position();
next_search_start_ = result.first - begin;
}
}
else
{
// No match. Next search can start with the new data.
next_search_start_ = end.position();
next_search_start_ = end - begin;
}
// Check if buffer is full.
@ -527,11 +593,10 @@ void async_read_until(AsyncReadStream& s,
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::detail::const_buffers_iterator<
const_buffers_type> iterator;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = b.data();
iterator begin(buffers, 0);
iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
iterator begin = iterator::begin(buffers);
iterator end = iterator::end(buffers);
// Look for a match.
std::size_t next_search_start;
@ -543,20 +608,20 @@ void async_read_until(AsyncReadStream& s,
{
// Full match. We're done.
asio::error_code ec;
std::size_t bytes = result.first.position() + delim.length();
std::size_t bytes = result.first - begin + delim.length();
s.io_service().post(detail::bind_handler(handler, ec, bytes));
return;
}
else
{
// Partial match. Next search needs to start from beginning of match.
next_search_start = result.first.position();
next_search_start = result.first - begin;
}
}
else
{
// No match. Next search can start with the new data.
next_search_start = end.position();
next_search_start = end - begin;
}
// Check if buffer is full.
@ -611,34 +676,34 @@ namespace detail
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::detail::const_buffers_iterator<
const_buffers_type> iterator;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = streambuf_.data();
iterator begin(buffers, next_search_start_);
iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
iterator begin = iterator::begin(buffers);
iterator start = begin + next_search_start_;
iterator end = iterator::end(buffers);
// Look for a match.
boost::match_results<iterator> match_results;
if (boost::regex_search(begin, end, match_results, expr_,
if (boost::regex_search(start, end, match_results, expr_,
boost::match_default | boost::match_partial))
{
if (match_results[0].matched)
{
// Full match. We're done.
std::size_t bytes = match_results[0].second.position();
std::size_t bytes = match_results[0].second - begin;
handler_(ec, bytes);
return;
}
else
{
// Partial match. Next search needs to start from beginning of match.
next_search_start_ = match_results[0].first.position();
next_search_start_ = match_results[0].first - begin;
}
}
else
{
// No match. Next search can start with the new data.
next_search_start_ = end.position();
next_search_start_ = end - begin;
}
// Check if buffer is full.
@ -701,11 +766,10 @@ void async_read_until(AsyncReadStream& s,
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::detail::const_buffers_iterator<
const_buffers_type> iterator;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = b.data();
iterator begin(buffers, 0);
iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
iterator begin = iterator::begin(buffers);
iterator end = iterator::end(buffers);
// Look for a match.
std::size_t next_search_start;
@ -717,20 +781,20 @@ void async_read_until(AsyncReadStream& s,
{
// Full match. We're done.
asio::error_code ec;
std::size_t bytes = match_results[0].second.position();
std::size_t bytes = match_results[0].second - begin;
s.io_service().post(detail::bind_handler(handler, ec, bytes));
return;
}
else
{
// Partial match. Next search needs to start from beginning of match.
next_search_start = match_results[0].first.position();
next_search_start = match_results[0].first - begin;
}
}
else
{
// No match. Next search can start with the new data.
next_search_start = end.position();
next_search_start = end - begin;
}
// Check if buffer is full.
@ -749,6 +813,182 @@ void async_read_until(AsyncReadStream& s,
s, b, expr, next_search_start, handler));
}
namespace detail
{
template <typename AsyncReadStream, typename Allocator,
typename MatchCondition, typename ReadHandler>
class read_until_match_handler
{
public:
read_until_match_handler(AsyncReadStream& stream,
asio::basic_streambuf<Allocator>& streambuf,
MatchCondition match_condition, std::size_t next_search_start,
ReadHandler handler)
: stream_(stream),
streambuf_(streambuf),
match_condition_(match_condition),
next_search_start_(next_search_start),
handler_(handler)
{
}
void operator()(const asio::error_code& ec,
std::size_t bytes_transferred)
{
// Check for errors.
if (ec)
{
std::size_t bytes = 0;
handler_(ec, bytes);
return;
}
// Commit received data to streambuf's get area.
streambuf_.commit(bytes_transferred);
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = streambuf_.data();
iterator begin = iterator::begin(buffers);
iterator start = begin + next_search_start_;
iterator end = iterator::end(buffers);
// Look for a match.
std::pair<iterator, bool> result = match_condition_(start, end);
if (result.first != end)
{
if (result.second)
{
// Full match. We're done.
std::size_t bytes = result.first - begin;
handler_(ec, bytes);
return;
}
else
{
// Partial match. Next search needs to start from beginning of match.
next_search_start_ = result.first - begin;
}
}
else
{
// No match. Next search can start with the new data.
next_search_start_ = end - begin;
}
// Check if buffer is full.
if (streambuf_.size() == streambuf_.max_size())
{
std::size_t bytes = 0;
asio::error_code ec(error::not_found);
handler_(ec, bytes);
return;
}
// Start a new asynchronous read operation to obtain more data.
std::size_t bytes_available =
std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
}
//private:
AsyncReadStream& stream_;
asio::basic_streambuf<Allocator>& streambuf_;
MatchCondition match_condition_;
std::size_t next_search_start_;
ReadHandler handler_;
};
template <typename AsyncReadStream, typename Allocator,
typename MatchCondition, typename ReadHandler>
inline void* asio_handler_allocate(std::size_t size,
read_until_match_handler<AsyncReadStream,
Allocator, MatchCondition, ReadHandler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename AsyncReadStream, typename Allocator,
typename MatchCondition, typename ReadHandler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
read_until_match_handler<AsyncReadStream,
Allocator, MatchCondition, ReadHandler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename AsyncReadStream, typename Allocator,
typename MatchCondition, typename ReadHandler>
inline void asio_handler_invoke(const Function& function,
read_until_match_handler<AsyncReadStream,
Allocator, MatchCondition, ReadHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
} // namespace detail
template <typename AsyncReadStream, typename Allocator,
typename MatchCondition, typename ReadHandler>
void async_read_until(AsyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
MatchCondition match_condition, ReadHandler handler,
typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
{
// Determine the range of the data to be searched.
typedef typename asio::basic_streambuf<
Allocator>::const_buffers_type const_buffers_type;
typedef asio::buffers_iterator<const_buffers_type> iterator;
const_buffers_type buffers = b.data();
iterator begin = iterator::begin(buffers);
iterator end = iterator::end(buffers);
// Look for a match.
std::size_t next_search_start;
std::pair<iterator, bool> result = match_condition(begin, end);
if (result.first != end)
{
if (result.second)
{
// Full match. We're done.
asio::error_code ec;
std::size_t bytes = result.first - begin;
s.io_service().post(detail::bind_handler(handler, ec, bytes));
return;
}
else
{
// Partial match. Next search needs to start from beginning of match.
next_search_start = result.first - begin;
}
}
else
{
// No match. Next search can start with the new data.
next_search_start = end - begin;
}
// Check if buffer is full.
if (b.size() == b.max_size())
{
asio::error_code ec(error::not_found);
s.io_service().post(detail::bind_handler(handler, ec, 0));
return;
}
// Start a new asynchronous read operation to obtain more data.
std::size_t bytes_available =
std::min<std::size_t>(512, b.max_size() - b.size());
s.async_read_some(b.prepare(bytes_available),
detail::read_until_match_handler<
AsyncReadStream, Allocator, MatchCondition, ReadHandler>(
s, b, match_condition, next_search_start, handler));
}
} // namespace asio
#include "asio/detail/pop_options.hpp"

View File

@ -0,0 +1,541 @@
//
// serial_port_base.ipp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_SERIAL_PORT_BASE_IPP
#define ASIO_SERIAL_PORT_BASE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
inline serial_port_base::baud_rate::baud_rate(unsigned int rate)
: value_(rate)
{
}
inline unsigned int serial_port_base::baud_rate::value() const
{
return value_;
}
inline asio::error_code serial_port_base::baud_rate::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
storage.BaudRate = value_;
#else
speed_t baud;
switch (value_)
{
// Do POSIX-specified rates first.
case 0: baud = B0; break;
case 50: baud = B50; break;
case 75: baud = B75; break;
case 110: baud = B110; break;
case 134: baud = B134; break;
case 150: baud = B150; break;
case 200: baud = B200; break;
case 300: baud = B300; break;
case 600: baud = B600; break;
case 1200: baud = B1200; break;
case 1800: baud = B1800; break;
case 2400: baud = B2400; break;
case 4800: baud = B4800; break;
case 9600: baud = B9600; break;
case 19200: baud = B19200; break;
case 38400: baud = B38400; break;
// And now the extended ones conditionally.
# ifdef B7200
case 7200: baud = B7200; break;
# endif
# ifdef B14400
case 14400: baud = B14400; break;
# endif
# ifdef B57600
case 57600: baud = B57600; break;
# endif
# ifdef B115200
case 115200: baud = B115200; break;
# endif
# ifdef B230400
case 230400: baud = B230400; break;
# endif
# ifdef B460800
case 460800: baud = B460800; break;
# endif
# ifdef B500000
case 500000: baud = B500000; break;
# endif
# ifdef B576000
case 576000: baud = B576000; break;
# endif
# ifdef B921600
case 921600: baud = B921600; break;
# endif
# ifdef B1000000
case 1000000: baud = B1000000; break;
# endif
# ifdef B1152000
case 1152000: baud = B1152000; break;
# endif
# ifdef B2000000
case 2000000: baud = B2000000; break;
# endif
# ifdef B3000000
case 3000000: baud = B3000000; break;
# endif
# ifdef B3500000
case 3500000: baud = B3500000; break;
# endif
# ifdef B4000000
case 4000000: baud = B4000000; break;
# endif
default:
baud = B0;
ec = asio::error::invalid_argument;
return ec;
}
# if defined(_BSD_SOURCE)
::cfsetspeed(&storage, baud);
# else
::cfsetispeed(&storage, baud);
::cfsetospeed(&storage, baud);
# endif
#endif
ec = asio::error_code();
return ec;
}
inline asio::error_code serial_port_base::baud_rate::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
value_ = storage.BaudRate;
#else
speed_t baud = ::cfgetospeed(&storage);
switch (baud)
{
// First do those specified by POSIX.
case B0: value_ = 0; break;
case B50: value_ = 50; break;
case B75: value_ = 75; break;
case B110: value_ = 110; break;
case B134: value_ = 134; break;
case B150: value_ = 150; break;
case B200: value_ = 200; break;
case B300: value_ = 300; break;
case B600: value_ = 600; break;
case B1200: value_ = 1200; break;
case B1800: value_ = 1800; break;
case B2400: value_ = 2400; break;
case B4800: value_ = 4800; break;
case B9600: value_ = 9600; break;
case B19200: value_ = 19200; break;
case B38400: value_ = 38400; break;
// Now conditionally handle a bunch of extended rates.
# ifdef B7200
case B7200: value_ = 7200; break;
# endif
# ifdef B14400
case B14400: value_ = 14400; break;
# endif
# ifdef B57600
case B57600: value_ = 57600; break;
# endif
# ifdef B115200
case B115200: value_ = 115200; break;
# endif
# ifdef B230400
case B230400: value_ = 230400; break;
# endif
# ifdef B460800
case B460800: value_ = 460800; break;
# endif
# ifdef B500000
case B500000: value_ = 500000; break;
# endif
# ifdef B576000
case B576000: value_ = 576000; break;
# endif
# ifdef B921600
case B921600: value_ = 921600; break;
# endif
# ifdef B1000000
case B1000000: value_ = 1000000; break;
# endif
# ifdef B1152000
case B1152000: value_ = 1152000; break;
# endif
# ifdef B2000000
case B2000000: value_ = 2000000; break;
# endif
# ifdef B3000000
case B3000000: value_ = 3000000; break;
# endif
# ifdef B3500000
case B3500000: value_ = 3500000; break;
# endif
# ifdef B4000000
case B4000000: value_ = 4000000; break;
# endif
default:
value_ = 0;
ec = asio::error::invalid_argument;
return ec;
}
#endif
ec = asio::error_code();
return ec;
}
inline serial_port_base::flow_control::flow_control(
serial_port_base::flow_control::type t)
: value_(t)
{
if (t != none && t != software && t != hardware)
throw std::out_of_range("invalid flow_control value");
}
inline serial_port_base::flow_control::type
serial_port_base::flow_control::value() const
{
return value_;
}
inline asio::error_code serial_port_base::flow_control::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
storage.fOutxCtsFlow = FALSE;
storage.fOutxDsrFlow = FALSE;
storage.fTXContinueOnXoff = TRUE;
storage.fDtrControl = DTR_CONTROL_ENABLE;
storage.fDsrSensitivity = FALSE;
storage.fOutX = FALSE;
storage.fInX = FALSE;
storage.fRtsControl = RTS_CONTROL_ENABLE;
switch (value_)
{
case none:
break;
case software:
storage.fOutX = TRUE;
storage.fInX = TRUE;
break;
case hardware:
storage.fOutxCtsFlow = TRUE;
storage.fRtsControl = RTS_CONTROL_HANDSHAKE;
break;
default:
break;
}
#else
switch (value_)
{
case none:
storage.c_iflag &= ~(IXOFF | IXON);
# if defined(_BSD_SOURCE)
storage.c_cflag &= ~CRTSCTS;
# endif
break;
case software:
storage.c_iflag |= IXOFF | IXON;
# if defined(_BSD_SOURCE)
storage.c_cflag &= ~CRTSCTS;
# endif
break;
case hardware:
# if defined(_BSD_SOURCE)
storage.c_iflag &= ~(IXOFF | IXON);
storage.c_cflag |= CRTSCTS;
break;
# else
ec = asio::error::operation_not_supported;
return ec;
# endif
default:
break;
}
#endif
ec = asio::error_code();
return ec;
}
inline asio::error_code serial_port_base::flow_control::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
if (storage.fOutX && storage.fInX)
{
value_ = software;
}
else if (storage.fOutxCtsFlow && storage.fRtsControl == RTS_CONTROL_HANDSHAKE)
{
value_ = hardware;
}
else
{
value_ = none;
}
#else
if (storage.c_iflag & (IXOFF | IXON))
{
value_ = software;
}
# if defined(_BSD_SOURCE)
else if (storage.c_cflag & CRTSCTS)
{
value_ = hardware;
}
# endif
else
{
value_ = none;
}
#endif
ec = asio::error_code();
return ec;
}
inline serial_port_base::parity::parity(serial_port_base::parity::type t)
: value_(t)
{
if (t != none && t != odd && t != even)
throw std::out_of_range("invalid parity value");
}
inline serial_port_base::parity::type serial_port_base::parity::value() const
{
return value_;
}
inline asio::error_code serial_port_base::parity::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
switch (value_)
{
case none:
storage.fParity = FALSE;
storage.Parity = NOPARITY;
break;
case odd:
storage.fParity = TRUE;
storage.Parity = ODDPARITY;
break;
case even:
storage.fParity = TRUE;
storage.Parity = EVENPARITY;
break;
default:
break;
}
#else
switch (value_)
{
case none:
storage.c_iflag |= IGNPAR;
storage.c_cflag &= ~(PARENB | PARODD);
break;
case even:
storage.c_iflag &= ~(IGNPAR | PARMRK);
storage.c_iflag |= INPCK;
storage.c_cflag |= PARENB;
storage.c_cflag &= ~PARODD;
break;
case odd:
storage.c_iflag &= ~(IGNPAR | PARMRK);
storage.c_iflag |= INPCK;
storage.c_cflag |= (PARENB | PARODD);
break;
default:
break;
}
#endif
ec = asio::error_code();
return ec;
}
inline asio::error_code serial_port_base::parity::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
if (storage.Parity == EVENPARITY)
{
value_ = even;
}
else if (storage.Parity == ODDPARITY)
{
value_ = odd;
}
else
{
value_ = none;
}
#else
if (storage.c_cflag & PARENB)
{
if (storage.c_cflag & PARODD)
{
value_ = odd;
}
else
{
value_ = even;
}
}
else
{
value_ = none;
}
#endif
ec = asio::error_code();
return ec;
}
inline serial_port_base::stop_bits::stop_bits(
serial_port_base::stop_bits::type t)
: value_(t)
{
if (t != one && t != onepointfive && t != two)
throw std::out_of_range("invalid stop_bits value");
}
inline serial_port_base::stop_bits::type
serial_port_base::stop_bits::value() const
{
return value_;
}
inline asio::error_code serial_port_base::stop_bits::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
switch (value_)
{
case one:
storage.StopBits = ONESTOPBIT;
break;
case onepointfive:
storage.StopBits = ONE5STOPBITS;
break;
case two:
storage.StopBits = TWOSTOPBITS;
break;
default:
break;
}
#else
switch (value_)
{
case one:
storage.c_cflag &= ~CSTOPB;
break;
case two:
storage.c_cflag |= CSTOPB;
break;
default:
ec = asio::error::operation_not_supported;
return ec;
}
#endif
ec = asio::error_code();
return ec;
}
inline asio::error_code serial_port_base::stop_bits::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
if (storage.StopBits == ONESTOPBIT)
{
value_ = one;
}
else if (storage.StopBits == ONE5STOPBITS)
{
value_ = onepointfive;
}
else if (storage.StopBits == TWOSTOPBITS)
{
value_ = two;
}
else
{
value_ = one;
}
#else
value_ = (storage.c_cflag & CSTOPB) ? two : one;
#endif
ec = asio::error_code();
return ec;
}
inline serial_port_base::character_size::character_size(unsigned int t)
: value_(t)
{
if (t < 5 || t > 8)
throw std::out_of_range("invalid character_size value");
}
inline unsigned int serial_port_base::character_size::value() const
{
return value_;
}
inline asio::error_code serial_port_base::character_size::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
storage.ByteSize = value_;
#else
storage.c_cflag &= ~CSIZE;
switch (value_)
{
case 5: storage.c_cflag |= CS5; break;
case 6: storage.c_cflag |= CS6; break;
case 7: storage.c_cflag |= CS7; break;
case 8: storage.c_cflag |= CS8; break;
default: break;
}
#endif
ec = asio::error_code();
return ec;
}
inline asio::error_code serial_port_base::character_size::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
value_ = storage.ByteSize;
#else
if ((storage.c_cflag & CSIZE) == CS5) { value_ = 5; }
else if ((storage.c_cflag & CSIZE) == CS6) { value_ = 6; }
else if ((storage.c_cflag & CSIZE) == CS7) { value_ = 7; }
else if ((storage.c_cflag & CSIZE) == CS8) { value_ = 8; }
else
{
// Hmmm, use 8 for now.
value_ = 8;
}
#endif
ec = asio::error_code();
return ec;
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_SERIAL_PORT_BASE_IPP

View File

@ -0,0 +1,296 @@
//
// write_at.ipp
// ~~~~~~~~~~~~
//
// 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_WRITE_AT_IPP
#define ASIO_WRITE_AT_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/buffer.hpp"
#include "asio/completion_condition.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/consuming_buffers.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition>
std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec)
{
asio::detail::consuming_buffers<
const_buffer, ConstBufferSequence> tmp(buffers);
std::size_t total_transferred = 0;
while (tmp.begin() != tmp.end())
{
std::size_t bytes_transferred = d.write_some_at(
offset + total_transferred, tmp, ec);
tmp.consume(bytes_transferred);
total_transferred += bytes_transferred;
if (completion_condition(ec, total_transferred))
return total_transferred;
}
ec = asio::error_code();
return total_transferred;
}
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t bytes_transferred = write_at(
d, offset, buffers, transfer_all(), ec);
asio::detail::throw_error(ec);
return bytes_transferred;
}
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition)
{
asio::error_code ec;
std::size_t bytes_transferred = write_at(
d, offset, buffers, completion_condition, ec);
asio::detail::throw_error(ec);
return bytes_transferred;
}
template <typename SyncRandomAccessWriteDevice, typename Allocator,
typename CompletionCondition>
std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, asio::error_code& ec)
{
std::size_t bytes_transferred = write_at(
d, offset, b.data(), completion_condition, ec);
b.consume(bytes_transferred);
return bytes_transferred;
}
template <typename SyncRandomAccessWriteDevice, typename Allocator>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b)
{
asio::error_code ec;
std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec);
asio::detail::throw_error(ec);
return bytes_transferred;
}
template <typename SyncRandomAccessWriteDevice, typename Allocator,
typename CompletionCondition>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition)
{
asio::error_code ec;
std::size_t bytes_transferred = write_at(
d, offset, b, completion_condition, ec);
asio::detail::throw_error(ec);
return bytes_transferred;
}
namespace detail
{
template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition, typename WriteHandler>
class write_at_handler
{
public:
typedef asio::detail::consuming_buffers<
const_buffer, ConstBufferSequence> buffers_type;
write_at_handler(AsyncRandomAccessWriteDevice& stream,
boost::uint64_t offset, const buffers_type& buffers,
CompletionCondition completion_condition, WriteHandler handler)
: stream_(stream),
buffers_(buffers),
offset_(offset),
total_transferred_(0),
completion_condition_(completion_condition),
handler_(handler)
{
}
void operator()(const asio::error_code& ec,
std::size_t bytes_transferred)
{
total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred);
if (completion_condition_(ec, total_transferred_)
|| buffers_.begin() == buffers_.end())
{
handler_(ec, total_transferred_);
}
else
{
stream_.async_write_some_at(
offset_ + total_transferred_, buffers_, *this);
}
}
//private:
AsyncRandomAccessWriteDevice& stream_;
buffers_type buffers_;
boost::uint64_t offset_;
std::size_t total_transferred_;
CompletionCondition completion_condition_;
WriteHandler handler_;
};
template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition, typename WriteHandler>
inline void* asio_handler_allocate(std::size_t size,
write_at_handler<AsyncRandomAccessWriteDevice, ConstBufferSequence,
CompletionCondition, WriteHandler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition, typename WriteHandler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
write_at_handler<AsyncRandomAccessWriteDevice, ConstBufferSequence,
CompletionCondition, WriteHandler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename AsyncRandomAccessWriteDevice,
typename ConstBufferSequence, typename CompletionCondition,
typename WriteHandler>
inline void asio_handler_invoke(const Function& function,
write_at_handler<AsyncRandomAccessWriteDevice, ConstBufferSequence,
CompletionCondition, WriteHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
} // namespace detail
template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition, typename WriteHandler>
inline void async_write_at(AsyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, WriteHandler handler)
{
asio::detail::consuming_buffers<
const_buffer, ConstBufferSequence> tmp(buffers);
d.async_write_some_at(offset, tmp,
detail::write_at_handler<AsyncRandomAccessWriteDevice,
ConstBufferSequence, CompletionCondition, WriteHandler>(
d, offset, tmp, completion_condition, handler));
}
template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename WriteHandler>
inline void async_write_at(AsyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers,
WriteHandler handler)
{
async_write_at(d, offset, buffers, transfer_all(), handler);
}
namespace detail
{
template <typename AsyncRandomAccessWriteDevice, typename Allocator,
typename WriteHandler>
class write_at_streambuf_handler
{
public:
write_at_streambuf_handler(
asio::basic_streambuf<Allocator>& streambuf,
WriteHandler handler)
: streambuf_(streambuf),
handler_(handler)
{
}
void operator()(const asio::error_code& ec,
std::size_t bytes_transferred)
{
streambuf_.consume(bytes_transferred);
handler_(ec, bytes_transferred);
}
//private:
asio::basic_streambuf<Allocator>& streambuf_;
WriteHandler handler_;
};
template <typename AsyncRandomAccessWriteDevice, typename Allocator,
typename WriteHandler>
inline void* asio_handler_allocate(std::size_t size,
write_at_streambuf_handler<AsyncRandomAccessWriteDevice,
Allocator, WriteHandler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename AsyncRandomAccessWriteDevice, typename Allocator,
typename WriteHandler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
write_at_streambuf_handler<AsyncRandomAccessWriteDevice,
Allocator, WriteHandler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename AsyncRandomAccessWriteDevice,
typename Allocator, typename WriteHandler>
inline void asio_handler_invoke(const Function& function,
write_at_streambuf_handler<AsyncRandomAccessWriteDevice,
Allocator, WriteHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
} // namespace detail
template <typename AsyncRandomAccessWriteDevice, typename Allocator,
typename CompletionCondition, typename WriteHandler>
inline void async_write_at(AsyncRandomAccessWriteDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, WriteHandler handler)
{
async_write_at(d, offset, b.data(), completion_condition,
detail::write_at_streambuf_handler<
AsyncRandomAccessWriteDevice, Allocator, WriteHandler>(b, handler));
}
template <typename AsyncRandomAccessWriteDevice, typename Allocator,
typename WriteHandler>
inline void async_write_at(AsyncRandomAccessWriteDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
WriteHandler handler)
{
async_write_at(d, offset, b, transfer_all(), handler);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WRITE_AT_IPP

View File

@ -100,6 +100,32 @@ template <typename Service> bool has_service(io_service& ios);
* }
* }
* @endcode
*
* @par Stopping the io_service from running out of work
*
* Some applications may need to prevent an io_service's run() call from
* returning when there is no more work to do. For example, the io_service may
* be being run in a background thread that is launched prior to the
* application's asynchronous operations. The run() call may be kept running by
* creating an object of type asio::io_service::work:
*
* @code asio::io_service io_service;
* asio::io_service::work work(io_service);
* ... @endcode
*
* To effect a shutdown, the application will then need to call the io_service's
* stop() member function. This will cause the io_service run() call to return
* as soon as possible, abandoning unfinished operations and without permitting
* ready handlers to be dispatched.
*
* Alternatively, if the application requires that all operations and handlers
* be allowed to finish normally, the work object may be explicitly destroyed.
*
* @code asio::io_service io_service;
* auto_ptr<asio::io_service::work> work(
* new asio::io_service::work(io_service));
* ...
* work.reset(); // Allow run() to exit. @endcode
*/
class io_service
: private noncopyable
@ -159,6 +185,9 @@ public:
* @return The number of handlers that were executed.
*
* @throws asio::system_error Thrown on failure.
*
* @note The poll() function may also be used to dispatch ready handlers,
* but without blocking.
*/
std::size_t run();
@ -178,6 +207,9 @@ public:
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of handlers that were executed.
*
* @note The poll() function may also be used to dispatch ready handlers,
* but without blocking.
*/
std::size_t run(asio::error_code& ec);

View File

@ -0,0 +1,118 @@
//
// icmp.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_IP_ICMP_HPP
#define ASIO_IP_ICMP_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_raw_socket.hpp"
#include "asio/ip/basic_endpoint.hpp"
#include "asio/ip/basic_resolver.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace ip {
/// Encapsulates the flags needed for ICMP.
/**
* The asio::ip::icmp class contains flags necessary for ICMP sockets.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Safe.
*
* @par Concepts:
* Protocol, InternetProtocol.
*/
class icmp
{
public:
/// The type of a ICMP endpoint.
typedef basic_endpoint<icmp> endpoint;
/// The type of a resolver query.
typedef basic_resolver_query<icmp> resolver_query;
/// The type of a resolver iterator.
typedef basic_resolver_iterator<icmp> resolver_iterator;
/// Construct to represent the IPv4 ICMP protocol.
static icmp v4()
{
return icmp(IPPROTO_ICMP, PF_INET);
}
/// Construct to represent the IPv6 ICMP protocol.
static icmp v6()
{
return icmp(IPPROTO_ICMPV6, PF_INET6);
}
/// Obtain an identifier for the type of the protocol.
int type() const
{
return SOCK_RAW;
}
/// Obtain an identifier for the protocol.
int protocol() const
{
return protocol_;
}
/// Obtain an identifier for the protocol family.
int family() const
{
return family_;
}
/// The ICMP socket type.
typedef basic_raw_socket<icmp> socket;
/// The ICMP resolver type.
typedef basic_resolver<icmp> resolver;
/// Compare two protocols for equality.
friend bool operator==(const icmp& p1, const icmp& p2)
{
return p1.protocol_ == p2.protocol_ && p1.family_ == p2.family_;
}
/// Compare two protocols for inequality.
friend bool operator!=(const icmp& p1, const icmp& p2)
{
return p1.protocol_ != p2.protocol_ || p1.family_ != p2.family_;
}
private:
// Construct with a specific family.
explicit icmp(int protocol, int family)
: protocol_(protocol),
family_(family)
{
}
int protocol_;
int family_;
};
} // namespace ip
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IP_ICMP_HPP

View File

@ -0,0 +1,265 @@
//
// basic_endpoint.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Derived from a public domain implementation written by Daniel Casimiro.
//
// 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_LOCAL_BASIC_ENDPOINT_HPP
#define ASIO_LOCAL_BASIC_ENDPOINT_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 <cstddef>
#include <cstring>
#include <ostream>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/throw_error.hpp"
#if !defined(ASIO_DISABLE_LOCAL_SOCKETS)
# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# define ASIO_HAS_LOCAL_SOCKETS 1
# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS)
#if defined(ASIO_HAS_LOCAL_SOCKETS) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace local {
/// Describes an endpoint for a UNIX socket.
/**
* The asio::local::basic_endpoint class template describes an endpoint
* that may be associated with a particular UNIX socket.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* Endpoint.
*/
template <typename Protocol>
class basic_endpoint
{
public:
/// The protocol type associated with the endpoint.
typedef Protocol protocol_type;
/// The type of the endpoint structure. This type is dependent on the
/// underlying implementation of the socket layer.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined data_type;
#else
typedef asio::detail::socket_addr_type data_type;
#endif
/// Default constructor.
basic_endpoint()
{
init("", 0);
}
/// Construct an endpoint using the specified path name.
basic_endpoint(const char* path)
{
using namespace std; // For strlen.
init(path, strlen(path));
}
/// Construct an endpoint using the specified path name.
basic_endpoint(const std::string& path)
{
init(path.data(), path.length());
}
/// Copy constructor.
basic_endpoint(const basic_endpoint& other)
: data_(other.data_),
path_length_(other.path_length_)
{
}
/// Assign from another endpoint.
basic_endpoint& operator=(const basic_endpoint& other)
{
data_ = other.data_;
path_length_ = other.path_length_;
return *this;
}
/// The protocol associated with the endpoint.
protocol_type protocol() const
{
return protocol_type();
}
/// Get the underlying endpoint in the native type.
data_type* data()
{
return &data_.base;
}
/// Get the underlying endpoint in the native type.
const data_type* data() const
{
return &data_.base;
}
/// Get the underlying size of the endpoint in the native type.
std::size_t size() const
{
return path_length_
+ offsetof(asio::detail::sockaddr_un_type, sun_path);
}
/// Set the underlying size of the endpoint in the native type.
void resize(std::size_t size)
{
if (size > sizeof(asio::detail::sockaddr_un_type))
{
asio::system_error e(asio::error::invalid_argument);
boost::throw_exception(e);
}
else if (size == 0)
{
path_length_ = 0;
}
else
{
path_length_ = size
- offsetof(asio::detail::sockaddr_un_type, sun_path);
// The path returned by the operating system may be NUL-terminated.
if (path_length_ > 0 && data_.local.sun_path[path_length_] == 0)
--path_length_;
}
}
/// Get the capacity of the endpoint in the native type.
std::size_t capacity() const
{
return sizeof(asio::detail::sockaddr_un_type);
}
/// Get the path associated with the endpoint.
std::string path() const
{
return std::string(data_.local.sun_path, path_length_);
}
/// Set the path associated with the endpoint.
void path(const char* p)
{
using namespace std; // For strlen.
init(p, strlen(p));
}
/// Set the path associated with the endpoint.
void path(const std::string& p)
{
init(p.data(), p.length());
}
/// Compare two endpoints for equality.
friend bool operator==(const basic_endpoint<Protocol>& e1,
const basic_endpoint<Protocol>& e2)
{
return e1.path() == e2.path();
}
/// Compare two endpoints for inequality.
friend bool operator!=(const basic_endpoint<Protocol>& e1,
const basic_endpoint<Protocol>& e2)
{
return e1.path() != e2.path();
}
/// Compare endpoints for ordering.
friend bool operator<(const basic_endpoint<Protocol>& e1,
const basic_endpoint<Protocol>& e2)
{
return e1.path() < e2.path();
}
private:
// The underlying UNIX socket address.
union data_union
{
asio::detail::socket_addr_type base;
asio::detail::sockaddr_un_type local;
} data_;
// The length of the path associated with the endpoint.
std::size_t path_length_;
// Initialise with a specified path.
void init(const char* path, std::size_t path_length)
{
if (path_length > sizeof(data_.local.sun_path) - 1)
{
// The buffer is not large enough to store this address.
asio::error_code ec(asio::error::name_too_long);
asio::detail::throw_error(ec);
}
using namespace std; // For memcpy.
data_.local = asio::detail::sockaddr_un_type();
data_.local.sun_family = AF_UNIX;
memcpy(data_.local.sun_path, path, path_length);
path_length_ = path_length;
// NUL-terminate normal path names. Names that start with a NUL are in the
// UNIX domain protocol's "abstract namespace" and are not NUL-terminated.
if (path_length > 0 && data_.local.sun_path[0] == 0)
data_.local.sun_path[path_length] = 0;
}
};
/// Output an endpoint as a string.
/**
* Used to output a human-readable string for a specified endpoint.
*
* @param os The output stream to which the string will be written.
*
* @param endpoint The endpoint to be written.
*
* @return The output stream.
*
* @relates asio::local::basic_endpoint
*/
template <typename Elem, typename Traits, typename Protocol>
std::basic_ostream<Elem, Traits>& operator<<(
std::basic_ostream<Elem, Traits>& os,
const basic_endpoint<Protocol>& endpoint)
{
os << endpoint.path();
return os;
}
} // namespace local
} // namespace asio
#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_LOCAL_BASIC_ENDPOINT_HPP

View File

@ -0,0 +1,100 @@
//
// connect_pair.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_LOCAL_CONNECT_PAIR_HPP
#define ASIO_LOCAL_CONNECT_PAIR_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_socket.hpp"
#include "asio/error.hpp"
#include "asio/local/basic_endpoint.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/throw_error.hpp"
#if defined(ASIO_HAS_LOCAL_SOCKETS) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace local {
/// Create a pair of connected sockets.
template <typename Protocol, typename SocketService1, typename SocketService2>
void connect_pair(
basic_socket<Protocol, SocketService1>& socket1,
basic_socket<Protocol, SocketService2>& socket2);
/// Create a pair of connected sockets.
template <typename Protocol, typename SocketService1, typename SocketService2>
asio::error_code connect_pair(
basic_socket<Protocol, SocketService1>& socket1,
basic_socket<Protocol, SocketService2>& socket2,
asio::error_code& ec);
template <typename Protocol, typename SocketService1, typename SocketService2>
inline void connect_pair(
basic_socket<Protocol, SocketService1>& socket1,
basic_socket<Protocol, SocketService2>& socket2)
{
asio::error_code ec;
connect_pair(socket1, socket2, ec);
asio::detail::throw_error(ec);
}
template <typename Protocol, typename SocketService1, typename SocketService2>
inline asio::error_code connect_pair(
basic_socket<Protocol, SocketService1>& socket1,
basic_socket<Protocol, SocketService2>& socket2,
asio::error_code& ec)
{
// Check that this function is only being used with a UNIX domain socket.
asio::local::basic_endpoint<Protocol>* tmp
= static_cast<typename Protocol::endpoint*>(0);
(void)tmp;
Protocol protocol;
asio::detail::socket_type sv[2];
if (asio::detail::socket_ops::socketpair(protocol.family(),
protocol.type(), protocol.protocol(), sv, ec)
== asio::detail::socket_error_retval)
return ec;
if (socket1.assign(protocol, sv[0], ec))
{
asio::error_code temp_ec;
asio::detail::socket_ops::close(sv[0], temp_ec);
asio::detail::socket_ops::close(sv[1], temp_ec);
return ec;
}
if (socket2.assign(protocol, sv[1], ec))
{
asio::error_code temp_ec;
socket1.close(temp_ec);
asio::detail::socket_ops::close(sv[1], temp_ec);
return ec;
}
return ec;
}
} // namespace local
} // namespace asio
#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_LOCAL_CONNECT_PAIR_HPP

View File

@ -0,0 +1,78 @@
//
// datagram_protocol.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_LOCAL_DATAGRAM_PROTOCOL_HPP
#define ASIO_LOCAL_DATAGRAM_PROTOCOL_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_datagram_socket.hpp"
#include "asio/local/basic_endpoint.hpp"
#include "asio/detail/socket_types.hpp"
#if defined(ASIO_HAS_LOCAL_SOCKETS) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace local {
/// Encapsulates the flags needed for datagram-oriented UNIX sockets.
/**
* The asio::local::datagram_protocol class contains flags necessary for
* datagram-oriented UNIX domain sockets.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Safe.
*
* @par Concepts:
* Protocol.
*/
class datagram_protocol
{
public:
/// Obtain an identifier for the type of the protocol.
int type() const
{
return SOCK_DGRAM;
}
/// Obtain an identifier for the protocol.
int protocol() const
{
return 0;
}
/// Obtain an identifier for the protocol family.
int family() const
{
return AF_UNIX;
}
/// The type of a UNIX domain endpoint.
typedef basic_endpoint<datagram_protocol> endpoint;
/// The UNIX domain socket type.
typedef basic_datagram_socket<datagram_protocol> socket;
};
} // namespace local
} // namespace asio
#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP

View File

@ -0,0 +1,86 @@
//
// stream_protocol.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_LOCAL_STREAM_PROTOCOL_HPP
#define ASIO_LOCAL_STREAM_PROTOCOL_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_socket_acceptor.hpp"
#include "asio/basic_socket_iostream.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/local/basic_endpoint.hpp"
#include "asio/detail/socket_types.hpp"
#if defined(ASIO_HAS_LOCAL_SOCKETS) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace local {
/// Encapsulates the flags needed for stream-oriented UNIX sockets.
/**
* The asio::local::stream_protocol class contains flags necessary for
* stream-oriented UNIX domain sockets.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Safe.
*
* @par Concepts:
* Protocol.
*/
class stream_protocol
{
public:
/// Obtain an identifier for the type of the protocol.
int type() const
{
return SOCK_STREAM;
}
/// Obtain an identifier for the protocol.
int protocol() const
{
return 0;
}
/// Obtain an identifier for the protocol family.
int family() const
{
return AF_UNIX;
}
/// The type of a UNIX domain endpoint.
typedef basic_endpoint<stream_protocol> endpoint;
/// The UNIX domain socket type.
typedef basic_stream_socket<stream_protocol> socket;
/// The UNIX domain acceptor type.
typedef basic_socket_acceptor<stream_protocol> acceptor;
/// The UNIX domain iostream type.
typedef basic_socket_iostream<stream_protocol> iostream;
};
} // namespace local
} // namespace asio
#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_LOCAL_STREAM_PROTOCOL_HPP

View File

@ -0,0 +1,280 @@
//
// basic_descriptor.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_POSIX_BASIC_DESCRIPTOR_HPP
#define ASIO_POSIX_BASIC_DESCRIPTOR_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/basic_io_object.hpp"
#include "asio/error.hpp"
#include "asio/posix/descriptor_base.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
namespace posix {
/// Provides POSIX descriptor functionality.
/**
* The posix::basic_descriptor class template provides the ability to wrap a
* POSIX descriptor.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename DescriptorService>
class basic_descriptor
: public basic_io_object<DescriptorService>,
public descriptor_base
{
public:
/// The native representation of a descriptor.
typedef typename DescriptorService::native_type native_type;
/// A basic_descriptor is always the lowest layer.
typedef basic_descriptor<DescriptorService> lowest_layer_type;
/// Construct a basic_descriptor without opening it.
/**
* This constructor creates a descriptor without opening it.
*
* @param io_service The io_service object that the descriptor will use to
* dispatch handlers for any asynchronous operations performed on the
* descriptor.
*/
explicit basic_descriptor(asio::io_service& io_service)
: basic_io_object<DescriptorService>(io_service)
{
}
/// Construct a basic_descriptor on an existing native descriptor.
/**
* This constructor creates a descriptor object to hold an existing native
* descriptor.
*
* @param io_service The io_service object that the descriptor will use to
* dispatch handlers for any asynchronous operations performed on the
* descriptor.
*
* @param native_descriptor A native descriptor.
*
* @throws asio::system_error Thrown on failure.
*/
basic_descriptor(asio::io_service& io_service,
const native_type& native_descriptor)
: basic_io_object<DescriptorService>(io_service)
{
asio::error_code ec;
this->service.assign(this->implementation, native_descriptor, ec);
asio::detail::throw_error(ec);
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_descriptor cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Assign an existing native descriptor to the descriptor.
/*
* This function opens the descriptor to hold an existing native descriptor.
*
* @param native_descriptor A native descriptor.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_type& native_descriptor)
{
asio::error_code ec;
this->service.assign(this->implementation, native_descriptor, ec);
asio::detail::throw_error(ec);
}
/// Assign an existing native descriptor to the descriptor.
/*
* This function opens the descriptor to hold an existing native descriptor.
*
* @param native_descriptor A native descriptor.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code assign(const native_type& native_descriptor,
asio::error_code& ec)
{
return this->service.assign(this->implementation, native_descriptor, ec);
}
/// Determine whether the descriptor is open.
bool is_open() const
{
return this->service.is_open(this->implementation);
}
/// Close the descriptor.
/**
* This function is used to close the descriptor. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @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 descriptor.
/**
* This function is used to close the descriptor. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code close(asio::error_code& ec)
{
return this->service.close(this->implementation, ec);
}
/// Get the native descriptor representation.
/**
* This function may be used to obtain the underlying representation of the
* descriptor. This is intended to allow access to native descriptor
* functionality that is not otherwise provided.
*/
native_type native()
{
return this->service.native(this->implementation);
}
/// Cancel all asynchronous operations associated with the descriptor.
/**
* This function causes all outstanding asynchronous read or write 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 descriptor.
/**
* This function causes all outstanding asynchronous read or write 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);
}
/// Perform an IO control command on the descriptor.
/**
* This function is used to execute an IO control command on the descriptor.
*
* @param command The IO control command to be performed on the descriptor.
*
* @throws asio::system_error Thrown on failure.
*
* @sa IoControlCommand @n
* asio::posix::descriptor_base::bytes_readable @n
* asio::posix::descriptor_base::non_blocking_io
*
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::posix::stream_descriptor descriptor(io_service);
* ...
* asio::posix::stream_descriptor::bytes_readable command;
* descriptor.io_control(command);
* std::size_t bytes_readable = command.get();
* @endcode
*/
template <typename IoControlCommand>
void io_control(IoControlCommand& command)
{
asio::error_code ec;
this->service.io_control(this->implementation, command, ec);
asio::detail::throw_error(ec);
}
/// Perform an IO control command on the descriptor.
/**
* This function is used to execute an IO control command on the descriptor.
*
* @param command The IO control command to be performed on the descriptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa IoControlCommand @n
* asio::posix::descriptor_base::bytes_readable @n
* asio::posix::descriptor_base::non_blocking_io
*
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::posix::stream_descriptor descriptor(io_service);
* ...
* asio::posix::stream_descriptor::bytes_readable command;
* asio::error_code ec;
* descriptor.io_control(command, ec);
* if (ec)
* {
* // An error occurred.
* }
* std::size_t bytes_readable = command.get();
* @endcode
*/
template <typename IoControlCommand>
asio::error_code io_control(IoControlCommand& command,
asio::error_code& ec)
{
return this->service.io_control(this->implementation, command, ec);
}
protected:
/// Protected destructor to prevent deletion through this type.
~basic_descriptor()
{
}
};
} // namespace posix
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP

View File

@ -0,0 +1,304 @@
//
// basic_stream_descriptor.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_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
#define ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_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/posix/basic_descriptor.hpp"
#include "asio/posix/stream_descriptor_service.hpp"
#include "asio/detail/throw_error.hpp"
#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace posix {
/// Provides stream-oriented descriptor functionality.
/**
* The posix::basic_stream_descriptor class template provides asynchronous and
* blocking stream-oriented descriptor functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename StreamDescriptorService = stream_descriptor_service>
class basic_stream_descriptor
: public basic_descriptor<StreamDescriptorService>
{
public:
/// The native representation of a descriptor.
typedef typename StreamDescriptorService::native_type native_type;
/// Construct a basic_stream_descriptor without opening it.
/**
* This constructor creates a stream descriptor without opening it. The
* descriptor 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 descriptor will
* use to dispatch handlers for any asynchronous operations performed on the
* descriptor.
*/
explicit basic_stream_descriptor(asio::io_service& io_service)
: basic_descriptor<StreamDescriptorService>(io_service)
{
}
/// Construct a basic_stream_descriptor on an existing native descriptor.
/**
* This constructor creates a stream descriptor object to hold an existing
* native descriptor.
*
* @param io_service The io_service object that the stream descriptor will
* use to dispatch handlers for any asynchronous operations performed on the
* descriptor.
*
* @param native_descriptor The new underlying descriptor implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_descriptor(asio::io_service& io_service,
const native_type& native_descriptor)
: basic_descriptor<StreamDescriptorService>(io_service, native_descriptor)
{
}
/// Write some data to the descriptor.
/**
* This function is used to write data to the stream descriptor. 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 descriptor.
*
* @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
* descriptor.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.write_some(this->implementation, buffers, ec);
asio::detail::throw_error(ec);
return s;
}
/// Write some data to the descriptor.
/**
* This function is used to write data to the stream descriptor. 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 descriptor.
*
* @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.write_some(this->implementation, buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the stream
* descriptor. The function call always returns immediately.
*
* @param buffers One or more data buffers to be written to the descriptor.
* 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
* descriptor.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_write_some(this->implementation, buffers, handler);
}
/// Read some data from the descriptor.
/**
* This function is used to read data from the stream descriptor. 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
* descriptor.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.read_some(this->implementation, buffers, ec);
asio::detail::throw_error(ec);
return s;
}
/// Read some data from the descriptor.
/**
* This function is used to read data from the stream descriptor. 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.read_some(this->implementation, buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the stream
* descriptor. 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
* descriptor.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_read_some(this->implementation, buffers, handler);
}
};
} // namespace posix
} // namespace asio
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP

View File

@ -0,0 +1,93 @@
//
// descriptor_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_POSIX_DESCRIPTOR_BASE_HPP
#define ASIO_POSIX_DESCRIPTOR_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/push_options.hpp"
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/io_control.hpp"
#include "asio/detail/socket_option.hpp"
namespace asio {
namespace posix {
/// The descriptor_base class is used as a base for the basic_stream_descriptor
/// class template so that we have a common place to define the associated
/// IO control commands.
class descriptor_base
{
public:
/// IO control command to set the blocking mode of the descriptor.
/**
* Implements the FIONBIO IO control command.
*
* @par Example
* @code
* asio::posix::stream_descriptor descriptor(io_service);
* ...
* asio::descriptor_base::non_blocking_io command(true);
* descriptor.io_control(command);
* @endcode
*
* @par Concepts:
* IoControlCommand.
*/
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined non_blocking_io;
#else
typedef asio::detail::io_control::non_blocking_io non_blocking_io;
#endif
/// IO control command to get the amount of data that can be read without
/// blocking.
/**
* Implements the FIONREAD IO control command.
*
* @par Example
* @code
* asio::posix::stream_descriptor descriptor(io_service);
* ...
* asio::descriptor_base::bytes_readable command(true);
* descriptor.io_control(command);
* std::size_t bytes_readable = command.get();
* @endcode
*
* @par Concepts:
* IoControlCommand.
*/
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined bytes_readable;
#else
typedef asio::detail::io_control::bytes_readable bytes_readable;
#endif
protected:
/// Protected destructor to prevent deletion through this type.
~descriptor_base()
{
}
};
} // namespace posix
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_POSIX_DESCRIPTOR_BASE_HPP

View File

@ -0,0 +1,39 @@
//
// stream_descriptor.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_POSIX_STREAM_DESCRIPTOR_HPP
#define ASIO_POSIX_STREAM_DESCRIPTOR_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/posix/basic_stream_descriptor.hpp"
#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace posix {
/// Typedef for the typical usage of a stream-oriented descriptor.
typedef basic_stream_descriptor<> stream_descriptor;
} // namespace posix
} // namespace asio
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_POSIX_STREAM_DESCRIPTOR_HPP

View File

@ -0,0 +1,200 @@
//
// stream_descriptor_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_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP
#define ASIO_POSIX_STREAM_DESCRIPTOR_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_descriptor_service.hpp"
#if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1
# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace posix {
/// Default service implementation for a stream descriptor.
class stream_descriptor_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_service::service
#else
: public asio::detail::service_base<stream_descriptor_service>
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_service::id id;
#endif
private:
// The type of the platform-specific implementation.
#if defined(ASIO_HAS_EPOLL)
typedef detail::reactive_descriptor_service<
detail::epoll_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::reactive_descriptor_service<
detail::kqueue_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_DEV_POLL)
typedef detail::reactive_descriptor_service<
detail::dev_poll_reactor<false> > service_impl_type;
#else
typedef detail::reactive_descriptor_service<
detail::select_reactor<false> > service_impl_type;
#endif
public:
/// The type of a stream descriptor implementation.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef service_impl_type::implementation_type implementation_type;
#endif
/// The native descriptor type.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_type;
#else
typedef service_impl_type::native_type native_type;
#endif
/// Construct a new stream descriptor service for the specified io_service.
explicit stream_descriptor_service(asio::io_service& io_service)
: asio::detail::service_base<stream_descriptor_service>(io_service),
service_impl_(asio::use_service<service_impl_type>(io_service))
{
}
/// Destroy all user-defined descriptorr objects owned by the service.
void shutdown_service()
{
}
/// Construct a new stream descriptor implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}
/// Destroy a stream descriptor implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}
/// Assign an existing native descriptor to a stream descriptor.
asio::error_code assign(implementation_type& impl,
const native_type& native_descriptor, asio::error_code& ec)
{
return service_impl_.assign(impl, native_descriptor, ec);
}
/// Determine whether the descriptor is open.
bool is_open(const implementation_type& impl) const
{
return service_impl_.is_open(impl);
}
/// Close a stream descriptor implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.close(impl, ec);
}
/// Get the native descriptor implementation.
native_type native(implementation_type& impl)
{
return service_impl_.native(impl);
}
/// Cancel all asynchronous operations associated with the descriptor.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}
/// Perform an IO control command on the descriptor.
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);
}
/// Write the given data to the stream.
template <typename ConstBufferSequence>
std::size_t write_some(implementation_type& impl,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return service_impl_.write_some(impl, buffers, ec);
}
/// Start an asynchronous write.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, WriteHandler descriptorr)
{
service_impl_.async_write_some(impl, buffers, descriptorr);
}
/// Read some data from the stream.
template <typename MutableBufferSequence>
std::size_t read_some(implementation_type& impl,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return service_impl_.read_some(impl, buffers, ec);
}
/// Start an asynchronous read.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, ReadHandler descriptorr)
{
service_impl_.async_read_some(impl, buffers, descriptorr);
}
private:
// The service that provides the platform-specific implementation.
service_impl_type& service_impl_;
};
} // namespace posix
} // namespace asio
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP

View File

@ -0,0 +1,323 @@
//
// raw_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_RAW_SOCKET_SERVICE_HPP
#define ASIO_RAW_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 raw socket.
template <typename Protocol>
class raw_socket_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_service::service
#else
: public asio::detail::service_base<raw_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 raw 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 raw socket service for the specified io_service.
explicit raw_socket_service(asio::io_service& io_service)
: asio::detail::service_base<
raw_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 raw socket implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}
/// Destroy a raw socket implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}
// Open a new raw socket implementation.
asio::error_code open(implementation_type& impl,
const protocol_type& protocol, asio::error_code& ec)
{
if (protocol.type() == SOCK_RAW)
service_impl_.open(impl, protocol, ec);
else
ec = asio::error::invalid_argument;
return ec;
}
/// Assign an existing native socket to a raw 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 raw 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 raw 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 raw 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 raw data 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 raw data 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_RAW_SOCKET_SERVICE_HPP

View File

@ -29,6 +29,9 @@ namespace asio {
/**
* @defgroup read asio::read
*
* @brief Attempt to read a certain amount of data from a stream before
* returning.
*/
/*@{*/
@ -269,6 +272,9 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
/*@}*/
/**
* @defgroup async_read asio::async_read
*
* @brief Start an asynchronous operation to read a certain amount of data from
* a stream.
*/
/*@{*/

View File

@ -0,0 +1,568 @@
//
// read_at.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_READ_AT_HPP
#define ASIO_READ_AT_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/cstdint.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_streambuf.hpp"
#include "asio/error.hpp"
namespace asio {
/**
* @defgroup read_at asio::read_at
*
* @brief Attempt to read a certain amount of data at the specified offset
* before returning.
*/
/*@{*/
/// Attempt to read a certain amount of data at the specified offset before
/// returning.
/**
* This function is used to read a certain number of bytes of data from a
* random access device at the specified offset. The call will block until one
* of the following conditions is true:
*
* @li The supplied buffers are full. That is, the bytes transferred is equal to
* the sum of the buffer sizes.
*
* @li An error occurred.
*
* This operation is implemented in terms of one or more calls to the device's
* read_some_at function.
*
* @param d The device from which the data is to be read. The type must support
* the SyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read. The sum
* of the buffer sizes indicates the maximum number of bytes to read from the
* device.
*
* @returns The number of bytes transferred.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code asio::read_at(d, 42, 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.
*
* @note This overload is equivalent to calling:
* @code asio::read_at(
* d, 42, buffers,
* asio::transfer_all()); @endcode
*/
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers);
/// Attempt to read a certain amount of data at the specified offset before
/// returning.
/**
* This function is used to read a certain number of bytes of data from a
* random access device at the specified offset. The call will block until one
* of the following conditions is true:
*
* @li The supplied buffers are full. That is, the bytes transferred is equal to
* the sum of the buffer sizes.
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* read_some_at function.
*
* @param d The device from which the data is to be read. The type must support
* the SyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read. The sum
* of the buffer sizes indicates the maximum number of bytes to read from the
* device.
*
* @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the read operation is complete. False
* indicates that further calls to the device's read_some_at function are
* required.
*
* @returns The number of bytes transferred.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code asio::read_at(d, 42, asio::buffer(data, size),
* asio::transfer_at_least(32)); @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 SyncRandomAccessReadDevice, typename MutableBufferSequence,
typename CompletionCondition>
std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition);
/// Attempt to read a certain amount of data at the specified offset before
/// returning.
/**
* This function is used to read a certain number of bytes of data from a
* random access device at the specified offset. The call will block until one
* of the following conditions is true:
*
* @li The supplied buffers are full. That is, the bytes transferred is equal to
* the sum of the buffer sizes.
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* read_some_at function.
*
* @param d The device from which the data is to be read. The type must support
* the SyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read. The sum
* of the buffer sizes indicates the maximum number of bytes to read from the
* device.
*
* @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* const asio::error_code& error, // Result of latest read_some_at
* // operation.
*
* std::size_t bytes_transferred // Number of bytes transferred
* // so far.
* ); @endcode
* A return value of true indicates that the read operation is complete. False
* indicates that further calls to the device's read_some_at function are
* required.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. If an error occurs, returns the total
* number of bytes successfully transferred prior to the error.
*/
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
typename CompletionCondition>
std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec);
/// Attempt to read a certain amount of data at the specified offset before
/// returning.
/**
* This function is used to read a certain number of bytes of data from a
* random access device at the specified offset. The call will block until one
* of the following conditions is true:
*
* @li An error occurred.
*
* This operation is implemented in terms of one or more calls to the device's
* read_some_at function.
*
* @param d The device from which the data is to be read. The type must support
* the SyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param b The basic_streambuf object into which the data will be read.
*
* @returns The number of bytes transferred.
*
* @throws asio::system_error Thrown on failure.
*
* @note This overload is equivalent to calling:
* @code asio::read_at(
* d, 42, b,
* asio::transfer_all()); @endcode
*/
template <typename SyncRandomAccessReadDevice, typename Allocator>
std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, basic_streambuf<Allocator>& b);
/// Attempt to read a certain amount of data at the specified offset before
/// returning.
/**
* This function is used to read a certain number of bytes of data from a
* random access device at the specified offset. The call will block until one
* of the following conditions is true:
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* read_some_at function.
*
* @param d The device from which the data is to be read. The type must support
* the SyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param b The basic_streambuf object into which the data will be read.
*
* @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the read operation is complete. False
* indicates that further calls to the device's read_some_at function are
* required.
*
* @returns The number of bytes transferred.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename SyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition>
std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, basic_streambuf<Allocator>& b,
CompletionCondition completion_condition);
/// Attempt to read a certain amount of data at the specified offset before
/// returning.
/**
* This function is used to read a certain number of bytes of data from a
* random access device at the specified offset. The call will block until one
* of the following conditions is true:
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* read_some_at function.
*
* @param d The device from which the data is to be read. The type must support
* the SyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param b The basic_streambuf object into which the data will be read.
*
* @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the read operation is complete. False
* indicates that further calls to the device's read_some_at function are
* required.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. If an error occurs, returns the total
* number of bytes successfully transferred prior to the error.
*/
template <typename SyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition>
std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, asio::error_code& ec);
/*@}*/
/**
* @defgroup async_read_at asio::async_read_at
*
* @brief Start an asynchronous operation to read a certain amount of data at
* the specified offset.
*/
/*@{*/
/// Start an asynchronous operation to read a certain amount of data at the
/// specified offset.
/**
* This function is used to asynchronously read a certain number of bytes of
* data from a random access device at the specified offset. The function call
* always returns immediately. The asynchronous operation will continue until
* one of the following conditions is true:
*
* @li The supplied buffers are full. That is, the bytes transferred is equal to
* the sum of the buffer sizes.
*
* @li An error occurred.
*
* This operation is implemented in terms of one or more calls to the device's
* async_read_some_at function.
*
* @param d The device from which the data is to be read. The type must support
* the AsyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read. The sum
* of the buffer sizes indicates the maximum number of bytes to read from the
* device. 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(
* // Result of operation.
* const asio::error_code& error,
*
* // Number of bytes copied into the buffers. If an error
* // occurred, this will be the number of bytes successfully
* // transferred prior to the error.
* std::size_t bytes_transferred
* ); @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 read into a single data buffer use the @ref buffer function as follows:
* @code
* asio::async_read_at(d, 42, 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.
*
* @note This overload is equivalent to calling:
* @code asio::async_read_at(
* d, 42, buffers,
* asio::transfer_all(),
* handler); @endcode
*/
template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
typename ReadHandler>
void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset,
const MutableBufferSequence& buffers, ReadHandler handler);
/// Start an asynchronous operation to read a certain amount of data at the
/// specified offset.
/**
* This function is used to asynchronously read a certain number of bytes of
* data from a random access device at the specified offset. The function call
* always returns immediately. The asynchronous operation will continue until
* one of the following conditions is true:
*
* @li The supplied buffers are full. That is, the bytes transferred is equal to
* the sum of the buffer sizes.
*
* @li The completion_condition function object returns true.
*
* @param d The device from which the data is to be read. The type must support
* the AsyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read. The sum
* of the buffer sizes indicates the maximum number of bytes to read from the
* device. 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 completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the read operation is complete. False
* indicates that further calls to the device's async_read_some_at function are
* required.
*
* @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(
* // Result of operation.
* const asio::error_code& error,
*
* // Number of bytes copied into the buffers. If an error
* // occurred, this will be the number of bytes successfully
* // transferred prior to the error.
* std::size_t bytes_transferred
* ); @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 read into a single data buffer use the @ref buffer function as follows:
* @code asio::async_read_at(d, 42,
* asio::buffer(data, size),
* asio::transfer_at_least(32),
* 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 AsyncRandomAccessReadDevice, typename MutableBufferSequence,
typename CompletionCondition, typename ReadHandler>
void async_read_at(AsyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, ReadHandler handler);
/// Start an asynchronous operation to read a certain amount of data at the
/// specified offset.
/**
* This function is used to asynchronously read a certain number of bytes of
* data from a random access device at the specified offset. The function call
* always returns immediately. The asynchronous operation will continue until
* one of the following conditions is true:
*
* @li An error occurred.
*
* This operation is implemented in terms of one or more calls to the device's
* async_read_some_at function.
*
* @param d The device from which the data is to be read. The type must support
* the AsyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param b A basic_streambuf object into which the data will be read. Ownership
* of the streambuf is retained by the caller, which must guarantee that it
* remains 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(
* // Result of operation.
* const asio::error_code& error,
*
* // Number of bytes copied into the buffers. If an error
* // occurred, this will be the number of bytes successfully
* // transferred prior to the error.
* std::size_t bytes_transferred
* ); @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 This overload is equivalent to calling:
* @code asio::async_read_at(
* d, 42, b,
* asio::transfer_all(),
* handler); @endcode
*/
template <typename AsyncRandomAccessReadDevice, typename Allocator,
typename ReadHandler>
void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset,
basic_streambuf<Allocator>& b, ReadHandler handler);
/// Start an asynchronous operation to read a certain amount of data at the
/// specified offset.
/**
* This function is used to asynchronously read a certain number of bytes of
* data from a random access device at the specified offset. The function call
* always returns immediately. The asynchronous operation will continue until
* one of the following conditions is true:
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* async_read_some_at function.
*
* @param d The device from which the data is to be read. The type must support
* the AsyncRandomAccessReadDevice concept.
*
* @param offset The offset at which the data will be read.
*
* @param b A basic_streambuf object into which the data will be read. Ownership
* of the streambuf is retained by the caller, which must guarantee that it
* remains valid until the handler is called.
*
* @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the read operation is complete. False
* indicates that further calls to the device's async_read_some_at function are
* required.
*
* @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(
* // Result of operation.
* const asio::error_code& error,
*
* // Number of bytes copied into the buffers. If an error
* // occurred, this will be the number of bytes successfully
* // transferred prior to the error.
* std::size_t bytes_transferred
* ); @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 AsyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition, typename ReadHandler>
void async_read_at(AsyncRandomAccessReadDevice& d,
boost::uint64_t offset, basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, ReadHandler handler);
/*@}*/
} // namespace asio
#include "asio/impl/read_at.ipp"
#include "asio/detail/pop_options.hpp"
#endif // ASIO_READ_AT_HPP

View File

@ -21,6 +21,9 @@
#include <cstddef>
#include <boost/config.hpp>
#include <boost/regex.hpp>
#include <boost/type_traits/is_function.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/utility/enable_if.hpp>
#include <string>
#include "asio/detail/pop_options.hpp"
@ -29,12 +32,45 @@
namespace asio {
namespace detail
{
template <typename T>
struct has_result_type
{
struct big { char a[100]; };
template <typename U> static big helper(U, ...);
template <typename U> static char helper(U, typename U::result_type* = 0);
static const T& ref();
enum { value = (sizeof((helper)((ref)())) == 1) };
};
} // namespace detail
/// Type trait used to determine whether a type can be used as a match condition
/// function with read_until and async_read_until.
template <typename T>
struct is_match_condition
{
#if defined(GENERATING_DOCUMENTATION)
/// The value member is true if the type may be used as a match condition.
static const bool value;
#else
enum
{
value = boost::is_function<typename boost::remove_pointer<T>::type>::value
|| detail::has_result_type<T>::value
};
#endif
};
/**
* @defgroup read_until asio::read_until
*
* @brief Read data into a streambuf until it contains a delimiter, matches a
* regular expression, or a function object indicates a match.
*/
/*@{*/
/// Read data into a streambuf until a delimiter is encountered.
/// Read data into a streambuf until it contains a specified delimiter.
/**
* This function is used to read data into the specified streambuf until the
* streambuf's get area contains the specified delimiter. The call will block
@ -60,6 +96,10 @@ namespace asio {
*
* @throws asio::system_error Thrown on failure.
*
* @note After a successful read_until operation, the streambuf may contain
* additional data beyond the delimiter. An application will typically leave
* that data in the streambuf for a subsequent read_until operation to examine.
*
* @par Example
* To read data into a streambuf until a newline is encountered:
* @code asio::streambuf b;
@ -72,7 +112,7 @@ template <typename SyncReadStream, typename Allocator>
std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b, char delim);
/// Read data into a streambuf until a delimiter is encountered.
/// Read data into a streambuf until it contains a specified delimiter.
/**
* This function is used to read data into the specified streambuf until the
* streambuf's get area contains the specified delimiter. The call will block
@ -97,13 +137,17 @@ std::size_t read_until(SyncReadStream& s,
*
* @returns The number of bytes in the streambuf's get area up to and including
* the delimiter. Returns 0 if an error occurred.
*
* @note After a successful read_until operation, the streambuf may contain
* additional data beyond the delimiter. An application will typically leave
* that data in the streambuf for a subsequent read_until operation to examine.
*/
template <typename SyncReadStream, typename Allocator>
std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b, char delim,
asio::error_code& ec);
/// Read data into a streambuf until a delimiter is encountered.
/// Read data into a streambuf until it contains a specified delimiter.
/**
* This function is used to read data into the specified streambuf until the
* streambuf's get area contains the specified delimiter. The call will block
@ -129,6 +173,10 @@ std::size_t read_until(SyncReadStream& s,
*
* @throws asio::system_error Thrown on failure.
*
* @note After a successful read_until operation, the streambuf may contain
* additional data beyond the delimiter. An application will typically leave
* that data in the streambuf for a subsequent read_until operation to examine.
*
* @par Example
* To read data into a streambuf until a newline is encountered:
* @code asio::streambuf b;
@ -141,7 +189,7 @@ template <typename SyncReadStream, typename Allocator>
std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b, const std::string& delim);
/// Read data into a streambuf until a delimiter is encountered.
/// Read data into a streambuf until it contains a specified delimiter.
/**
* This function is used to read data into the specified streambuf until the
* streambuf's get area contains the specified delimiter. The call will block
@ -166,13 +214,18 @@ std::size_t read_until(SyncReadStream& s,
*
* @returns The number of bytes in the streambuf's get area up to and including
* the delimiter. Returns 0 if an error occurred.
*
* @note After a successful read_until operation, the streambuf may contain
* additional data beyond the delimiter. An application will typically leave
* that data in the streambuf for a subsequent read_until operation to examine.
*/
template <typename SyncReadStream, typename Allocator>
std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b, const std::string& delim,
asio::error_code& ec);
/// Read data into a streambuf until a regular expression is located.
/// Read data into a streambuf until some part of the data it contains matches
/// a regular expression.
/**
* This function is used to read data into the specified streambuf until the
* streambuf's get area contains some data that matches a regular expression.
@ -198,6 +251,11 @@ std::size_t read_until(SyncReadStream& s,
*
* @throws asio::system_error Thrown on failure.
*
* @note After a successful read_until operation, the streambuf may contain
* additional data beyond that which matched the regular expression. An
* application will typically leave that data in the streambuf for a subsequent
* read_until operation to examine.
*
* @par Example
* To read data into a streambuf until a CR-LF sequence is encountered:
* @code asio::streambuf b;
@ -210,7 +268,8 @@ template <typename SyncReadStream, typename Allocator>
std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b, const boost::regex& expr);
/// Read data into a streambuf until a regular expression is located.
/// Read data into a streambuf until some part of the data it contains matches
/// a regular expression.
/**
* This function is used to read data into the specified streambuf until the
* streambuf's get area contains some data that matches a regular expression.
@ -236,20 +295,189 @@ std::size_t read_until(SyncReadStream& s,
* @returns The number of bytes in the streambuf's get area up to and including
* the substring that matches the regular expression. Returns 0 if an error
* occurred.
*
* @note After a successful read_until operation, the streambuf may contain
* additional data beyond that which matched the regular expression. An
* application will typically leave that data in the streambuf for a subsequent
* read_until operation to examine.
*/
template <typename SyncReadStream, typename Allocator>
std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
asio::error_code& ec);
/// Read data into a streambuf until a function object indicates a match.
/**
* This function is used to read data into the specified streambuf until a
* user-defined match condition function object, when applied to the data
* contained in the streambuf, indicates a successful match. The call will
* block until one of the following conditions is true:
*
* @li The match condition function object returns a std::pair where the second
* element evaluates to true.
*
* @li An error occurred.
*
* This operation is implemented in terms of zero or more calls to the stream's
* read_some function. If the match condition function object already indicates
* a match, the function returns immediately.
*
* @param s The stream from which the data is to be read. The type must support
* the SyncReadStream concept.
*
* @param b A streambuf object into which the data will be read.
*
* @param match_condition The function object to be called to determine whether
* a match exists. The signature of the function object must be:
* @code pair<iterator, bool> match_condition(iterator begin, iterator end);
* @endcode
* where @c iterator represents the type:
* @code buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>
* @endcode
* The iterator parameters @c begin and @c end define the range of bytes to be
* scanned to determine whether there is a match. The @c first member of the
* return value is an iterator marking one-past-the-end of the bytes that have
* been consumed by the match function. This iterator is used to calculate the
* @c begin parameter for any subsequent invocation of the match condition. The
* @c second member of the return value is true if a match has been found, false
* otherwise.
*
* @returns The number of bytes in the streambuf's get area that have been fully
* consumed by the match function.
*
* @throws asio::system_error Thrown on failure.
*
* @note After a successful read_until operation, the streambuf may contain
* additional data beyond that which matched the function object. An application
* will typically leave that data in the streambuf for a subsequent
*
* @note The default implementation of the @c is_match_condition type trait
* evaluates to true for function pointers and function objects with a
* @c result_type typedef. It must be specialised for other user-defined
* function objects.
*
* @par Examples
* To read data into a streambuf until whitespace is encountered:
* @code typedef asio::buffers_iterator<
* asio::streambuf::const_buffers_type> iterator;
*
* std::pair<iterator, bool>
* match_whitespace(iterator begin, iterator end)
* {
* iterator i = begin;
* while (i != end)
* if (std::isspace(*i++))
* return std::make_pair(i, true);
* return std::make_pair(i, false);
* }
* ...
* asio::streambuf b;
* asio::read_until(s, b, match_whitespace);
* @endcode
*
* To read data into a streambuf until a matching character is found:
* @code class match_char
* {
* public:
* explicit match_char(char c) : c_(c) {}
*
* template <typename Iterator>
* std::pair<Iterator, bool> operator()(
* Iterator begin, Iterator end) const
* {
* Iterator i = begin;
* while (i != end)
* if (c_ == *i++)
* return std::make_pair(i, true);
* return std::make_pair(i, false);
* }
*
* private:
* char c_;
* };
*
* namespace asio {
* template <> struct is_match_condition<match_char>
* : public boost::true_type {};
* } // namespace asio
* ...
* asio::streambuf b;
* asio::read_until(s, b, match_char('a'));
* @endcode
*/
template <typename SyncReadStream, typename Allocator, typename MatchCondition>
std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
typename boost::enable_if<is_match_condition<MatchCondition> >::type* = 0);
/// Read data into a streambuf until a function object indicates a match.
/**
* This function is used to read data into the specified streambuf until a
* user-defined match condition function object, when applied to the data
* contained in the streambuf, indicates a successful match. The call will
* block until one of the following conditions is true:
*
* @li The match condition function object returns a std::pair where the second
* element evaluates to true.
*
* @li An error occurred.
*
* This operation is implemented in terms of zero or more calls to the stream's
* read_some function. If the match condition function object already indicates
* a match, the function returns immediately.
*
* @param s The stream from which the data is to be read. The type must support
* the SyncReadStream concept.
*
* @param b A streambuf object into which the data will be read.
*
* @param match_condition The function object to be called to determine whether
* a match exists. The signature of the function object must be:
* @code pair<iterator, bool> match_condition(iterator begin, iterator end);
* @endcode
* where @c iterator represents the type:
* @code buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>
* @endcode
* The iterator parameters @c begin and @c end define the range of bytes to be
* scanned to determine whether there is a match. The @c first member of the
* return value is an iterator marking one-past-the-end of the bytes that have
* been consumed by the match function. This iterator is used to calculate the
* @c begin parameter for any subsequent invocation of the match condition. The
* @c second member of the return value is true if a match has been found, false
* otherwise.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes in the streambuf's get area that have been fully
* consumed by the match function. Returns 0 if an error occurred.
*
* @note After a successful read_until operation, the streambuf may contain
* additional data beyond that which matched the function object. An application
* will typically leave that data in the streambuf for a subsequent
*
* @note The default implementation of the @c is_match_condition type trait
* evaluates to true for function pointers and function objects with a
* @c result_type typedef. It must be specialised for other user-defined
* function objects.
*/
template <typename SyncReadStream, typename Allocator, typename MatchCondition>
std::size_t read_until(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
MatchCondition match_condition, asio::error_code& ec,
typename boost::enable_if<is_match_condition<MatchCondition> >::type* = 0);
/*@}*/
/**
* @defgroup async_read_until asio::async_read_until
*/
* @defgroup async_read_until asio::async_read_until
*
* @brief Start an asynchronous operation to read data into a streambuf until it
* contains a delimiter, matches a regular expression, or a function object
* indicates a match.
*/
/*@{*/
/// Start an asynchronous operation to read data into a streambuf until a
/// delimiter is encountered.
/// Start an asynchronous operation to read data into a streambuf until it
/// contains a specified delimiter.
/**
* This function is used to asynchronously read data into the specified
* streambuf until the streambuf's get area contains the specified delimiter.
@ -277,18 +505,24 @@ std::size_t read_until(SyncReadStream& s,
* 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.
* // Result of operation.
* const asio::error_code& error,
*
* std::size_t bytes_transferred // The number of bytes in the
* // streambuf's get area up to
* // and including the delimiter.
* // 0 if an error occurred.
* // The number of bytes in the streambuf's get
* // area up to and including the delimiter.
* // 0 if an error occurred.
* std::size_t bytes_transferred
* ); @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 After a successful async_read_until operation, the streambuf may
* contain additional data beyond the delimiter. An application will typically
* leave that data in the streambuf for a subsequent async_read_until operation
* to examine.
*
* @par Example
* To asynchronously read data into a streambuf until a newline is encountered:
* @code asio::streambuf b;
@ -311,8 +545,8 @@ void async_read_until(AsyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
char delim, ReadHandler handler);
/// Start an asynchronous operation to read data into a streambuf until a
/// delimiter is encountered.
/// Start an asynchronous operation to read data into a streambuf until it
/// contains a specified delimiter.
/**
* This function is used to asynchronously read data into the specified
* streambuf until the streambuf's get area contains the specified delimiter.
@ -340,18 +574,24 @@ void async_read_until(AsyncReadStream& s,
* 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.
* // Result of operation.
* const asio::error_code& error,
*
* std::size_t bytes_transferred // The number of bytes in the
* // streambuf's get area up to
* // and including the delimiter.
* // 0 if an error occurred.
* // The number of bytes in the streambuf's get
* // area up to and including the delimiter.
* // 0 if an error occurred.
* std::size_t bytes_transferred
* ); @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 After a successful async_read_until operation, the streambuf may
* contain additional data beyond the delimiter. An application will typically
* leave that data in the streambuf for a subsequent async_read_until operation
* to examine.
*
* @par Example
* To asynchronously read data into a streambuf until a newline is encountered:
* @code asio::streambuf b;
@ -374,8 +614,8 @@ void async_read_until(AsyncReadStream& s,
asio::basic_streambuf<Allocator>& b, const std::string& delim,
ReadHandler handler);
/// Start an asynchronous operation to read data into a streambuf until a
/// regular expression is located.
/// Start an asynchronous operation to read data into a streambuf until some
/// part of its data matches a regular expression.
/**
* This function is used to asynchronously read data into the specified
* streambuf until the streambuf's get area contains some data that matches a
@ -404,20 +644,25 @@ void async_read_until(AsyncReadStream& s,
* 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.
* // Result of operation.
* const asio::error_code& error,
*
* std::size_t bytes_transferred // The number of bytes in the
* // streambuf's get area up to
* // and including the substring
* // that matches the regular.
* // expression. 0 if an error
* // occurred.
* // The number of bytes in the streambuf's get
* // area up to and including the substring
* // that matches the regular. expression.
* // 0 if an error occurred.
* std::size_t bytes_transferred
* ); @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 After a successful async_read_until operation, the streambuf may
* contain additional data beyond that which matched the regular expression. An
* application will typically leave that data in the streambuf for a subsequent
* async_read_until operation to examine.
*
* @par Example
* To asynchronously read data into a streambuf until a CR-LF sequence is
* encountered:
@ -441,6 +686,132 @@ void async_read_until(AsyncReadStream& s,
asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
ReadHandler handler);
/// Start an asynchronous operation to read data into a streambuf until a
/// function object indicates a match.
/**
* This function is used to asynchronously read data into the specified
* streambuf until a user-defined match condition function object, when applied
* to the data contained in the streambuf, indicates a successful match. The
* function call always returns immediately. The asynchronous operation will
* continue until one of the following conditions is true:
*
* @li The match condition function object returns a std::pair where the second
* element evaluates to true.
*
* @li An error occurred.
*
* This operation is implemented in terms of zero or more calls to the stream's
* async_read_some function. If the match condition function object already
* indicates a match, the operation completes immediately.
*
* @param s The stream from which the data is to be read. The type must support
* the AsyncReadStream concept.
*
* @param b A streambuf object into which the data will be read.
*
* @param match_condition The function object to be called to determine whether
* a match exists. The signature of the function object must be:
* @code pair<iterator, bool> match_condition(iterator begin, iterator end);
* @endcode
* where @c iterator represents the type:
* @code buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>
* @endcode
* The iterator parameters @c begin and @c end define the range of bytes to be
* scanned to determine whether there is a match. The @c first member of the
* return value is an iterator marking one-past-the-end of the bytes that have
* been consumed by the match function. This iterator is used to calculate the
* @c begin parameter for any subsequent invocation of the match condition. The
* @c second member of the return value is true if a match has been found, false
* otherwise.
*
* @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(
* // Result of operation.
* const asio::error_code& error,
*
* // The number of bytes in the streambuf's get
* // area that have been fully consumed by the
* // match function. O if an error occurred.
* std::size_t bytes_transferred
* ); @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 After a successful async_read_until operation, the streambuf may
* contain additional data beyond that which matched the function object. An
* application will typically leave that data in the streambuf for a subsequent
* async_read_until operation to examine.
*
* @note The default implementation of the @c is_match_condition type trait
* evaluates to true for function pointers and function objects with a
* @c result_type typedef. It must be specialised for other user-defined
* function objects.
*
* @par Examples
* To asynchronously read data into a streambuf until whitespace is encountered:
* @code typedef asio::buffers_iterator<
* asio::streambuf::const_buffers_type> iterator;
*
* std::pair<iterator, bool>
* match_whitespace(iterator begin, iterator end)
* {
* iterator i = begin;
* while (i != end)
* if (std::isspace(*i++))
* return std::make_pair(i, true);
* return std::make_pair(i, false);
* }
* ...
* void handler(const asio::error_code& e, std::size_t size);
* ...
* asio::streambuf b;
* asio::async_read_until(s, b, match_whitespace, handler);
* @endcode
*
* To asynchronously read data into a streambuf until a matching character is
* found:
* @code class match_char
* {
* public:
* explicit match_char(char c) : c_(c) {}
*
* template <typename Iterator>
* std::pair<Iterator, bool> operator()(
* Iterator begin, Iterator end) const
* {
* Iterator i = begin;
* while (i != end)
* if (c_ == *i++)
* return std::make_pair(i, true);
* return std::make_pair(i, false);
* }
*
* private:
* char c_;
* };
*
* namespace asio {
* template <> struct is_match_condition<match_char>
* : public boost::true_type {};
* } // namespace asio
* ...
* void handler(const asio::error_code& e, std::size_t size);
* ...
* asio::streambuf b;
* asio::async_read_until(s, b, match_char('a'), handler);
* @endcode
*/
template <typename AsyncReadStream, typename Allocator,
typename MatchCondition, typename ReadHandler>
void async_read_until(AsyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
MatchCondition match_condition, ReadHandler handler,
typename boost::enable_if<is_match_condition<MatchCondition> >::type* = 0);
/*@}*/
} // namespace asio

View File

@ -0,0 +1,38 @@
//
// serial_port.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_SERIAL_PORT_HPP
#define ASIO_SERIAL_PORT_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_serial_port.hpp"
#if defined(ASIO_HAS_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
/// Typedef for the typical usage of a serial port.
typedef basic_serial_port<> serial_port;
} // namespace asio
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_SERIAL_PORT_HPP

View File

@ -0,0 +1,157 @@
//
// serial_port_base.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_SERIAL_PORT_BASE_HPP
#define ASIO_SERIAL_PORT_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/push_options.hpp"
#include <stdexcept>
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# include <termios.h>
#endif
#include "asio/detail/pop_options.hpp"
#include "asio/error_code.hpp"
#include "asio/detail/socket_types.hpp"
#if defined(GENERATING_DOCUMENTATION)
# define ASIO_OPTION_STORAGE implementation_defined
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# define ASIO_OPTION_STORAGE DCB
#else
# define ASIO_OPTION_STORAGE termios
#endif
namespace asio {
/// The serial_port_base class is used as a base for the basic_serial_port class
/// template so that we have a common place to define the serial port options.
class serial_port_base
{
public:
/// Serial port option to permit changing the baud rate.
/**
* Implements changing the baud rate for a given serial port.
*/
class baud_rate
{
public:
explicit baud_rate(unsigned int rate = 0);
unsigned int value() const;
asio::error_code store(ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
asio::error_code load(const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
unsigned int value_;
};
/// Serial port option to permit changing the flow control.
/**
* Implements changing the flow control for a given serial port.
*/
class flow_control
{
public:
enum type { none, software, hardware };
explicit flow_control(type t = none);
type value() const;
asio::error_code store(ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
asio::error_code load(const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
type value_;
};
/// Serial port option to permit changing the parity.
/**
* Implements changing the parity for a given serial port.
*/
class parity
{
public:
enum type { none, odd, even };
explicit parity(type t = none);
type value() const;
asio::error_code store(ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
asio::error_code load(const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
type value_;
};
/// Serial port option to permit changing the number of stop bits.
/**
* Implements changing the number of stop bits for a given serial port.
*/
class stop_bits
{
public:
enum type { one, onepointfive, two };
explicit stop_bits(type t = one);
type value() const;
asio::error_code store(ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
asio::error_code load(const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
type value_;
};
/// Serial port option to permit changing the character size.
/**
* Implements changing the character size for a given serial port.
*/
class character_size
{
public:
explicit character_size(unsigned int t = 8);
unsigned int value() const;
asio::error_code store(ASIO_OPTION_STORAGE& storage,
asio::error_code& ec) const;
asio::error_code load(const ASIO_OPTION_STORAGE& storage,
asio::error_code& ec);
private:
unsigned int value_;
};
protected:
/// Protected destructor to prevent deletion through this type.
~serial_port_base()
{
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
private:
// Workaround to enable the empty base optimisation with Borland C++.
char dummy_;
#endif
};
} // namespace asio
#include "asio/impl/serial_port_base.ipp"
#undef ASIO_OPTION_STORAGE
#include "asio/detail/pop_options.hpp"
#endif // ASIO_SERIAL_PORT_BASE_HPP

View File

@ -0,0 +1,222 @@
//
// serial_port_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_SERIAL_PORT_SERVICE_HPP
#define ASIO_SERIAL_PORT_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 <string>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/reactive_serial_port_service.hpp"
#include "asio/detail/win_iocp_serial_port_service.hpp"
#if !defined(ASIO_DISABLE_SERIAL_PORT)
# if defined(ASIO_HAS_IOCP) \
|| !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# define ASIO_HAS_SERIAL_PORT 1
# endif // defined(ASIO_HAS_IOCP)
#endif // !defined(ASIO_DISABLE_STREAM_HANDLE)
#if defined(ASIO_HAS_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
/// Default service implementation for a serial port.
class serial_port_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_service::service
#else
: public asio::detail::service_base<serial_port_service>
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_service::id id;
#endif
private:
// The type of the platform-specific implementation.
#if defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_serial_port_service service_impl_type;
#elif defined(ASIO_HAS_EPOLL)
typedef detail::reactive_serial_port_service<
detail::epoll_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::reactive_serial_port_service<
detail::kqueue_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_DEV_POLL)
typedef detail::reactive_serial_port_service<
detail::dev_poll_reactor<false> > service_impl_type;
#else
typedef detail::reactive_serial_port_service<
detail::select_reactor<false> > service_impl_type;
#endif
public:
/// The type of a serial port implementation.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef service_impl_type::implementation_type implementation_type;
#endif
/// The native handle type.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_type;
#else
typedef service_impl_type::native_type native_type;
#endif
/// Construct a new serial port service for the specified io_service.
explicit serial_port_service(asio::io_service& io_service)
: asio::detail::service_base<serial_port_service>(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 serial port implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}
/// Destroy a serial port implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}
/// Open a serial port.
asio::error_code open(implementation_type& impl,
const std::string& device, asio::error_code& ec)
{
return service_impl_.open(impl, device, ec);
}
/// Assign an existing native handle to a serial port.
asio::error_code assign(implementation_type& impl,
const native_type& native_handle, asio::error_code& ec)
{
return service_impl_.assign(impl, native_handle, ec);
}
/// Determine whether the handle is open.
bool is_open(const implementation_type& impl) const
{
return service_impl_.is_open(impl);
}
/// Close a serial port implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.close(impl, ec);
}
/// Get the native handle implementation.
native_type native(implementation_type& impl)
{
return service_impl_.native(impl);
}
/// Cancel all asynchronous operations associated with the handle.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}
/// Set a serial port option.
template <typename SettableSerialPortOption>
asio::error_code set_option(implementation_type& impl,
const SettableSerialPortOption& option, asio::error_code& ec)
{
return service_impl_.set_option(impl, option, ec);
}
/// Get a serial port option.
template <typename GettableSerialPortOption>
asio::error_code get_option(const implementation_type& impl,
GettableSerialPortOption& option, asio::error_code& ec) const
{
return service_impl_.get_option(impl, option, ec);
}
/// Send a break sequence to the serial port.
asio::error_code send_break(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.send_break(impl, ec);
}
/// Write the given data to the stream.
template <typename ConstBufferSequence>
std::size_t write_some(implementation_type& impl,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return service_impl_.write_some(impl, buffers, ec);
}
/// Start an asynchronous write.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, WriteHandler handler)
{
service_impl_.async_write_some(impl, buffers, handler);
}
/// Read some data from the stream.
template <typename MutableBufferSequence>
std::size_t read_some(implementation_type& impl,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return service_impl_.read_some(impl, buffers, ec);
}
/// Start an asynchronous read.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, ReadHandler handler)
{
service_impl_.async_read_some(impl, buffers, handler);
}
private:
// The service that provides the platform-specific implementation.
service_impl_type& service_impl_;
};
} // namespace asio
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_SERIAL_PORT_SERVICE_HPP

View File

@ -168,14 +168,11 @@ public:
((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) ==
SSL_SENT_SHUTDOWN);
if (is_shut_down_sent && is_shut_down_received && is_operation_done)
if (is_shut_down_sent && is_shut_down_received && is_operation_done && !is_write_needed)
// SSL connection is shut down cleanly
return handler_(asio::error_code(), 1);
if (is_shut_down_received && !is_write_needed)
return handler_(asio::error::eof, 0);
if (is_shut_down_received)
if (is_shut_down_received && !is_operation_done)
// Shutdown has been requested, while we were reading or writing...
// abort our action...
return handler_(asio::error::shut_down, 0);
@ -225,7 +222,7 @@ public:
return start();
}
else if (is_read_needed)
else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received))
{
return read_();
}

View File

@ -58,7 +58,7 @@ public:
*/
template <typename Function>
explicit thread(Function f)
: impl_(f)
: impl_(f, asio::detail::thread::external)
{
}

View File

@ -18,6 +18,6 @@
// ASIO_VERSION % 100 is the sub-minor version
// ASIO_VERSION / 100 % 1000 is the minor version
// ASIO_VERSION / 100000 is the major version
#define ASIO_VERSION 100000 // 1.0.0
#define ASIO_VERSION 100100 // 1.1.0
#endif // ASIO_VERSION_HPP

View File

@ -0,0 +1,211 @@
//
// basic_handle.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_WINDOWS_BASIC_HANDLE_HPP
#define ASIO_WINDOWS_BASIC_HANDLE_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/basic_io_object.hpp"
#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
namespace windows {
/// Provides Windows handle functionality.
/**
* The windows::basic_handle class template provides the ability to wrap a
* Windows handle.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename HandleService>
class basic_handle
: public basic_io_object<HandleService>
{
public:
/// The native representation of a handle.
typedef typename HandleService::native_type native_type;
/// A basic_handle is always the lowest layer.
typedef basic_handle<HandleService> lowest_layer_type;
/// Construct a basic_handle without opening it.
/**
* This constructor creates a handle without opening it.
*
* @param io_service The io_service object that the handle will use to
* dispatch handlers for any asynchronous operations performed on the handle.
*/
explicit basic_handle(asio::io_service& io_service)
: basic_io_object<HandleService>(io_service)
{
}
/// Construct a basic_handle on an existing native handle.
/**
* This constructor creates a handle object to hold an existing native handle.
*
* @param io_service The io_service object that the handle will use to
* dispatch handlers for any asynchronous operations performed on the handle.
*
* @param native_handle A native handle.
*
* @throws asio::system_error Thrown on failure.
*/
basic_handle(asio::io_service& io_service,
const native_type& native_handle)
: basic_io_object<HandleService>(io_service)
{
asio::error_code ec;
this->service.assign(this->implementation, native_handle, ec);
asio::detail::throw_error(ec);
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_handle cannot contain any further layers, it simply
* returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Assign an existing native handle to the handle.
/*
* This function opens the handle to hold an existing native handle.
*
* @param native_handle A native handle.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_type& native_handle)
{
asio::error_code ec;
this->service.assign(this->implementation, native_handle, ec);
asio::detail::throw_error(ec);
}
/// Assign an existing native handle to the handle.
/*
* This function opens the handle to hold an existing native handle.
*
* @param native_handle A native handle.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code assign(const native_type& native_handle,
asio::error_code& ec)
{
return this->service.assign(this->implementation, native_handle, ec);
}
/// Determine whether the handle is open.
bool is_open() const
{
return this->service.is_open(this->implementation);
}
/// Close the handle.
/**
* This function is used to close the handle. Any asynchronous read or write
* operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @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 handle.
/**
* This function is used to close the handle. Any asynchronous read or write
* operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code close(asio::error_code& ec)
{
return this->service.close(this->implementation, ec);
}
/// Get the native handle representation.
/**
* This function may be used to obtain the underlying representation of the
* handle. This is intended to allow access to native handle functionality
* that is not otherwise provided.
*/
native_type native()
{
return this->service.native(this->implementation);
}
/// Cancel all asynchronous operations associated with the handle.
/**
* This function causes all outstanding asynchronous read or write 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 handle.
/**
* This function causes all outstanding asynchronous read or write 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);
}
protected:
/// Protected destructor to prevent deletion through this type.
~basic_handle()
{
}
};
} // namespace windows
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WINDOWS_BASIC_HANDLE_HPP

View File

@ -0,0 +1,320 @@
//
// basic_random_access_handle.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_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP
#define ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_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/windows/basic_handle.hpp"
#include "asio/windows/random_access_handle_service.hpp"
#include "asio/detail/throw_error.hpp"
#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace windows {
/// Provides random-access handle functionality.
/**
* The windows::basic_random_access_handle class template provides asynchronous
* and blocking random-access handle functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename RandomAccessHandleService = random_access_handle_service>
class basic_random_access_handle
: public basic_handle<RandomAccessHandleService>
{
public:
/// The native representation of a handle.
typedef typename RandomAccessHandleService::native_type native_type;
/// Construct a basic_random_access_handle without opening it.
/**
* This constructor creates a random-access handle without opening it. The
* handle needs to be opened before data can be written to or or read from it.
*
* @param io_service The io_service object that the random-access handle will
* use to dispatch handlers for any asynchronous operations performed on the
* handle.
*/
explicit basic_random_access_handle(asio::io_service& io_service)
: basic_handle<RandomAccessHandleService>(io_service)
{
}
/// Construct a basic_random_access_handle on an existing native handle.
/**
* This constructor creates a random-access handle object to hold an existing
* native handle.
*
* @param io_service The io_service object that the random-access handle will
* use to dispatch handlers for any asynchronous operations performed on the
* handle.
*
* @param native_handle The new underlying handle implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_random_access_handle(asio::io_service& io_service,
const native_type& native_handle)
: basic_handle<RandomAccessHandleService>(io_service, native_handle)
{
}
/// Write some data to the handle at the specified offset.
/**
* This function is used to write data to the random-access handle. The
* function call will block until one or more bytes of the data has been
* written successfully, or until an error occurs.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
*
* @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_at operation may not write all of the data. Consider
* using the @ref write_at 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
* handle.write_some_at(42, 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_at(boost::uint64_t offset,
const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.write_some_at(
this->implementation, offset, buffers, ec);
asio::detail::throw_error(ec);
return s;
}
/// Write some data to the handle at the specified offset.
/**
* This function is used to write data to the random-access handle. The
* function call will block until one or more bytes of the data has been
* written successfully, or until an error occurs.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
*
* @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_at function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some_at(boost::uint64_t offset,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return this->service.write_some_at(
this->implementation, offset, buffers, ec);
}
/// Start an asynchronous write at the specified offset.
/**
* This function is used to asynchronously write data to the random-access
* handle. The function call always returns immediately.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
* 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_at 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
* handle.async_write_some_at(42, 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_at(boost::uint64_t offset,
const ConstBufferSequence& buffers, WriteHandler handler)
{
this->service.async_write_some_at(
this->implementation, offset, buffers, handler);
}
/// Read some data from the handle at the specified offset.
/**
* This function is used to read data from the random-access handle. The
* function call will block until one or more bytes of data has been read
* successfully, or until an error occurs.
*
* @param offset The offset at which the data will be read.
*
* @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_at 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
* handle.read_some_at(42, 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_at(boost::uint64_t offset,
const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.read_some_at(
this->implementation, offset, buffers, ec);
asio::detail::throw_error(ec);
return s;
}
/// Read some data from the handle at the specified offset.
/**
* This function is used to read data from the random-access handle. The
* function call will block until one or more bytes of data has been read
* successfully, or until an error occurs.
*
* @param offset The offset at which the data will be read.
*
* @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_at 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_at(boost::uint64_t offset,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return this->service.read_some_at(
this->implementation, offset, buffers, ec);
}
/// Start an asynchronous read at the specified offset.
/**
* This function is used to asynchronously read data from the random-access
* handle. The function call always returns immediately.
*
* @param offset The offset at which the data will be read.
*
* @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_at 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
* handle.async_read_some_at(42, 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_at(boost::uint64_t offset,
const MutableBufferSequence& buffers, ReadHandler handler)
{
this->service.async_read_some_at(
this->implementation, offset, buffers, handler);
}
};
} // namespace windows
} // namespace asio
#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP

View File

@ -0,0 +1,302 @@
//
// basic_stream_handle.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_WINDOWS_BASIC_STREAM_HANDLE_HPP
#define ASIO_WINDOWS_BASIC_STREAM_HANDLE_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/windows/basic_handle.hpp"
#include "asio/windows/stream_handle_service.hpp"
#include "asio/detail/throw_error.hpp"
#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace windows {
/// Provides stream-oriented handle functionality.
/**
* The windows::basic_stream_handle class template provides asynchronous and
* blocking stream-oriented handle functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename StreamHandleService = stream_handle_service>
class basic_stream_handle
: public basic_handle<StreamHandleService>
{
public:
/// The native representation of a handle.
typedef typename StreamHandleService::native_type native_type;
/// Construct a basic_stream_handle without opening it.
/**
* This constructor creates a stream handle without opening it. The handle
* 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 handle will use to
* dispatch handlers for any asynchronous operations performed on the handle.
*/
explicit basic_stream_handle(asio::io_service& io_service)
: basic_handle<StreamHandleService>(io_service)
{
}
/// Construct a basic_stream_handle on an existing native handle.
/**
* This constructor creates a stream handle object to hold an existing native
* handle.
*
* @param io_service The io_service object that the stream handle will use to
* dispatch handlers for any asynchronous operations performed on the handle.
*
* @param native_handle The new underlying handle implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_handle(asio::io_service& io_service,
const native_type& native_handle)
: basic_handle<StreamHandleService>(io_service, native_handle)
{
}
/// Write some data to the handle.
/**
* This function is used to write data to the stream handle. 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 handle.
*
* @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
* handle.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.write_some(this->implementation, buffers, ec);
asio::detail::throw_error(ec);
return s;
}
/// Write some data to the handle.
/**
* This function is used to write data to the stream handle. 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 handle.
*
* @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.write_some(this->implementation, buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the stream handle.
* The function call always returns immediately.
*
* @param buffers One or more data buffers to be written to the handle.
* 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
* handle.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_write_some(this->implementation, buffers, handler);
}
/// Read some data from the handle.
/**
* This function is used to read data from the stream handle. 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
* handle.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.read_some(this->implementation, buffers, ec);
asio::detail::throw_error(ec);
return s;
}
/// Read some data from the handle.
/**
* This function is used to read data from the stream handle. 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.read_some(this->implementation, buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the stream handle.
* 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
* handle.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_read_some(this->implementation, buffers, handler);
}
};
} // namespace windows
} // namespace asio
#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP

View File

@ -0,0 +1,39 @@
//
// random_access_handle.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_WINDOWS_RANDOM_ACCESS_HANDLE_HPP
#define ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_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/windows/basic_random_access_handle.hpp"
#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace windows {
/// Typedef for the typical usage of a random-access handle.
typedef basic_random_access_handle<> random_access_handle;
} // namespace windows
} // namespace asio
#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP

View File

@ -0,0 +1,179 @@
//
// random_access_handle_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_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP
#define ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_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/cstdint.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/win_iocp_handle_service.hpp"
#if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
# if defined(ASIO_HAS_IOCP)
# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1
# endif // defined(ASIO_HAS_IOCP)
#endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace windows {
/// Default service implementation for a random-access handle.
class random_access_handle_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_service::service
#else
: public asio::detail::service_base<random_access_handle_service>
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_service::id id;
#endif
private:
// The type of the platform-specific implementation.
typedef detail::win_iocp_handle_service service_impl_type;
public:
/// The type of a random-access handle implementation.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef service_impl_type::implementation_type implementation_type;
#endif
/// The native handle type.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_type;
#else
typedef service_impl_type::native_type native_type;
#endif
/// Construct a new random-access handle service for the specified io_service.
explicit random_access_handle_service(asio::io_service& io_service)
: asio::detail::service_base<
random_access_handle_service>(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 random-access handle implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}
/// Destroy a random-access handle implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}
/// Assign an existing native handle to a random-access handle.
asio::error_code assign(implementation_type& impl,
const native_type& native_handle, asio::error_code& ec)
{
return service_impl_.assign(impl, native_handle, ec);
}
/// Determine whether the handle is open.
bool is_open(const implementation_type& impl) const
{
return service_impl_.is_open(impl);
}
/// Close a random-access handle implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.close(impl, ec);
}
/// Get the native handle implementation.
native_type native(implementation_type& impl)
{
return service_impl_.native(impl);
}
/// Cancel all asynchronous operations associated with the handle.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}
/// Write the given data at the specified offset.
template <typename ConstBufferSequence>
std::size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return service_impl_.write_some_at(impl, offset, buffers, ec);
}
/// Start an asynchronous write at the specified offset.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some_at(implementation_type& impl, boost::uint64_t offset,
const ConstBufferSequence& buffers, WriteHandler handler)
{
service_impl_.async_write_some_at(impl, offset, buffers, handler);
}
/// Read some data from the specified offset.
template <typename MutableBufferSequence>
std::size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return service_impl_.read_some_at(impl, offset, buffers, ec);
}
/// Start an asynchronous read at the specified offset.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
const MutableBufferSequence& buffers, ReadHandler handler)
{
service_impl_.async_read_some_at(impl, offset, buffers, handler);
}
private:
// The service that provides the platform-specific implementation.
service_impl_type& service_impl_;
};
} // namespace windows
} // namespace asio
#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP

View File

@ -0,0 +1,39 @@
//
// stream_handle.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_WINDOWS_STREAM_HANDLE_HPP
#define ASIO_WINDOWS_STREAM_HANDLE_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/windows/basic_stream_handle.hpp"
#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace windows {
/// Typedef for the typical usage of a stream-oriented handle.
typedef basic_stream_handle<> stream_handle;
} // namespace windows
} // namespace asio
#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WINDOWS_STREAM_HANDLE_HPP

View File

@ -0,0 +1,177 @@
//
// stream_handle_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_WINDOWS_STREAM_HANDLE_SERVICE_HPP
#define ASIO_WINDOWS_STREAM_HANDLE_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/service_base.hpp"
#include "asio/detail/win_iocp_handle_service.hpp"
#if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
# if defined(ASIO_HAS_IOCP)
# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1
# endif // defined(ASIO_HAS_IOCP)
#endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace windows {
/// Default service implementation for a stream handle.
class stream_handle_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_service::service
#else
: public asio::detail::service_base<stream_handle_service>
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_service::id id;
#endif
private:
// The type of the platform-specific implementation.
typedef detail::win_iocp_handle_service service_impl_type;
public:
/// The type of a stream handle implementation.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef service_impl_type::implementation_type implementation_type;
#endif
/// The native handle type.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_type;
#else
typedef service_impl_type::native_type native_type;
#endif
/// Construct a new stream handle service for the specified io_service.
explicit stream_handle_service(asio::io_service& io_service)
: asio::detail::service_base<stream_handle_service>(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 stream handle implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}
/// Destroy a stream handle implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}
/// Assign an existing native handle to a stream handle.
asio::error_code assign(implementation_type& impl,
const native_type& native_handle, asio::error_code& ec)
{
return service_impl_.assign(impl, native_handle, ec);
}
/// Determine whether the handle is open.
bool is_open(const implementation_type& impl) const
{
return service_impl_.is_open(impl);
}
/// Close a stream handle implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.close(impl, ec);
}
/// Get the native handle implementation.
native_type native(implementation_type& impl)
{
return service_impl_.native(impl);
}
/// Cancel all asynchronous operations associated with the handle.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}
/// Write the given data to the stream.
template <typename ConstBufferSequence>
std::size_t write_some(implementation_type& impl,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return service_impl_.write_some(impl, buffers, ec);
}
/// Start an asynchronous write.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, WriteHandler handler)
{
service_impl_.async_write_some(impl, buffers, handler);
}
/// Read some data from the stream.
template <typename MutableBufferSequence>
std::size_t read_some(implementation_type& impl,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return service_impl_.read_some(impl, buffers, ec);
}
/// Start an asynchronous read.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, ReadHandler handler)
{
service_impl_.async_read_some(impl, buffers, handler);
}
private:
// The service that provides the platform-specific implementation.
service_impl_type& service_impl_;
};
} // namespace windows
} // namespace asio
#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP

View File

@ -29,6 +29,8 @@ namespace asio {
/**
* @defgroup write asio::write
*
* @brief Write a certain amount of data to a stream before returning.
*/
/*@{*/
@ -166,7 +168,7 @@ template <typename SyncWriteStream, typename ConstBufferSequence,
std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec);
/// Write a certain amount of data to a stream before returning.
/// Write all of the supplied data to a stream before returning.
/**
* This function is used to write a certain number of bytes of data to a stream.
* The call will block until one of the following conditions is true:
@ -279,10 +281,13 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
/*@}*/
/**
* @defgroup async_write asio::async_write
*
* @brief Start an asynchronous operation to write a certain amount of data to a
* stream.
*/
/*@{*/
/// Start an asynchronous operation to write of all of the supplied data to a
/// Start an asynchronous operation to write all of the supplied data to a
/// stream.
/**
* This function is used to asynchronously write a certain number of bytes of
@ -405,7 +410,7 @@ template <typename AsyncWriteStream, typename ConstBufferSequence,
void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, WriteHandler handler);
/// Start an asynchronous operation to write a certain amount of data to a
/// Start an asynchronous operation to write all of the supplied data to a
/// stream.
/**
* This function is used to asynchronously write a certain number of bytes of

View File

@ -0,0 +1,555 @@
//
// write_at.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_WRITE_AT_HPP
#define ASIO_WRITE_AT_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/cstdint.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_streambuf.hpp"
#include "asio/error.hpp"
namespace asio {
/**
* @defgroup write_at asio::write_at
*
* @brief Write a certain amount of data at a specified offset before returning.
*/
/*@{*/
/// Write all of the supplied data at the specified offset before returning.
/**
* This function is used to write a certain number of bytes of data to a random
* access device at a specified offset. The call will block until one of the
* following conditions is true:
*
* @li All of the data in the supplied buffers has been written. That is, the
* bytes transferred is equal to the sum of the buffer sizes.
*
* @li An error occurred.
*
* This operation is implemented in terms of one or more calls to the device's
* write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the SyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more buffers containing the data to be written. The sum
* of the buffer sizes indicates the maximum number of bytes to write to the
* device.
*
* @returns The number of bytes transferred.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code asio::write_at(d, 42, 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.
*
* @note This overload is equivalent to calling:
* @code asio::write_at(
* d, offset, buffers,
* asio::transfer_all()); @endcode
*/
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers);
/// Write a certain amount of data at a specified offset before returning.
/**
* This function is used to write a certain number of bytes of data to a random
* access device at a specified offset. The call will block until one of the
* following conditions is true:
*
* @li All of the data in the supplied buffers has been written. That is, the
* bytes transferred is equal to the sum of the buffer sizes.
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the SyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more buffers containing the data to be written. The sum
* of the buffer sizes indicates the maximum number of bytes to write to the
* device.
*
* @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the write operation is complete. False
* indicates that further calls to the device's write_some_at function are
* required.
*
* @returns The number of bytes transferred.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code asio::write_at(d, 42, asio::buffer(data, size),
* asio::transfer_at_least(32)); @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 SyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition>
std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition);
/// Write a certain amount of data at a specified offset before returning.
/**
* This function is used to write a certain number of bytes of data to a random
* access device at a specified offset. The call will block until one of the
* following conditions is true:
*
* @li All of the data in the supplied buffers has been written. That is, the
* bytes transferred is equal to the sum of the buffer sizes.
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the SyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more buffers containing the data to be written. The sum
* of the buffer sizes indicates the maximum number of bytes to write to the
* device.
*
* @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the write operation is complete. False
* indicates that further calls to the device's write_some_at function are
* required.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. If an error occurs, returns the total
* number of bytes successfully transferred prior to the error.
*/
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition>
std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec);
/// Write all of the supplied data at the specified offset before returning.
/**
* This function is used to write a certain number of bytes of data to a random
* access device at a specified offset. The call will block until one of the
* following conditions is true:
*
* @li All of the data in the supplied basic_streambuf has been written.
*
* @li An error occurred.
*
* This operation is implemented in terms of one or more calls to the device's
* write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the SyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param b The basic_streambuf object from which data will be written.
*
* @returns The number of bytes transferred.
*
* @throws asio::system_error Thrown on failure.
*
* @note This overload is equivalent to calling:
* @code asio::write_at(
* d, 42, b,
* asio::transfer_all()); @endcode
*/
template <typename SyncRandomAccessWriteDevice, typename Allocator>
std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, basic_streambuf<Allocator>& b);
/// Write a certain amount of data at a specified offset before returning.
/**
* This function is used to write a certain number of bytes of data to a random
* access device at a specified offset. The call will block until one of the
* following conditions is true:
*
* @li All of the data in the supplied basic_streambuf has been written.
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the SyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param b The basic_streambuf object from which data will be written.
*
* @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the write operation is complete. False
* indicates that further calls to the device's write_some_at function are
* required.
*
* @returns The number of bytes transferred.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename SyncRandomAccessWriteDevice, typename Allocator,
typename CompletionCondition>
std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset,
basic_streambuf<Allocator>& b, CompletionCondition completion_condition);
/// Write a certain amount of data at a specified offset before returning.
/**
* This function is used to write a certain number of bytes of data to a random
* access device at a specified offset. The call will block until one of the
* following conditions is true:
*
* @li All of the data in the supplied basic_streambuf has been written.
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the SyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param b The basic_streambuf object from which data will be written.
*
* @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the write operation is complete. False
* indicates that further calls to the device's write_some_at function are
* required.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. If an error occurs, returns the total
* number of bytes successfully transferred prior to the error.
*/
template <typename SyncRandomAccessWriteDevice, typename Allocator,
typename CompletionCondition>
std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset,
basic_streambuf<Allocator>& b, CompletionCondition completion_condition,
asio::error_code& ec);
/*@}*/
/**
* @defgroup async_write_at asio::async_write_at
*
* @brief Start an asynchronous operation to write a certain amount of data at
* the specified offset.
*/
/*@{*/
/// Start an asynchronous operation to write all of the supplied data at the
/// specified offset.
/**
* This function is used to asynchronously write a certain number of bytes of
* data to a random access device at a specified offset. The function call
* always returns immediately. The asynchronous operation will continue until
* one of the following conditions is true:
*
* @li All of the data in the supplied buffers has been written. That is, the
* bytes transferred is equal to the sum of the buffer sizes.
*
* @li An error occurred.
*
* This operation is implemented in terms of one or more calls to the device's
* async_write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the AsyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more buffers containing the data to be written.
* 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(
* // Result of operation.
* const asio::error_code& error,
*
* // Number of bytes written from the buffers. If an error
* // occurred, this will be less than the sum of the buffer sizes.
* std::size_t bytes_transferred
* ); @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 write a single data buffer use the @ref buffer function as follows:
* @code
* asio::async_write_at(d, 42, 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 AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename WriteHandler>
void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset,
const ConstBufferSequence& buffers, WriteHandler handler);
/// Start an asynchronous operation to write a certain amount of data at the
/// specified offset.
/**
* This function is used to asynchronously write a certain number of bytes of
* data to a random access device at a specified offset. The function call
* always returns immediately. The asynchronous operation will continue until
* one of the following conditions is true:
*
* @li All of the data in the supplied buffers has been written. That is, the
* bytes transferred is equal to the sum of the buffer sizes.
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* async_write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the AsyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more buffers containing the data to be written.
* 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 completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the write operation is complete. False
* indicates that further calls to the device's async_write_some_at function are
* required.
*
* @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(
* // Result of operation.
* const asio::error_code& error,
*
* // Number of bytes written from the buffers. If an error
* // occurred, this will be less than the sum of the buffer sizes.
* std::size_t bytes_transferred
* ); @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 write a single data buffer use the @ref buffer function as follows:
* @code asio::async_write_at(d, 42,
* asio::buffer(data, size),
* asio::transfer_at_least(32),
* 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 AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition, typename WriteHandler>
void async_write_at(AsyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, WriteHandler handler);
/// Start an asynchronous operation to write all of the supplied data at the
/// specified offset.
/**
* This function is used to asynchronously write a certain number of bytes of
* data to a random access device at a specified offset. The function call
* always returns immediately. The asynchronous operation will continue until
* one of the following conditions is true:
*
* @li All of the data in the supplied basic_streambuf has been written.
*
* @li An error occurred.
*
* This operation is implemented in terms of one or more calls to the device's
* async_write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the AsyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param b A basic_streambuf object from which data will be written. Ownership
* of the streambuf is retained by the caller, which must guarantee that it
* remains 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(
* // Result of operation.
* const asio::error_code& error,
*
* // Number of bytes written from the buffers. If an error
* // occurred, this will be less than the sum of the buffer sizes.
* std::size_t bytes_transferred
* ); @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 AsyncRandomAccessWriteDevice, typename Allocator,
typename WriteHandler>
void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset,
basic_streambuf<Allocator>& b, WriteHandler handler);
/// Start an asynchronous operation to write a certain amount of data at the
/// specified offset.
/**
* This function is used to asynchronously write a certain number of bytes of
* data to a random access device at a specified offset. The function call
* always returns immediately. The asynchronous operation will continue until
* one of the following conditions is true:
*
* @li All of the data in the supplied basic_streambuf has been written.
*
* @li The completion_condition function object returns true.
*
* This operation is implemented in terms of one or more calls to the device's
* async_write_some_at function.
*
* @param d The device to which the data is to be written. The type must support
* the AsyncRandomAccessWriteDevice concept.
*
* @param offset The offset at which the data will be written.
*
* @param b A basic_streambuf object from which data will be written. Ownership
* of the streambuf is retained by the caller, which must guarantee that it
* remains valid until the handler is called.
*
* @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object
* must be:
* @code bool completion_condition(
* // Result of latest async_write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
* A return value of true indicates that the write operation is complete. False
* indicates that further calls to the device's async_write_some_at function are
* required.
*
* @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(
* // Result of operation.
* const asio::error_code& error,
*
* // Number of bytes written from the buffers. If an error
* // occurred, this will be less than the sum of the buffer sizes.
* std::size_t bytes_transferred
* ); @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 AsyncRandomAccessWriteDevice, typename Allocator,
typename CompletionCondition, typename WriteHandler>
void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset,
basic_streambuf<Allocator>& b, CompletionCondition completion_condition,
WriteHandler handler);
/*@}*/
} // namespace asio
#include "asio/impl/write_at.ipp"
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WRITE_AT_HPP