asio 1.1.1 sync
This commit is contained in:
parent
63d36a4b70
commit
4d46faf014
@ -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;
|
||||
};
|
||||
|
||||
|
||||
798
libtorrent/include/asio/basic_raw_socket.hpp
Normal file
798
libtorrent/include/asio/basic_raw_socket.hpp
Normal 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
|
||||
608
libtorrent/include/asio/basic_serial_port.hpp
Normal file
608
libtorrent/include/asio/basic_serial_port.hpp
Normal 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
|
||||
@ -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.
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
318
libtorrent/include/asio/buffers_iterator.hpp
Normal file
318
libtorrent/include/asio/buffers_iterator.hpp
Normal 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
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
138
libtorrent/include/asio/detail/descriptor_ops.hpp
Normal file
138
libtorrent/include/asio/detail/descriptor_ops.hpp
Normal 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
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
76
libtorrent/include/asio/detail/handler_base_from_member.hpp
Normal file
76
libtorrent/include/asio/detail/handler_base_from_member.hpp
Normal 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
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
291
libtorrent/include/asio/detail/indirect_handler_queue.hpp
Normal file
291
libtorrent/include/asio/detail/indirect_handler_queue.hpp
Normal 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
|
||||
@ -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.
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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
|
||||
|
||||
709
libtorrent/include/asio/detail/reactive_descriptor_service.hpp
Normal file
709
libtorrent/include/asio/detail/reactive_descriptor_service.hpp
Normal 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
|
||||
267
libtorrent/include/asio/detail/reactive_serial_port_service.hpp
Normal file
267
libtorrent/include/asio/detail/reactive_serial_port_service.hpp
Normal 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
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
462
libtorrent/include/asio/detail/task_io_service_2lock.hpp
Normal file
462
libtorrent/include/asio/detail/task_io_service_2lock.hpp
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
832
libtorrent/include/asio/detail/win_iocp_handle_service.hpp
Normal file
832
libtorrent/include/asio/detail/win_iocp_handle_service.hpp
Normal 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
|
||||
@ -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_;
|
||||
|
||||
292
libtorrent/include/asio/detail/win_iocp_serial_port_service.hpp
Normal file
292
libtorrent/include/asio/detail/win_iocp_serial_port_service.hpp
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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),
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
337
libtorrent/include/asio/impl/read_at.ipp
Normal file
337
libtorrent/include/asio/impl/read_at.ipp
Normal 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
|
||||
@ -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"
|
||||
|
||||
541
libtorrent/include/asio/impl/serial_port_base.ipp
Normal file
541
libtorrent/include/asio/impl/serial_port_base.ipp
Normal 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
|
||||
296
libtorrent/include/asio/impl/write_at.ipp
Normal file
296
libtorrent/include/asio/impl/write_at.ipp
Normal 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
|
||||
@ -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);
|
||||
|
||||
|
||||
118
libtorrent/include/asio/ip/icmp.hpp
Normal file
118
libtorrent/include/asio/ip/icmp.hpp
Normal 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
|
||||
265
libtorrent/include/asio/local/basic_endpoint.hpp
Normal file
265
libtorrent/include/asio/local/basic_endpoint.hpp
Normal 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
|
||||
100
libtorrent/include/asio/local/connect_pair.hpp
Normal file
100
libtorrent/include/asio/local/connect_pair.hpp
Normal 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
|
||||
78
libtorrent/include/asio/local/datagram_protocol.hpp
Normal file
78
libtorrent/include/asio/local/datagram_protocol.hpp
Normal 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
|
||||
86
libtorrent/include/asio/local/stream_protocol.hpp
Normal file
86
libtorrent/include/asio/local/stream_protocol.hpp
Normal 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
|
||||
280
libtorrent/include/asio/posix/basic_descriptor.hpp
Normal file
280
libtorrent/include/asio/posix/basic_descriptor.hpp
Normal 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
|
||||
304
libtorrent/include/asio/posix/basic_stream_descriptor.hpp
Normal file
304
libtorrent/include/asio/posix/basic_stream_descriptor.hpp
Normal 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
|
||||
93
libtorrent/include/asio/posix/descriptor_base.hpp
Normal file
93
libtorrent/include/asio/posix/descriptor_base.hpp
Normal 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
|
||||
39
libtorrent/include/asio/posix/stream_descriptor.hpp
Normal file
39
libtorrent/include/asio/posix/stream_descriptor.hpp
Normal 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
|
||||
200
libtorrent/include/asio/posix/stream_descriptor_service.hpp
Normal file
200
libtorrent/include/asio/posix/stream_descriptor_service.hpp
Normal 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
|
||||
323
libtorrent/include/asio/raw_socket_service.hpp
Normal file
323
libtorrent/include/asio/raw_socket_service.hpp
Normal 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
|
||||
@ -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.
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
|
||||
568
libtorrent/include/asio/read_at.hpp
Normal file
568
libtorrent/include/asio/read_at.hpp
Normal 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
|
||||
@ -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
|
||||
|
||||
38
libtorrent/include/asio/serial_port.hpp
Normal file
38
libtorrent/include/asio/serial_port.hpp
Normal 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
|
||||
157
libtorrent/include/asio/serial_port_base.hpp
Normal file
157
libtorrent/include/asio/serial_port_base.hpp
Normal 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
|
||||
222
libtorrent/include/asio/serial_port_service.hpp
Normal file
222
libtorrent/include/asio/serial_port_service.hpp
Normal 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
|
||||
@ -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_();
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ public:
|
||||
*/
|
||||
template <typename Function>
|
||||
explicit thread(Function f)
|
||||
: impl_(f)
|
||||
: impl_(f, asio::detail::thread::external)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
211
libtorrent/include/asio/windows/basic_handle.hpp
Normal file
211
libtorrent/include/asio/windows/basic_handle.hpp
Normal 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
|
||||
320
libtorrent/include/asio/windows/basic_random_access_handle.hpp
Normal file
320
libtorrent/include/asio/windows/basic_random_access_handle.hpp
Normal 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
|
||||
302
libtorrent/include/asio/windows/basic_stream_handle.hpp
Normal file
302
libtorrent/include/asio/windows/basic_stream_handle.hpp
Normal 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
|
||||
39
libtorrent/include/asio/windows/random_access_handle.hpp
Normal file
39
libtorrent/include/asio/windows/random_access_handle.hpp
Normal 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
|
||||
179
libtorrent/include/asio/windows/random_access_handle_service.hpp
Normal file
179
libtorrent/include/asio/windows/random_access_handle_service.hpp
Normal 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
|
||||
39
libtorrent/include/asio/windows/stream_handle.hpp
Normal file
39
libtorrent/include/asio/windows/stream_handle.hpp
Normal 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
|
||||
177
libtorrent/include/asio/windows/stream_handle_service.hpp
Normal file
177
libtorrent/include/asio/windows/stream_handle_service.hpp
Normal 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
|
||||
@ -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
|
||||
|
||||
555
libtorrent/include/asio/write_at.hpp
Normal file
555
libtorrent/include/asio/write_at.hpp
Normal 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
|
||||
Loading…
x
Reference in New Issue
Block a user