diff --git a/doc/reference.qbk b/doc/reference.qbk index d08c67c6..07fe13c1 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -424,7 +424,7 @@ This function is used to asynchronously read a certain number of bytes of data f * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. [heading Parameters] @@ -574,7 +574,7 @@ Start an asynchronous operation to read a certain amount of data from a stream. This function is used to asynchronously read a certain number of bytes of data from a stream. The function call always returns immediately. The asynchronous operation will continue until one of the following conditions is true: -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function, and is known as a [*composed operation]. The program must ensure that the stream performs no other read operations (such as async\_read, the stream's async\_read\_some function, or any other composed operations that perform reads) until this operation completes. @@ -795,7 +795,7 @@ This function is used to asynchronously read a certain number of bytes of data f * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. [heading Parameters] @@ -951,7 +951,7 @@ Start an asynchronous operation to read a certain amount of data at the specifie 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: -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's async\_read\_some\_at function. @@ -1666,7 +1666,7 @@ This function is used to asynchronously write a certain number of bytes of data * 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. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's async\_write\_some function, and is known as a [*composed operation]. The program must ensure that the stream performs no other write operations (such as async\_write, the stream's async\_write\_some function, or any other composed operations that perform writes) until this operation completes. @@ -1746,7 +1746,7 @@ 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 data to a stream. The function call always returns immediately. The asynchronous operation will continue until one of the following conditions is true: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. * An error occurred. @@ -1806,10 +1806,10 @@ Start an asynchronous operation to write a certain amount of data to a stream. This function is used to asynchronously write a certain number of bytes of data to a stream. The function call always returns immediately. The asynchronous operation will continue until one of the following conditions is true: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's async\_write\_some function, and is known as a [*composed operation]. The program must ensure that the stream performs no other write operations (such as async\_write, the stream's async\_write\_some function, or any other composed operations that perform writes) until this operation completes. @@ -2015,7 +2015,7 @@ This function is used to asynchronously write a certain number of bytes of data * 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. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's async\_write\_some\_at function. @@ -2098,7 +2098,7 @@ Start an asynchronous operation to write all of the supplied data at the specifi 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. * An error occurred. @@ -2161,10 +2161,10 @@ Start an asynchronous operation to write a certain amount of data at the specifi 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's async\_write\_some\_at function. @@ -3901,10 +3901,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -3952,10 +3952,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -7430,10 +7430,10 @@ Changing the expiry time of a timer while there are pending asynchronous waits c -* The boost::asio::basic_deadline_timer::expires_from_now() function cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled. If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed. If it returns 1 then the wait handler was successfully cancelled. +* The `boost::asio::basic_deadline_timer::expires_from_now()` function cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled. If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed. If it returns 1 then the wait handler was successfully cancelled. -* If a wait handler is cancelled, the boost::system::error_code passed to it contains the value boost::asio::error::operation_aborted. +* If a wait handler is cancelled, the boost::system::error\_code passed to it contains the value `boost::asio::error::operation_aborted`. @@ -7464,7 +7464,7 @@ For each call to `async_wait()`, the supplied handler will be called exactly onc * The timer has expired. -* The timer was cancelled, in which case the handler is passed the error code boost::asio::error::operation_aborted. +* The timer was cancelled, in which case the handler is passed the error code `boost::asio::error::operation_aborted`. [heading Parameters] @@ -10211,10 +10211,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -10262,10 +10262,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -16320,10 +16320,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -16368,10 +16368,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -22849,10 +22849,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -22900,10 +22900,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -27034,10 +27034,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -27085,10 +27085,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -35911,7 +35911,7 @@ Disable sends or receives on the socket. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -36129,10 +36129,10 @@ Changing the expiry time of a timer while there are pending asynchronous waits c -* The boost::asio::basic_deadline_timer::expires_from_now() function cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled. If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed. If it returns 1 then the wait handler was successfully cancelled. +* The `boost::asio::basic_deadline_timer::expires_from_now()` function cancels any pending asynchronous waits, and returns the number of asynchronous waits that were cancelled. If it returns 0 then you were too late and the wait handler has already been executed, or will soon be executed. If it returns 1 then the wait handler was successfully cancelled. -* If a wait handler is cancelled, the boost::system::error_code passed to it contains the value boost::asio::error::operation_aborted. +* If a wait handler is cancelled, the boost::system::error\_code passed to it contains the value `boost::asio::error::operation_aborted`. @@ -36558,7 +36558,7 @@ The implementation type of the deadline timer. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -37483,13 +37483,13 @@ Provides core I/O functionality. The [link boost_asio.reference.io_service `io_service`] class provides the core I/O functionality for users of the asynchronous I/O objects, including: -* boost::asio::ip::tcp::socket +* `boost::asio::ip::tcp::socket` -* boost::asio::ip::tcp::acceptor +* `boost::asio::ip::tcp::acceptor` -* boost::asio::ip::udp::socket +* `boost::asio::ip::udp::socket` -* boost::asio::deadline_timer. +* `boost::asio::deadline_timer`. The [link boost_asio.reference.io_service `io_service`] class also includes facilities intended for developers of custom asynchronous services. @@ -37688,7 +37688,7 @@ The [link boost_asio.reference.io_service `io_service`] guarantees that the hand This function throws an exception only if: -* the handler's asio_handler_allocate function; or +* the handler's `asio_handler_allocate` function; or * the handler's copy constructor @@ -38000,7 +38000,7 @@ The [link boost_asio.reference.io_service `io_service`] guarantees that the hand This function throws an exception only if: -* the handler's asio_handler_allocate function; or +* the handler's `asio_handler_allocate` function; or * the handler's copy constructor @@ -38342,13 +38342,13 @@ Destructor. On destruction, the [link boost_asio.reference.io_service `io_service`] performs the following sequence of operations: -* For each service object svc in the io_service set, in reverse order of the beginning of service object lifetime, performs svc->shutdown_service(). +* For each service object `svc` in the [link boost_asio.reference.io_service `io_service`] set, in reverse order of the beginning of service object lifetime, performs `svc->shutdown_service()`. -* Uninvoked handler objects that were scheduled for deferred invocation on the io_service, or any associated strand, are destroyed. +* Uninvoked handler objects that were scheduled for deferred invocation on the [link boost_asio.reference.io_service `io_service`], or any associated strand, are destroyed. -* For each service object svc in the io_service set, in reverse order of the beginning of service object lifetime, performs delete static_cast(svc). +* For each service object `svc` in the [link boost_asio.reference.io_service `io_service`] set, in reverse order of the beginning of service object lifetime, performs `delete static_cast(svc)`. [heading Remarks] @@ -38356,10 +38356,10 @@ On destruction, the [link boost_asio.reference.io_service `io_service`] performs The destruction sequence described above permits programs to simplify their resource management by using `shared_ptr<>`. Where an object's lifetime is tied to the lifetime of a connection (or some other sequence of asynchronous operations), a `shared_ptr` to the object would be bound into the handlers for all asynchronous operations associated with it. This works as follows: -* When a single connection ends, all associated asynchronous operations complete. The corresponding handler objects are destroyed, and all shared_ptr references to the objects are destroyed. +* When a single connection ends, all associated asynchronous operations complete. The corresponding handler objects are destroyed, and all `shared_ptr` references to the objects are destroyed. -* To shut down the whole program, the io_service function stop() is called to terminate any run() calls as soon as possible. The io_service destructor defined above destroys all handlers, causing all shared_ptr references to all connection objects to be destroyed. +* To shut down the whole program, the [link boost_asio.reference.io_service `io_service`] function `stop()` is called to terminate any `run()` calls as soon as possible. The [link boost_asio.reference.io_service `io_service`] destructor defined above destroys all handlers, causing all `shared_ptr` references to all connection objects to be destroyed. @@ -38592,33 +38592,33 @@ The [link boost_asio.reference.io_service__strand `io_service::strand`] class pr Given: -* a strand object s +* a strand object `s` -* an object a meeting completion handler requirements +* an object `a` meeting completion handler requirements -* an object a1 which is an arbitrary copy of a made by the implementation +* an object `a1` which is an arbitrary copy of `a` made by the implementation -* an object b meeting completion handler requirements +* an object `b` meeting completion handler requirements -* an object b1 which is an arbitrary copy of b made by the implementation +* an object `b1` which is an arbitrary copy of `b` made by the implementation if any of the following conditions are true: -* s.post(a) happens-before s.post(b) +* `s.post(a)` happens-before `s.post(b)` -* s.post(a) happens-before s.dispatch(b), where the latter is performed outside the strand +* `s.post(a)` happens-before `s.dispatch(b)`, where the latter is performed outside the strand -* s.dispatch(a) happens-before s.post(b), where the former is performed outside the strand +* `s.dispatch(a)` happens-before `s.post(b)`, where the former is performed outside the strand -* s.dispatch(a) happens-before s.dispatch(b), where both are performed outside the strand +* `s.dispatch(a)` happens-before `s.dispatch(b)`, where both are performed outside the strand then `asio_handler_invoke(a1, &a1)` happens-before `asio_handler_invoke(b1, &b1)`. @@ -39105,11 +39105,26 @@ Implements version-independent IP addresses. [Compare addresses for ordering. ] ] + [ + [[link boost_asio.reference.ip__address.operator_lt__eq_ [*operator<=]]] + [Compare addresses for ordering. ] + ] + [ [[link boost_asio.reference.ip__address.operator_eq__eq_ [*operator==]]] [Compare two addresses for equality. ] ] + [ + [[link boost_asio.reference.ip__address.operator_gt_ [*operator>]]] + [Compare addresses for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__address.operator_gt__eq_ [*operator>=]]] + [Compare addresses for ordering. ] + ] + ] [heading Related Functions] @@ -39431,6 +39446,28 @@ The output stream. +[endsect] + + + +[section:operator_lt__eq_ ip::address::operator<=] + +[indexterm2 operator<=..ip::address] +Compare addresses for ordering. + + + friend bool operator<=( + const address & a1, + const address & a2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/address.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + [endsect] @@ -39529,6 +39566,50 @@ Compare two addresses for equality. [endsect] + +[section:operator_gt_ ip::address::operator>] + +[indexterm2 operator>..ip::address] +Compare addresses for ordering. + + + friend bool operator>( + const address & a1, + const address & a2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/address.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_gt__eq_ ip::address::operator>=] + +[indexterm2 operator>=..ip::address] +Compare addresses for ordering. + + + friend bool operator>=( + const address & a1, + const address & a2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/address.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + [section:to_string ip::address::to_string] [indexterm2 to_string..ip::address] @@ -41423,11 +41504,26 @@ Describes an endpoint for a version-independent IP socket. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.ip__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -41781,6 +41877,28 @@ The output stream. +[section:operator_lt__eq_ ip::basic_endpoint::operator<=] + +[indexterm2 operator<=..ip::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator<=( + const basic_endpoint< InternetProtocol > & e1, + const basic_endpoint< InternetProtocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + [section:operator_eq_ ip::basic_endpoint::operator=] [indexterm2 operator=..ip::basic_endpoint] @@ -41817,6 +41935,50 @@ Compare two endpoints for equality. [endsect] + +[section:operator_gt_ ip::basic_endpoint::operator>] + +[indexterm2 operator>..ip::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator>( + const basic_endpoint< InternetProtocol > & e1, + const basic_endpoint< InternetProtocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_gt__eq_ ip::basic_endpoint::operator>=] + +[indexterm2 operator>=..ip::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator>=( + const basic_endpoint< InternetProtocol > & e1, + const basic_endpoint< InternetProtocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + [section:port ip::basic_endpoint::port] [indexterm2 port..ip::basic_endpoint] @@ -44159,11 +44321,26 @@ The type of a ICMP endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.ip__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -46137,7 +46314,7 @@ Construct a new resolver service for the specified [link boost_asio.reference.io Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -46717,11 +46894,26 @@ The type of a TCP endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.ip__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -47935,11 +48127,26 @@ The type of a UDP endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.ip__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -49164,11 +49371,26 @@ Describes an endpoint for a UNIX socket. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.local__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -49449,6 +49671,28 @@ The output stream. +[section:operator_lt__eq_ local::basic_endpoint::operator<=] + +[indexterm2 operator<=..local::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator<=( + const basic_endpoint< Protocol > & e1, + const basic_endpoint< Protocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/local/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + [section:operator_eq_ local::basic_endpoint::operator=] [indexterm2 operator=..local::basic_endpoint] @@ -49485,6 +49729,50 @@ Compare two endpoints for equality. [endsect] + +[section:operator_gt_ local::basic_endpoint::operator>] + +[indexterm2 operator>..local::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator>( + const basic_endpoint< Protocol > & e1, + const basic_endpoint< Protocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/local/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_gt__eq_ local::basic_endpoint::operator>=] + +[indexterm2 operator>=..local::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator>=( + const basic_endpoint< Protocol > & e1, + const basic_endpoint< Protocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/local/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + [section:path local::basic_endpoint::path] [indexterm2 path..local::basic_endpoint] @@ -49857,11 +50145,26 @@ The type of a UNIX domain endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.local__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -50836,11 +51139,26 @@ The type of a UNIX domain endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.local__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -55429,7 +55747,7 @@ Read some data from the stream. Destroy all user-defined descriptorr objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -56333,7 +56651,7 @@ Disable sends or receives on the socket. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -56516,7 +56834,7 @@ This function is used to read a certain number of bytes of data from a stream. T * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's read\_some function. @@ -56600,7 +56918,7 @@ This function is used to read a certain number of bytes of data from a stream. T * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's read\_some function. @@ -56728,7 +57046,7 @@ Attempt to read a certain amount of data from a stream before returning. This function is used to read a certain number of bytes of data from a stream. The call will block until one of the following conditions is true: -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's read\_some function. @@ -56798,7 +57116,7 @@ Attempt to read a certain amount of data from a stream before returning. This function is used to read a certain number of bytes of data from a stream. The call will block until one of the following conditions is true: -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's read\_some function. @@ -57024,7 +57342,7 @@ This function is used to read a certain number of bytes of data from a random ac * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's read\_some\_at function. @@ -57111,7 +57429,7 @@ This function is used to read a certain number of bytes of data from a random ac * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's read\_some\_at function. @@ -57245,7 +57563,7 @@ Attempt to read a certain amount of data at the specified offset before returnin 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: -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's read\_some\_at function. @@ -57318,7 +57636,7 @@ Attempt to read a certain amount of data at the specified offset before returnin 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: -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's read\_some\_at function. @@ -59527,7 +59845,7 @@ Set a serial port option. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -60180,7 +60498,7 @@ Set a socket option. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -63730,7 +64048,7 @@ Set peer verification mode. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -65605,7 +65923,7 @@ Shut down SSL on the stream. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -65710,33 +66028,33 @@ The [link boost_asio.reference.io_service__strand `io_service::strand`] class pr Given: -* a strand object s +* a strand object `s` -* an object a meeting completion handler requirements +* an object `a` meeting completion handler requirements -* an object a1 which is an arbitrary copy of a made by the implementation +* an object `a1` which is an arbitrary copy of `a` made by the implementation -* an object b meeting completion handler requirements +* an object `b` meeting completion handler requirements -* an object b1 which is an arbitrary copy of b made by the implementation +* an object `b1` which is an arbitrary copy of `b` made by the implementation if any of the following conditions are true: -* s.post(a) happens-before s.post(b) +* `s.post(a)` happens-before `s.post(b)` -* s.post(a) happens-before s.dispatch(b), where the latter is performed outside the strand +* `s.post(a)` happens-before `s.dispatch(b)`, where the latter is performed outside the strand -* s.dispatch(a) happens-before s.post(b), where the former is performed outside the strand +* `s.dispatch(a)` happens-before `s.post(b)`, where the former is performed outside the strand -* s.dispatch(a) happens-before s.dispatch(b), where both are performed outside the strand +* `s.dispatch(a)` happens-before `s.dispatch(b)`, where both are performed outside the strand then `asio_handler_invoke(a1, &a1)` happens-before `asio_handler_invoke(b1, &b1)`. @@ -66512,7 +66830,7 @@ Disable sends or receives on the socket. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -71192,7 +71510,7 @@ Read some data from the specified offset. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -71773,7 +72091,7 @@ Read some data from the stream. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -71990,7 +72308,7 @@ This function is used to write a certain number of bytes of data to a stream. Th * 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. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's write\_some function. @@ -72074,7 +72392,7 @@ This function is used to write a certain number of bytes of data to a stream. Th * 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. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's write\_some function. @@ -72133,7 +72451,7 @@ 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. * An error occurred. @@ -72205,10 +72523,10 @@ Write a certain amount of 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's write\_some function. @@ -72278,10 +72596,10 @@ Write a certain amount of 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the stream's write\_some function. @@ -72507,7 +72825,7 @@ This function is used to write a certain number of bytes of data to a random acc * 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. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's write\_some\_at function. @@ -72594,7 +72912,7 @@ This function is used to write a certain number of bytes of data to a random acc * 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. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's write\_some\_at function. @@ -72656,7 +72974,7 @@ 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. * An error occurred. @@ -72731,10 +73049,10 @@ 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's write\_some\_at function. @@ -72807,10 +73125,10 @@ 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's write\_some\_at function. diff --git a/doc/reference.xsl b/doc/reference.xsl index 55d817f9..684292cc 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -103,7 +103,8 @@ + not(contains(ancestor::*/compoundname, '_helper')) and + not(contains(name, '_helper'))"> @@ -164,6 +165,23 @@ + + + + + + + + + + + + + + + + + @@ -365,8 +383,11 @@ -* - +* + + + + @@ -1054,8 +1075,14 @@ explicit static - - + virtual + + + + + + + ``[link boost_asio.reference...overload ]``( - static + + + + + + static virtual () const; @@ -1394,10 +1427,15 @@ + + + + + - ``[link boost_asio.reference. ``[link boost_asio.reference..overload ]``(); `` [''''&raquo;''' diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index c9f2d48e..aef7f185 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -81,7 +81,7 @@ All of the asio classes can be used by simply including the `"asio.hpp"` header -Since this example users timers, we need to include the appropriate Boost.Date\_Time header file for manipulating times. +Since this example uses timers, we need to include the appropriate Boost.Date\_Time header file for manipulating times. ``''''''``#include diff --git a/example/local/iostream_client.cpp b/example/local/iostream_client.cpp index 34eff7eb..f4453997 100644 --- a/example/local/iostream_client.cpp +++ b/example/local/iostream_client.cpp @@ -28,10 +28,13 @@ int main(int argc, char* argv[]) return 1; } - boost::asio::io_service io_service; - stream_protocol::endpoint ep(argv[1]); stream_protocol::iostream s(ep); + if (!s) + { + std::cerr << "Unable to connect\n"; + return 1; + } using namespace std; // For strlen. std::cout << "Enter message: "; diff --git a/example/tutorial/timer_dox.txt b/example/tutorial/timer_dox.txt index a9960e8e..f4ccf01d 100644 --- a/example/tutorial/timer_dox.txt +++ b/example/tutorial/timer_dox.txt @@ -21,7 +21,7 @@ header file. \until asio.hpp -Since this example users timers, we need to include the appropriate +Since this example uses timers, we need to include the appropriate Boost.Date_Time header file for manipulating times. \until posix_time.hpp diff --git a/include/boost/asio/basic_datagram_socket.hpp b/include/boost/asio/basic_datagram_socket.hpp index 3b3dedbb..52728099 100644 --- a/include/boost/asio/basic_datagram_socket.hpp +++ b/include/boost/asio/basic_datagram_socket.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_deadline_timer.hpp b/include/boost/asio/basic_deadline_timer.hpp index 1284daaf..dc471e29 100644 --- a/include/boost/asio/basic_deadline_timer.hpp +++ b/include/boost/asio/basic_deadline_timer.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_io_object.hpp b/include/boost/asio/basic_io_object.hpp index 3cb6b68c..414f3656 100644 --- a/include/boost/asio/basic_io_object.hpp +++ b/include/boost/asio/basic_io_object.hpp @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_raw_socket.hpp b/include/boost/asio/basic_raw_socket.hpp index 09810d41..0b877dee 100644 --- a/include/boost/asio/basic_raw_socket.hpp +++ b/include/boost/asio/basic_raw_socket.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include -#include -#include #include +#include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_serial_port.hpp b/include/boost/asio/basic_serial_port.hpp index 539119a0..4936c9c2 100644 --- a/include/boost/asio/basic_serial_port.hpp +++ b/include/boost/asio/basic_serial_port.hpp @@ -16,22 +16,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { @@ -616,9 +614,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_BASIC_SERIAL_PORT_HPP diff --git a/include/boost/asio/basic_socket.hpp b/include/boost/asio/basic_socket.hpp index 6b89623a..50a0c477 100644 --- a/include/boost/asio/basic_socket.hpp +++ b/include/boost/asio/basic_socket.hpp @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - +#include #include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_socket_acceptor.hpp b/include/boost/asio/basic_socket_acceptor.hpp index d23dc33b..5192df73 100644 --- a/include/boost/asio/basic_socket_acceptor.hpp +++ b/include/boost/asio/basic_socket_acceptor.hpp @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_socket_iostream.hpp b/include/boost/asio/basic_socket_iostream.hpp index e4c7ec16..a8cea4fe 100644 --- a/include/boost/asio/basic_socket_iostream.hpp +++ b/include/boost/asio/basic_socket_iostream.hpp @@ -15,22 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_NO_IOSTREAM) -#include #include #include #include #include #include -#include - #include #include @@ -79,6 +72,8 @@ } \ /**/ +#include + namespace boost { namespace asio { @@ -148,11 +143,11 @@ public: } // namespace asio } // namespace boost +#include + #undef BOOST_ASIO_PRIVATE_CTR_DEF #undef BOOST_ASIO_PRIVATE_CONNECT_DEF #endif // defined(BOOST_NO_IOSTREAM) -#include - #endif // BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP diff --git a/include/boost/asio/basic_socket_streambuf.hpp b/include/boost/asio/basic_socket_streambuf.hpp index 695e8e11..35e96d0d 100644 --- a/include/boost/asio/basic_socket_streambuf.hpp +++ b/include/boost/asio/basic_socket_streambuf.hpp @@ -15,15 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_NO_IOSTREAM) -#include #include #include #include @@ -31,12 +26,10 @@ #include #include #include -#include - #include +#include #include #include -#include #if !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY) #define BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY 5 @@ -74,6 +67,8 @@ } \ /**/ +#include + namespace boost { namespace asio { @@ -288,10 +283,10 @@ private: } // namespace asio } // namespace boost +#include + #undef BOOST_ASIO_PRIVATE_CONNECT_DEF #endif // !defined(BOOST_NO_IOSTREAM) -#include - #endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP diff --git a/include/boost/asio/basic_stream_socket.hpp b/include/boost/asio/basic_stream_socket.hpp index 15658bc7..956d6236 100644 --- a/include/boost/asio/basic_stream_socket.hpp +++ b/include/boost/asio/basic_stream_socket.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_streambuf.hpp b/include/boost/asio/basic_streambuf.hpp index e5f8a8dc..546a4aca 100644 --- a/include/boost/asio/basic_streambuf.hpp +++ b/include/boost/asio/basic_streambuf.hpp @@ -15,28 +15,23 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_NO_IOSTREAM) -#include #include #include -#include #include #include #include #include #include -#include - +#include #include #include +#include + namespace boost { namespace asio { @@ -108,7 +103,11 @@ namespace asio { * is >> s; * @endcode */ +#if defined(GENERATING_DOCUMENTATION) template > +#else +template +#endif class basic_streambuf : public std::streambuf, private noncopyable @@ -338,8 +337,27 @@ protected: private: std::size_t max_size_; std::vector buffer_; + + // Helper function to get the preferred size for reading data. + friend std::size_t read_size_helper( + basic_streambuf& sb, std::size_t max_size) + { + return std::min( + std::max(512, sb.buffer_.capacity() - sb.size()), + std::min(max_size, sb.max_size() - sb.size())); + } }; +// Helper function to get the preferred size for reading data. Used for any +// user-provided specialisations of basic_streambuf. +template +inline std::size_t read_size_helper( + basic_streambuf& sb, std::size_t max_size) +{ + return std::min(512, + std::min(max_size, sb.max_size() - sb.size())); +} + } // namespace asio } // namespace boost diff --git a/include/boost/asio/basic_streambuf_fwd.hpp b/include/boost/asio/basic_streambuf_fwd.hpp new file mode 100644 index 00000000..215937ea --- /dev/null +++ b/include/boost/asio/basic_streambuf_fwd.hpp @@ -0,0 +1,35 @@ +// +// basic_streambuf_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP +#define BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +namespace boost { +namespace asio { + +template > +class basic_streambuf; + +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP diff --git a/include/boost/asio/buffer.hpp b/include/boost/asio/buffer.hpp index 3fe81923..f925361c 100644 --- a/include/boost/asio/buffer.hpp +++ b/include/boost/asio/buffer.hpp @@ -15,16 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include -#include #include #include -#include +#include +#include #if defined(BOOST_MSVC) # if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) @@ -43,11 +39,17 @@ #endif // defined(__GNUC__) #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) -# include # include -# include #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ + || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +# include +#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/buffered_read_stream.hpp b/include/boost/asio/buffered_read_stream.hpp index d7bf6ff1..935f5b91 100644 --- a/include/boost/asio/buffered_read_stream.hpp +++ b/include/boost/asio/buffered_read_stream.hpp @@ -15,23 +15,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include #include -#include - #include #include -#include -#include #include #include #include #include +#include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/buffered_read_stream_fwd.hpp b/include/boost/asio/buffered_read_stream_fwd.hpp index 8eb24f86..87f27d9f 100644 --- a/include/boost/asio/buffered_read_stream_fwd.hpp +++ b/include/boost/asio/buffered_read_stream_fwd.hpp @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { @@ -26,6 +24,4 @@ class buffered_read_stream; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP diff --git a/include/boost/asio/buffered_stream.hpp b/include/boost/asio/buffered_stream.hpp index 0cbc2807..ceeb6f29 100644 --- a/include/boost/asio/buffered_stream.hpp +++ b/include/boost/asio/buffered_stream.hpp @@ -15,19 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include #include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/buffered_stream_fwd.hpp b/include/boost/asio/buffered_stream_fwd.hpp index 066f52cf..d23bc26f 100644 --- a/include/boost/asio/buffered_stream_fwd.hpp +++ b/include/boost/asio/buffered_stream_fwd.hpp @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { @@ -26,6 +24,4 @@ class buffered_stream; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_BUFFERED_STREAM_FWD_HPP diff --git a/include/boost/asio/buffered_write_stream.hpp b/include/boost/asio/buffered_write_stream.hpp index fb38b257..c918a0a2 100644 --- a/include/boost/asio/buffered_write_stream.hpp +++ b/include/boost/asio/buffered_write_stream.hpp @@ -15,24 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include #include -#include - #include #include #include -#include -#include -#include #include #include #include +#include +#include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/buffered_write_stream_fwd.hpp b/include/boost/asio/buffered_write_stream_fwd.hpp index 74cdb83a..8f0f4095 100644 --- a/include/boost/asio/buffered_write_stream_fwd.hpp +++ b/include/boost/asio/buffered_write_stream_fwd.hpp @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { @@ -26,6 +24,4 @@ class buffered_write_stream; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP diff --git a/include/boost/asio/buffers_iterator.hpp b/include/boost/asio/buffers_iterator.hpp index 0b654b8c..254e4e86 100644 --- a/include/boost/asio/buffers_iterator.hpp +++ b/include/boost/asio/buffers_iterator.hpp @@ -15,20 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include #include #include #include #include -#include - #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/completion_condition.hpp b/include/boost/asio/completion_condition.hpp index 747591c6..dfb48edb 100644 --- a/include/boost/asio/completion_condition.hpp +++ b/include/boost/asio/completion_condition.hpp @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/datagram_socket_service.hpp b/include/boost/asio/datagram_socket_service.hpp index 74bf7033..4d324e28 100644 --- a/include/boost/asio/datagram_socket_service.hpp +++ b/include/boost/asio/datagram_socket_service.hpp @@ -15,16 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -32,6 +26,8 @@ # include #endif +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/deadline_timer.hpp b/include/boost/asio/deadline_timer.hpp index 7f8d1e38..3ed7b676 100644 --- a/include/boost/asio/deadline_timer.hpp +++ b/include/boost/asio/deadline_timer.hpp @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include // Must come before posix_time. +#include #include #include #include -#include - namespace boost { namespace asio { @@ -34,6 +32,4 @@ typedef basic_deadline_timer deadline_timer; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DEADLINE_TIMER_HPP diff --git a/include/boost/asio/deadline_timer_service.hpp b/include/boost/asio/deadline_timer_service.hpp index 624791db..77060c44 100644 --- a/include/boost/asio/deadline_timer_service.hpp +++ b/include/boost/asio/deadline_timer_service.hpp @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - +#include #include #include -#include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/array_fwd.hpp b/include/boost/asio/detail/array_fwd.hpp new file mode 100644 index 00000000..3d47a9af --- /dev/null +++ b/include/boost/asio/detail/array_fwd.hpp @@ -0,0 +1,25 @@ +// +// detail/array_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_ARRAY_FWD_HPP +#define BOOST_ASIO_DETAIL_ARRAY_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace boost { + +template +class array; + +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_ARRAY_FWD_HPP diff --git a/include/boost/asio/detail/base_from_completion_cond.hpp b/include/boost/asio/detail/base_from_completion_cond.hpp index 1b1f1422..797e3ced 100644 --- a/include/boost/asio/detail/base_from_completion_cond.hpp +++ b/include/boost/asio/detail/base_from_completion_cond.hpp @@ -1,6 +1,6 @@ // -// base_from_completion_cond.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/base_from_completion_cond.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -32,7 +33,8 @@ protected: { } - std::size_t check(const boost::system::error_code& ec, + std::size_t check_for_completion( + const boost::system::error_code& ec, std::size_t total_transferred) { return detail::adapt_completion_condition_result( @@ -51,7 +53,8 @@ protected: { } - static std::size_t check(const boost::system::error_code& ec, + static std::size_t check_for_completion( + const boost::system::error_code& ec, std::size_t total_transferred) { return transfer_all_t()(ec, total_transferred); diff --git a/include/boost/asio/detail/bind_handler.hpp b/include/boost/asio/detail/bind_handler.hpp index e161893e..c8136a1f 100644 --- a/include/boost/asio/detail/bind_handler.hpp +++ b/include/boost/asio/detail/bind_handler.hpp @@ -1,6 +1,6 @@ // -// bind_handler.hpp -// ~~~~~~~~~~~~~~~~ +// detail/bind_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/buffer_resize_guard.hpp b/include/boost/asio/detail/buffer_resize_guard.hpp index af67c468..bcffc1ab 100644 --- a/include/boost/asio/detail/buffer_resize_guard.hpp +++ b/include/boost/asio/detail/buffer_resize_guard.hpp @@ -1,6 +1,6 @@ // -// buffer_resize_guard.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/buffer_resize_guard.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/buffer_sequence_adapter.hpp b/include/boost/asio/detail/buffer_sequence_adapter.hpp index ce9652ef..2cfd880f 100644 --- a/include/boost/asio/detail/buffer_sequence_adapter.hpp +++ b/include/boost/asio/detail/buffer_sequence_adapter.hpp @@ -1,6 +1,6 @@ // -// buffer_sequence_adapter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/buffer_sequence_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,9 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + +#include namespace boost { namespace asio { @@ -33,14 +35,14 @@ protected: const boost::asio::mutable_buffer& buffer) { buf.buf = boost::asio::buffer_cast(buffer); - buf.len = boost::asio::buffer_size(buffer); + buf.len = static_cast(boost::asio::buffer_size(buffer)); } static void init_native_buffer(WSABUF& buf, const boost::asio::const_buffer& buffer) { buf.buf = const_cast(boost::asio::buffer_cast(buffer)); - buf.len = boost::asio::buffer_size(buffer); + buf.len = static_cast(boost::asio::buffer_size(buffer)); } #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef iovec native_buffer_type; diff --git a/include/boost/asio/detail/buffered_stream_storage.hpp b/include/boost/asio/detail/buffered_stream_storage.hpp index 9b834269..9a2929e9 100644 --- a/include/boost/asio/detail/buffered_stream_storage.hpp +++ b/include/boost/asio/detail/buffered_stream_storage.hpp @@ -1,6 +1,6 @@ // -// buffered_stream_storage.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/buffered_stream_storage.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/call_stack.hpp b/include/boost/asio/detail/call_stack.hpp index 0d7d52c3..561a8265 100644 --- a/include/boost/asio/detail/call_stack.hpp +++ b/include/boost/asio/detail/call_stack.hpp @@ -1,6 +1,6 @@ // -// call_stack.hpp -// ~~~~~~~~~~~~~~ +// detail/call_stack.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/completion_handler.hpp b/include/boost/asio/detail/completion_handler.hpp index d78e6c89..6701fb32 100644 --- a/include/boost/asio/detail/completion_handler.hpp +++ b/include/boost/asio/detail/completion_handler.hpp @@ -1,6 +1,6 @@ // -// completion_handler.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -30,6 +31,8 @@ template class completion_handler : public operation { public: + BOOST_ASIO_DEFINE_HANDLER_PTR(completion_handler); + completion_handler(Handler h) : operation(&completion_handler::do_complete), handler_(h) @@ -41,20 +44,21 @@ public: { // Take ownership of the handler object. completion_handler* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); + ptr p = { boost::addressof(h->handler_), h, h }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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_); + p.h = boost::addressof(handler); + p.reset(); // Make the upcall if required. if (owner) { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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_); - ptr.reset(); boost::asio::detail::fenced_block b; boost_asio_handler_invoke_helpers::invoke(handler, handler); } diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp new file mode 100644 index 00000000..abd2044c --- /dev/null +++ b/include/boost/asio/detail/config.hpp @@ -0,0 +1,205 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONFIG_HPP +#define BOOST_ASIO_DETAIL_CONFIG_HPP + +#include + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either BOOST_ASIO_SEPARATE_COMPILATION or +// BOOST_ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(BOOST_ASIO_HEADER_ONLY) +# if !defined(BOOST_ASIO_SEPARATE_COMPILATION) +# if !defined(BOOST_ASIO_DYN_LINK) +# define BOOST_ASIO_HEADER_ONLY +# endif // !defined(BOOST_ASIO_DYN_LINK) +# endif // !defined(BOOST_ASIO_SEPARATE_COMPILATION) +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + +#if defined(BOOST_ASIO_HEADER_ONLY) +# define BOOST_ASIO_DECL inline +#else // defined(BOOST_ASIO_HEADER_ONLY) +# if defined(BOOST_HAS_DECLSPEC) +// We need to import/export our code only if the user has specifically asked +// for it by defining BOOST_ASIO_DYN_LINK. +# if defined(BOOST_ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllexport) +# else // defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllimport) +# endif // defined(BOOST_ASIO_SOURCE) +# endif // defined(BOOST_ASIO_DYN_LINK) +# endif // defined(BOOST_HAS_DECLSPEC) +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +// If BOOST_ASIO_DECL isn't defined yet define it now. +#if !defined(BOOST_ASIO_DECL) +# define BOOST_ASIO_DECL +#endif // !defined(BOOST_ASIO_DECL) + +// Windows: target OS version. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || defined(__BORLANDC__) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") +# else // defined(_MSC_VER) || defined(__BORLANDC__) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# define _WIN32_WINNT 0x0501 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# endif // defined(__CYGWIN__) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(BOOST_ASIO_NO_NOMINMAX) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) +# if !defined(BOOST_ASIO_DISABLE_IOCP) +# define BOOST_ASIO_HAS_IOCP 1 +# endif // !defined(BOOST_ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Linux: epoll, eventfd and timerfd. +#if defined(__linux__) +# include +# if !defined(BOOST_ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define BOOST_ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define BOOST_ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if defined(BOOST_ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define BOOST_ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(BOOST_ASIO_HAS_EPOLL) +#endif // defined(__linux__) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(BOOST_ASIO_DISABLE_KQUEUE) +# define BOOST_ASIO_HAS_KQUEUE 1 +# endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# define BOOST_ASIO_HAS_DEV_POLL 1 +# endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# define BOOST_ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# endif // !defined(__SYMBIAN32__) +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +// Windows: stream handles. +#if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) + +#endif // BOOST_ASIO_DETAIL_CONFIG_HPP diff --git a/include/boost/asio/detail/consuming_buffers.hpp b/include/boost/asio/detail/consuming_buffers.hpp index 3604cbaa..23114a07 100644 --- a/include/boost/asio/detail/consuming_buffers.hpp +++ b/include/boost/asio/detail/consuming_buffers.hpp @@ -1,6 +1,6 @@ // -// consuming_buffers.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// detail/consuming_buffers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,18 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include #include #include -#include - #include +#include + namespace boost { namespace asio { namespace detail { @@ -157,12 +153,14 @@ public: consuming_buffers(const Buffers& buffers) : buffers_(buffers), at_end_(buffers_.begin() == buffers_.end()), - first_(*buffers_.begin()), begin_remainder_(buffers_.begin()), max_size_((std::numeric_limits::max)()) { if (!at_end_) + { + first_ = *buffers_.begin(); ++begin_remainder_; + } } // Copy constructor. diff --git a/include/boost/asio/detail/deadline_timer_service.hpp b/include/boost/asio/detail/deadline_timer_service.hpp index 5ba21b15..f1ab2f82 100644 --- a/include/boost/asio/detail/deadline_timer_service.hpp +++ b/include/boost/asio/detail/deadline_timer_service.hpp @@ -1,6 +1,6 @@ // -// deadline_timer_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/deadline_timer_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include -#include - #include #include #include @@ -33,6 +27,13 @@ #include #include #include +#include + +#include +#include +#include + +#include namespace boost { namespace asio { @@ -152,59 +153,21 @@ public: ec = boost::system::error_code(); } - template - class wait_handler : public timer_op - { - public: - wait_handler(Handler handler) - : timer_op(&wait_handler::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - wait_handler* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder1 - handler(h->handler_, h->ec_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous wait on the timer. template void async_wait(implementation_type& impl, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef wait_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef wait_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); impl.might_have_pending_waits = true; - scheduler_.schedule_timer(timer_queue_, impl.expiry, ptr.get(), &impl); - ptr.release(); + scheduler_.schedule_timer(timer_queue_, impl.expiry, p.p, &impl); + p.v = p.p = 0; } private: diff --git a/include/boost/asio/detail/descriptor_ops.hpp b/include/boost/asio/detail/descriptor_ops.hpp index c4969f70..4f82cd65 100644 --- a/include/boost/asio/detail/descriptor_ops.hpp +++ b/include/boost/asio/detail/descriptor_ops.hpp @@ -1,6 +1,6 @@ // -// descriptor_ops.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/descriptor_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,28 +15,35 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include +#include #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include +#include +#include + +#include + namespace boost { namespace asio { namespace detail { namespace descriptor_ops { -inline void clear_error(boost::system::error_code& ec) +// Descriptor state bits. +enum { - errno = 0; - ec = boost::system::error_code(); -} + // The user wants a non-blocking descriptor. + user_set_non_blocking = 1, + + // The descriptor has been set non-blocking. + internal_non_blocking = 2, + + // Helper "state" used to determine whether the descriptor is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking +}; + +typedef unsigned char state_type; template inline ReturnType error_wrapper(ReturnType return_value, @@ -47,132 +54,54 @@ inline ReturnType error_wrapper(ReturnType return_value, return return_value; } -inline int open(const char* path, int flags, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::open(path, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int open(const char* path, int flags, + boost::system::error_code& ec); -inline int close(int d, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::close(d), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int close(int d, state_type& state, + boost::system::error_code& ec); -inline void init_buf_iov_base(void*& base, void* addr) -{ - base = addr; -} - -template -inline void init_buf_iov_base(T& base, void* addr) -{ - base = static_cast(addr); -} +BOOST_ASIO_DECL bool set_internal_non_blocking(int d, + state_type& state, boost::system::error_code& ec); typedef iovec buf; -inline void init_buf(buf& b, void* data, size_t size) -{ - init_buf_iov_base(b.iov_base, data); - b.iov_len = size; -} +BOOST_ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, boost::system::error_code& ec); -inline void init_buf(buf& b, const void* data, size_t size) -{ - init_buf_iov_base(b.iov_base, const_cast(data)); - b.iov_len = size; -} +BOOST_ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred); -inline int scatter_read(int d, buf* bufs, size_t count, - boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::readv(d, bufs, static_cast(count)), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL std::size_t sync_write(int d, state_type state, + const buf* bufs, std::size_t count, bool all_empty, + boost::system::error_code& ec); -inline int gather_write(int d, const buf* bufs, size_t count, - boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::writev(d, bufs, static_cast(count)), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL bool non_blocking_write(int d, + const buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred); -inline int ioctl(int d, long cmd, ioctl_arg_type* arg, - boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::ioctl(d, cmd, arg), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, boost::system::error_code& ec); -inline int fcntl(int d, long cmd, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::fcntl(d, cmd), ec); - if (result != -1) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int fcntl(int d, long cmd, boost::system::error_code& ec); -inline int fcntl(int d, long cmd, long arg, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::fcntl(d, cmd, arg), ec); - if (result != -1) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int fcntl(int d, long cmd, + long arg, boost::system::error_code& ec); -inline int poll_read(int d, boost::system::error_code& ec) -{ - clear_error(ec); - pollfd fds; - fds.fd = d; - fds.events = POLLIN; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int poll_read(int d, boost::system::error_code& ec); -inline int poll_write(int d, boost::system::error_code& ec) -{ - clear_error(ec); - pollfd fds; - fds.fd = d; - fds.events = POLLOUT; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int poll_write(int d, boost::system::error_code& ec); } // namespace descriptor_ops } // namespace detail } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP diff --git a/include/boost/asio/detail/descriptor_read_op.hpp b/include/boost/asio/detail/descriptor_read_op.hpp new file mode 100644 index 00000000..c068108f --- /dev/null +++ b/include/boost/asio/detail/descriptor_read_op.hpp @@ -0,0 +1,116 @@ +// +// detail/descriptor_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP +#define BOOST_ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class descriptor_read_op_base : public reactor_op +{ +public: + descriptor_read_op_base(int descriptor, + const MutableBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_read_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static bool do_perform(reactor_op* base) + { + descriptor_read_op_base* o(static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return descriptor_ops::non_blocking_read(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); + } + +private: + int descriptor_; + MutableBufferSequence buffers_; +}; + +template +class descriptor_read_op + : public descriptor_read_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); + + descriptor_read_op(int descriptor, + const MutableBufferSequence& buffers, Handler handler) + : descriptor_read_op_base( + descriptor, buffers, &descriptor_read_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_read_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP diff --git a/include/boost/asio/detail/descriptor_write_op.hpp b/include/boost/asio/detail/descriptor_write_op.hpp new file mode 100644 index 00000000..09838548 --- /dev/null +++ b/include/boost/asio/detail/descriptor_write_op.hpp @@ -0,0 +1,116 @@ +// +// detail/descriptor_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP +#define BOOST_ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class descriptor_write_op_base : public reactor_op +{ +public: + descriptor_write_op_base(int descriptor, + const ConstBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_write_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static bool do_perform(reactor_op* base) + { + descriptor_write_op_base* o(static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return descriptor_ops::non_blocking_write(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); + } + +private: + int descriptor_; + ConstBufferSequence buffers_; +}; + +template +class descriptor_write_op + : public descriptor_write_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); + + descriptor_write_op(int descriptor, + const ConstBufferSequence& buffers, Handler handler) + : descriptor_write_op_base( + descriptor, buffers, &descriptor_write_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_write_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP diff --git a/include/boost/asio/detail/dev_poll_reactor.hpp b/include/boost/asio/detail/dev_poll_reactor.hpp index e00f501b..963def3d 100644 --- a/include/boost/asio/detail/dev_poll_reactor.hpp +++ b/include/boost/asio/detail/dev_poll_reactor.hpp @@ -1,6 +1,6 @@ // -// dev_poll_reactor.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,36 +15,28 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_DEV_POLL) -#include #include #include -#include -#include -#include #include -#include -#include - -#include -#include +#include #include #include #include #include #include #include -#include #include #include #include #include #include +#include + +#include namespace boost { namespace asio { @@ -63,358 +55,91 @@ public: }; // Constructor. - dev_poll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - io_service_(use_service(io_service)), - mutex_(), - dev_poll_fd_(do_dev_poll_create()), - interrupter_(), - shutdown_(false) - { - // Add the interrupter's descriptor to /dev/poll. - ::pollfd ev = { 0 }; - ev.fd = interrupter_.read_descriptor(); - ev.events = POLLIN | POLLERR; - ev.revents = 0; - ::write(dev_poll_fd_, &ev, sizeof(ev)); - } + BOOST_ASIO_DECL dev_poll_reactor(boost::asio::io_service& io_service); // Destructor. - ~dev_poll_reactor() - { - shutdown_service(); - ::close(dev_poll_fd_); - } + BOOST_ASIO_DECL ~dev_poll_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - op_queue ops; - - for (int i = 0; i < max_ops; ++i) - op_queue_[i].get_all_operations(ops); - - timer_queues_.get_all_timers(ops); - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task. - void init_task() - { - io_service_.init_task(); - } + BOOST_ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type, per_descriptor_data&) + BOOST_ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, - per_descriptor_data&, reactor_op* op, bool allow_speculative) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (allow_speculative) - { - if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) - { - if (!op_queue_[op_type].has_operation(descriptor)) - { - if (op->perform()) - { - lock.unlock(); - io_service_.post_immediate_completion(op); - return; - } - } - } - } - - bool first = op_queue_[op_type].enqueue_operation(descriptor, op); - io_service_.work_started(); - if (first) - { - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLERR | POLLHUP; - if (op_type == read_op - || op_queue_[read_op].has_operation(descriptor)) - ev.events |= POLLIN; - if (op_type == write_op - || op_queue_[write_op].has_operation(descriptor)) - ev.events |= POLLOUT; - if (op_type == except_op - || op_queue_[except_op].has_operation(descriptor)) - ev.events |= POLLPRI; - interrupter_.interrupt(); - } - } + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool allow_speculative); // 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, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); - } + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Remove the descriptor from /dev/poll. - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLREMOVE; - interrupter_.interrupt(); - - // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); - } + BOOST_ASIO_DECL void close_descriptor( + socket_type descriptor, per_descriptor_data&); // Add a new timer queue to the reactor. template - void add_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& queue); // Remove a timer queue from the reactor. template - void remove_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template - void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - interrupter_.interrupt(); - } - } + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue& queue, void* token); // Run /dev/poll once until interrupted or events are ready to be dispatched. - void run(bool block, op_queue& ops) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // We can return immediately if there's no work to do and the reactor is - // not supposed to block. - if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() - && op_queue_[except_op].empty() && timer_queues_.all_empty()) - return; - - // Write the pending event registration changes to the /dev/poll descriptor. - std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); - if (events_size > 0) - { - errno = 0; - int result = ::write(dev_poll_fd_, - &pending_event_changes_[0], events_size); - if (result != static_cast(events_size)) - { - boost::system::error_code ec = boost::system::error_code( - errno, boost::asio::error::get_system_category()); - for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) - { - int descriptor = pending_event_changes_[i].fd; - for (int j = 0; j < max_ops; ++j) - op_queue_[j].cancel_operations(descriptor, ops, ec); - } - } - pending_event_changes_.clear(); - pending_event_change_index_.clear(); - } - - int timeout = block ? get_timeout() : 0; - lock.unlock(); - - // Block on the /dev/poll descriptor. - ::pollfd events[128] = { { 0 } }; - ::dvpoll dp = { 0 }; - dp.dp_fds = events; - dp.dp_nfds = 128; - dp.dp_timeout = timeout; - int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); - - lock.lock(); - - // Dispatch the waiting events. - for (int i = 0; i < num_events; ++i) - { - int descriptor = events[i].fd; - if (descriptor == interrupter_.read_descriptor()) - { - interrupter_.reset(); - } - else - { - bool more_reads = false; - bool more_writes = false; - bool more_except = false; - - // 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 = - op_queue_[except_op].perform_operations(descriptor, ops); - else - more_except = op_queue_[except_op].has_operation(descriptor); - - if (events[i].events & (POLLIN | POLLERR | POLLHUP)) - more_reads = op_queue_[read_op].perform_operations(descriptor, ops); - else - more_reads = op_queue_[read_op].has_operation(descriptor); - - if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) - more_writes = op_queue_[write_op].perform_operations(descriptor, ops); - else - more_writes = op_queue_[write_op].has_operation(descriptor); - - if ((events[i].events & (POLLERR | POLLHUP)) != 0 - && !more_except && !more_reads && !more_writes) - { - // If we have an event and no operations associated with the - // descriptor then we need to delete the descriptor from /dev/poll. - // The poll operation can produce POLLHUP or POLLERR events when there - // is no operation pending, so if we do not remove the descriptor we - // can end up in a tight polling loop. - ::pollfd ev = { 0 }; - ev.fd = descriptor; - ev.events = POLLREMOVE; - ev.revents = 0; - ::write(dev_poll_fd_, &ev, sizeof(ev)); - } - else - { - ::pollfd ev = { 0 }; - ev.fd = descriptor; - ev.events = POLLERR | POLLHUP; - if (more_reads) - ev.events |= POLLIN; - if (more_writes) - ev.events |= POLLOUT; - if (more_except) - ev.events |= POLLPRI; - ev.revents = 0; - int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); - if (result != sizeof(ev)) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - for (int j = 0; j < max_ops; ++j) - op_queue_[j].cancel_operations(descriptor, ops, ec); - } - } - } - } - timer_queues_.get_ready_timers(ops); - } + BOOST_ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the select loop. - void interrupt() - { - interrupter_.interrupt(); - } + BOOST_ASIO_DECL void interrupt(); private: // Create the /dev/poll file descriptor. Throws an exception if the descriptor // cannot be created. - static int do_dev_poll_create() - { - int fd = ::open("/dev/poll", O_RDWR); - if (fd == -1) - { - boost::throw_exception( - boost::system::system_error( - boost::system::error_code(errno, - boost::asio::error::get_system_category()), - "/dev/poll")); - } - return fd; - } + BOOST_ASIO_DECL static int do_dev_poll_create(); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the /dev/poll DP_POLL operation. The timeout // value is returned as a number of milliseconds. A return value of -1 // indicates that the poll should block indefinitely. - int get_timeout() - { - // By default we will wait no longer than 5 minutes. This will ensure that - // any changes to the system clock are detected after no longer than this. - return timer_queues_.wait_duration_msec(5 * 60 * 1000); - } + BOOST_ASIO_DECL int get_timeout(); // Cancel all operations associated with the given descriptor. The do_cancel // function of the handler objects will be invoked. This function does not // acquire the dev_poll_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor, - const boost::system::error_code& ec) - { - bool need_interrupt = false; - op_queue ops; - for (int i = 0; i < max_ops; ++i) - need_interrupt = op_queue_[i].cancel_operations( - descriptor, ops, ec) || need_interrupt; - io_service_.post_deferred_completions(ops); - if (need_interrupt) - interrupter_.interrupt(); - } + BOOST_ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec); // Add a pending event entry for the given descriptor. - ::pollfd& add_pending_event_change(int descriptor) - { - hash_map::iterator iter - = pending_event_change_index_.find(descriptor); - if (iter == pending_event_change_index_.end()) - { - std::size_t index = pending_event_changes_.size(); - pending_event_changes_.reserve(pending_event_changes_.size() + 1); - pending_event_change_index_.insert(std::make_pair(descriptor, index)); - pending_event_changes_.push_back(::pollfd()); - pending_event_changes_[index].fd = descriptor; - pending_event_changes_[index].revents = 0; - return pending_event_changes_[index]; - } - else - { - return pending_event_changes_[iter->second]; - } - } + BOOST_ASIO_DECL ::pollfd& add_pending_event_change(int descriptor); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -448,8 +173,13 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_DEV_POLL) - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + #endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP diff --git a/include/boost/asio/detail/dev_poll_reactor_fwd.hpp b/include/boost/asio/detail/dev_poll_reactor_fwd.hpp index 238cee52..7e8defc5 100644 --- a/include/boost/asio/detail/dev_poll_reactor_fwd.hpp +++ b/include/boost/asio/detail/dev_poll_reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// dev_poll_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/dev_poll_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#if !defined(BOOST_ASIO_DISABLE_DEV_POLL) -#if defined(__sun) // This service is only supported on Solaris. - -// Define this to indicate that /dev/poll is supported on the target platform. -#define BOOST_ASIO_HAS_DEV_POLL 1 +#if defined(BOOST_ASIO_HAS_DEV_POLL) namespace boost { namespace asio { @@ -33,9 +29,6 @@ class dev_poll_reactor; } // namespace asio } // namespace boost -#endif // defined(__sun) -#endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) - -#include +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) #endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/epoll_reactor.hpp b/include/boost/asio/detail/epoll_reactor.hpp index 46849448..0471436a 100644 --- a/include/boost/asio/detail/epoll_reactor.hpp +++ b/include/boost/asio/detail/epoll_reactor.hpp @@ -1,6 +1,6 @@ // -// epoll_reactor.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,43 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_EPOLL) -#include -#include -#include -#include -#include -#include -#include - -#include #include +#include #include #include #include #include #include -#include #include #include #include #include #include -#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) -# define BOOST_ASIO_HAS_TIMERFD 1 -#endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) - -#if defined(BOOST_ASIO_HAS_TIMERFD) -# include -# include -# include -#endif // defined(BOOST_ASIO_HAS_TIMERFD) +#include namespace boost { namespace asio { @@ -80,342 +61,69 @@ public: typedef descriptor_state* per_descriptor_data; // Constructor. - epoll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - io_service_(use_service(io_service)), - mutex_(), - epoll_fd_(do_epoll_create()), -#if defined(BOOST_ASIO_HAS_TIMERFD) - timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), -#else // defined(BOOST_ASIO_HAS_TIMERFD) - timer_fd_(-1), -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - interrupter_(), - shutdown_(false) - { - // Add the interrupter's descriptor to epoll. - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLET; - ev.data.ptr = &interrupter_; - epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); - interrupter_.interrupt(); - - // Add the timer descriptor to epoll. - if (timer_fd_ != -1) - { - ev.events = EPOLLIN | EPOLLERR; - ev.data.ptr = &timer_fd_; - epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); - } - } + BOOST_ASIO_DECL epoll_reactor(boost::asio::io_service& io_service); // Destructor. - ~epoll_reactor() - { - close(epoll_fd_); - if (timer_fd_ != -1) - close(timer_fd_); - } + BOOST_ASIO_DECL ~epoll_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - op_queue ops; - - descriptor_map::iterator iter = registered_descriptors_.begin(); - descriptor_map::iterator end = registered_descriptors_.end(); - while (iter != end) - { - for (int i = 0; i < max_ops; ++i) - ops.push(iter->second.op_queue_[i]); - iter->second.shutdown_ = true; - ++iter; - } - - timer_queues_.get_all_timers(ops); - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task. - void init_task() - { - io_service_.init_task(); - } + BOOST_ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) + BOOST_ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - mutex::scoped_lock lock(registered_descriptors_mutex_); - - descriptor_map::iterator new_entry = registered_descriptors_.insert( - std::make_pair(descriptor, descriptor_state())).first; - descriptor_data = &new_entry->second; - - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; - ev.data.ptr = descriptor_data; - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) - return errno; - - descriptor_data->shutdown_ = false; - - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, - reactor_op* op, bool allow_speculative) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - if (descriptor_data->shutdown_) - return; - - if (descriptor_data->op_queue_[op_type].empty()) - { - if (allow_speculative - && (op_type != read_op - || descriptor_data->op_queue_[except_op].empty())) - { - if (op->perform()) - { - descriptor_lock.unlock(); - io_service_.post_immediate_completion(op); - return; - } - } - else - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLHUP - | EPOLLOUT | EPOLLPRI | EPOLLET; - ev.data.ptr = descriptor_data; - epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - } - } - - descriptor_data->op_queue_[op_type].push(op); - io_service_.work_started(); - } + reactor_op* op, bool allow_speculative); // 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, per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - op_queue ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = boost::asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - - // Remove the descriptor from the set of known descriptors. The descriptor - // will be automatically removed from the epoll set when it is closed. - descriptor_data->shutdown_ = true; - - op_queue ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = boost::asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - registered_descriptors_.erase(descriptor); - - descriptors_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + BOOST_ASIO_DECL void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); // Add a new timer queue to the reactor. template - void add_timer_queue(timer_queue& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& timer_queue); // Remove a timer queue from the reactor. template - void remove_timer_queue(timer_queue& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - { -#if defined(BOOST_ASIO_HAS_TIMERFD) - if (timer_fd_ != -1) - { - itimerspec new_timeout; - itimerspec old_timeout; - int flags = get_timeout(new_timeout); - timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); - return; - } -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - interrupter_.interrupt(); - } - } - } + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - mutex::scoped_lock lock(mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue& timer_queue, void* token); // Run epoll once until interrupted or events are ready to be dispatched. - void run(bool block, op_queue& ops) - { - // Calculate a timeout only if timerfd is not used. - int timeout; - if (timer_fd_ != -1) - timeout = block ? -1 : 0; - else - { - mutex::scoped_lock lock(mutex_); - timeout = block ? get_timeout() : 0; - } - - // Block on the epoll descriptor. - epoll_event events[128]; - int num_events = epoll_wait(epoll_fd_, events, 128, timeout); - -#if defined(BOOST_ASIO_HAS_TIMERFD) - bool check_timers = (timer_fd_ == -1); -#else // defined(BOOST_ASIO_HAS_TIMERFD) - bool check_timers = true; -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - - // Dispatch the waiting events. - for (int i = 0; i < num_events; ++i) - { - void* ptr = events[i].data.ptr; - if (ptr == &interrupter_) - { - // No need to reset the interrupter since we're leaving the descriptor - // in a ready-to-read state and relying on edge-triggered notifications - // to make it so that we only get woken up when the descriptor's epoll - // registration is updated. - -#if defined(BOOST_ASIO_HAS_TIMERFD) - if (timer_fd_ == -1) - check_timers = true; -#else // defined(BOOST_ASIO_HAS_TIMERFD) - check_timers = true; -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - } -#if defined(BOOST_ASIO_HAS_TIMERFD) - else if (ptr == &timer_fd_) - { - check_timers = true; - } -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - else - { - descriptor_state* descriptor_data = static_cast(ptr); - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; - for (int j = max_ops - 1; j >= 0; --j) - { - if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP)) - { - while (reactor_op* op = descriptor_data->op_queue_[j].front()) - { - if (op->perform()) - { - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - else - break; - } - } - } - } - } - - if (check_timers) - { - mutex::scoped_lock common_lock(mutex_); - timer_queues_.get_ready_timers(ops); - -#if defined(BOOST_ASIO_HAS_TIMERFD) - if (timer_fd_ != -1) - { - itimerspec new_timeout; - itimerspec old_timeout; - int flags = get_timeout(new_timeout); - timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); - } -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - } - } + BOOST_ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the select loop. - void interrupt() - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLET; - ev.data.ptr = &interrupter_; - epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); - } + BOOST_ASIO_DECL void interrupt(); private: // The hint to pass to epoll_create to size its data structures. @@ -423,44 +131,26 @@ private: // Create the epoll file descriptor. Throws an exception if the descriptor // cannot be created. - static int do_epoll_create() - { - int fd = epoll_create(epoll_size); - if (fd == -1) - { - boost::throw_exception( - boost::system::system_error( - boost::system::error_code(errno, - boost::asio::error::get_system_category()), - "epoll")); - } - return fd; - } + BOOST_ASIO_DECL static int do_epoll_create(); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + BOOST_ASIO_DECL void update_timeout(); // Get the timeout value for the epoll_wait call. The timeout value is // returned as a number of milliseconds. A return value of -1 indicates // that epoll_wait should block indefinitely. - int get_timeout() - { - // By default we will wait no longer than 5 minutes. This will ensure that - // any changes to the system clock are detected after no longer than this. - return timer_queues_.wait_duration_msec(5 * 60 * 1000); - } + BOOST_ASIO_DECL int get_timeout(); #if defined(BOOST_ASIO_HAS_TIMERFD) // Get the timeout value for the timer descriptor. The return value is the // flag argument to be used when calling timerfd_settime. - int get_timeout(itimerspec& ts) - { - ts.it_interval.tv_sec = 0; - ts.it_interval.tv_nsec = 0; - - long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); - ts.it_value.tv_sec = usec / 1000000; - ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; - - return usec ? 0 : TFD_TIMER_ABSTIME; - } + BOOST_ASIO_DECL int get_timeout(itimerspec& ts); #endif // defined(BOOST_ASIO_HAS_TIMERFD) // The io_service implementation used to post completions. @@ -502,8 +192,13 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_EPOLL) - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + #endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP diff --git a/include/boost/asio/detail/epoll_reactor_fwd.hpp b/include/boost/asio/detail/epoll_reactor_fwd.hpp index 214cee54..dc0e92de 100644 --- a/include/boost/asio/detail/epoll_reactor_fwd.hpp +++ b/include/boost/asio/detail/epoll_reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// epoll_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// detail/epoll_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#if !defined(BOOST_ASIO_DISABLE_EPOLL) -#if defined(__linux__) // This service is only supported on Linux. - -#include -#include -#include - -#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45. - -// Define this to indicate that epoll is supported on the target platform. -#define BOOST_ASIO_HAS_EPOLL 1 +#if defined(BOOST_ASIO_HAS_EPOLL) namespace boost { namespace asio { @@ -39,10 +29,6 @@ class epoll_reactor; } // namespace asio } // namespace boost -#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) -#endif // defined(__linux__) -#endif // !defined(BOOST_ASIO_DISABLE_EPOLL) - -#include +#endif // defined(BOOST_ASIO_HAS_EPOLL) #endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/event.hpp b/include/boost/asio/detail/event.hpp index e8d185fe..c33b65ae 100644 --- a/include/boost/asio/detail/event.hpp +++ b/include/boost/asio/detail/event.hpp @@ -1,6 +1,6 @@ // -// event.hpp -// ~~~~~~~~~ +// detail/event.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -47,6 +43,4 @@ typedef posix_event event; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_EVENT_HPP diff --git a/include/boost/asio/detail/eventfd_select_interrupter.hpp b/include/boost/asio/detail/eventfd_select_interrupter.hpp index 4749ec92..b2cb68b7 100644 --- a/include/boost/asio/detail/eventfd_select_interrupter.hpp +++ b/include/boost/asio/detail/eventfd_select_interrupter.hpp @@ -1,6 +1,6 @@ // -// eventfd_select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/eventfd_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) @@ -16,36 +16,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include - -#if defined(__linux__) -# if !defined(BOOST_ASIO_DISABLE_EVENTFD) -# include -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) -# define BOOST_ASIO_HAS_EVENTFD -# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) -# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) -#endif // defined(__linux__) +#include #if defined(BOOST_ASIO_HAS_EVENTFD) #include -#include -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 -# include -#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 -# include -#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 -#include - -#include -#include namespace boost { namespace asio { @@ -55,87 +30,16 @@ class eventfd_select_interrupter { public: // Constructor. - eventfd_select_interrupter() - { -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 - write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); -#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 - write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); -#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 - if (read_descriptor_ != -1) - { - ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); - } - else - { - int pipe_fds[2]; - if (pipe(pipe_fds) == 0) - { - read_descriptor_ = pipe_fds[0]; - ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); - write_descriptor_ = pipe_fds[1]; - ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); - } - else - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - boost::system::system_error e(ec, "eventfd_select_interrupter"); - boost::throw_exception(e); - } - } - } + BOOST_ASIO_DECL eventfd_select_interrupter(); // Destructor. - ~eventfd_select_interrupter() - { - if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) - ::close(write_descriptor_); - if (read_descriptor_ != -1) - ::close(read_descriptor_); - } + BOOST_ASIO_DECL ~eventfd_select_interrupter(); // Interrupt the select call. - void interrupt() - { - uint64_t counter(1UL); - int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); - (void)result; - } + BOOST_ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. - bool reset() - { - if (write_descriptor_ == read_descriptor_) - { - for (;;) - { - // Only perform one read. The kernel maintains an atomic counter. - uint64_t counter(0); - errno = 0; - int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); - if (bytes_read < 0 && errno == EINTR) - continue; - bool was_interrupted = (bytes_read > 0); - return was_interrupted; - } - } - else - { - for (;;) - { - // Clear all data from the pipe. - char data[1024]; - int bytes_read = ::read(read_descriptor_, data, sizeof(data)); - if (bytes_read < 0 && errno == EINTR) - continue; - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = ::read(read_descriptor_, data, sizeof(data)); - return was_interrupted; - } - } - } + BOOST_ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. int read_descriptor() const @@ -161,8 +65,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_EVENTFD) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_EVENTFD) + #endif // BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP diff --git a/include/boost/asio/detail/fd_set_adapter.hpp b/include/boost/asio/detail/fd_set_adapter.hpp index 059362ec..138264f4 100644 --- a/include/boost/asio/detail/fd_set_adapter.hpp +++ b/include/boost/asio/detail/fd_set_adapter.hpp @@ -1,6 +1,6 @@ // -// fd_set_adapter.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,12 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - +#include #include #include @@ -38,6 +33,4 @@ typedef posix_fd_set_adapter fd_set_adapter; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP diff --git a/include/boost/asio/detail/fenced_block.hpp b/include/boost/asio/detail/fenced_block.hpp index c80161f3..b04ed0d5 100644 --- a/include/boost/asio/detail/fenced_block.hpp +++ b/include/boost/asio/detail/fenced_block.hpp @@ -1,6 +1,6 @@ // -// fenced_block.hpp -// ~~~~~~~~~~~~~~~~ +// detail/fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -67,6 +63,4 @@ typedef null_fenced_block fenced_block; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/gcc_fenced_block.hpp b/include/boost/asio/detail/gcc_fenced_block.hpp index 0c086a6c..fd737cf0 100644 --- a/include/boost/asio/detail/gcc_fenced_block.hpp +++ b/include/boost/asio/detail/gcc_fenced_block.hpp @@ -1,6 +1,6 @@ // -// gcc_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/gcc_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +#include + namespace boost { namespace asio { namespace detail { @@ -55,11 +53,11 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(__GNUC__) // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) // && !defined(__INTEL_COMPILER) && !defined(__ICL) // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) -#include - #endif // BOOST_ASIO_DETAIL_GCC_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/gcc_x86_fenced_block.hpp b/include/boost/asio/detail/gcc_x86_fenced_block.hpp index fc23d662..5353f871 100644 --- a/include/boost/asio/detail/gcc_x86_fenced_block.hpp +++ b/include/boost/asio/detail/gcc_x86_fenced_block.hpp @@ -1,6 +1,6 @@ // -// gcc_x86_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/gcc_x86_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#include + namespace boost { namespace asio { namespace detail { @@ -56,8 +54,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - #include +#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + #endif // BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/handler_alloc_helpers.hpp b/include/boost/asio/detail/handler_alloc_helpers.hpp index d385972e..00d4c022 100644 --- a/include/boost/asio/detail/handler_alloc_helpers.hpp +++ b/include/boost/asio/detail/handler_alloc_helpers.hpp @@ -1,6 +1,6 @@ // -// handler_alloc_helpers.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/handler_alloc_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - -#include #include +#include + +#include // Calls to asio_handler_allocate and asio_handler_deallocate must be made from // a namespace that does not contain any overloads of these functions. The @@ -56,205 +54,31 @@ inline void deallocate(void* p, std::size_t s, Handler& h) } // namespace boost_asio_handler_alloc_helpers -namespace boost { -namespace asio { -namespace detail { - -// Traits for handler allocation. -template -struct handler_alloc_traits -{ - typedef Handler handler_type; - typedef Object value_type; - typedef Object* pointer_type; - BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object)); -}; - -template -class handler_ptr; - -// Helper class to provide RAII on uninitialised handler memory. -template -class raw_handler_ptr - : private noncopyable -{ -public: - typedef typename Alloc_Traits::handler_type handler_type; - typedef typename Alloc_Traits::value_type value_type; - typedef typename Alloc_Traits::pointer_type pointer_type; - BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size); - - // Constructor allocates the memory. - raw_handler_ptr(handler_type& handler) - : handler_(handler), - pointer_(static_cast( - boost_asio_handler_alloc_helpers::allocate(value_size, handler_))) - { - } - - // Destructor automatically deallocates memory, unless it has been stolen by - // a handler_ptr object. - ~raw_handler_ptr() - { - if (pointer_) - boost_asio_handler_alloc_helpers::deallocate( - pointer_, value_size, handler_); - } - -private: - friend class handler_ptr; - handler_type& handler_; - pointer_type pointer_; -}; - -// Helper class to provide RAII on uninitialised handler memory. -template -class handler_ptr - : private noncopyable -{ -public: - typedef typename Alloc_Traits::handler_type handler_type; - typedef typename Alloc_Traits::value_type value_type; - typedef typename Alloc_Traits::pointer_type pointer_type; - BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size); - typedef raw_handler_ptr raw_ptr_type; - - // Take ownership of existing memory. - handler_ptr(handler_type& handler, pointer_type pointer) - : handler_(handler), - pointer_(pointer) - { - } - - // Construct object in raw memory and take ownership if construction succeeds. - handler_ptr(raw_ptr_type& raw_ptr) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5, Arg6& a6) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5, Arg6& a6, Arg7& a7) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type( - a1, a2, a3, a4, a5, a6, a7, a8)) - { - raw_ptr.pointer_ = 0; - } - - // Destructor automatically deallocates memory, unless it has been released. - ~handler_ptr() - { - reset(); - } - - // Get the memory. - pointer_type get() const - { - return pointer_; - } - - // Release ownership of the memory. - pointer_type release() - { - pointer_type tmp = pointer_; - pointer_ = 0; - return tmp; - } - - // Explicitly destroy and deallocate the memory. - void reset() - { - if (pointer_) - { - pointer_->value_type::~value_type(); - boost_asio_handler_alloc_helpers::deallocate( - pointer_, value_size, handler_); - pointer_ = 0; - } - } - -private: - handler_type& handler_; - pointer_type pointer_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost +#define BOOST_ASIO_DEFINE_HANDLER_PTR(op) \ + struct ptr \ + { \ + Handler* h; \ + void* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + boost_asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \ + v = 0; \ + } \ + } \ + } \ + /**/ #include diff --git a/include/boost/asio/detail/handler_invoke_helpers.hpp b/include/boost/asio/detail/handler_invoke_helpers.hpp index 8952d8db..996bde9a 100644 --- a/include/boost/asio/detail/handler_invoke_helpers.hpp +++ b/include/boost/asio/detail/handler_invoke_helpers.hpp @@ -1,6 +1,6 @@ // -// handler_invoke_helpers.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/handler_invoke_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - #include +#include + // Calls to asio_handler_invoke must be made from a namespace that does not // contain overloads of this function. The boost_asio_handler_invoke_helpers // namespace is defined here for that purpose. diff --git a/include/boost/asio/detail/hash_map.hpp b/include/boost/asio/detail/hash_map.hpp index 36c9a99b..c58096b5 100644 --- a/include/boost/asio/detail/hash_map.hpp +++ b/include/boost/asio/detail/hash_map.hpp @@ -1,6 +1,6 @@ // -// hash_map.hpp -// ~~~~~~~~~~~~ +// detail/hash_map.hpp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,34 +15,39 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include -#include - #include -#include + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include namespace boost { namespace asio { namespace detail { -template -inline std::size_t calculate_hash_value(const T& t) +inline std::size_t calculate_hash_value(int i) { - return boost::hash_value(t); + return static_cast(i); } -#if defined(_WIN64) +inline std::size_t calculate_hash_value(void* p) +{ + return reinterpret_cast(p) + + (reinterpret_cast(p) >> 3); +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) inline std::size_t calculate_hash_value(SOCKET s) { return static_cast(s); } -#endif // defined(_WIN64) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Note: assumes K and V are POD types. template diff --git a/include/boost/asio/detail/impl/descriptor_ops.ipp b/include/boost/asio/detail/impl/descriptor_ops.ipp new file mode 100644 index 00000000..3862d59a --- /dev/null +++ b/include/boost/asio/detail/impl/descriptor_ops.ipp @@ -0,0 +1,372 @@ +// +// detail/impl/descriptor_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP +#define BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace descriptor_ops { + +int open(const char* path, int flags, boost::system::error_code& ec) +{ + errno = 0; + int result = error_wrapper(::open(path, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +} + +int close(int d, state_type& state, boost::system::error_code& ec) +{ + int result = 0; + if (d != -1) + { + if (state & internal_non_blocking) + { +#if defined(__SYMBIAN32__) + int flags = ::fcntl(d, F_GETFL, 0); + if (flags >= 0) + ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 0; + ::ioctl(d, FIONBIO, &arg); +#endif // defined(__SYMBIAN32__) + state &= ~internal_non_blocking; + } + + errno = 0; + result = error_wrapper(::close(d), ec); + } + + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +bool set_internal_non_blocking(int d, + state_type& state, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + + errno = 0; +#if defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); + if (result >= 0) + { + errno = 0; + result = error_wrapper(::fcntl(d, F_SETFL, result | O_NONBLOCK), ec); + } +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 1; + int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); +#endif // defined(__SYMBIAN32__) + + if (result >= 0) + { + ec = boost::system::error_code(); + state |= internal_non_blocking; + return true; + } + + return false; +} + +std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + int bytes = error_wrapper(::readv(d, bufs, static_cast(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, ec) < 0) + return 0; + } +} + +bool non_blocking_read(int d, buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + errno = 0; + int bytes = error_wrapper(::readv(d, bufs, static_cast(count)), ec); + + // Check for end of stream. + if (bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +std::size_t sync_write(int d, state_type state, const buf* bufs, + std::size_t count, bool all_empty, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = boost::system::error_code(); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + int bytes = error_wrapper(::writev(d, bufs, static_cast(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, ec) < 0) + return 0; + } +} + +bool non_blocking_write(int d, const buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + errno = 0; + int bytes = error_wrapper(::writev(d, bufs, static_cast(count)), ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::ioctl(d, cmd, arg), ec); + + if (result >= 0) + { + ec = boost::system::error_code(); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the descriptor is + // already in the correct state. This ensures that the underlying + // descriptor is put into the state that has been requested by the user. If + // the ioctl syscall was successful then we need to update the flags to + // match. + if (cmd == static_cast(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int fcntl(int d, long cmd, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd), ec); + if (result != -1) + ec = boost::system::error_code(); + return result; +} + +int fcntl(int d, long cmd, long arg, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd, arg), ec); + if (result != -1) + ec = boost::system::error_code(); + return result; +} + +int poll_read(int d, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLIN; + fds.revents = 0; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +} + +int poll_write(int d, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLOUT; + fds.revents = 0; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +} + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP diff --git a/include/boost/asio/detail/impl/dev_poll_reactor.hpp b/include/boost/asio/detail/impl/dev_poll_reactor.hpp new file mode 100644 index 00000000..d86faeba --- /dev/null +++ b/include/boost/asio/detail/impl/dev_poll_reactor.hpp @@ -0,0 +1,74 @@ +// +// detail/impl/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_DEV_POLL) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void dev_poll_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void dev_poll_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void dev_poll_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool earliest = queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + interrupter_.interrupt(); + } +} + +template +std::size_t dev_poll_reactor::cancel_timer( + timer_queue& queue, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP diff --git a/include/boost/asio/detail/impl/dev_poll_reactor.ipp b/include/boost/asio/detail/impl/dev_poll_reactor.ipp new file mode 100644 index 00000000..8ea6297e --- /dev/null +++ b/include/boost/asio/detail/impl/dev_poll_reactor.ipp @@ -0,0 +1,337 @@ +// +// detail/impl/dev_poll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_DEV_POLL) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +dev_poll_reactor::dev_poll_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), + mutex_(), + dev_poll_fd_(do_dev_poll_create()), + interrupter_(), + shutdown_(false) +{ + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); +} + +dev_poll_reactor::~dev_poll_reactor() +{ + shutdown_service(); + ::close(dev_poll_fd_); +} + +void dev_poll_reactor::shutdown_service() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); +} + +void dev_poll_reactor::init_task() +{ + io_service_.init_task(); +} + +int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&) +{ + return 0; +} + +void dev_poll_reactor::start_op(int op_type, socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, + reactor_op* op, bool allow_speculative) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (allow_speculative) + { + if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) + { + if (!op_queue_[op_type].has_operation(descriptor)) + { + if (op->perform()) + { + lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + } + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLERR | POLLHUP; + if (op_type == read_op + || op_queue_[read_op].has_operation(descriptor)) + ev.events |= POLLIN; + if (op_type == write_op + || op_queue_[write_op].has_operation(descriptor)) + ev.events |= POLLOUT; + if (op_type == except_op + || op_queue_[except_op].has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } +} + +void dev_poll_reactor::cancel_ops(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void dev_poll_reactor::close_descriptor(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLREMOVE; + interrupter_.interrupt(); + + // Cancel any outstanding operations associated with the descriptor. + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void dev_poll_reactor::run(bool block, op_queue& ops) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() + && op_queue_[except_op].empty() && timer_queues_.all_empty()) + return; + + // Write the pending event registration changes to the /dev/poll descriptor. + std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); + if (events_size > 0) + { + errno = 0; + int result = ::write(dev_poll_fd_, + &pending_event_changes_[0], events_size); + if (result != static_cast(events_size)) + { + boost::system::error_code ec = boost::system::error_code( + errno, boost::asio::error::get_system_category()); + for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) + { + int descriptor = pending_event_changes_[i].fd; + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + pending_event_changes_.clear(); + pending_event_change_index_.clear(); + } + + int timeout = block ? get_timeout() : 0; + lock.unlock(); + + // Block on the /dev/poll descriptor. + ::pollfd events[128] = { { 0 } }; + ::dvpoll dp = { 0 }; + dp.dp_fds = events; + dp.dp_nfds = 128; + dp.dp_timeout = timeout; + int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); + + lock.lock(); + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].fd; + if (descriptor == interrupter_.read_descriptor()) + { + interrupter_.reset(); + } + else + { + bool more_reads = false; + bool more_writes = false; + bool more_except = false; + + // 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 = + op_queue_[except_op].perform_operations(descriptor, ops); + else + more_except = op_queue_[except_op].has_operation(descriptor); + + if (events[i].events & (POLLIN | POLLERR | POLLHUP)) + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); + else + more_reads = op_queue_[read_op].has_operation(descriptor); + + if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) + more_writes = op_queue_[write_op].perform_operations(descriptor, ops); + else + more_writes = op_queue_[write_op].has_operation(descriptor); + + if ((events[i].events & (POLLERR | POLLHUP)) != 0 + && !more_except && !more_reads && !more_writes) + { + // If we have an event and no operations associated with the + // descriptor then we need to delete the descriptor from /dev/poll. + // The poll operation can produce POLLHUP or POLLERR events when there + // is no operation pending, so if we do not remove the descriptor we + // can end up in a tight polling loop. + ::pollfd ev = { 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + else + { + ::pollfd ev = { 0 }; + ev.fd = descriptor; + ev.events = POLLERR | POLLHUP; + if (more_reads) + ev.events |= POLLIN; + if (more_writes) + ev.events |= POLLOUT; + if (more_except) + ev.events |= POLLPRI; + ev.revents = 0; + int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); + if (result != sizeof(ev)) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + } + } + timer_queues_.get_ready_timers(ops); +} + +void dev_poll_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +int dev_poll_reactor::do_dev_poll_create() +{ + int fd = ::open("/dev/poll", O_RDWR); + if (fd == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "/dev/poll"); + } + return fd; +} + +void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +int dev_poll_reactor::get_timeout() +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + return timer_queues_.wait_duration_msec(5 * 60 * 1000); +} + +void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) +{ + bool need_interrupt = false; + op_queue ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + io_service_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor) +{ + hash_map::iterator iter + = pending_event_change_index_.find(descriptor); + if (iter == pending_event_change_index_.end()) + { + std::size_t index = pending_event_changes_.size(); + pending_event_changes_.reserve(pending_event_changes_.size() + 1); + pending_event_change_index_.insert(std::make_pair(descriptor, index)); + pending_event_changes_.push_back(::pollfd()); + pending_event_changes_[index].fd = descriptor; + pending_event_changes_[index].revents = 0; + return pending_event_changes_[index]; + } + else + { + return pending_event_changes_[iter->second]; + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP diff --git a/include/boost/asio/detail/impl/epoll_reactor.hpp b/include/boost/asio/detail/impl/epoll_reactor.hpp new file mode 100644 index 00000000..444ebc86 --- /dev/null +++ b/include/boost/asio/detail/impl/epoll_reactor.hpp @@ -0,0 +1,72 @@ +// +// detail/impl/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(BOOST_ASIO_HAS_EPOLL) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void epoll_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void epoll_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void epoll_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool earliest = queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + update_timeout(); + } +} + +template +std::size_t epoll_reactor::cancel_timer( + timer_queue& queue, void* token) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP diff --git a/include/boost/asio/detail/impl/epoll_reactor.ipp b/include/boost/asio/detail/impl/epoll_reactor.ipp new file mode 100644 index 00000000..35c1a5c9 --- /dev/null +++ b/include/boost/asio/detail/impl/epoll_reactor.ipp @@ -0,0 +1,375 @@ +// +// detail/impl/epoll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_EPOLL) + +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_TIMERFD) +# include +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + +#include + +namespace boost { +namespace asio { +namespace detail { + +epoll_reactor::epoll_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), + mutex_(), + epoll_fd_(do_epoll_create()), +#if defined(BOOST_ASIO_HAS_TIMERFD) + timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), +#else // defined(BOOST_ASIO_HAS_TIMERFD) + timer_fd_(-1), +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + interrupter_(), + shutdown_(false) +{ + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + interrupter_.interrupt(); + + // Add the timer descriptor to epoll. + if (timer_fd_ != -1) + { + ev.events = EPOLLIN | EPOLLERR; + ev.data.ptr = &timer_fd_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); + } +} + +epoll_reactor::~epoll_reactor() +{ + close(epoll_fd_); + if (timer_fd_ != -1) + close(timer_fd_); +} + +void epoll_reactor::shutdown_service() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + descriptor_map::iterator iter = registered_descriptors_.begin(); + descriptor_map::iterator end = registered_descriptors_.end(); + while (iter != end) + { + for (int i = 0; i < max_ops; ++i) + ops.push(iter->second.op_queue_[i]); + iter->second.shutdown_ = true; + ++iter; + } + + timer_queues_.get_all_timers(ops); +} + +void epoll_reactor::init_task() +{ + io_service_.init_task(); +} + +int epoll_reactor::register_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock lock(registered_descriptors_mutex_); + + descriptor_map::iterator new_entry = registered_descriptors_.insert( + std::make_pair(descriptor, descriptor_state())).first; + descriptor_data = &new_entry->second; + + descriptor_data->shutdown_ = false; + + lock.unlock(); + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + return errno; + + return 0; +} + +void epoll_reactor::start_op(int op_type, socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, + reactor_op* op, bool allow_speculative) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + if (descriptor_data->shutdown_) + return; + + if (descriptor_data->op_queue_[op_type].empty()) + { + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) + { + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + else + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP + | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + } + } + + descriptor_data->op_queue_[op_type].push(op); + io_service_.work_started(); +} + +void epoll_reactor::cancel_ops(socket_type, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void epoll_reactor::close_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the epoll set when it is closed. + descriptor_data->shutdown_ = true; + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + registered_descriptors_.erase(descriptor); + + descriptors_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void epoll_reactor::run(bool block, op_queue& ops) +{ + // Calculate a timeout only if timerfd is not used. + int timeout; + if (timer_fd_ != -1) + timeout = block ? -1 : 0; + else + { + mutex::scoped_lock lock(mutex_); + timeout = block ? get_timeout() : 0; + } + + // Block on the epoll descriptor. + epoll_event events[128]; + int num_events = epoll_wait(epoll_fd_, events, 128, timeout); + +#if defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = (timer_fd_ == -1); +#else // defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on edge-triggered notifications + // to make it so that we only get woken up when the descriptor's epoll + // registration is updated. + +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ == -1) + check_timers = true; +#else // defined(BOOST_ASIO_HAS_TIMERFD) + check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + } +#if defined(BOOST_ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + check_timers = true; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + else + { + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP)) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } + } + } + + if (check_timers) + { + mutex::scoped_lock common_lock(mutex_); + timer_queues_.get_ready_timers(ops); + +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + } +} + +void epoll_reactor::interrupt() +{ + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); +} + +int epoll_reactor::do_epoll_create() +{ + int fd = epoll_create(epoll_size); + if (fd == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "epoll"); + } + return fd; +} + +void epoll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +void epoll_reactor::update_timeout() +{ +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + return; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + interrupter_.interrupt(); +} + +int epoll_reactor::get_timeout() +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + return timer_queues_.wait_duration_msec(5 * 60 * 1000); +} + +#if defined(BOOST_ASIO_HAS_TIMERFD) +int epoll_reactor::get_timeout(itimerspec& ts) +{ + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.it_value.tv_sec = usec / 1000000; + ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; + + return usec ? 0 : TFD_TIMER_ABSTIME; +} +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP diff --git a/include/boost/asio/detail/impl/eventfd_select_interrupter.ipp b/include/boost/asio/detail/impl/eventfd_select_interrupter.ipp new file mode 100644 index 00000000..5bcc55be --- /dev/null +++ b/include/boost/asio/detail/impl/eventfd_select_interrupter.ipp @@ -0,0 +1,127 @@ +// +// detail/impl/eventfd_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_EVENTFD) + +#include +#include +#include +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +eventfd_select_interrupter::eventfd_select_interrupter() +{ +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "eventfd_select_interrupter"); + } + } +} + +eventfd_select_interrupter::~eventfd_select_interrupter() +{ + if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) + ::close(write_descriptor_); + if (read_descriptor_ != -1) + ::close(read_descriptor_); +} + +void eventfd_select_interrupter::interrupt() +{ + uint64_t counter(1UL); + int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); + (void)result; +} + +bool eventfd_select_interrupter::reset() +{ + if (write_descriptor_ == read_descriptor_) + { + for (;;) + { + // Only perform one read. The kernel maintains an atomic counter. + uint64_t counter(0); + errno = 0; + int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + return was_interrupted; + } + } + else + { + for (;;) + { + // Clear all data from the pipe. + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_EVENTFD) + +#endif // BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP diff --git a/include/boost/asio/detail/impl/kqueue_reactor.hpp b/include/boost/asio/detail/impl/kqueue_reactor.hpp new file mode 100644 index 00000000..9719086b --- /dev/null +++ b/include/boost/asio/detail/impl/kqueue_reactor.hpp @@ -0,0 +1,76 @@ +// +// detail/impl/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_KQUEUE) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void kqueue_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void kqueue_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void kqueue_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool earliest = queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + interrupter_.interrupt(); + } +} + +template +std::size_t kqueue_reactor::cancel_timer( + timer_queue& queue, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + +#endif // BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP diff --git a/include/boost/asio/detail/impl/kqueue_reactor.ipp b/include/boost/asio/detail/impl/kqueue_reactor.ipp new file mode 100644 index 00000000..8d3dcc04 --- /dev/null +++ b/include/boost/asio/detail/impl/kqueue_reactor.ipp @@ -0,0 +1,355 @@ +// +// detail/impl/kqueue_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_KQUEUE) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +kqueue_reactor::kqueue_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), + mutex_(), + kqueue_fd_(do_kqueue_create()), + interrupter_(), + shutdown_(false) +{ + // The interrupter is put into a permanently readable state. Whenever we + // want to interrupt the blocked kevent call we register a one-shot read + // operation against the descriptor. + interrupter_.interrupt(); +} + +kqueue_reactor::~kqueue_reactor() +{ + close(kqueue_fd_); +} + +void kqueue_reactor::shutdown_service() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + descriptor_map::iterator iter = registered_descriptors_.begin(); + descriptor_map::iterator end = registered_descriptors_.end(); + while (iter != end) + { + for (int i = 0; i < max_ops; ++i) + ops.push(iter->second.op_queue_[i]); + iter->second.shutdown_ = true; + ++iter; + } + + timer_queues_.get_all_timers(ops); +} + +void kqueue_reactor::init_task() +{ + io_service_.init_task(); +} + +int kqueue_reactor::register_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock lock(registered_descriptors_mutex_); + + descriptor_map::iterator new_entry = registered_descriptors_.insert( + std::make_pair(descriptor, descriptor_state())).first; + descriptor_data = &new_entry->second; + + descriptor_data->shutdown_ = false; + + return 0; +} + +void kqueue_reactor::start_op(int op_type, socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, + reactor_op* op, bool allow_speculative) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + if (descriptor_data->shutdown_) + return; + + bool first = descriptor_data->op_queue_[op_type].empty(); + if (first) + { + if (allow_speculative) + { + if (op_type != read_op || descriptor_data->op_queue_[except_op].empty()) + { + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + } + } + + descriptor_data->op_queue_[op_type].push(op); + io_service_.work_started(); + + if (first) + { + struct kevent event; + switch (op_type) + { + case read_op: + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + break; + case write_op: + EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + break; + case except_op: + if (!descriptor_data->op_queue_[read_op].empty()) + return; // Already registered for read events. + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); + break; + } + + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + op->ec_ = boost::system::error_code(errno, + boost::asio::error::get_system_category()); + descriptor_data->op_queue_[op_type].pop(); + io_service_.post_deferred_completion(op); + } + } +} + +void kqueue_reactor::cancel_ops(socket_type, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void kqueue_reactor::close_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the kqueue set when it is closed. + descriptor_data->shutdown_ = true; + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + registered_descriptors_.erase(descriptor); + + descriptors_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void kqueue_reactor::run(bool block, op_queue& ops) +{ + mutex::scoped_lock lock(mutex_); + + // Determine how long to block while waiting for events. + timespec timeout_buf = { 0, 0 }; + timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf; + + lock.unlock(); + + // Block on the kqueue descriptor. + struct kevent events[128]; + int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].ident; + void* ptr = events[i].udata; + if (ptr == &interrupter_) + { + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on one-shot notifications. + } + else + { + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int filter[max_ops] = + { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events[i].filter == filter[j]) + { + if (j != except_op || events[i].flags & EV_OOBAND) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (events[i].flags & EV_ERROR) + { + op->ec_ = boost::system::error_code(events[i].data, + boost::asio::error::get_system_category()); + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } + } + + // Renew registration for event notifications. + struct kevent event; + switch (events[i].filter) + { + case EVFILT_READ: + if (!descriptor_data->op_queue_[read_op].empty()) + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else if (!descriptor_data->op_queue_[except_op].empty()) + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); + else + continue; + case EVFILT_WRITE: + if (!descriptor_data->op_queue_[write_op].empty()) + EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else + continue; + default: + break; + } + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + boost::system::error_code error(errno, + boost::asio::error::get_system_category()); + for (int j = 0; j < max_ops; ++j) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + op->ec_ = error; + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + } + } + } + } + + lock.lock(); + timer_queues_.get_ready_timers(ops); +} + +void kqueue_reactor::interrupt() +{ + struct kevent event; + EV_SET(&event, interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_); + ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); +} + +int kqueue_reactor::do_kqueue_create() +{ + int fd = ::kqueue(); + if (fd == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "kqueue"); + } + return fd; +} + +void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timespec* kqueue_reactor::get_timeout(timespec& ts) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + return &ts; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + +#endif // BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP diff --git a/include/boost/asio/detail/impl/pipe_select_interrupter.ipp b/include/boost/asio/detail/impl/pipe_select_interrupter.ipp new file mode 100644 index 00000000..f2a72916 --- /dev/null +++ b/include/boost/asio/detail/impl/pipe_select_interrupter.ipp @@ -0,0 +1,98 @@ +// +// detail/impl/pipe_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_WINDOWS) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(BOOST_ASIO_HAS_EVENTFD) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +pipe_select_interrupter::pipe_select_interrupter() +{ + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "pipe_select_interrupter"); + } +} + +pipe_select_interrupter::~pipe_select_interrupter() +{ + if (read_descriptor_ != -1) + ::close(read_descriptor_); + if (write_descriptor_ != -1) + ::close(write_descriptor_); +} + +void pipe_select_interrupter::interrupt() +{ + char byte = 0; + int result = ::write(write_descriptor_, &byte, 1); + (void)result; +} + +bool pipe_select_interrupter::reset() +{ + for (;;) + { + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(BOOST_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP diff --git a/include/boost/asio/detail/impl/posix_event.ipp b/include/boost/asio/detail/impl/posix_event.ipp new file mode 100644 index 00000000..7e89b6c1 --- /dev/null +++ b/include/boost/asio/detail/impl/posix_event.ipp @@ -0,0 +1,48 @@ +// +// detail/impl/posix_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_EVENT_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +posix_event::posix_event() + : signalled_(false) +{ + int error = ::pthread_cond_init(&cond_, 0); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "event"); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_EVENT_IPP diff --git a/include/boost/asio/detail/impl/posix_mutex.ipp b/include/boost/asio/detail/impl/posix_mutex.ipp new file mode 100644 index 00000000..a4f81bb1 --- /dev/null +++ b/include/boost/asio/detail/impl/posix_mutex.ipp @@ -0,0 +1,48 @@ +// +// detail/impl/posix_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +posix_mutex::posix_mutex() +{ + int error = ::pthread_mutex_init(&mutex_, 0); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "mutex"); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP diff --git a/include/boost/asio/detail/impl/posix_thread.ipp b/include/boost/asio/detail/impl/posix_thread.ipp new file mode 100644 index 00000000..5dc41fa0 --- /dev/null +++ b/include/boost/asio/detail/impl/posix_thread.ipp @@ -0,0 +1,76 @@ +// +// detail/impl/posix_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_THREAD_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +posix_thread::~posix_thread() +{ + if (!joined_) + ::pthread_detach(thread_); +} + +void posix_thread::join() +{ + if (!joined_) + { + ::pthread_join(thread_, 0); + joined_ = true; + } +} + +void posix_thread::start_thread(func_base* arg) +{ + int error = ::pthread_create(&thread_, 0, + boost_asio_detail_posix_thread_function, arg); + if (error != 0) + { + delete arg; + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } +} + +void* boost_asio_detail_posix_thread_function(void* arg) +{ + posix_thread::auto_func_base_ptr func = { + static_cast(arg) }; + func.ptr->run(); + return 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_THREAD_IPP diff --git a/include/boost/asio/detail/impl/posix_tss_ptr.ipp b/include/boost/asio/detail/impl/posix_tss_ptr.ipp new file mode 100644 index 00000000..1c626e58 --- /dev/null +++ b/include/boost/asio/detail/impl/posix_tss_ptr.ipp @@ -0,0 +1,48 @@ +// +// detail/impl/posix_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void posix_tss_ptr_create(pthread_key_t& key) +{ + int error = ::pthread_key_create(&key, 0); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "tss"); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP diff --git a/include/boost/asio/detail/impl/reactive_descriptor_service.ipp b/include/boost/asio/detail/impl/reactive_descriptor_service.ipp new file mode 100644 index 00000000..6f0dc5aa --- /dev/null +++ b/include/boost/asio/detail/impl/reactive_descriptor_service.ipp @@ -0,0 +1,138 @@ +// +// detail/impl/reactive_descriptor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +reactive_descriptor_service::reactive_descriptor_service( + boost::asio::io_service& io_service) + : reactor_(boost::asio::use_service(io_service)) +{ + reactor_.init_task(); +} + +void reactive_descriptor_service::shutdown_service() +{ +} + +void reactive_descriptor_service::construct( + reactive_descriptor_service::implementation_type& impl) +{ + impl.descriptor_ = -1; + impl.state_ = 0; +} + +void reactive_descriptor_service::destroy( + reactive_descriptor_service::implementation_type& impl) +{ + if (is_open(impl)) + reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); + + boost::system::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); +} + +boost::system::error_code reactive_descriptor_service::assign( + reactive_descriptor_service::implementation_type& impl, + const native_type& native_descriptor, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_descriptor, impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.descriptor_ = native_descriptor; + impl.state_ = 0; + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code reactive_descriptor_service::close( + reactive_descriptor_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); + + if (descriptor_ops::close(impl.descriptor_, impl.state_, ec) == 0) + construct(impl); + + return ec; +} + +boost::system::error_code reactive_descriptor_service::cancel( + reactive_descriptor_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); + ec = boost::system::error_code(); + return ec; +} + +void reactive_descriptor_service::start_op( + reactive_descriptor_service::implementation_type& impl, + int op_type, reactor_op* op, bool non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & descriptor_ops::non_blocking) || + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, op->ec_)) + { + reactor_.start_op(op_type, impl.descriptor_, + impl.reactor_data_, op, non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/reactive_serial_port_service.ipp b/include/boost/asio/detail/impl/reactive_serial_port_service.ipp new file mode 100644 index 00000000..b4672099 --- /dev/null +++ b/include/boost/asio/detail/impl/reactive_serial_port_service.ipp @@ -0,0 +1,153 @@ +// +// detail/impl/reactive_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +reactive_serial_port_service::reactive_serial_port_service( + boost::asio::io_service& io_service) + : descriptor_service_(io_service) +{ +} + +void reactive_serial_port_service::shutdown_service() +{ + descriptor_service_.shutdown_service(); +} + +boost::system::error_code reactive_serial_port_service::open( + reactive_serial_port_service::implementation_type& impl, + const std::string& device, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + descriptor_ops::state_type state = 0; + 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) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // Set up default serial port options. + termios ios; + errno = 0; + 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; + ios.c_cflag |= CREAD | CLOCAL; + errno = 0; + s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); + } + if (s < 0) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // We're done. Take ownership of the serial port descriptor. + if (descriptor_service_.assign(impl, fd, ec)) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + } + + return ec; +} + +boost::system::error_code reactive_serial_port_service::do_set_option( + reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::store_function_type store, + const void* option, boost::system::error_code& ec) +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native(impl), &ios), ec); + if (ec) + return ec; + + if (store(option, ios, ec)) + return ec; + + errno = 0; + descriptor_ops::error_wrapper(::tcsetattr( + descriptor_service_.native(impl), TCSANOW, &ios), ec); + return ec; +} + +boost::system::error_code reactive_serial_port_service::do_get_option( + const reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::load_function_type load, + void* option, boost::system::error_code& ec) const +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native(impl), &ios), ec); + if (ec) + return ec; + + return load(option, ios, ec); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/reactive_socket_service_base.ipp b/include/boost/asio/detail/impl/reactive_socket_service_base.ipp new file mode 100644 index 00000000..cecbe73a --- /dev/null +++ b/include/boost/asio/detail/impl/reactive_socket_service_base.ipp @@ -0,0 +1,214 @@ +// +// detail/reactive_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP +#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +reactive_socket_service_base::reactive_socket_service_base( + boost::asio::io_service& io_service) + : reactor_(use_service(io_service)) +{ + reactor_.init_task(); +} + +void reactive_socket_service_base::shutdown_service() +{ +} + +void reactive_socket_service_base::construct( + reactive_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; +} + +void reactive_socket_service_base::destroy( + reactive_socket_service_base::base_implementation_type& impl) +{ + if (impl.socket_ != invalid_socket) + { + reactor_.close_descriptor(impl.socket_, impl.reactor_data_); + + boost::system::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + } +} + +boost::system::error_code reactive_socket_service_base::close( + reactive_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + reactor_.close_descriptor(impl.socket_, impl.reactor_data_); + + if (socket_ops::close(impl.socket_, impl.state_, true, ec) == 0) + construct(impl); + + return ec; +} + +boost::system::error_code reactive_socket_service_base::cancel( + reactive_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + reactor_.cancel_ops(impl.socket_, impl.reactor_data_); + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code reactive_socket_service_base::do_open( + reactive_socket_service_base::base_implementation_type& impl, + int af, int type, int protocol, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(af, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code reactive_socket_service_base::do_assign( + reactive_socket_service_base::base_implementation_type& impl, int type, + const reactive_socket_service_base::native_type& native_socket, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_socket, impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = boost::system::error_code(); + return ec; +} + +void reactive_socket_service_base::start_op( + reactive_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op, bool non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, op->ec_)) + { + reactor_.start_op(op_type, impl.socket_, + impl.reactor_data_, op, non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op); +} + +void reactive_socket_service_base::start_accept_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, bool peer_is_open) +{ + if (!peer_is_open) + start_op(impl, reactor::read_op, op, true, false); + else + { + op->ec_ = boost::asio::error::already_open; + reactor_.post_immediate_completion(op); + } +} + +void reactive_socket_service_base::start_connect_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, size_t addrlen) +{ + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + reactor_.start_op(reactor::connect_op, + impl.socket_, impl.reactor_data_, op, false); + return; + } + } + } + + reactor_.post_immediate_completion(op); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP diff --git a/include/boost/asio/detail/impl/resolver_service_base.ipp b/include/boost/asio/detail/impl/resolver_service_base.ipp new file mode 100644 index 00000000..d1af0be4 --- /dev/null +++ b/include/boost/asio/detail/impl/resolver_service_base.ipp @@ -0,0 +1,108 @@ +// +// detail/impl/resolver_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP +#define BOOST_ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class resolver_service_base::work_io_service_runner +{ +public: + work_io_service_runner(boost::asio::io_service& io_service) + : io_service_(io_service) {} + void operator()() { io_service_.run(); } +private: + boost::asio::io_service& io_service_; +}; + +resolver_service_base::resolver_service_base( + boost::asio::io_service& io_service) + : io_service_impl_(boost::asio::use_service(io_service)), + work_io_service_(new boost::asio::io_service), + work_io_service_impl_(boost::asio::use_service< + io_service_impl>(*work_io_service_)), + work_(new boost::asio::io_service::work(*work_io_service_)), + work_thread_(0) +{ +} + +resolver_service_base::~resolver_service_base() +{ + shutdown_service(); +} + +void resolver_service_base::shutdown_service() +{ + work_.reset(); + if (work_io_service_) + { + work_io_service_->stop(); + if (work_thread_) + { + work_thread_->join(); + work_thread_.reset(); + } + work_io_service_.reset(); + } +} + +void resolver_service_base::construct( + resolver_service_base::implementation_type& impl) +{ + impl.reset(static_cast(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::destroy( + resolver_service_base::implementation_type&) +{ +} + +void resolver_service_base::cancel( + resolver_service_base::implementation_type& impl) +{ + impl.reset(static_cast(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::start_resolve_op(operation* op) +{ + start_work_thread(); + io_service_impl_.work_started(); + work_io_service_impl_.post_immediate_completion(op); +} + +void resolver_service_base::start_work_thread() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!work_thread_) + { + work_thread_.reset(new boost::asio::detail::thread( + work_io_service_runner(*work_io_service_))); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP diff --git a/include/boost/asio/detail/impl/select_reactor.hpp b/include/boost/asio/detail/impl/select_reactor.hpp new file mode 100644 index 00000000..e4595746 --- /dev/null +++ b/include/boost/asio/detail/impl/select_reactor.hpp @@ -0,0 +1,81 @@ +// +// detail/impl/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) \ + || (!defined(BOOST_ASIO_HAS_DEV_POLL) \ + && !defined(BOOST_ASIO_HAS_EPOLL) \ + && !defined(BOOST_ASIO_HAS_KQUEUE)) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void select_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void select_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void select_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool earliest = queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + interrupter_.interrupt(); + } +} + +template +std::size_t select_reactor::cancel_timer( + timer_queue& queue, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || (!defined(BOOST_ASIO_HAS_DEV_POLL) + // && !defined(BOOST_ASIO_HAS_EPOLL) + // && !defined(BOOST_ASIO_HAS_KQUEUE)) + +#endif // BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP diff --git a/include/boost/asio/detail/impl/select_reactor.ipp b/include/boost/asio/detail/impl/select_reactor.ipp new file mode 100644 index 00000000..26582d36 --- /dev/null +++ b/include/boost/asio/detail/impl/select_reactor.ipp @@ -0,0 +1,271 @@ +// +// detail/impl/select_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) \ + || (!defined(BOOST_ASIO_HAS_DEV_POLL) \ + && !defined(BOOST_ASIO_HAS_EPOLL) \ + && !defined(BOOST_ASIO_HAS_KQUEUE)) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +select_reactor::select_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), + mutex_(), + interrupter_(), +#if defined(BOOST_ASIO_HAS_IOCP) + stop_thread_(false), + thread_(0), +#endif // defined(BOOST_ASIO_HAS_IOCP) + shutdown_(false) +{ +#if defined(BOOST_ASIO_HAS_IOCP) + boost::asio::detail::signal_blocker sb; + thread_ = new boost::asio::detail::thread( + bind_handler(&select_reactor::call_run_thread, this)); +#endif // defined(BOOST_ASIO_HAS_IOCP) +} + +select_reactor::~select_reactor() +{ + shutdown_service(); +} + +void select_reactor::shutdown_service() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; +#if defined(BOOST_ASIO_HAS_IOCP) + stop_thread_ = true; +#endif // defined(BOOST_ASIO_HAS_IOCP) + lock.unlock(); + +#if defined(BOOST_ASIO_HAS_IOCP) + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } +#endif // defined(BOOST_ASIO_HAS_IOCP) + + op_queue ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); +} + +void select_reactor::init_task() +{ + io_service_.init_task(); +} + +int select_reactor::register_descriptor(socket_type, + select_reactor::per_descriptor_data&) +{ + return 0; +} + +void select_reactor::start_op(int op_type, socket_type descriptor, + select_reactor::per_descriptor_data&, reactor_op* op, bool) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) + interrupter_.interrupt(); + } +} + +void select_reactor::cancel_ops(socket_type descriptor, + select_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void select_reactor::close_descriptor(socket_type descriptor, + select_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void select_reactor::run(bool block, op_queue& ops) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + +#if defined(BOOST_ASIO_HAS_IOCP) + // Check if the thread is supposed to stop. + if (stop_thread_) + return; +#endif // defined(BOOST_ASIO_HAS_IOCP) + + // Set up the descriptor sets. + fd_set_adapter fds[max_select_ops]; + fds[read_op].set(interrupter_.read_descriptor()); + socket_type max_fd = 0; + bool have_work_to_do = !timer_queues_.all_empty(); + for (int i = 0; i < max_select_ops; ++i) + { + have_work_to_do = have_work_to_do || !op_queue_[i].empty(); + op_queue_[i].get_descriptors(fds[i], ops); + if (fds[i].max_descriptor() > max_fd) + max_fd = fds[i].max_descriptor(); + } + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); + op_queue_[connect_op].get_descriptors(fds[write_op], ops); + if (fds[write_op].max_descriptor() > max_fd) + max_fd = fds[write_op].max_descriptor(); + op_queue_[connect_op].get_descriptors(fds[except_op], ops); + if (fds[except_op].max_descriptor() > max_fd) + max_fd = fds[except_op].max_descriptor(); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!block && !have_work_to_do) + return; + + // Determine how long to block while waiting for events. + timeval tv_buf = { 0, 0 }; + timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; + + lock.unlock(); + + // Block on the select call until descriptors become ready. + boost::system::error_code ec; + int retval = socket_ops::select(static_cast(max_fd + 1), + fds[read_op], fds[write_op], fds[except_op], tv, ec); + + // Reset the interrupter. + if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor())) + interrupter_.reset(); + + lock.lock(); + + // Dispatch all ready operations. + if (retval > 0) + { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + op_queue_[connect_op].perform_operations_for_descriptors( + fds[except_op], ops); + op_queue_[connect_op].perform_operations_for_descriptors( + fds[write_op], ops); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + for (int i = max_select_ops - 1; i >= 0; --i) + op_queue_[i].perform_operations_for_descriptors(fds[i], ops); + } + timer_queues_.get_ready_timers(ops); +} + +void select_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +#if defined(BOOST_ASIO_HAS_IOCP) +void select_reactor::run_thread() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + op_queue ops; + run(true, ops); + io_service_.post_deferred_completions(ops); + lock.lock(); + } +} + +void select_reactor::call_run_thread(select_reactor* reactor) +{ + reactor->run_thread(); +} +#endif // defined(BOOST_ASIO_HAS_IOCP) + +void select_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void select_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timeval* select_reactor::get_timeout(timeval& tv) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + return &tv; +} + +void select_reactor::cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) +{ + bool need_interrupt = false; + op_queue ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + io_service_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || (!defined(BOOST_ASIO_HAS_DEV_POLL) + // && !defined(BOOST_ASIO_HAS_EPOLL) + // && !defined(BOOST_ASIO_HAS_KQUEUE)) + +#endif // BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP diff --git a/include/boost/asio/detail/impl/service_registry.hpp b/include/boost/asio/detail/impl/service_registry.hpp new file mode 100644 index 00000000..59eb3f78 --- /dev/null +++ b/include/boost/asio/detail/impl/service_registry.hpp @@ -0,0 +1,72 @@ +// +// detail/impl/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP +#define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +Service& service_registry::use_service() +{ + boost::asio::io_service::service::key key; + init_key(key, Service::id); + factory_type factory = &service_registry::create; + return *static_cast(do_use_service(key, factory)); +} + +template +void service_registry::add_service(Service* new_service) +{ + boost::asio::io_service::service::key key; + init_key(key, Service::id); + return do_add_service(key, new_service); +} + +template +bool service_registry::has_service() const +{ + boost::asio::io_service::service::key key; + init_key(key, Service::id); + return do_has_service(key); +} + +#if !defined(BOOST_ASIO_NO_TYPEID) +template +void service_registry::init_key(boost::asio::io_service::service::key& key, + const boost::asio::detail::service_id& /*id*/) +{ + key.type_info_ = &typeid(typeid_wrapper); + key.id_ = 0; +} +#endif // !defined(BOOST_ASIO_NO_TYPEID) + +template +boost::asio::io_service::service* service_registry::create( + boost::asio::io_service& owner) +{ + return new Service(owner); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP diff --git a/include/boost/asio/detail/impl/service_registry.ipp b/include/boost/asio/detail/impl/service_registry.ipp new file mode 100644 index 00000000..9f7381ee --- /dev/null +++ b/include/boost/asio/detail/impl/service_registry.ipp @@ -0,0 +1,166 @@ +// +// detail/impl/service_registry.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP +#define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +service_registry::service_registry(boost::asio::io_service& o) + : owner_(o), + first_service_(0) +{ +} + +service_registry::~service_registry() +{ + // Shutdown all services. This must be done in a separate loop before the + // services are destroyed since the destructors of user-defined handler + // objects may try to access other service objects. + boost::asio::io_service::service* service = first_service_; + while (service) + { + service->shutdown_service(); + service = service->next_; + } + + // Destroy all services. + while (first_service_) + { + boost::asio::io_service::service* next_service = first_service_->next_; + destroy(first_service_); + first_service_ = next_service; + } +} + +void service_registry::init_key(boost::asio::io_service::service::key& key, + const boost::asio::io_service::id& id) +{ + key.type_info_ = 0; + key.id_ = &id; +} + +bool service_registry::keys_match( + const boost::asio::io_service::service::key& key1, + const boost::asio::io_service::service::key& key2) +{ + if (key1.id_ && key2.id_) + if (key1.id_ == key2.id_) + return true; + if (key1.type_info_ && key2.type_info_) + if (*key1.type_info_ == *key2.type_info_) + return true; + return false; +} + +void service_registry::destroy(boost::asio::io_service::service* service) +{ + delete service; +} + +boost::asio::io_service::service* service_registry::do_use_service( + const boost::asio::io_service::service::key& key, + factory_type factory) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // First see if there is an existing service object with the given key. + boost::asio::io_service::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Create a new service object. The service registry's mutex is not locked + // at this time to allow for nested calls into this function from the new + // service's constructor. + lock.unlock(); + auto_service_ptr new_service = { factory(owner_) }; + new_service.ptr_->key_ = key; + lock.lock(); + + // Check that nobody else created another service object of the same type + // while the lock was released. + service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Service was successfully initialised, pass ownership to registry. + new_service.ptr_->next_ = first_service_; + first_service_ = new_service.ptr_; + new_service.ptr_ = 0; + return first_service_; +} + +void service_registry::do_add_service( + const boost::asio::io_service::service::key& key, + boost::asio::io_service::service* new_service) +{ + if (&owner_ != &new_service->io_service()) + boost::throw_exception(invalid_service_owner()); + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Check if there is an existing service object with the given key. + boost::asio::io_service::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + boost::throw_exception(service_already_exists()); + service = service->next_; + } + + // Take ownership of the service object. + new_service->key_ = key; + new_service->next_ = first_service_; + first_service_ = new_service; +} + +bool service_registry::do_has_service( + const boost::asio::io_service::service::key& key) const +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + boost::asio::io_service::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return true; + service = service->next_; + } + + return false; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP diff --git a/include/boost/asio/detail/impl/socket_ops.ipp b/include/boost/asio/detail/impl/socket_ops.ipp new file mode 100644 index 00000000..12b812a0 --- /dev/null +++ b/include/boost/asio/detail/impl/socket_ops.ipp @@ -0,0 +1,2860 @@ +// +// detail/impl/socket_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_IPP +#define BOOST_ASIO_DETAIL_SOCKET_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace socket_ops { + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +struct msghdr { int msg_namelen; }; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) +// HP-UX doesn't declare these functions extern "C", so they are declared again +// here to avoid linker errors about undefined symbols. +extern "C" char* if_indextoname(unsigned int, char*); +extern "C" unsigned int if_nametoindex(const char*); +#endif // defined(__hpux) + +inline void clear_last_error() +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + WSASetLastError(0); +#else + errno = 0; +#endif +} + +template +inline ReturnType error_wrapper(ReturnType return_value, + boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + ec = boost::system::error_code(WSAGetLastError(), + boost::asio::error::get_system_category()); +#else + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); +#endif + return return_value; +} + +template +inline socket_type call_accept(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return invalid_socket; + } + + clear_last_error(); + + socket_type new_s = error_wrapper(call_accept( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (new_s == invalid_socket) + return new_s; + +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + int optval = 1; + int result = error_wrapper(::setsockopt(new_s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(new_s); + return invalid_socket; + } +#endif + + ec = boost::system::error_code(); + return new_s; +} + +socket_type sync_accept(socket_type s, state_type state, + socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec) +{ + // Accept a socket. + for (;;) + { + // Try to complete the operation without blocking. + socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket >= 0) + return new_socket; + + // Operation failed. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + { + if (state & user_set_non_blocking) + return invalid_socket; + // Fall through to retry operation. + } + else if (ec == boost::asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return invalid_socket; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, ec) < 0) + return invalid_socket; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_aborted; + + if (!ec) + { + // Get the address of the peer. + if (addr && addrlen) + { + LPSOCKADDR local_addr = 0; + int local_addr_length = 0; + LPSOCKADDR remote_addr = 0; + int remote_addr_length = 0; + GetAcceptExSockaddrs(output_buffer, 0, address_length, + address_length, &local_addr, &local_addr_length, + &remote_addr, &remote_addr_length); + if (static_cast(remote_addr_length) > *addrlen) + { + ec = boost::asio::error::invalid_argument; + } + else + { + using namespace std; // For memcpy. + memcpy(addr, remote_addr, remote_addr_length); + *addrlen = static_cast(remote_addr_length); + } + } + + // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname + // and getpeername will work on the accepted socket. + SOCKET update_ctx_param = s; + socket_ops::state_type state = 0; + socket_ops::setsockopt(new_socket, state, + SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + &update_ctx_param, sizeof(SOCKET), ec); + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, socket_type& new_socket) +{ + for (;;) + { + // Accept the waiting connection. + new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket >= 0) + return true; + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Operation failed. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + { + if (state & user_set_non_blocking) + return true; + // Fall through to retry operation. + } + else if (ec == boost::asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return true; + + return false; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +template +inline int call_bind(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::bind(s, addr, (SockLenType)addrlen); +} + +int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_bind( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +int close(socket_type s, state_type& state, + bool destruction, boost::system::error_code& ec) +{ + int result = 0; + if (s != invalid_socket) + { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if ((state & non_blocking) && (state & user_set_linger)) + { + ioctl_arg_type arg = 0; + ::ioctlsocket(s, FIONBIO, &arg); + state &= ~non_blocking; + } +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (state & non_blocking) + { +#if defined(__SYMBIAN32__) + int flags = ::fcntl(s, F_GETFL, 0); + if (flags >= 0) + ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 0; + ::ioctl(s, FIONBIO, &arg); +#endif // defined(__SYMBIAN32__) + state &= ~non_blocking; + } +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + if (destruction && (state & user_set_linger)) + { + ::linger opt; + opt.l_onoff = 0; + opt.l_linger = 0; + boost::system::error_code ignored_ec; + socket_ops::setsockopt(s, state, SOL_SOCKET, + SO_LINGER, &opt, sizeof(opt), ignored_ec); + } + + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::closesocket(s), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::close(s), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = boost::system::error_code(); + } + + return result; +} + +bool set_internal_non_blocking(socket_type s, + state_type& state, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = 1; + int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); +#elif defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + if (result >= 0) + { + clear_last_error(); + result = error_wrapper(::fcntl(s, F_SETFL, result | O_NONBLOCK), ec); + } +#else + ioctl_arg_type arg = 1; + int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); +#endif + + if (result >= 0) + { + ec = boost::system::error_code(); + state |= internal_non_blocking; + return true; + } + + return false; +} + +int shutdown(socket_type s, int what, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::shutdown(s, what), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +template +inline int call_connect(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::connect(s, addr, (SockLenType)addrlen); +} + +int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_connect( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + // Perform the connect operation. + socket_ops::connect(s, addr, addrlen, ec); + if (ec != boost::asio::error::in_progress + && ec != boost::asio::error::would_block) + { + // The connect operation finished immediately. + return; + } + + // Wait for socket to become ready. + if (socket_ops::poll_connect(s, ec) < 0) + return; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == socket_error_retval) + return; + + // Return the result of the connect operation. + ec = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); +} + +bool non_blocking_connect(socket_type s, boost::system::error_code& ec) +{ + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == 0) + { + if (connect_error) + { + ec = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); + } + else + ec = boost::system::error_code(); + } + + return true; +} + +int socketpair(int af, int type, int protocol, + socket_type sv[2], boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(af); + (void)(type); + (void)(protocol); + (void)(sv); + ec = boost::asio::error::operation_not_supported; + return socket_error_retval; +#else + clear_last_error(); + int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +#endif +} + +bool sockatmark(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + +#if defined(SIOCATMARK) + ioctl_arg_type value = 0; +# if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec); +# else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec); +# endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = boost::system::error_code(); +# if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = boost::asio::error::not_socket; +# endif // defined(ENOTTY) +#else // defined(SIOCATMARK) + int value = error_wrapper(::sockatmark(s), ec); + if (value != -1) + ec = boost::system::error_code(); +#endif // defined(SIOCATMARK) + + return ec ? false : value != 0; +} + +size_t available(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + ioctl_arg_type value = 0; +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = boost::system::error_code(); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = boost::asio::error::not_socket; +#endif // defined(ENOTTY) + + return ec ? static_cast(0) : static_cast(value); +} + +int listen(socket_type s, int backlog, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::listen(s, backlog), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast(addr); +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +void init_buf(buf& b, void* data, size_t size) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(data); + b.len = static_cast(size); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, data); + b.iov_len = size; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +void init_buf(buf& b, const void* data, size_t size) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(const_cast(data)); + b.len = static_cast(size); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, const_cast(data)); + b.iov_len = size; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +{ + name = addr; +} + +inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) +{ + name = const_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +{ + name = reinterpret_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +{ + name = reinterpret_cast(const_cast(addr)); +} + +int recv(socket_type s, buf* bufs, size_t count, int flags, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = error_wrapper(::WSARecv(s, bufs, + recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = count; + int result = error_wrapper(::recvmsg(s, &msg, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + boost::system::error_code& ec, size_t bytes_transferred) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } + + // Check for connection closed. + else if (!ec && bytes_transferred == 0 + && (state & stream_oriented) != 0 + && !all_empty) + { + ec = boost::asio::error::eof; + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + int bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = boost::asio::error::eof; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +int recvfrom(socket_type s, buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = *addrlen; + msg.msg_iov = bufs; + msg.msg_iovlen = count; + int result = error_wrapper(::recvmsg(s, &msg, flags), ec); + *addrlen = msg.msg_namelen; + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, + size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +int send(socket_type s, const buf* bufs, size_t count, int flags, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = error_wrapper(::WSASend(s, const_cast(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = count; +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + int result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_send(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, bool all_empty, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + int bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +int sendto(socket_type s, const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + int result = error_wrapper(::WSASendTo(s, const_cast(bufs), + send_buf_count, &bytes_transferred, flags, addr, + static_cast(addrlen), 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = addrlen; + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = count; +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + int result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_sendto(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, ec) < 0) + return 0; + } +} + +#if !defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +socket_type socket(int af, int type, int protocol, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, + WSA_FLAG_OVERLAPPED), ec); + if (s == invalid_socket) + return s; + + if (af == AF_INET6) + { + // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to + // false. This will only succeed on Windows Vista and later versions of + // Windows, where a dual-stack IPv4/v6 implementation is available. + DWORD optval = 0; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&optval), sizeof(optval)); + } + + ec = boost::system::error_code(); + + return s; +#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + socket_type s = error_wrapper(::socket(af, type, protocol), ec); + if (s == invalid_socket) + return s; + + int optval = 1; + int result = error_wrapper(::setsockopt(s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(s); + return invalid_socket; + } + + return s; +#else + int s = error_wrapper(::socket(af, type, protocol), ec); + if (s >= 0) + ec = boost::system::error_code(); + return s; +#endif +} + +template +inline int call_setsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + const void* optval, std::size_t optlen) +{ + return ::setsockopt(s, level, optname, + (const char*)optval, (SockLenType)optlen); +} + +int setsockopt(socket_type s, state_type& state, int level, int optname, + const void* optval, std::size_t optlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (optlen != sizeof(int)) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + if (*static_cast(optval)) + state |= enable_connection_aborted; + else + state &= ~enable_connection_aborted; + ec = boost::system::error_code(); + return 0; + } + + if (level == SOL_SOCKET && optname == SO_LINGER) + state |= user_set_linger; + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); + if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) + { + clear_last_error(); + return error_wrapper(sso(s, level, optname, + reinterpret_cast(optval), + static_cast(optlen)), ec); + } + } + ec = boost::asio::error::fault; + return socket_error_retval; +#else // defined(__BORLANDC__) + clear_last_error(); + int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result == 0) + { + ec = boost::system::error_code(); + +#if defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + // To implement portable behaviour for SO_REUSEADDR with UDP sockets we + // need to also set SO_REUSEPORT on BSD-based platforms. + if ((state & datagram_oriented) + && level == SOL_SOCKET && optname == SO_REUSEADDR) + { + call_setsockopt(&msghdr::msg_namelen, s, + SOL_SOCKET, SO_REUSEPORT, optval, optlen); + } +#endif + } + + return result; +#endif // defined(__BORLANDC__) +} + +template +inline int call_getsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + void* optval, std::size_t* optlen) +{ + SockLenType tmp_optlen = (SockLenType)*optlen; + int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); + *optlen = (std::size_t)tmp_optlen; + return result; +} + +int getsockopt(socket_type s, state_type state, int level, int optname, + void* optval, size_t* optlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (*optlen != sizeof(int)) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + *static_cast(optval) = (state & enable_connection_aborted) ? 1 : 0; + ec = boost::system::error_code(); + return 0; + } + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); + if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) + { + clear_last_error(); + int tmp_optlen = static_cast(*optlen); + int result = error_wrapper(gso(s, level, optname, + reinterpret_cast(optval), &tmp_optlen), ec); + *optlen = static_cast(tmp_optlen); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are + // only supported on Windows Vista and later. To simplify program logic + // we will fake success of getting this option and specify that the + // value is non-zero (i.e. true). This corresponds to the behavior of + // IPv6 sockets on Windows platforms pre-Vista. + *static_cast(optval) = 1; + ec = boost::system::error_code(); + } + return result; + } + } + ec = boost::asio::error::fault; + return socket_error_retval; +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only + // supported on Windows Vista and later. To simplify program logic we will + // fake success of getting this option and specify that the value is + // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets + // on Windows platforms pre-Vista. + *static_cast(optval) = 1; + ec = boost::system::error_code(); + } + if (result == 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); +#if defined(__linux__) + if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) + && (optname == SO_SNDBUF || optname == SO_RCVBUF)) + { + // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel + // to set the buffer size to N*2. Linux puts additional stuff into the + // buffers so that only about half is actually available to the application. + // The retrieved value is divided by 2 here to make it appear as though the + // correct value has been set. + *static_cast(optval) /= 2; + } +#endif // defined(__linux__) + if (result == 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +template +inline int call_getpeername(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getpeername(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (cached) + { + // Check if socket is still connected. + DWORD connect_time = 0; + size_t connect_time_len = sizeof(connect_time); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME, + &connect_time, &connect_time_len, ec) == socket_error_retval) + { + return socket_error_retval; + } + if (connect_time == 0xFFFFFFFF) + { + ec = boost::asio::error::not_connected; + return socket_error_retval; + } + + // The cached value is still valid. + ec = boost::system::error_code(); + return 0; + } +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)cached; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + clear_last_error(); + int result = error_wrapper(call_getpeername( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +template +inline int call_getsockname(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getsockname(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_getsockname( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +int ioctl(socket_type s, state_type& state, long cmd, + ioctl_arg_type* arg, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, cmd, arg), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result >= 0) + { + ec = boost::system::error_code(); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the socket is already in + // the correct state. This ensures that the underlying socket is put into + // the state that has been requested by the user. If the ioctl syscall was + // successful then we need to update the flags to match. + if (cmd == static_cast(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (!readfds && !writefds && !exceptfds && timeout) + { + DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + if (milliseconds == 0) + milliseconds = 1; // Force context switch. + ::Sleep(milliseconds); + ec = boost::system::error_code(); + return 0; + } + + // The select() call allows timeout values measured in microseconds, but the + // system clock (as wrapped by boost::posix_time::microsec_clock) typically + // has a resolution of 10 milliseconds. This can lead to a spinning select + // reactor, meaning increased CPU usage, when waiting for the earliest + // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight + // spin we'll use a minimum timeout of 1 millisecond. + if (timeout && timeout->tv_sec == 0 + && timeout->tv_usec > 0 && timeout->tv_usec < 1000) + timeout->tv_usec = 1000; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) && defined(__HP_aCC) + timespec ts; + ts.tv_sec = timeout ? timeout->tv_sec : 0; + ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; + return error_wrapper(::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0), ec); +#else + int result = error_wrapper(::select(nfds, readfds, + writefds, exceptfds, timeout), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif +} + +int poll_read(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + clear_last_error(); + int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLIN; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) +} + +int poll_write(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + clear_last_error(); + int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) +} + +int poll_connect(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + fd_set except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + clear_last_error(); + int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) +} + +const char* inet_ntop(int af, const void* src, char* dest, size_t length, + unsigned long scope_id, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy. + + if (af != AF_INET && af != AF_INET6) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + DWORD address_length; + if (af == AF_INET) + { + address_length = sizeof(sockaddr_in4_type); + address.v4.sin_family = AF_INET; + address.v4.sin_port = 0; + memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); + } + else // AF_INET6 + { + address_length = sizeof(sockaddr_in6_type); + address.v6.sin6_family = AF_INET6; + address.v6.sin6_port = 0; + address.v6.sin6_flowinfo = 0; + address.v6.sin6_scope_id = scope_id; + memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); + } + + DWORD string_length = static_cast(length); +#if defined(BOOST_NO_ANSI_APIS) + LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); + int result = error_wrapper(::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length), ec); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); +#else + int result = error_wrapper(::WSAAddressToStringA( + &address.base, address_length, 0, dest, &string_length), ec); +#endif + + // Windows may set error code on success. + if (result != socket_error_retval) + ec = boost::system::error_code(); + + // Windows may not set an error code on failure. + else if (result == socket_error_retval && !ec) + ec = boost::asio::error::invalid_argument; + + return result == socket_error_retval ? 0 : dest; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); + if (result == 0 && !ec) + ec = boost::asio::error::invalid_argument; + if (result != 0 && af == AF_INET6 && scope_id != 0) + { + using namespace std; // For strcat and sprintf. + char if_name[IF_NAMESIZE + 1] = "%"; + const in6_addr_type* ipv6_address = static_cast(src); + bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); + if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) + sprintf(if_name + 1, "%lu", scope_id); + strcat(dest, if_name); + } + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy and strcmp. + + if (af != AF_INET && af != AF_INET6) + { + ec = boost::asio::error::address_family_not_supported; + return -1; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + int address_length = sizeof(sockaddr_storage_type); +#if defined(BOOST_NO_ANSI_APIS) + int num_wide_chars = strlen(src) + 1; + LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); + ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); + int result = error_wrapper(::WSAStringToAddressW( + wide_buffer, af, 0, &address.base, &address_length), ec); +#else + int result = error_wrapper(::WSAStringToAddressA( + const_cast(src), af, 0, &address.base, &address_length), ec); +#endif + + if (af == AF_INET) + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); + ec = boost::system::error_code(); + } + else if (strcmp(src, "255.255.255.255") == 0) + { + static_cast(dest)->s_addr = INADDR_NONE; + ec = boost::system::error_code(); + } + } + else // AF_INET6 + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); + if (scope_id) + *scope_id = address.v6.sin6_scope_id; + ec = boost::system::error_code(); + } + } + + // Windows may not set an error code on failure. + if (result == socket_error_retval && !ec) + ec = boost::asio::error::invalid_argument; + + if (result != socket_error_retval) + ec = boost::system::error_code(); + + return result == socket_error_retval ? -1 : 1; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::inet_pton(af, src, dest), ec); + if (result <= 0 && !ec) + ec = boost::asio::error::invalid_argument; + if (result > 0 && af == AF_INET6 && scope_id) + { + using namespace std; // For strchr and atoi. + *scope_id = 0; + if (const char* if_name = strchr(src, '%')) + { + in6_addr_type* ipv6_address = static_cast(dest); + bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); + if (is_link_local) + *scope_id = if_nametoindex(if_name + 1); + if (*scope_id == 0) + *scope_id = atoi(if_name + 1); + } + } + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +int gethostname(char* name, int namelen, boost::system::error_code& ec) +{ + clear_last_error(); + int result = error_wrapper(::gethostname(name, namelen), ec); +#if defined(BOOST_WINDOWS) + if (result == 0) + ec = boost::system::error_code(); +#endif + return result; +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ + || defined(__MACH__) && defined(__APPLE__) + +// The following functions are only needed for emulation of getaddrinfo and +// getnameinfo. + +inline boost::system::error_code translate_netdb_error(int error) +{ + switch (error) + { + case 0: + return boost::system::error_code(); + case HOST_NOT_FOUND: + return boost::asio::error::host_not_found; + case TRY_AGAIN: + return boost::asio::error::host_not_found_try_again; + case NO_RECOVERY: + return boost::asio::error::no_recovery; + case NO_DATA: + return boost::asio::error::no_data; + default: + BOOST_ASSERT(false); + return boost::asio::error::invalid_argument; + } +} + +inline hostent* gethostbyaddr(const char* addr, int length, int af, + hostent* result, char* buffer, int buflength, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); + if (!retval) + return 0; + ec = boost::system::error_code(); + *result = *retval; + return retval; +#elif defined(__sun) || defined(__QNX__) + int error = 0; + hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyaddr( + addr, length, af, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, + buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline hostent* gethostbyname(const char* name, int af, struct hostent* result, + char* buffer, int buflength, int ai_flags, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + (void)(ai_flags); + if (af != AF_INET) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + hostent* retval = error_wrapper(::gethostbyname(name), ec); + if (!retval) + return 0; + ec = boost::system::error_code(); + *result = *retval; + return result; +#elif defined(__sun) || defined(__QNX__) + (void)(ai_flags); + if (af != AF_INET) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + int error = 0; + hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, + buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyname( + name, af, ai_flags, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + (void)(ai_flags); + if (af != AF_INET) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyname_r(name, result, + buffer, buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline void freehostent(hostent* h) +{ +#if defined(__MACH__) && defined(__APPLE__) + if (h) + ::freehostent(h); +#else + (void)(h); +#endif +} + +// Emulation of getaddrinfo based on implementation in: +// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. + +struct gai_search +{ + const char* host; + int family; +}; + +inline int gai_nsearch(const char* host, + const addrinfo_type* hints, gai_search (&search)[2]) +{ + int search_count = 0; + if (host == 0 || host[0] == '\0') + { + if (hints->ai_flags & AI_PASSIVE) + { + // No host and AI_PASSIVE implies wildcard bind. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = "0.0.0.0"; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = "0::0"; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = "0::0"; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = "0.0.0.0"; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + else + { + // No host and not AI_PASSIVE means connect to local host. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = "localhost"; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + } + else + { + // Host is specified. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = host; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = host; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = host; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = host; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + return search_count; +} + +template +inline T* gai_alloc(std::size_t size = sizeof(T)) +{ + using namespace std; + T* p = static_cast(::operator new(size, std::nothrow)); + if (p) + memset(p, 0, size); + return p; +} + +inline void gai_free(void* p) +{ + ::operator delete(p); +} + +inline void gai_strcpy(char* target, const char* source, std::size_t max_size) +{ + using namespace std; +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + strcpy_s(target, max_size, source); +#else + *target = 0; + strncat(target, source, max_size); +#endif +} + +enum { gai_clone_flag = 1 << 30 }; + +inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, + const void* addr, int family) +{ + using namespace std; + + addrinfo_type* ai = gai_alloc(); + if (ai == 0) + return EAI_MEMORY; + + ai->ai_next = 0; + **next = ai; + *next = &ai->ai_next; + + ai->ai_canonname = 0; + ai->ai_socktype = hints->ai_socktype; + if (ai->ai_socktype == 0) + ai->ai_flags |= gai_clone_flag; + ai->ai_protocol = hints->ai_protocol; + ai->ai_family = family; + + switch (ai->ai_family) + { + case AF_INET: + { + sockaddr_in4_type* sinptr = gai_alloc(); + if (sinptr == 0) + return EAI_MEMORY; + sinptr->sin_family = AF_INET; + memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); + ai->ai_addr = reinterpret_cast(sinptr); + ai->ai_addrlen = sizeof(sockaddr_in4_type); + break; + } + case AF_INET6: + { + sockaddr_in6_type* sin6ptr = gai_alloc(); + if (sin6ptr == 0) + return EAI_MEMORY; + sin6ptr->sin6_family = AF_INET6; + memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); + ai->ai_addr = reinterpret_cast(sin6ptr); + ai->ai_addrlen = sizeof(sockaddr_in6_type); + break; + } + default: + break; + } + + return 0; +} + +inline addrinfo_type* gai_clone(addrinfo_type* ai) +{ + using namespace std; + + addrinfo_type* new_ai = gai_alloc(); + if (new_ai == 0) + return new_ai; + + new_ai->ai_next = ai->ai_next; + ai->ai_next = new_ai; + + new_ai->ai_flags = 0; + new_ai->ai_family = ai->ai_family; + new_ai->ai_socktype = ai->ai_socktype; + new_ai->ai_protocol = ai->ai_protocol; + new_ai->ai_canonname = 0; + new_ai->ai_addrlen = ai->ai_addrlen; + new_ai->ai_addr = gai_alloc(ai->ai_addrlen); + memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); + + return new_ai; +} + +inline int gai_port(addrinfo_type* aihead, int port, int socktype) +{ + int num_found = 0; + + for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) + { + if (ai->ai_flags & gai_clone_flag) + { + if (ai->ai_socktype != 0) + { + ai = gai_clone(ai); + if (ai == 0) + return -1; + // ai now points to newly cloned entry. + } + } + else if (ai->ai_socktype != socktype) + { + // Ignore if mismatch on socket type. + continue; + } + + ai->ai_socktype = socktype; + + switch (ai->ai_family) + { + case AF_INET: + { + sockaddr_in4_type* sinptr = + reinterpret_cast(ai->ai_addr); + sinptr->sin_port = port; + ++num_found; + break; + } + case AF_INET6: + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast(ai->ai_addr); + sin6ptr->sin6_port = port; + ++num_found; + break; + } + default: + break; + } + } + + return num_found; +} + +inline int gai_serv(addrinfo_type* aihead, + const addrinfo_type* hints, const char* serv) +{ + using namespace std; + + int num_found = 0; + + if ( +#if defined(AI_NUMERICSERV) + (hints->ai_flags & AI_NUMERICSERV) || +#endif + isdigit(static_cast(serv[0]))) + { + int port = htons(atoi(serv)); + if (hints->ai_socktype) + { + // Caller specifies socket type. + int rc = gai_port(aihead, port, hints->ai_socktype); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + else + { + // Caller does not specify socket type. + int rc = gai_port(aihead, port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + rc = gai_port(aihead, port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + else + { + // Try service name with TCP first, then UDP. + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) + { + servent* sptr = getservbyname(serv, "tcp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) + { + servent* sptr = getservbyname(serv, "udp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + } + + if (num_found == 0) + { + if (hints->ai_socktype == 0) + { + // All calls to getservbyname() failed. + return EAI_NONAME; + } + else + { + // Service not supported for socket type. + return EAI_SERVICE; + } + } + + return 0; +} + +inline int gai_echeck(const char* host, const char* service, + int flags, int family, int socktype, int protocol) +{ + (void)(flags); + (void)(protocol); + + // Host or service must be specified. + if (host == 0 || host[0] == '\0') + if (service == 0 || service[0] == '\0') + return EAI_NONAME; + + // Check combination of family and socket type. + switch (family) + { + case AF_UNSPEC: + break; + case AF_INET: + case AF_INET6: + if (service != 0 && service[0] != '\0') + if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return EAI_SOCKTYPE; + break; + default: + return EAI_FAMILY; + } + + return 0; +} + +inline void freeaddrinfo_emulation(addrinfo_type* aihead) +{ + addrinfo_type* ai = aihead; + while (ai) + { + gai_free(ai->ai_addr); + gai_free(ai->ai_canonname); + addrinfo_type* ainext = ai->ai_next; + gai_free(ai); + ai = ainext; + } +} + +inline int getaddrinfo_emulation(const char* host, const char* service, + const addrinfo_type* hintsp, addrinfo_type** result) +{ + // Set up linked list of addrinfo structures. + addrinfo_type* aihead = 0; + addrinfo_type** ainext = &aihead; + char* canon = 0; + + // Supply default hints if not specified by caller. + addrinfo_type hints = addrinfo_type(); + hints.ai_family = AF_UNSPEC; + if (hintsp) + hints = *hintsp; + + // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED + // and AI_ALL flags. +#if defined(AI_V4MAPPED) + if (hints.ai_family != AF_INET6) + hints.ai_flags &= ~AI_V4MAPPED; +#endif +#if defined(AI_ALL) + if (hints.ai_family != AF_INET6) + hints.ai_flags &= ~AI_ALL; +#endif + + // Basic error checking. + int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, + hints.ai_socktype, hints.ai_protocol); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + + gai_search search[2]; + int search_count = gai_nsearch(host, &hints, search); + for (gai_search* sptr = search; sptr < search + search_count; ++sptr) + { + // Check for IPv4 dotted decimal string. + in4_addr_type inaddr; + boost::system::error_code ec; + if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == AF_INET) + { + rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Check for IPv6 hex string. + in6_addr_type in6addr; + if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == AF_INET6) + { + rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Look up hostname. + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyname(sptr->host, + sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); + if (hptr == 0) + { + if (search_count == 2) + { + // Failure is OK if there are multiple searches. + continue; + } + freeaddrinfo_emulation(aihead); + gai_free(canon); + if (ec == boost::asio::error::host_not_found) + return EAI_NONAME; + if (ec == boost::asio::error::host_not_found_try_again) + return EAI_AGAIN; + if (ec == boost::asio::error::no_recovery) + return EAI_FAIL; + if (ec == boost::asio::error::no_data) + return EAI_NONAME; + return EAI_NONAME; + } + + // Check for address family mismatch if one was specified. + if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + + // Save canonical name first time. + if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] + && (hints.ai_flags & AI_CANONNAME) && canon == 0) + { + std::size_t canon_len = strlen(hptr->h_name) + 1; + canon = gai_alloc(canon_len); + if (canon == 0) + { + freeaddrinfo_emulation(aihead); + socket_ops::freehostent(hptr); + return EAI_MEMORY; + } + gai_strcpy(canon, hptr->h_name, canon_len); + } + + // Create an addrinfo structure for each returned address. + for (char** ap = hptr->h_addr_list; *ap; ++ap) + { + rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + } + + socket_ops::freehostent(hptr); + } + + // Check if we found anything. + if (aihead == 0) + { + gai_free(canon); + return EAI_NONAME; + } + + // Return canonical name in first entry. + if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) + { + if (canon) + { + aihead->ai_canonname = canon; + canon = 0; + } + else + { + std::size_t canonname_len = strlen(search[0].host) + 1; + aihead->ai_canonname = gai_alloc(canonname_len); + if (aihead->ai_canonname == 0) + { + freeaddrinfo_emulation(aihead); + return EAI_MEMORY; + } + gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); + } + } + gai_free(canon); + + // Process the service name. + if (service != 0 && service[0] != '\0') + { + rc = gai_serv(aihead, &hints, service); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + } + + // Return result to caller. + *result = aihead; + return 0; +} + +inline boost::system::error_code getnameinfo_emulation( + const socket_addr_type* sa, std::size_t salen, char* host, + std::size_t hostlen, char* serv, std::size_t servlen, int flags, + boost::system::error_code& ec) +{ + using namespace std; + + const char* addr; + size_t addr_len; + unsigned short port; + switch (sa->sa_family) + { + case AF_INET: + if (salen != sizeof(sockaddr_in4_type)) + { + return ec = boost::asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin_addr); + addr_len = sizeof(in4_addr_type); + port = reinterpret_cast(sa)->sin_port; + break; + case AF_INET6: + if (salen != sizeof(sockaddr_in6_type)) + { + return ec = boost::asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin6_addr); + addr_len = sizeof(in6_addr_type); + port = reinterpret_cast(sa)->sin6_port; + break; + default: + return ec = boost::asio::error::address_family_not_supported; + } + + if (host && hostlen > 0) + { + if (flags & NI_NUMERICHOST) + { + if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + else + { + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyaddr(addr, + static_cast(addr_len), sa->sa_family, + &hent, hbuf, sizeof(hbuf), ec); + if (hptr && hptr->h_name && hptr->h_name[0] != '\0') + { + if (flags & NI_NOFQDN) + { + char* dot = strchr(hptr->h_name, '.'); + if (dot) + { + *dot = 0; + } + } + gai_strcpy(host, hptr->h_name, hostlen); + socket_ops::freehostent(hptr); + } + else + { + socket_ops::freehostent(hptr); + if (flags & NI_NAMEREQD) + { + return ec = boost::asio::error::host_not_found; + } + if (socket_ops::inet_ntop(sa->sa_family, + addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + } + } + + if (serv && servlen > 0) + { + if (flags & NI_NUMERICSERV) + { + if (servlen < 6) + { + return ec = boost::asio::error::no_buffer_space; + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else + sprintf(serv, "%u", ntohs(port)); +#endif + } + else + { +#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \ + && !defined(BOOST_ASIO_DISABLE_THREADS) + static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + ::pthread_mutex_lock(&mutex); +#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + // && !defined(BOOST_ASIO_DISABLE_THREADS) + servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); + if (sptr && sptr->s_name && sptr->s_name[0] != '\0') + { + gai_strcpy(serv, sptr->s_name, servlen); + } + else + { + if (servlen < 6) + { + return ec = boost::asio::error::no_buffer_space; + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else + sprintf(serv, "%u", ntohs(port)); +#endif + } +#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \ + && !defined(BOOST_ASIO_DISABLE_THREADS) + ::pthread_mutex_unlock(&mutex); +#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + // && !defined(BOOST_ASIO_DISABLE_THREADS) + } + } + + ec = boost::system::error_code(); + return ec; +} + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // || defined(__MACH__) && defined(__APPLE__) + +inline boost::system::error_code translate_addrinfo_error(int error) +{ + switch (error) + { + case 0: + return boost::system::error_code(); + case EAI_AGAIN: + return boost::asio::error::host_not_found_try_again; + case EAI_BADFLAGS: + return boost::asio::error::invalid_argument; + case EAI_FAIL: + return boost::asio::error::no_recovery; + case EAI_FAMILY: + return boost::asio::error::address_family_not_supported; + case EAI_MEMORY: + return boost::asio::error::no_memory; + case EAI_NONAME: +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: +#endif +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + return boost::asio::error::host_not_found; + case EAI_SERVICE: + return boost::asio::error::service_not_found; + case EAI_SOCKTYPE: + return boost::asio::error::socket_type_not_supported; + default: // Possibly the non-portable EAI_SYSTEM. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + return boost::system::error_code( + WSAGetLastError(), boost::asio::error::get_system_category()); +#else + return boost::system::error_code( + errno, boost::asio::error::get_system_category()); +#endif + } +} + +boost::system::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec) +{ + host = (host && *host) ? host : 0; + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + int error = ::getaddrinfo(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gai_t)(const char*, + const char*, const addrinfo_type*, addrinfo_type**); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) + { + int error = gai(host, service, &hints, result); + return ec = translate_addrinfo_error(error); + } + } + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +#else + int error = ::getaddrinfo(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +#endif +} + +boost::system::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec) +{ + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + socket_ops::getaddrinfo(host, service, hints, result, ec); + return ec; +} + +void freeaddrinfo(addrinfo_type* ai) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + ::freeaddrinfo(ai); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *fai_t)(addrinfo_type*); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) + { + fai(ai); + return; + } + } + freeaddrinfo_emulation(ai); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + freeaddrinfo_emulation(ai); +#else + ::freeaddrinfo(ai); +#endif +} + +boost::system::error_code getnameinfo(const socket_addr_type* addr, + std::size_t addrlen, char* host, std::size_t hostlen, + char* serv, std::size_t servlen, int flags, boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + clear_last_error(); + int error = ::getnameinfo(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gni_t)(const socket_addr_type*, + int, char*, DWORD, char*, DWORD, int); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) + { + clear_last_error(); + int error = gni(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); + } + } + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + using namespace std; // For memcpy. + sockaddr_storage_type tmp_addr; + memcpy(&tmp_addr, addr, addrlen); + tmp_addr.ss_len = addrlen; + addr = reinterpret_cast(&tmp_addr); + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +#else + clear_last_error(); + int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); + return ec = translate_addrinfo_error(error); +#endif +} + +boost::system::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec) +{ + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + + return ec; +} + +boost::system::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec) +{ + if (cancel_token.expired()) + { + ec = boost::asio::error::operation_aborted; + } + else + { + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + } + + return ec; +} + +u_long_type network_to_host_long(u_long_type value) +{ + return ntohl(value); +} + +u_long_type host_to_network_long(u_long_type value) +{ + return htonl(value); +} + +u_short_type network_to_host_short(u_short_type value) +{ + return ntohs(value); +} + +u_short_type host_to_network_short(u_short_type value) +{ + return htons(value); +} + +} // namespace socket_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_IPP diff --git a/include/boost/asio/detail/impl/socket_select_interrupter.ipp b/include/boost/asio/detail/impl/socket_select_interrupter.ipp new file mode 100644 index 00000000..d697a6ec --- /dev/null +++ b/include/boost/asio/detail/impl/socket_select_interrupter.ipp @@ -0,0 +1,153 @@ +// +// detail/impl/socket_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +socket_select_interrupter::socket_select_interrupter() +{ + boost::system::error_code ec; + socket_holder acceptor(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (acceptor.get() == invalid_socket) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + int opt = 1; + socket_ops::state_type acceptor_state = 0; + socket_ops::setsockopt(acceptor.get(), acceptor_state, + SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); + + using namespace std; // For memset. + sockaddr_in4_type addr; + std::size_t addr_len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr.sin_port = 0; + if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, + &addr_len, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + // Some broken firewalls on Windows will intermittently cause getsockname to + // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We + // explicitly specify the target address here to work around this problem. + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + if (socket_ops::listen(acceptor.get(), + SOMAXCONN, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder client(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (client.get() == invalid_socket) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); + if (server.get() == invalid_socket) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + ioctl_arg_type non_blocking = 1; + socket_ops::state_type client_state = 0; + if (socket_ops::ioctl(client.get(), client_state, + FIONBIO, &non_blocking, ec)) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(client.get(), client_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + non_blocking = 1; + socket_ops::state_type server_state = 0; + if (socket_ops::ioctl(server.get(), server_state, + FIONBIO, &non_blocking, ec)) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(server.get(), server_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + read_descriptor_ = server.release(); + write_descriptor_ = client.release(); +} + +socket_select_interrupter::~socket_select_interrupter() +{ + boost::system::error_code ec; + socket_ops::state_type state = socket_ops::internal_non_blocking; + if (read_descriptor_ != invalid_socket) + socket_ops::close(read_descriptor_, state, true, ec); + if (write_descriptor_ != invalid_socket) + socket_ops::close(write_descriptor_, state, true, ec); +} + +void socket_select_interrupter::interrupt() +{ + char byte = 0; + socket_ops::buf b; + socket_ops::init_buf(b, &byte, 1); + boost::system::error_code ec; + socket_ops::send(write_descriptor_, &b, 1, 0, ec); +} + +bool socket_select_interrupter::reset() +{ + char data[1024]; + socket_ops::buf b; + socket_ops::init_buf(b, data, sizeof(data)); + boost::system::error_code ec; + int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + return was_interrupted; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP diff --git a/include/boost/asio/detail/impl/strand_service.hpp b/include/boost/asio/detail/impl/strand_service.hpp new file mode 100644 index 00000000..e959947a --- /dev/null +++ b/include/boost/asio/detail/impl/strand_service.hpp @@ -0,0 +1,142 @@ +// +// detail/impl/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +inline strand_service::strand_impl::strand_impl() + : operation(&strand_service::do_complete), + count_(0) +{ +} + +struct strand_service::on_dispatch_exit +{ + io_service_impl* io_service_; + strand_impl* impl_; + + ~on_dispatch_exit() + { + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + io_service_->post_immediate_completion(impl_); + } +}; + +inline void strand_service::destroy(strand_service::implementation_type& impl) +{ + impl = 0; +} + +template +void strand_service::dispatch(strand_service::implementation_type& impl, + Handler handler) +{ + // If we are already in the strand then the handler can run immediately. + if (call_stack::contains(impl)) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + return; + } + + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + // If we are running inside the io_service, and no other handler is queued + // or running, then the handler can run immediately. + bool can_dispatch = call_stack::contains(&io_service_); + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + if (can_dispatch && first) + { + // Immediate invocation is allowed. + impl->mutex_.unlock(); + + // Memory must be releaesed before any upcall is made. + p.reset(); + + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_dispatch_exit on_exit = { &io_service_, impl }; + (void)on_exit; + + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + return; + } + + // Immediate invocation is not allowed, so enqueue for later. + impl->queue_.push(p.p); + impl->mutex_.unlock(); + p.v = p.p = 0; + + // The first handler to be enqueued is responsible for scheduling the + // strand. + if (first) + io_service_.post_immediate_completion(impl); +} + +// Request the io_service to invoke the given handler and return immediately. +template +void strand_service::post(strand_service::implementation_type& impl, + Handler handler) +{ + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + // Add the handler to the queue. + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + impl->queue_.push(p.p); + impl->mutex_.unlock(); + p.v = p.p = 0; + + // The first handler to be enqueue is responsible for scheduling the strand. + if (first) + io_service_.post_immediate_completion(impl); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP diff --git a/include/boost/asio/detail/impl/strand_service.ipp b/include/boost/asio/detail/impl/strand_service.ipp new file mode 100644 index 00000000..f94570aa --- /dev/null +++ b/include/boost/asio/detail/impl/strand_service.ipp @@ -0,0 +1,108 @@ +// +// detail/impl/strand_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct strand_service::on_do_complete_exit +{ + io_service_impl* owner_; + strand_impl* impl_; + + ~on_do_complete_exit() + { + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + owner_->post_immediate_completion(impl_); + } +}; + +strand_service::strand_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(boost::asio::use_service(io_service)), + mutex_(), + salt_(0) +{ +} + +void strand_service::shutdown_service() +{ + op_queue ops; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + for (std::size_t i = 0; i < num_implementations; ++i) + if (strand_impl* impl = implementations_[i].get()) + ops.push(impl->queue_); +} + +void strand_service::construct(strand_service::implementation_type& impl) +{ + std::size_t salt = salt_++; + std::size_t index = reinterpret_cast(&impl); + index += (reinterpret_cast(&impl) >> 3); + index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2); + index = index % num_implementations; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (!implementations_[index]) + implementations_[index].reset(new strand_impl); + impl = implementations_[index].get(); +} + +void strand_service::do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) +{ + if (owner) + { + strand_impl* impl = static_cast(base); + + // Get the next handler to be executed. + impl->mutex_.lock(); + operation* o = impl->queue_.front(); + impl->queue_.pop(); + impl->mutex_.unlock(); + + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_do_complete_exit on_exit = { owner, impl }; + (void)on_exit; + + o->complete(*owner); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/task_io_service.hpp b/include/boost/asio/detail/impl/task_io_service.hpp new file mode 100644 index 00000000..ed5b2c47 --- /dev/null +++ b/include/boost/asio/detail/impl/task_io_service.hpp @@ -0,0 +1,62 @@ +// +// detail/impl/task_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP +#define BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void task_io_service::dispatch(Handler handler) +{ + if (call_stack::contains(this)) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + else + post(handler); +} + +template +void task_io_service::post(Handler handler) +{ + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + post_immediate_completion(p.p); + p.v = p.p = 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP diff --git a/include/boost/asio/detail/impl/task_io_service.ipp b/include/boost/asio/detail/impl/task_io_service.ipp new file mode 100644 index 00000000..4cc23262 --- /dev/null +++ b/include/boost/asio/detail/impl/task_io_service.ipp @@ -0,0 +1,356 @@ +// +// detail/impl/task_io_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct task_io_service::task_cleanup +{ + ~task_cleanup() + { + // Enqueue the completed operations and reinsert the task at the end of + // the operation queue. + lock_->lock(); + task_io_service_->task_interrupted_ = true; + task_io_service_->op_queue_.push(*ops_); + task_io_service_->op_queue_.push(&task_io_service_->task_operation_); + } + + task_io_service* task_io_service_; + mutex::scoped_lock* lock_; + op_queue* ops_; +}; + +struct task_io_service::work_finished_on_block_exit +{ + ~work_finished_on_block_exit() + { + task_io_service_->work_finished(); + } + + task_io_service* task_io_service_; +}; + +struct task_io_service::idle_thread_info +{ + event wakeup_event; + idle_thread_info* next; +}; + +task_io_service::task_io_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + mutex_(), + task_(0), + task_interrupted_(true), + outstanding_work_(0), + stopped_(false), + shutdown_(false), + first_idle_thread_(0) +{ +} + +void task_io_service::init(std::size_t /*concurrency_hint*/) +{ +} + +void task_io_service::shutdown_service() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + // Destroy handler objects. + while (!op_queue_.empty()) + { + operation* o = op_queue_.front(); + op_queue_.pop(); + if (o != &task_operation_) + o->destroy(); + } + + // Reset to initial state. + task_ = 0; +} + +void task_io_service::init_task() +{ + mutex::scoped_lock lock(mutex_); + if (!shutdown_ && !task_) + { + task_ = &use_service(this->get_io_service()); + op_queue_.push(&task_operation_); + wake_one_thread_and_unlock(lock); + } +} + +std::size_t task_io_service::run(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + call_stack::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + mutex::scoped_lock lock(mutex_); + + std::size_t n = 0; + for (; do_one(lock, &this_idle_thread); lock.lock()) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +std::size_t task_io_service::run_one(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + call_stack::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + mutex::scoped_lock lock(mutex_); + + return do_one(lock, &this_idle_thread); +} + +std::size_t task_io_service::poll(boost::system::error_code& ec) +{ + if (outstanding_work_ == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + mutex::scoped_lock lock(mutex_); + + std::size_t n = 0; + for (; do_one(lock, 0); lock.lock()) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +std::size_t task_io_service::poll_one(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + call_stack::context ctx(this); + + mutex::scoped_lock lock(mutex_); + + return do_one(lock, 0); +} + +void task_io_service::stop() +{ + mutex::scoped_lock lock(mutex_); + stop_all_threads(lock); +} + +void task_io_service::reset() +{ + mutex::scoped_lock lock(mutex_); + stopped_ = false; +} + +void task_io_service::post_immediate_completion(task_io_service::operation* op) +{ + work_started(); + post_deferred_completion(op); +} + +void task_io_service::post_deferred_completion(task_io_service::operation* op) +{ + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void task_io_service::post_deferred_completions( + op_queue& ops) +{ + if (!ops.empty()) + { + mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); + } +} + +std::size_t task_io_service::do_one(mutex::scoped_lock& lock, + task_io_service::idle_thread_info* this_idle_thread) +{ + bool polling = !this_idle_thread; + bool task_has_run = false; + while (!stopped_) + { + if (!op_queue_.empty()) + { + // Prepare to execute first handler from queue. + operation* o = op_queue_.front(); + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + if (o == &task_operation_) + { + task_interrupted_ = more_handlers || polling; + + // If the task has already run and we're polling then we're done. + if (task_has_run && polling) + { + task_interrupted_ = true; + op_queue_.push(&task_operation_); + return 0; + } + task_has_run = true; + + if (!more_handlers || !wake_one_idle_thread_and_unlock(lock)) + lock.unlock(); + + op_queue completed_ops; + task_cleanup c = { this, &lock, &completed_ops }; + (void)c; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(!more_handlers && !polling, completed_ops); + } + else + { + if (more_handlers) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + // Complete the operation. May throw an exception. + o->complete(*this); // deletes the operation object + + return 1; + } + } + else if (this_idle_thread) + { + // Nothing to run right now, so just wait for work to do. + this_idle_thread->next = first_idle_thread_; + first_idle_thread_ = this_idle_thread; + this_idle_thread->wakeup_event.clear(lock); + this_idle_thread->wakeup_event.wait(lock); + } + else + { + return 0; + } + } + + return 0; +} + +void task_io_service::stop_all_threads( + mutex::scoped_lock& lock) +{ + stopped_ = true; + + while (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); + } + + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } +} + +bool task_io_service::wake_one_idle_thread_and_unlock( + mutex::scoped_lock& lock) +{ + if (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal_and_unlock(lock); + return true; + } + return false; +} + +void task_io_service::wake_one_thread_and_unlock( + mutex::scoped_lock& lock) +{ + if (!wake_one_idle_thread_and_unlock(lock)) + { + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + lock.unlock(); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/throw_error.ipp b/include/boost/asio/detail/impl/throw_error.ipp new file mode 100644 index 00000000..e66cca59 --- /dev/null +++ b/include/boost/asio/detail/impl/throw_error.ipp @@ -0,0 +1,47 @@ +// +// detail/impl/throw_error.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_THROW_ERROR_IPP +#define BOOST_ASIO_DETAIL_IMPL_THROW_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void do_throw_error(const boost::system::error_code& err) +{ + boost::system::system_error e(err); + boost::throw_exception(e); +} + +void do_throw_error(const boost::system::error_code& err, const char* location) +{ + boost::system::system_error e(err, location); + boost::throw_exception(e); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_THROW_ERROR_IPP diff --git a/include/boost/asio/detail/impl/timer_queue.ipp b/include/boost/asio/detail/impl/timer_queue.ipp new file mode 100644 index 00000000..6a12d5a3 --- /dev/null +++ b/include/boost/asio/detail/impl/timer_queue.ipp @@ -0,0 +1,87 @@ +// +// detail/impl/timer_queue.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP +#define BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HEADER_ONLY) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +timer_queue >::timer_queue() +{ +} + +timer_queue >::~timer_queue() +{ +} + +bool timer_queue >::enqueue_timer( + const time_type& time, timer_op* op, void* token) +{ + return impl_.enqueue_timer(time, op, token); +} + +bool timer_queue >::empty() const +{ + return impl_.empty(); +} + +long timer_queue >::wait_duration_msec( + long max_duration) const +{ + return impl_.wait_duration_msec(max_duration); +} + +long timer_queue >::wait_duration_usec( + long max_duration) const +{ + return impl_.wait_duration_usec(max_duration); +} + +void timer_queue >::get_ready_timers( + op_queue& ops) +{ + impl_.get_ready_timers(ops); +} + +void timer_queue >::get_all_timers( + op_queue& ops) +{ + impl_.get_all_timers(ops); +} + +std::size_t timer_queue >::cancel_timer( + void* timer_token, op_queue& ops) +{ + return impl_.cancel_timer(timer_token, ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP diff --git a/include/boost/asio/detail/impl/timer_queue_set.ipp b/include/boost/asio/detail/impl/timer_queue_set.ipp new file mode 100644 index 00000000..275b9c5a --- /dev/null +++ b/include/boost/asio/detail/impl/timer_queue_set.ipp @@ -0,0 +1,103 @@ +// +// detail/impl/timer_queue_set.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP +#define BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +timer_queue_set::timer_queue_set() + : first_(0) +{ +} + +void timer_queue_set::insert(timer_queue_base* q) +{ + q->next_ = first_; + first_ = q; +} + +void timer_queue_set::erase(timer_queue_base* q) +{ + if (first_) + { + if (q == first_) + { + first_ = q->next_; + q->next_ = 0; + return; + } + + for (timer_queue_base* p = first_; p->next_; p = p->next_) + { + if (p->next_ == q) + { + p->next_ = q->next_; + q->next_ = 0; + return; + } + } + } +} + +bool timer_queue_set::all_empty() const +{ + for (timer_queue_base* p = first_; p; p = p->next_) + if (!p->empty()) + return false; + return true; +} + +long timer_queue_set::wait_duration_msec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_msec(min_duration); + return min_duration; +} + +long timer_queue_set::wait_duration_usec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_usec(min_duration); + return min_duration; +} + +void timer_queue_set::get_ready_timers(op_queue& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_ready_timers(ops); +} + +void timer_queue_set::get_all_timers(op_queue& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_all_timers(ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP diff --git a/include/boost/asio/detail/impl/win_event.ipp b/include/boost/asio/detail/impl/win_event.ipp new file mode 100644 index 00000000..d383c5b6 --- /dev/null +++ b/include/boost/asio/detail/impl/win_event.ipp @@ -0,0 +1,52 @@ +// +// detail/win_event.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_EVENT_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_event::win_event() + : event_(::CreateEvent(0, true, false, 0)) +{ + if (!event_) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "event"); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_EVENT_IPP diff --git a/include/boost/asio/detail/impl/win_iocp_handle_service.ipp b/include/boost/asio/detail/impl/win_iocp_handle_service.ipp new file mode 100644 index 00000000..3169632b --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_handle_service.ipp @@ -0,0 +1,454 @@ +// +// detail/impl/win_iocp_handle_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_handle_service::overlapped_wrapper + : public OVERLAPPED +{ +public: + explicit overlapped_wrapper(boost::system::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(&hEvent) |= 1; + } + else + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + + ~overlapped_wrapper() + { + if (hEvent) + { + ::CloseHandle(hEvent); + } + } +}; + +win_iocp_handle_service::win_iocp_handle_service( + boost::asio::io_service& io_service) + : iocp_service_(boost::asio::use_service(io_service)), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_handle_service::shutdown_service() +{ + // Close all implementations, causing all operations to complete. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_handle_service::construct( + win_iocp_handle_service::implementation_type& impl) +{ + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_handle_service::destroy( + win_iocp_handle_service::implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +boost::system::error_code win_iocp_handle_service::assign( + win_iocp_handle_service::implementation_type& impl, + const native_type& native_handle, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (iocp_service_.register_handle(native_handle, ec)) + return ec; + + impl.handle_ = native_handle; + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_handle_service::close( + win_iocp_handle_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + if (!::CloseHandle(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } + + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_handle_service::cancel( + win_iocp_handle_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::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 = boost::system::error_code(); + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + else + { + ec = boost::system::error_code(); + } + } + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = boost::system::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 = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = boost::asio::error::operation_not_supported; + } + + return ec; +} + +size_t win_iocp_handle_service::do_write( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const boost::asio::const_buffer& buffer, boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a handle is a no-op. + if (boost::asio::buffer_size(buffer) == 0) + { + ec = boost::system::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_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING) + { + ec = boost::system::error_code(last_error, + boost::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 = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_write_op( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const boost::asio::const_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (boost::asio::buffer_size(buffer) == 0) + { + // A request to write 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +size_t win_iocp_handle_service::do_read( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const boost::asio::mutable_buffer& buffer, boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream handle is a no-op. + if (boost::asio::buffer_size(buffer) == 0) + { + ec = boost::system::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_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) + { + if (last_error == ERROR_HANDLE_EOF) + { + ec = boost::asio::error::eof; + } + else + { + ec = boost::system::error_code(last_error, + boost::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 = boost::asio::error::eof; + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + return 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_read_op( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const boost::asio::mutable_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (boost::asio::buffer_size(buffer) == 0) + { + // A request to read 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_handle_service::update_cancellation_thread_id( + win_iocp_handle_service::implementation_type& impl) +{ + 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); +} + +void win_iocp_handle_service::close_for_destruction(implementation_type& impl) +{ + if (is_open(impl)) + { + ::CloseHandle(impl.handle_); + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/win_iocp_io_service.hpp b/include/boost/asio/detail/impl/win_iocp_io_service.hpp new file mode 100644 index 00000000..9ff23426 --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_io_service.hpp @@ -0,0 +1,113 @@ +// +// detail/impl/win_iocp_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void win_iocp_io_service::dispatch(Handler handler) +{ + if (call_stack::contains(this)) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + else + post(handler); +} + +template +void win_iocp_io_service::post(Handler handler) +{ + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + post_immediate_completion(p.p); + p.v = p.p = 0; +} + +template +void win_iocp_io_service::add_timer_queue( + timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void win_iocp_io_service::remove_timer_queue( + timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void win_iocp_io_service::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + // If the service has been shut down we silently discard the timer. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return; + + mutex::scoped_lock lock(dispatch_mutex_); + + bool earliest = queue.enqueue_timer(time, op, token); + work_started(); + if (earliest) + update_timeout(); +} + +template +std::size_t win_iocp_io_service::cancel_timer( + timer_queue& queue, void* token) +{ + // If the service has been shut down we silently ignore the cancellation. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return 0; + + mutex::scoped_lock lock(dispatch_mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP diff --git a/include/boost/asio/detail/impl/win_iocp_io_service.ipp b/include/boost/asio/detail/impl/win_iocp_io_service.ipp new file mode 100644 index 00000000..0219ccdb --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_io_service.ipp @@ -0,0 +1,493 @@ +// +// detail/impl/win_iocp_io_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct win_iocp_io_service::work_finished_on_block_exit +{ + ~work_finished_on_block_exit() + { + io_service_->work_finished(); + } + + win_iocp_io_service* io_service_; +}; + +struct win_iocp_io_service::timer_thread_function +{ + void operator()() + { + while (::InterlockedExchangeAdd(&io_service_->shutdown_, 0) == 0) + { + if (::WaitForSingleObject(io_service_->waitable_timer_.handle, + INFINITE) == WAIT_OBJECT_0) + { + ::InterlockedExchange(&io_service_->dispatch_required_, 1); + ::PostQueuedCompletionStatus(io_service_->iocp_.handle, + 0, wake_for_dispatch, 0); + } + } + } + + win_iocp_io_service* io_service_; +}; + +win_iocp_io_service::win_iocp_io_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + iocp_(), + outstanding_work_(0), + stopped_(0), + shutdown_(0), + dispatch_required_(0) +{ +} + +void win_iocp_io_service::init(size_t concurrency_hint) +{ + iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, + static_cast((std::min)(concurrency_hint, DWORD(~0)))); + if (!iocp_.handle) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "iocp"); + } +} + +void win_iocp_io_service::shutdown_service() +{ + ::InterlockedExchange(&shutdown_, 1); + + if (timer_thread_) + { + LARGE_INTEGER timeout; + timeout.QuadPart = 1; + ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE); + } + + while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) + { + op_queue ops; + timer_queues_.get_all_timers(ops); + ops.push(completed_ops_); + if (!ops.empty()) + { + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } + } + else + { + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, + &completion_key, &overlapped, gqcs_timeout); + if (overlapped) + { + ::InterlockedDecrement(&outstanding_work_); + static_cast(overlapped)->destroy(); + } + } + } + + if (timer_thread_) + timer_thread_->join(); +} + +boost::system::error_code win_iocp_io_service::register_handle( + HANDLE handle, boost::system::error_code& ec) +{ + if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + return ec; +} + +size_t win_iocp_io_service::run(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + size_t n = 0; + while (do_one(true, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +size_t win_iocp_io_service::run_one(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + return do_one(true, ec); +} + +size_t win_iocp_io_service::poll(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + size_t n = 0; + while (do_one(false, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +size_t win_iocp_io_service::poll_one(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + return do_one(false, ec); +} + +void win_iocp_io_service::stop() +{ + if (::InterlockedExchange(&stopped_, 1) == 0) + { + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "pqcs"); + } + } +} + +void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op) +{ + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_service::post_deferred_completions( + op_queue& ops) +{ + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + completed_ops_.push(ops); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_service::on_pending(win_iocp_operation* op) +{ + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_service::on_completion(win_iocp_operation* op, + DWORD last_error, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast( + &boost::asio::error::get_system_category()); + op->Offset = last_error; + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_service::on_completion(win_iocp_operation* op, + const boost::system::error_code& ec, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast(&ec.category()); + op->Offset = ec.value(); + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec) +{ + for (;;) + { + // Try to acquire responsibility for dispatching timers and completed ops. + if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1) + { + mutex::scoped_lock lock(dispatch_mutex_); + + // Dispatch pending timers and operations. + op_queue ops; + ops.push(completed_ops_); + timer_queues_.get_ready_timers(ops); + post_deferred_completions(ops); + update_timeout(); + } + + // Get the next operation from the queue. + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::SetLastError(0); + BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, + &completion_key, &overlapped, block ? gqcs_timeout : 0); + DWORD last_error = ::GetLastError(); + + if (overlapped) + { + win_iocp_operation* op = static_cast(overlapped); + boost::system::error_code result_ec(last_error, + boost::asio::error::get_system_category()); + + // We may have been passed the last_error and bytes_transferred in the + // OVERLAPPED structure itself. + if (completion_key == overlapped_contains_result) + { + result_ec = boost::system::error_code(static_cast(op->Offset), + *reinterpret_cast(op->Internal)); + bytes_transferred = op->OffsetHigh; + } + + // Otherwise ensure any result has been saved into the OVERLAPPED + // structure. + else + { + op->Internal = reinterpret_cast(&result_ec.category()); + op->Offset = result_ec.value(); + op->OffsetHigh = bytes_transferred; + } + + // Dispatch the operation only if ready. The operation may not be ready + // if the initiating function (e.g. a call to WSARecv) has not yet + // returned. This is because the initiating function still wants access + // to the operation's OVERLAPPED structure. + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + op->complete(*this, result_ec, bytes_transferred); + ec = boost::system::error_code(); + return 1; + } + } + else if (!ok) + { + if (last_error != WAIT_TIMEOUT) + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + + // If we're not polling we need to keep going until we get a real handler. + if (block) + continue; + + ec = boost::system::error_code(); + return 0; + } + else if (completion_key == wake_for_dispatch) + { + // We have been woken up to try to acquire responsibility for dispatching + // timers and completed operations. + } + else + { + // The stopped_ flag is always checked to ensure that any leftover + // interrupts from a previous run invocation are ignored. + if (::InterlockedExchangeAdd(&stopped_, 0) != 0) + { + // Wake up next thread that is blocked on GetQueuedCompletionStatus. + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + + ec = boost::system::error_code(); + return 0; + } + } + } +} + +void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.insert(&queue); + + if (!waitable_timer_.handle) + { + waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0); + if (waitable_timer_.handle == 0) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "timer"); + } + } + + if (!timer_thread_) + { + timer_thread_function thread_function = { this }; + timer_thread_.reset(new thread(thread_function, 65536)); + } +} + +void win_iocp_io_service::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.erase(&queue); +} + +void win_iocp_io_service::update_timeout() +{ + if (timer_thread_) + { + // There's no point updating the waitable timer if the new timeout period + // exceeds the maximum timeout. In that case, we might as well wait for the + // existing period of the timer to expire. + long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec); + if (timeout_usec < max_timeout_usec) + { + LARGE_INTEGER timeout; + timeout.QuadPart = -timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/win_iocp_serial_port_service.ipp b/include/boost/asio/detail/impl/win_iocp_serial_port_service.ipp new file mode 100644 index 00000000..bd2310c7 --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_serial_port_service.ipp @@ -0,0 +1,182 @@ +// +// detail/impl/win_iocp_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_iocp_serial_port_service::win_iocp_serial_port_service( + boost::asio::io_service& io_service) + : handle_service_(io_service) +{ +} + +void win_iocp_serial_port_service::shutdown_service() +{ +} + +boost::system::error_code win_iocp_serial_port_service::open( + win_iocp_serial_port_service::implementation_type& impl, + const std::string& device, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::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 = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + // Determine the initial serial port parameters. + using namespace std; // For memset. + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = boost::system::error_code(last_error, + boost::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 = boost::system::error_code(last_error, + boost::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 = boost::system::error_code(last_error, + boost::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; +} + +boost::system::error_code win_iocp_serial_port_service::do_set_option( + win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::store_function_type store, + const void* option, boost::system::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 = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + if (store(option, dcb, ec)) + return ec; + + if (!::SetCommState(handle_service_.native(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_serial_port_service::do_get_option( + const win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::load_function_type load, + void* option, boost::system::error_code& ec) const +{ + using namespace std; // For memset. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + return load(option, dcb, ec); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/win_iocp_socket_service_base.ipp b/include/boost/asio/detail/impl/win_iocp_socket_service_base.ipp new file mode 100644 index 00000000..59fc0ef9 --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -0,0 +1,567 @@ +// +// detail/impl/win_iocp_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_iocp_socket_service_base::win_iocp_socket_service_base( + boost::asio::io_service& io_service) + : io_service_(io_service), + iocp_service_(use_service(io_service)), + reactor_(0), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_socket_service_base::shutdown_service() +{ + // Close all implementations, causing all operations to complete. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + base_implementation_type* impl = impl_list_; + while (impl) + { + boost::system::error_code ignored_ec; + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_socket_service_base::construct( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_socket_service_base::destroy( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +boost::system::error_code win_iocp_socket_service_base::close( + win_iocp_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); + } + + if (socket_ops::close(impl.socket_, impl.state_, false, ec) == 0) + { + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + } + + return ec; +} + +boost::system::error_code win_iocp_socket_service_base::cancel( + win_iocp_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + 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; + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast(sock); + if (!cancel_io_ex(sock_as_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 = boost::system::error_code(); + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + else + { + ec = boost::system::error_code(); + } + } +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = boost::system::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. + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast(sock); + if (!::CancelIo(sock_as_handle)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = boost::asio::error::operation_not_supported; + } +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + else + { + // Cancellation is not supported as CancelIo may not be used. + ec = boost::asio::error::operation_not_supported; + } +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + return ec; +} + +boost::system::error_code win_iocp_socket_service_base::do_open( + win_iocp_socket_service_base::base_implementation_type& impl, + int family, int type, int protocol, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(family, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + HANDLE sock_as_handle = reinterpret_cast(sock.get()); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_socket_service_base::do_assign( + win_iocp_socket_service_base::base_implementation_type& impl, + int type, socket_type native_socket, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + HANDLE sock_as_handle = reinterpret_cast(native_socket); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); + ec = boost::system::error_code(); + return ec; +} + +void win_iocp_socket_service_base::start_send_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASend(impl.socket_, buffers, + static_cast(buffer_count), &bytes_transferred, flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_send_to_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASendTo(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, &recv_flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_NETNAME_DELETED) + last_error = WSAECONNRESET; + else if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_null_buffers_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op) +{ + if ((impl.state_ & socket_ops::stream_oriented) != 0) + { + // For stream sockets on Windows, we may issue a 0-byte overlapped + // WSARecv to wait until there is data available on the socket. + ::WSABUF buf = { 0, 0 }; + start_receive_op(impl, &buf, 1, flags, false, op); + } + else + { + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + op); + } +} + +void win_iocp_socket_service_base::start_receive_from_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecvFrom(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, &recv_flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_accept_op( + win_iocp_socket_service_base::base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else if (peer_is_open) + iocp_service_.on_completion(op, boost::asio::error::already_open); + else + { + boost::system::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_socket_service_base::restart_accept_op( + socket_type s, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + new_socket.reset(); + iocp_service_.work_started(); + + boost::system::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_reactor_op( + win_iocp_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op) +{ + reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if (is_open(impl)) + { + r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false); + return; + } + else + op->ec_ = boost::asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op); +} + +void win_iocp_socket_service_base::start_connect_op( + win_iocp_socket_service_base::base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, std::size_t addrlen) +{ + reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if ((impl.state_ & socket_ops::non_blocking) != 0 + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + r.start_op(reactor::connect_op, impl.socket_, + impl.reactor_data_, op, false); + return; + } + } + } + + r.post_immediate_completion(op); +} + +void win_iocp_socket_service_base::close_for_destruction( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + if (is_open(impl)) + { + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); + } + + boost::system::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) +} + +void win_iocp_socket_service_base::update_cancellation_thread_id( + win_iocp_socket_service_base::base_implementation_type& impl) +{ +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + 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); +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + (void)impl; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) +} + +reactor& win_iocp_socket_service_base::get_reactor() +{ + reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (!r) + { + r = &(use_service(io_service_)); + interlocked_exchange_pointer(reinterpret_cast(&reactor_), r); + } + return *r; +} + +void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp) +{ +#if defined(_M_IX86) + return reinterpret_cast(InterlockedCompareExchange( + reinterpret_cast(dest), reinterpret_cast(exch), + reinterpret_cast(cmp))); +#else + return InterlockedCompareExchangePointer(dest, exch, cmp); +#endif +} + +void* win_iocp_socket_service_base::interlocked_exchange_pointer( + void** dest, void* val) +{ +#if defined(_M_IX86) + return reinterpret_cast(InterlockedExchange( + reinterpret_cast(dest), reinterpret_cast(val))); +#else + return InterlockedExchangePointer(dest, val); +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP diff --git a/include/boost/asio/detail/impl/win_mutex.ipp b/include/boost/asio/detail/impl/win_mutex.ipp new file mode 100644 index 00000000..3cceda13 --- /dev/null +++ b/include/boost/asio/detail/impl/win_mutex.ipp @@ -0,0 +1,78 @@ +// +// detail/impl/win_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_MUTEX_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_mutex::win_mutex() +{ + int error = do_init(); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "mutex"); +} + +int win_mutex::do_init() +{ +#if defined(__MINGW32__) + // Not sure if MinGW supports structured exception handling, so for now + // we'll just call the Windows API and hope. +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else + ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); +# endif + return 0; +#else + __try + { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else + ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); +# endif + } + __except(GetExceptionCode() == STATUS_NO_MEMORY + ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + return ERROR_OUTOFMEMORY; + } + + return 0; +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_MUTEX_IPP diff --git a/include/boost/asio/detail/impl/win_thread.ipp b/include/boost/asio/detail/impl/win_thread.ipp new file mode 100644 index 00000000..22d23007 --- /dev/null +++ b/include/boost/asio/detail/impl/win_thread.ipp @@ -0,0 +1,140 @@ +// +// detail/impl/win_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) && !defined(UNDER_CE) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_thread::~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. +} + +void win_thread::join() +{ + HANDLE handles[2] = { exit_event_, thread_ }; + ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); + ::CloseHandle(exit_event_); + if (terminate_threads()) + { + ::TerminateThread(thread_, 0); + } + else + { + ::QueueUserAPC(apc_function, thread_, 0); + ::WaitForSingleObject(thread_, INFINITE); + } +} + +void win_thread::start_thread(func_base* arg, unsigned int stack_size) +{ + ::HANDLE entry_event = 0; + arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); + if (!entry_event) + { + DWORD last_error = ::GetLastError(); + delete arg; + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread.entry_event"); + } + + arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); + if (!exit_event_) + { + DWORD last_error = ::GetLastError(); + delete arg; + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread.exit_event"); + } + + unsigned int thread_id = 0; + thread_ = reinterpret_cast(::_beginthreadex(0, + stack_size, win_thread_function, arg, 0, &thread_id)); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + delete arg; + if (entry_event) + ::CloseHandle(entry_event); + if (exit_event_) + ::CloseHandle(exit_event_); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } + + if (entry_event) + { + ::WaitForSingleObject(entry_event, INFINITE); + ::CloseHandle(entry_event); + } +} + +unsigned int __stdcall win_thread_function(void* arg) +{ + std::auto_ptr func( + static_cast(arg)); + + ::SetEvent(func->entry_event_); + + func->run(); + + // Signal that the thread has finished its work, but rather than returning go + // to sleep to put the thread into a well known state. If the thread is being + // joined during global object destruction then it may be killed using + // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx + // call will be interrupted using QueueUserAPC and the thread will shut down + // cleanly. + HANDLE exit_event = func->exit_event_; + func.reset(); + ::SetEvent(exit_event); + ::SleepEx(INFINITE, TRUE); + + return 0; +} + +#if defined(WINVER) && (WINVER < 0x0500) +void __stdcall apc_function(ULONG) {} +#else +void __stdcall apc_function(ULONG_PTR) {} +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP diff --git a/include/boost/asio/detail/impl/win_tss_ptr.ipp b/include/boost/asio/detail/impl/win_tss_ptr.ipp new file mode 100644 index 00000000..7da9be34 --- /dev/null +++ b/include/boost/asio/detail/impl/win_tss_ptr.ipp @@ -0,0 +1,59 @@ +// +// detail/impl/win_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +DWORD win_tss_ptr_create() +{ +#if defined(UNDER_CE) + enum { out_of_indexes = 0xFFFFFFFF }; +#else + enum { out_of_indexes = TLS_OUT_OF_INDEXES }; +#endif + + DWORD tss_key = ::TlsAlloc(); + if (tss_key == out_of_indexes) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "tss"); + } + return tss_key; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP diff --git a/include/boost/asio/detail/impl/winsock_init.ipp b/include/boost/asio/detail/impl/winsock_init.ipp new file mode 100644 index 00000000..082ea844 --- /dev/null +++ b/include/boost/asio/detail/impl/winsock_init.ipp @@ -0,0 +1,71 @@ +// +// detail/impl/winsock_init.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP +#define BOOST_ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void winsock_init_base::startup(data& d, + unsigned char major, unsigned char minor) +{ + if (::InterlockedIncrement(&d.init_count_) == 1) + { + WSADATA wsa_data; + long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); + ::InterlockedExchange(&d.result_, result); + } +} + +void winsock_init_base::cleanup(data& d) +{ + if (::InterlockedDecrement(&d.init_count_) == 0) + { + ::WSACleanup(); + } +} + +void winsock_init_base::throw_on_error(data& d) +{ + long result = ::InterlockedExchangeAdd(&d.result_, 0); + if (result != 0) + { + boost::system::error_code ec(result, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "winsock"); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP diff --git a/include/boost/asio/detail/io_control.hpp b/include/boost/asio/detail/io_control.hpp index 5021c2e8..cb02fee6 100644 --- a/include/boost/asio/detail/io_control.hpp +++ b/include/boost/asio/detail/io_control.hpp @@ -1,6 +1,6 @@ // -// io_control.hpp -// ~~~~~~~~~~~~~~ +// detail/io_control.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/kqueue_reactor.hpp b/include/boost/asio/detail/kqueue_reactor.hpp index c1a67058..db5cb887 100644 --- a/include/boost/asio/detail/kqueue_reactor.hpp +++ b/include/boost/asio/detail/kqueue_reactor.hpp @@ -1,6 +1,6 @@ // -// kqueue_reactor.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) @@ -16,41 +16,35 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_KQUEUE) -#include #include #include #include #include -#include -#include -#include -#include - -#include -#include #include +#include #include #include #include #include -#include #include #include #include #include #include +#include +#include // Older versions of Mac OS X may not define EV_OOBAND. #if !defined(EV_OOBAND) # define EV_OOBAND EV_FLAG1 #endif // !defined(EV_OOBAND) +#include + namespace boost { namespace asio { namespace detail { @@ -78,371 +72,83 @@ public: typedef descriptor_state* per_descriptor_data; // Constructor. - kqueue_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - io_service_(use_service(io_service)), - mutex_(), - kqueue_fd_(do_kqueue_create()), - interrupter_(), - shutdown_(false) - { - // The interrupter is put into a permanently readable state. Whenever we - // want to interrupt the blocked kevent call we register a one-shot read - // operation against the descriptor. - interrupter_.interrupt(); - } + BOOST_ASIO_DECL kqueue_reactor(boost::asio::io_service& io_service); // Destructor. - ~kqueue_reactor() - { - close(kqueue_fd_); - } + BOOST_ASIO_DECL ~kqueue_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - op_queue ops; - - descriptor_map::iterator iter = registered_descriptors_.begin(); - descriptor_map::iterator end = registered_descriptors_.end(); - while (iter != end) - { - for (int i = 0; i < max_ops; ++i) - ops.push(iter->second.op_queue_[i]); - iter->second.shutdown_ = true; - ++iter; - } - - timer_queues_.get_all_timers(ops); - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task. - void init_task() - { - io_service_.init_task(); - } + BOOST_ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) + BOOST_ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - mutex::scoped_lock lock(registered_descriptors_mutex_); - - descriptor_map::iterator new_entry = registered_descriptors_.insert( - std::make_pair(descriptor, descriptor_state())).first; - descriptor_data = &new_entry->second; - - descriptor_data->shutdown_ = false; - - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, - reactor_op* op, bool allow_speculative) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - if (descriptor_data->shutdown_) - return; - - bool first = descriptor_data->op_queue_[op_type].empty(); - if (first) - { - if (allow_speculative) - { - if (op_type != read_op || descriptor_data->op_queue_[except_op].empty()) - { - if (op->perform()) - { - descriptor_lock.unlock(); - io_service_.post_immediate_completion(op); - return; - } - } - } - } - - descriptor_data->op_queue_[op_type].push(op); - io_service_.work_started(); - - if (first) - { - struct kevent event; - switch (op_type) - { - case read_op: - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - break; - case write_op: - EV_SET(&event, descriptor, EVFILT_WRITE, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - break; - case except_op: - if (!descriptor_data->op_queue_[read_op].empty()) - return; // Already registered for read events. - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); - break; - } - - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - op->ec_ = boost::system::error_code(errno, - boost::asio::error::get_system_category()); - descriptor_data->op_queue_[op_type].pop(); - io_service_.post_deferred_completion(op); - } - } - } + reactor_op* op, bool allow_speculative); // 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, per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - op_queue ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = boost::asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - - // Remove the descriptor from the set of known descriptors. The descriptor - // will be automatically removed from the kqueue set when it is closed. - descriptor_data->shutdown_ = true; - - op_queue ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = boost::asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - registered_descriptors_.erase(descriptor); - - descriptors_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + BOOST_ASIO_DECL void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); // Add a new timer queue to the reactor. template - void add_timer_queue(timer_queue& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& queue); // Remove a timer queue from the reactor. template - void remove_timer_queue(timer_queue& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template - void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - interrupt(); - } - } + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - mutex::scoped_lock lock(mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue& queue, void* token); // Run the kqueue loop. - void run(bool block, op_queue& ops) - { - mutex::scoped_lock lock(mutex_); - - // Determine how long to block while waiting for events. - timespec timeout_buf = { 0, 0 }; - timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf; - - lock.unlock(); - - // Block on the kqueue descriptor. - struct kevent events[128]; - int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); - - // Dispatch the waiting events. - for (int i = 0; i < num_events; ++i) - { - int descriptor = events[i].ident; - void* ptr = events[i].udata; - if (ptr == &interrupter_) - { - // No need to reset the interrupter since we're leaving the descriptor - // in a ready-to-read state and relying on one-shot notifications. - } - else - { - descriptor_state* descriptor_data = static_cast(ptr); - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - static const int filter[max_ops] = - { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; - for (int j = max_ops - 1; j >= 0; --j) - { - if (events[i].filter == filter[j]) - { - if (j != except_op || events[i].flags & EV_OOBAND) - { - while (reactor_op* op = descriptor_data->op_queue_[j].front()) - { - if (events[i].flags & EV_ERROR) - { - op->ec_ = boost::system::error_code(events[i].data, - boost::asio::error::get_system_category()); - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - if (op->perform()) - { - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - else - break; - } - } - } - } - - // Renew registration for event notifications. - struct kevent event; - switch (events[i].filter) - { - case EVFILT_READ: - if (!descriptor_data->op_queue_[read_op].empty()) - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - else if (!descriptor_data->op_queue_[except_op].empty()) - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); - else - continue; - case EVFILT_WRITE: - if (!descriptor_data->op_queue_[write_op].empty()) - EV_SET(&event, descriptor, EVFILT_WRITE, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - else - continue; - default: - break; - } - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - boost::system::error_code error(errno, - boost::asio::error::get_system_category()); - for (int j = 0; j < max_ops; ++j) - { - while (reactor_op* op = descriptor_data->op_queue_[j].front()) - { - op->ec_ = error; - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - } - } - } - } - - lock.lock(); - timer_queues_.get_ready_timers(ops); - } + BOOST_ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the kqueue loop. - void interrupt() - { - struct kevent event; - EV_SET(&event, interrupter_.read_descriptor(), - EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_); - ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); - } + BOOST_ASIO_DECL void interrupt(); private: // Create the kqueue file descriptor. Throws an exception if the descriptor // cannot be created. - static int do_kqueue_create() - { - int fd = kqueue(); - if (fd == -1) - { - boost::throw_exception( - boost::system::system_error( - boost::system::error_code(errno, - boost::asio::error::get_system_category()), - "kqueue")); - } - return fd; - } + BOOST_ASIO_DECL static int do_kqueue_create(); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the kevent call. - timespec* get_timeout(timespec& ts) - { - // By default we will wait no longer than 5 minutes. This will ensure that - // any changes to the system clock are detected after no longer than this. - long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); - ts.tv_sec = usec / 1000000; - ts.tv_nsec = (usec % 1000000) * 1000; - return &ts; - } + BOOST_ASIO_DECL timespec* get_timeout(timespec& ts); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -480,8 +186,13 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_KQUEUE) - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + #endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP diff --git a/include/boost/asio/detail/kqueue_reactor_fwd.hpp b/include/boost/asio/detail/kqueue_reactor_fwd.hpp index 0471c391..97f8c96a 100644 --- a/include/boost/asio/detail/kqueue_reactor_fwd.hpp +++ b/include/boost/asio/detail/kqueue_reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// kqueue_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/kqueue_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) @@ -16,15 +16,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#if !defined(BOOST_ASIO_DISABLE_KQUEUE) - -#if (defined(__MACH__) && defined(__APPLE__)) \ - || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - -// Define this to indicate that kqueue is supported on the target platform. -#define BOOST_ASIO_HAS_KQUEUE 1 +#if defined(BOOST_ASIO_HAS_KQUEUE) namespace boost { namespace asio { @@ -36,11 +30,6 @@ class kqueue_reactor; } // namespace asio } // namespace boost -#endif // (defined(__MACH__) && defined(__APPLE__)) - // || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - -#endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) - -#include +#endif // defined(BOOST_ASIO_HAS_KQUEUE) #endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/local_free_on_block_exit.hpp b/include/boost/asio/detail/local_free_on_block_exit.hpp index 6a60173e..6c8e0380 100644 --- a/include/boost/asio/detail/local_free_on_block_exit.hpp +++ b/include/boost/asio/detail/local_free_on_block_exit.hpp @@ -1,6 +1,6 @@ // -// local_free_on_block_exit.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/local_free_on_block_exit.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -54,8 +52,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP diff --git a/include/boost/asio/detail/macos_fenced_block.hpp b/include/boost/asio/detail/macos_fenced_block.hpp index 496d7f0c..a653aee5 100644 --- a/include/boost/asio/detail/macos_fenced_block.hpp +++ b/include/boost/asio/detail/macos_fenced_block.hpp @@ -1,6 +1,6 @@ // -// macos_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/macos_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(__MACH__) && defined(__APPLE__) -#include #include -#include + +#include namespace boost { namespace asio { @@ -52,8 +48,8 @@ public: } // namespace asio } // namespace boost -#endif // defined(__MACH__) && defined(__APPLE__) - #include +#endif // defined(__MACH__) && defined(__APPLE__) + #endif // BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/mutex.hpp b/include/boost/asio/detail/mutex.hpp index e804ec25..f6019965 100644 --- a/include/boost/asio/detail/mutex.hpp +++ b/include/boost/asio/detail/mutex.hpp @@ -1,6 +1,6 @@ // -// mutex.hpp -// ~~~~~~~~~ +// detail/mutex.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -47,6 +43,4 @@ typedef posix_mutex mutex; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_MUTEX_HPP diff --git a/include/boost/asio/detail/noncopyable.hpp b/include/boost/asio/detail/noncopyable.hpp index b3a6e7cc..65ae9a26 100644 --- a/include/boost/asio/detail/noncopyable.hpp +++ b/include/boost/asio/detail/noncopyable.hpp @@ -1,6 +1,6 @@ // -// noncopyable.hpp -// ~~~~~~~~~~~~~~~ +// detail/noncopyable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/null_buffers_op.hpp b/include/boost/asio/detail/null_buffers_op.hpp deleted file mode 100644 index 02160af5..00000000 --- a/include/boost/asio/detail/null_buffers_op.hpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// null_buffers_op.hpp -// ~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP -#define BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -template -class null_buffers_op : public reactor_op -{ -public: - null_buffers_op(Handler handler) - : reactor_op(&null_buffers_op::do_perform, &null_buffers_op::do_complete), - handler_(handler) - { - } - - static bool do_perform(reactor_op*) - { - return true; - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - null_buffers_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an upcall, - // 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. - detail::binder2 - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - -private: - Handler handler_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP diff --git a/include/boost/asio/detail/null_event.hpp b/include/boost/asio/detail/null_event.hpp index 2dc0bf6d..3acc26c7 100644 --- a/include/boost/asio/detail/null_event.hpp +++ b/include/boost/asio/detail/null_event.hpp @@ -1,6 +1,6 @@ // -// null_event.hpp -// ~~~~~~~~~~~~~~ +// detail/null_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include +#include + namespace boost { namespace asio { namespace detail { @@ -72,8 +70,8 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_NULL_EVENT_HPP diff --git a/include/boost/asio/detail/null_fenced_block.hpp b/include/boost/asio/detail/null_fenced_block.hpp index ea8e0fce..ead4c876 100644 --- a/include/boost/asio/detail/null_fenced_block.hpp +++ b/include/boost/asio/detail/null_fenced_block.hpp @@ -1,6 +1,6 @@ // -// null_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// detail/null_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // diff --git a/include/boost/asio/detail/null_mutex.hpp b/include/boost/asio/detail/null_mutex.hpp index edc13584..8fca31cb 100644 --- a/include/boost/asio/detail/null_mutex.hpp +++ b/include/boost/asio/detail/null_mutex.hpp @@ -1,6 +1,6 @@ // -// null_mutex.hpp -// ~~~~~~~~~~~~~~ +// detail/null_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -61,8 +59,8 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_NULL_MUTEX_HPP diff --git a/include/boost/asio/detail/null_signal_blocker.hpp b/include/boost/asio/detail/null_signal_blocker.hpp index 65b55e96..9eeccb96 100644 --- a/include/boost/asio/detail/null_signal_blocker.hpp +++ b/include/boost/asio/detail/null_signal_blocker.hpp @@ -1,6 +1,6 @@ // -// null_signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/null_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include - -#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) +#if !defined(BOOST_HAS_THREADS) \ + || defined(BOOST_ASIO_DISABLE_THREADS) \ + || defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) #include +#include + namespace boost { namespace asio { namespace detail { @@ -58,8 +60,12 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) + // || defined(BOOST_ASIO_DISABLE_THREADS) + // || defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + #endif // BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP diff --git a/include/boost/asio/detail/null_thread.hpp b/include/boost/asio/detail/null_thread.hpp index ba163114..93fd7154 100644 --- a/include/boost/asio/detail/null_thread.hpp +++ b/include/boost/asio/detail/null_thread.hpp @@ -1,6 +1,6 @@ // -// null_thread.hpp -// ~~~~~~~~~~~~~~~ +// detail/null_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) -#include -#include -#include - -#include #include +#include +#include + +#include namespace boost { namespace asio { @@ -41,11 +35,10 @@ class null_thread public: // Constructor. template - null_thread(Function f) + null_thread(Function) { - boost::system::system_error e( + boost::asio::detail::throw_error( boost::asio::error::operation_not_supported, "thread"); - boost::throw_exception(e); } // Destructor. @@ -63,8 +56,8 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_NULL_THREAD_HPP diff --git a/include/boost/asio/detail/null_tss_ptr.hpp b/include/boost/asio/detail/null_tss_ptr.hpp index bd83e7ee..3eff2dcf 100644 --- a/include/boost/asio/detail/null_tss_ptr.hpp +++ b/include/boost/asio/detail/null_tss_ptr.hpp @@ -1,6 +1,6 @@ // -// null_tss_ptr.hpp -// ~~~~~~~~~~~~~~~~ +// detail/null_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include +#include + namespace boost { namespace asio { namespace detail { @@ -65,8 +63,8 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP diff --git a/include/boost/asio/detail/old_win_sdk_compat.hpp b/include/boost/asio/detail/old_win_sdk_compat.hpp index 5f841820..10cd8985 100644 --- a/include/boost/asio/detail/old_win_sdk_compat.hpp +++ b/include/boost/asio/detail/old_win_sdk_compat.hpp @@ -1,6 +1,6 @@ // -// old_win_sdk_compat.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/old_win_sdk_compat.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -36,6 +32,8 @@ // a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support // in that case. +#include + namespace boost { namespace asio { namespace detail { @@ -323,6 +321,8 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a) } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_OLD_WIN_SDK) // Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. @@ -337,6 +337,4 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#include - #endif // BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP diff --git a/include/boost/asio/detail/op_queue.hpp b/include/boost/asio/detail/op_queue.hpp index ddf3e187..e35e82d3 100644 --- a/include/boost/asio/detail/op_queue.hpp +++ b/include/boost/asio/detail/op_queue.hpp @@ -1,6 +1,6 @@ // -// op_queue.hpp -// ~~~~~~~~~~~~ +// detail/op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/operation.hpp b/include/boost/asio/detail/operation.hpp index 579b6b5a..e42455cb 100644 --- a/include/boost/asio/detail/operation.hpp +++ b/include/boost/asio/detail/operation.hpp @@ -1,6 +1,6 @@ // -// operation.hpp -// ~~~~~~~~~~~~~ +// detail/operation.hpp +// ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) # include #else -# include # include #endif @@ -33,13 +30,11 @@ namespace detail { #if defined(BOOST_ASIO_HAS_IOCP) typedef win_iocp_operation operation; #else -typedef task_io_service_operation operation; +typedef task_io_service_operation operation; #endif } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_OPERATION_HPP diff --git a/include/boost/asio/detail/pipe_select_interrupter.hpp b/include/boost/asio/detail/pipe_select_interrupter.hpp index 7f9e122e..054f731e 100644 --- a/include/boost/asio/detail/pipe_select_interrupter.hpp +++ b/include/boost/asio/detail/pipe_select_interrupter.hpp @@ -1,6 +1,6 @@ // -// pipe_select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/pipe_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,22 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if !defined(BOOST_WINDOWS) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(BOOST_ASIO_HAS_EVENTFD) #include -#include -#include -#include -#include - -#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - -#include -#include -#include - -#include -#include namespace boost { namespace asio { @@ -40,57 +32,16 @@ class pipe_select_interrupter { public: // Constructor. - pipe_select_interrupter() - { - int pipe_fds[2]; - if (pipe(pipe_fds) == 0) - { - read_descriptor_ = pipe_fds[0]; - ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); - write_descriptor_ = pipe_fds[1]; - ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); - } - else - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - boost::system::system_error e(ec, "pipe_select_interrupter"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL pipe_select_interrupter(); // Destructor. - ~pipe_select_interrupter() - { - if (read_descriptor_ != -1) - ::close(read_descriptor_); - if (write_descriptor_ != -1) - ::close(write_descriptor_); - } + BOOST_ASIO_DECL ~pipe_select_interrupter(); // Interrupt the select call. - void interrupt() - { - char byte = 0; - int result = ::write(write_descriptor_, &byte, 1); - (void)result; - } + BOOST_ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. - bool reset() - { - for (;;) - { - char data[1024]; - int bytes_read = ::read(read_descriptor_, data, sizeof(data)); - if (bytes_read < 0 && errno == EINTR) - continue; - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = ::read(read_descriptor_, data, sizeof(data)); - return was_interrupted; - } - } + BOOST_ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. int read_descriptor() const @@ -115,8 +66,15 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(BOOST_WINDOWS) + #endif // BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP diff --git a/include/boost/asio/detail/pop_options.hpp b/include/boost/asio/detail/pop_options.hpp index a26b2039..8653f1a0 100644 --- a/include/boost/asio/detail/pop_options.hpp +++ b/include/boost/asio/detail/pop_options.hpp @@ -1,6 +1,6 @@ // -// pop_options.hpp -// ~~~~~~~~~~~~~~~ +// detail/pop_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // diff --git a/include/boost/asio/detail/posix_event.hpp b/include/boost/asio/detail/posix_event.hpp index b2938cfa..13fa3d47 100644 --- a/include/boost/asio/detail/posix_event.hpp +++ b/include/boost/asio/detail/posix_event.hpp @@ -1,6 +1,6 @@ // -// posix_event.hpp -// ~~~~~~~~~~~~~~~ +// detail/posix_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,24 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include #include -#include #include -#include - -#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -42,19 +34,7 @@ class posix_event { public: // Constructor. - posix_event() - : signalled_(false) - { - int error = ::pthread_cond_init(&cond_, 0); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "event"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL posix_event(); // Destructor. ~posix_event() @@ -109,8 +89,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_EVENT_HPP diff --git a/include/boost/asio/detail/posix_fd_set_adapter.hpp b/include/boost/asio/detail/posix_fd_set_adapter.hpp index 09fc28d0..5395eb99 100644 --- a/include/boost/asio/detail/posix_fd_set_adapter.hpp +++ b/include/boost/asio/detail/posix_fd_set_adapter.hpp @@ -1,6 +1,6 @@ // -// posix_fd_set_adapter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/posix_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - -#include +#include #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include +#include + +#include + namespace boost { namespace asio { namespace detail { @@ -76,8 +75,8 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP diff --git a/include/boost/asio/detail/posix_mutex.hpp b/include/boost/asio/detail/posix_mutex.hpp index 6d9a44f5..4fcd8ace 100644 --- a/include/boost/asio/detail/posix_mutex.hpp +++ b/include/boost/asio/detail/posix_mutex.hpp @@ -1,6 +1,6 @@ // -// posix_mutex.hpp -// ~~~~~~~~~~~~~~~ +// detail/posix_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,24 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include -#include #include -#include - -#include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -46,18 +38,7 @@ public: typedef boost::asio::detail::scoped_lock scoped_lock; // Constructor. - posix_mutex() - { - int error = ::pthread_mutex_init(&mutex_, 0); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL posix_mutex(); // Destructor. ~posix_mutex() @@ -86,8 +67,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP diff --git a/include/boost/asio/detail/posix_signal_blocker.hpp b/include/boost/asio/detail/posix_signal_blocker.hpp index aebe39ba..247a7a8a 100644 --- a/include/boost/asio/detail/posix_signal_blocker.hpp +++ b/include/boost/asio/detail/posix_signal_blocker.hpp @@ -1,6 +1,6 @@ // -// posix_signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/posix_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,22 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include #include #include #include -#include - #include +#include + namespace boost { namespace asio { namespace detail { @@ -85,8 +80,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP diff --git a/include/boost/asio/detail/posix_thread.hpp b/include/boost/asio/detail/posix_thread.hpp index 41d8bc94..a87e3967 100644 --- a/include/boost/asio/detail/posix_thread.hpp +++ b/include/boost/asio/detail/posix_thread.hpp @@ -1,6 +1,6 @@ // -// posix_thread.hpp -// ~~~~~~~~~~~~~~~~ +// detail/posix_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,29 +15,23 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include -#include -#include #include -#include - -#include #include +#include + namespace boost { namespace asio { namespace detail { -extern "C" void* boost_asio_detail_posix_thread_function(void* arg); +extern "C" +{ + BOOST_ASIO_DECL void* boost_asio_detail_posix_thread_function(void* arg); +} class posix_thread : private noncopyable @@ -48,36 +42,14 @@ public: posix_thread(Function f) : joined_(false) { - std::auto_ptr arg(new func(f)); - int error = ::pthread_create(&thread_, 0, - boost_asio_detail_posix_thread_function, arg.get()); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "thread"); - boost::throw_exception(e); - } - arg.release(); + start_thread(new func(f)); } // Destructor. - ~posix_thread() - { - if (!joined_) - ::pthread_detach(thread_); - } + BOOST_ASIO_DECL ~posix_thread(); // Wait for the thread to exit. - void join() - { - if (!joined_) - { - ::pthread_join(thread_, 0); - joined_ = true; - } - } + BOOST_ASIO_DECL void join(); private: friend void* boost_asio_detail_posix_thread_function(void* arg); @@ -89,6 +61,12 @@ private: virtual void run() = 0; }; + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + template class func : public func_base @@ -108,24 +86,22 @@ private: Function f_; }; + BOOST_ASIO_DECL void start_thread(func_base* arg); + ::pthread_t thread_; bool joined_; }; -inline void* boost_asio_detail_posix_thread_function(void* arg) -{ - std::auto_ptr f( - static_cast(arg)); - f->run(); - return 0; -} - } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_THREAD_HPP diff --git a/include/boost/asio/detail/posix_tss_ptr.hpp b/include/boost/asio/detail/posix_tss_ptr.hpp index c83df96e..dfe83696 100644 --- a/include/boost/asio/detail/posix_tss_ptr.hpp +++ b/include/boost/asio/detail/posix_tss_ptr.hpp @@ -1,6 +1,6 @@ // -// posix_tss_ptr.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/posix_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,27 +15,22 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include -#include #include -#include - -#include #include +#include + namespace boost { namespace asio { namespace detail { +// Helper function to create thread-specific storage. +BOOST_ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key); + template class posix_tss_ptr : private noncopyable @@ -44,15 +39,7 @@ public: // Constructor. posix_tss_ptr() { - int error = ::pthread_key_create(&tss_key_, 0); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "tss"); - boost::throw_exception(e); - } + posix_tss_ptr_create(tss_key_); } // Destructor. @@ -77,14 +64,19 @@ private: // Thread-specific storage to allow unlocked access to determine whether a // thread is a member of the pool. pthread_key_t tss_key_; + }; } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP diff --git a/include/boost/asio/detail/push_options.hpp b/include/boost/asio/detail/push_options.hpp index cb0e9024..00a9b7ee 100644 --- a/include/boost/asio/detail/push_options.hpp +++ b/include/boost/asio/detail/push_options.hpp @@ -1,6 +1,6 @@ // -// push_options.hpp -// ~~~~~~~~~~~~~~~~ +// detail/push_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // diff --git a/include/boost/asio/detail/reactive_descriptor_service.hpp b/include/boost/asio/detail/reactive_descriptor_service.hpp index 536b96a5..993211a7 100644 --- a/include/boost/asio/detail/reactive_descriptor_service.hpp +++ b/include/boost/asio/detail/reactive_descriptor_service.hpp @@ -1,6 +1,6 @@ // -// reactive_descriptor_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/reactive_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include #include -#include #include #include #include #include +#include +#include #include #include -#include +#include #include -#include -#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include namespace boost { namespace asio { @@ -49,7 +52,7 @@ public: // Default constructor. implementation_type() : descriptor_(-1), - flags_(0) + state_(0) { } @@ -60,94 +63,29 @@ public: // The native descriptor representation. int descriptor_; - enum - { - // The user wants a non-blocking descriptor. - user_set_non_blocking = 1, - - // The descriptor has been set non-blocking. - internal_non_blocking = 2, - - // Helper "flag" used to determine whether the descriptor is non-blocking. - non_blocking = user_set_non_blocking | internal_non_blocking - }; - - // Flags indicating the current state of the descriptor. - unsigned char flags_; + // The current state of the descriptor. + descriptor_ops::state_type state_; // Per-descriptor data used by the reactor. 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(boost::asio::io_service& io_service) - : io_service_impl_(boost::asio::use_service(io_service)), - reactor_(boost::asio::use_service(io_service)) - { - reactor_.init_task(); - } + BOOST_ASIO_DECL reactive_descriptor_service( + boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } + BOOST_ASIO_DECL void shutdown_service(); // Construct a new descriptor implementation. - void construct(implementation_type& impl) - { - impl.descriptor_ = -1; - impl.flags_ = 0; - } + BOOST_ASIO_DECL void construct(implementation_type& impl); // 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; - boost::system::error_code ignored_ec; - descriptor_ops::ioctl(impl.descriptor_, - FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::internal_non_blocking; - } - - boost::system::error_code ignored_ec; - descriptor_ops::close(impl.descriptor_, ignored_ec); - - impl.descriptor_ = -1; - } - } + BOOST_ASIO_DECL void destroy(implementation_type& impl); // Assign a native descriptor to a descriptor implementation. - boost::system::error_code assign(implementation_type& impl, - const native_type& native_descriptor, boost::system::error_code& ec) - { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } - - if (int err = reactor_.register_descriptor( - native_descriptor, impl.reactor_data_)) - { - ec = boost::system::error_code(err, - boost::asio::error::get_system_category()); - return ec; - } - - impl.descriptor_ = native_descriptor; - impl.flags_ = 0; - ec = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl, + const native_type& native_descriptor, boost::system::error_code& ec); // Determine whether the descriptor is open. bool is_open(const implementation_type& impl) const @@ -156,31 +94,8 @@ public: } // Destroy a descriptor implementation. - boost::system::error_code close(implementation_type& impl, - boost::system::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; - boost::system::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 = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec); // Get the native descriptor representation. native_type native(const implementation_type& impl) const @@ -189,56 +104,16 @@ public: } // Cancel all operations associated with the descriptor. - boost::system::error_code cancel(implementation_type& impl, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); - ec = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec); // Perform an IO control command on the descriptor. template boost::system::error_code io_control(implementation_type& impl, IO_Control_Command& command, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - descriptor_ops::ioctl(impl.descriptor_, command.name(), - static_cast(command.data()), ec); - - // When updating the non-blocking mode we always perform the ioctl syscall, - // even if the flags would otherwise indicate that the descriptor is - // already in the correct state. This ensures that the underlying - // descriptor is put into the state that has been requested by the user. If - // the ioctl syscall was successful then we need to update the flags to - // match. - if (!ec && command.name() == static_cast(FIONBIO)) - { - if (*static_cast(command.data())) - { - impl.flags_ |= implementation_type::user_set_non_blocking; - } - else - { - // Clearing the non-blocking mode always overrides any internally-set - // non-blocking flag. Any subsequent asynchronous operations will need - // to re-enable non-blocking I/O. - impl.flags_ &= ~(implementation_type::user_set_non_blocking - | implementation_type::internal_non_blocking); - } - } - + descriptor_ops::ioctl(impl.descriptor_, impl.state_, + command.name(), static_cast(command.data()), ec); return ec; } @@ -247,148 +122,23 @@ public: size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // A request to read_some 0 bytes on a stream is a no-op. - if (bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Send the data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_sent = descriptor_ops::gather_write( - impl.descriptor_, bufs.buffers(), bufs.count(), ec); - - // Check if operation succeeded. - if (bytes_sent >= 0) - return bytes_sent; - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for descriptor to become ready. - if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0) - return 0; - } + return descriptor_ops::sync_write(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be written without blocking. size_t write_some(implementation_type& impl, const null_buffers&, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for descriptor to become ready. descriptor_ops::poll_write(impl.descriptor_, ec); return 0; } - template - class write_op_base : public reactor_op - { - public: - write_op_base(int descriptor, - const ConstBufferSequence& buffers, func_type complete_func) - : reactor_op(&write_op_base::do_perform, complete_func), - descriptor_(descriptor), - buffers_(buffers) - { - } - - static bool do_perform(reactor_op* base) - { - write_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Write the data. - boost::system::error_code ec; - int bytes = descriptor_ops::gather_write( - o->descriptor_, bufs.buffers(), bufs.count(), ec); - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - int descriptor_; - ConstBufferSequence buffers_; - }; - - template - class write_op : public write_op_base - { - public: - write_op(int descriptor, - const ConstBufferSequence& buffers, Handler handler) - : write_op_base( - descriptor, buffers, &write_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - write_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous write. The data being sent must be valid for the // lifetime of the asynchronous operation. template @@ -396,15 +146,16 @@ public: const ConstBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef write_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, impl.descriptor_, buffers, handler); + typedef descriptor_write_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler); - start_op(impl, reactor::write_op, ptr.get(), true, + start_op(impl, reactor::write_op, p.p, true, buffer_sequence_adapter::all_empty(buffers)); - ptr.release(); + p.v = p.p = 0; } // Start an asynchronous wait until data can be written without blocking. @@ -413,13 +164,14 @@ public: const null_buffers&, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); - start_op(impl, reactor::write_op, ptr.get(), false, false); - ptr.release(); + start_op(impl, reactor::write_op, p.p, false, false); + p.v = p.p = 0; } // Read some data from the stream. Returns the number of bytes read. @@ -427,157 +179,23 @@ public: size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // A request to read_some 0 bytes on a stream is a no-op. - if (bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Read some data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_read = descriptor_ops::scatter_read( - impl.descriptor_, bufs.buffers(), bufs.count(), ec); - - // Check if operation succeeded. - if (bytes_read > 0) - return bytes_read; - - // Check for EOF. - if (bytes_read == 0) - { - ec = boost::asio::error::eof; - return 0; - } - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for descriptor to become ready. - if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0) - return 0; - } + return descriptor_ops::sync_read(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be read without blocking. size_t read_some(implementation_type& impl, const null_buffers&, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for descriptor to become ready. descriptor_ops::poll_read(impl.descriptor_, ec); return 0; } - template - class read_op_base : public reactor_op - { - public: - read_op_base(int descriptor, - const MutableBufferSequence& buffers, func_type complete_func) - : reactor_op(&read_op_base::do_perform, complete_func), - descriptor_(descriptor), - buffers_(buffers) - { - } - - static bool do_perform(reactor_op* base) - { - read_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Read some data. - boost::system::error_code ec; - int bytes = descriptor_ops::scatter_read( - o->descriptor_, bufs.buffers(), bufs.count(), ec); - if (bytes == 0) - ec = boost::asio::error::eof; - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - int descriptor_; - MutableBufferSequence buffers_; - }; - - template - class read_op : public read_op_base - { - public: - read_op(int descriptor, - const MutableBufferSequence& buffers, Handler handler) - : read_op_base( - descriptor, buffers, &read_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - read_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous read. The buffer for the data being read must be // valid for the lifetime of the asynchronous operation. template @@ -585,16 +203,16 @@ public: const MutableBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef read_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl.descriptor_, buffers, handler); + typedef descriptor_read_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler); - start_op(impl, reactor::read_op, ptr.get(), true, + start_op(impl, reactor::read_op, p.p, true, buffer_sequence_adapter::all_empty(buffers)); - ptr.release(); + p.v = p.p = 0; } // Wait until data can be read without blocking. @@ -603,57 +221,20 @@ public: const null_buffers&, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); - start_op(impl, reactor::read_op, ptr.get(), false, false); - ptr.release(); + start_op(impl, reactor::read_op, p.p, false, false); + p.v = p.p = 0; } private: // Start the asynchronous operation. - void start_op(implementation_type& impl, int op_type, - reactor_op* op, bool non_blocking, bool noop) - { - if (!noop) - { - if (is_open(impl)) - { - if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) - { - reactor_.start_op(op_type, impl.descriptor_, - impl.reactor_data_, op, non_blocking); - return; - } - } - else - op->ec_ = boost::asio::error::bad_descriptor; - } - - io_service_impl_.post_immediate_completion(op); - } - - // Determine whether the descriptor has been set non-blocking. - bool is_non_blocking(implementation_type& impl) const - { - return (impl.flags_ & implementation_type::non_blocking); - } - - // Set the internal non-blocking flag. - bool set_non_blocking(implementation_type& impl, - boost::system::error_code& ec) - { - ioctl_arg_type non_blocking = 1; - if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) - return false; - impl.flags_ |= implementation_type::internal_non_blocking; - return true; - } - - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; + BOOST_ASIO_DECL void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop); // The selector that performs event demultiplexing for the service. reactor& reactor_; @@ -663,8 +244,12 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP diff --git a/include/boost/asio/detail/reactive_null_buffers_op.hpp b/include/boost/asio/detail/reactive_null_buffers_op.hpp new file mode 100644 index 00000000..a2a69112 --- /dev/null +++ b/include/boost/asio/detail/reactive_null_buffers_op.hpp @@ -0,0 +1,85 @@ +// +// detail/reactive_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_null_buffers_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); + + reactive_null_buffers_op(Handler handler) + : reactor_op(&reactive_null_buffers_op::do_perform, + &reactive_null_buffers_op::do_complete), + handler_(handler) + { + } + + static bool do_perform(reactor_op*) + { + return true; + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_null_buffers_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP diff --git a/include/boost/asio/detail/reactive_serial_port_service.hpp b/include/boost/asio/detail/reactive_serial_port_service.hpp index faa2149e..0955f1d4 100644 --- a/include/boost/asio/detail/reactive_serial_port_service.hpp +++ b/include/boost/asio/detail/reactive_serial_port_service.hpp @@ -1,6 +1,6 @@ // -// reactive_serial_port_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/reactive_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) @@ -16,23 +16,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#include -#include #include -#include - -#include - -#if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ - && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include #include +#include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -47,119 +44,55 @@ public: // The implementation type of the serial port. typedef reactive_descriptor_service::implementation_type implementation_type; - reactive_serial_port_service(boost::asio::io_service& io_service) - : descriptor_service_(io_service) - { - } + BOOST_ASIO_DECL reactive_serial_port_service( + boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - descriptor_service_.shutdown_service(); - } + BOOST_ASIO_DECL void shutdown_service(); - // Construct a new handle implementation. + // Construct a new serial port implementation. void construct(implementation_type& impl) { descriptor_service_.construct(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. void destroy(implementation_type& impl) { descriptor_service_.destroy(impl); } // Open the serial port using the specified device name. - boost::system::error_code open(implementation_type& impl, - const std::string& device, boost::system::error_code& ec) - { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } + BOOST_ASIO_DECL boost::system::error_code open(implementation_type& impl, + const std::string& device, boost::system::error_code& 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) - { - boost::system::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; - ios.c_cflag |= CREAD | CLOCAL; - descriptor_ops::clear_error(ec); - s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); - } - if (s < 0) - { - boost::system::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)) - { - boost::system::error_code ignored_ec; - descriptor_ops::close(fd, ignored_ec); - } - - return ec; - } - - // Assign a native handle to a handle implementation. + // Assign a native descriptor to a serial port implementation. boost::system::error_code assign(implementation_type& impl, const native_type& native_descriptor, boost::system::error_code& ec) { return descriptor_service_.assign(impl, native_descriptor, ec); } - // Determine whether the handle is open. + // Determine whether the serial port is open. bool is_open(const implementation_type& impl) const { return descriptor_service_.is_open(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. boost::system::error_code close(implementation_type& impl, boost::system::error_code& ec) { return descriptor_service_.close(impl, ec); } - // Get the native handle representation. + // Get the native serial port representation. native_type native(implementation_type& impl) { return descriptor_service_.native(impl); } - // Cancel all operations associated with the handle. + // Cancel all operations associated with the serial port. boost::system::error_code cancel(implementation_type& impl, boost::system::error_code& ec) { @@ -171,20 +104,9 @@ public: boost::system::error_code set_option(implementation_type& impl, const SettableSerialPortOption& option, boost::system::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; + return do_set_option(impl, + &reactive_serial_port_service::store_option, + &option, ec); } // Get an option from the serial port. @@ -192,21 +114,16 @@ public: boost::system::error_code get_option(const implementation_type& impl, GettableSerialPortOption& option, boost::system::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); + return do_get_option(impl, + &reactive_serial_port_service::load_option, + &option, ec); } // Send a break sequence to the serial port. boost::system::error_code send_break(implementation_type& impl, boost::system::error_code& ec) { - descriptor_ops::clear_error(ec); + errno = 0; descriptor_ops::error_wrapper(::tcsendbreak( descriptor_service_.native(impl), 0), ec); return ec; @@ -247,6 +164,41 @@ public: } private: + // Function pointer type for storing a serial port option. + typedef boost::system::error_code (*store_function_type)( + const void*, termios&, boost::system::error_code&); + + // Helper function template to store a serial port option. + template + static boost::system::error_code store_option(const void* option, + termios& storage, boost::system::error_code& ec) + { + return static_cast(option)->store( + storage, ec); + } + + // Helper function to set a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, boost::system::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef boost::system::error_code (*load_function_type)( + void*, const termios&, boost::system::error_code&); + + // Helper function template to load a serial port option. + template + static boost::system::error_code load_option(void* option, + const termios& storage, boost::system::error_code& ec) + { + return static_cast(option)->load(storage, ec); + } + + // Helper function to get a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, boost::system::error_code& ec) const; + // The implementation used for initiating asynchronous operations. reactive_descriptor_service descriptor_service_; }; @@ -255,9 +207,13 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) - // && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + #endif // BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP diff --git a/include/boost/asio/detail/reactive_socket_accept_op.hpp b/include/boost/asio/detail/reactive_socket_accept_op.hpp new file mode 100644 index 00000000..3b2413f5 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_accept_op.hpp @@ -0,0 +1,133 @@ +// +// detail/reactive_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_accept_op_base : public reactor_op +{ +public: + reactive_socket_accept_op_base(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, func_type complete_func) + : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_accept_op_base* o( + static_cast(base)); + + std::size_t addrlen = o->peer_endpoint_ ? o->peer_endpoint_->capacity() : 0; + socket_type new_socket = invalid_socket; + bool result = socket_ops::non_blocking_accept(o->socket_, + o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, + o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_socket); + + // On success, assign new connection to peer socket object. + if (new_socket >= 0) + { + socket_holder new_socket_holder(new_socket); + if (o->peer_endpoint_) + o->peer_endpoint_->resize(addrlen); + if (!o->peer_.assign(o->protocol_, new_socket, o->ec_)) + new_socket_holder.release(); + } + + return result; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; +}; + +template +class reactive_socket_accept_op : + public reactive_socket_accept_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); + + reactive_socket_accept_op(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler handler) + : reactive_socket_accept_op_base(socket, state, peer, + protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_accept_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_connect_op.hpp b/include/boost/asio/detail/reactive_socket_connect_op.hpp new file mode 100644 index 00000000..2bfb55d8 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_connect_op.hpp @@ -0,0 +1,103 @@ +// +// detail/reactive_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactive_socket_connect_op_base : public reactor_op +{ +public: + reactive_socket_connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func), + socket_(socket) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_connect_op_base* o( + static_cast(base)); + + return socket_ops::non_blocking_connect(o->socket_, o->ec_); + } + +private: + socket_type socket_; +}; + +template +class reactive_socket_connect_op : public reactive_socket_connect_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); + + reactive_socket_connect_op(socket_type socket, Handler handler) + : reactive_socket_connect_op_base(socket, + &reactive_socket_connect_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_connect_op* o + (static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_recv_op.hpp b/include/boost/asio/detail/reactive_socket_recv_op.hpp new file mode 100644 index 00000000..d58aa3f0 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_recv_op.hpp @@ -0,0 +1,120 @@ +// +// detail/reactive_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_recv_op_base : public reactor_op +{ +public: + reactive_socket_recv_op_base(socket_type socket, + socket_ops::state_type state, const MutableBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_recv_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return socket_ops::non_blocking_recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + (o->state_ & socket_ops::stream_oriented), + o->ec_, o->bytes_transferred_); + } + +private: + socket_type socket_; + socket_ops::state_type state_; + MutableBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_recv_op : + public reactive_socket_recv_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); + + reactive_socket_recv_op(socket_type socket, + socket_ops::state_type state, const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : reactive_socket_recv_op_base(socket, state, + buffers, flags, &reactive_socket_recv_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recv_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp new file mode 100644 index 00000000..469b6a5d --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp @@ -0,0 +1,130 @@ +// +// detail/reactive_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_recvfrom_op_base : public reactor_op +{ +public: + reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func), + socket_(socket), + protocol_type_(protocol_type), + buffers_(buffers), + sender_endpoint_(endpoint), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_recvfrom_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + std::size_t addr_len = o->sender_endpoint_.capacity(); + bool result = socket_ops::non_blocking_recvfrom(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_); + + if (result && !o->ec_) + o->sender_endpoint_.resize(addr_len); + + return result; + } + +private: + socket_type socket_; + int protocol_type_; + MutableBufferSequence buffers_; + Endpoint& sender_endpoint_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_recvfrom_op : + public reactive_socket_recvfrom_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); + + reactive_socket_recvfrom_op(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, Handler handler) + : reactive_socket_recvfrom_op_base( + socket, protocol_type, buffers, endpoint, flags, + &reactive_socket_recvfrom_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recvfrom_op* o( + static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_send_op.hpp b/include/boost/asio/detail/reactive_socket_send_op.hpp new file mode 100644 index 00000000..157d0750 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_send_op.hpp @@ -0,0 +1,117 @@ +// +// detail/reactive_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_send_op_base : public reactor_op +{ +public: + reactive_socket_send_op_base(socket_type socket, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_send_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return socket_ops::non_blocking_send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->ec_, o->bytes_transferred_); + } + +private: + socket_type socket_; + ConstBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_send_op : + public reactive_socket_send_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); + + reactive_socket_send_op(socket_type socket, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : reactive_socket_send_op_base(socket, + buffers, flags, &reactive_socket_send_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_send_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_sendto_op.hpp b/include/boost/asio/detail/reactive_socket_sendto_op.hpp new file mode 100644 index 00000000..6199ec29 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_sendto_op.hpp @@ -0,0 +1,120 @@ +// +// detail/reactive_socket_sendto_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_sendto_op_base : public reactor_op +{ +public: + reactive_socket_sendto_op_base(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + destination_(endpoint), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_sendto_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return socket_ops::non_blocking_sendto(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_); + } + +private: + socket_type socket_; + ConstBufferSequence buffers_; + Endpoint destination_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_sendto_op : + public reactive_socket_sendto_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); + + reactive_socket_sendto_op(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, Handler handler) + : reactive_socket_sendto_op_base(socket, + buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_sendto_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 5f7bbf5c..73aa0246 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -1,6 +1,6 @@ // -// reactive_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/reactive_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,29 +15,38 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include #include #include #include #include -#include #include -#include #include -#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include + namespace boost { namespace asio { namespace detail { template -class reactive_socket_service +class reactive_socket_service : + public reactive_socket_service_base { public: // The protocol type. @@ -50,132 +59,32 @@ public: typedef socket_type native_type; // The implementation type of the socket. - class implementation_type - : private boost::asio::detail::noncopyable + struct implementation_type : + reactive_socket_service_base::base_implementation_type { - public: // Default constructor. implementation_type() - : socket_(invalid_socket), - flags_(0), - protocol_(endpoint_type().protocol()) + : protocol_(endpoint_type().protocol()) { } - private: - // Only this service will have access to the internal values. - friend class reactive_socket_service; - - // The native socket representation. - socket_type socket_; - - enum - { - // The user wants a non-blocking socket. - user_set_non_blocking = 1, - - // The implementation wants a non-blocking socket (in order to be able to - // perform asynchronous read and write operations). - internal_non_blocking = 2, - - // Helper "flag" used to determine whether the socket is non-blocking. - non_blocking = user_set_non_blocking | internal_non_blocking, - - // User wants connection_aborted errors, which are disabled by default. - enable_connection_aborted = 4, - - // The user set the linger option. Needs to be checked when closing. - user_set_linger = 8 - }; - - // Flags indicating the current state of the socket. - unsigned char flags_; - // The protocol associated with the socket. protocol_type protocol_; - - // Per-descriptor data used by the reactor. - reactor::per_descriptor_data reactor_data_; }; // Constructor. reactive_socket_service(boost::asio::io_service& io_service) - : io_service_impl_(use_service(io_service)), - reactor_(use_service(io_service)) + : reactive_socket_service_base(io_service) { - reactor_.init_task(); - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } - - // Construct a new socket implementation. - void construct(implementation_type& impl) - { - impl.socket_ = invalid_socket; - impl.flags_ = 0; - } - - // Destroy a socket implementation. - void destroy(implementation_type& impl) - { - if (impl.socket_ != invalid_socket) - { - reactor_.close_descriptor(impl.socket_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::non_blocking) - { - ioctl_arg_type non_blocking = 0; - boost::system::error_code ignored_ec; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::non_blocking; - } - - if (impl.flags_ & implementation_type::user_set_linger) - { - ::linger opt; - opt.l_onoff = 0; - opt.l_linger = 0; - boost::system::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); - } - - boost::system::error_code ignored_ec; - socket_ops::close(impl.socket_, ignored_ec); - - impl.socket_ = invalid_socket; - } } // Open a new socket implementation. boost::system::error_code open(implementation_type& impl, const protocol_type& protocol, boost::system::error_code& ec) { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } - - socket_holder sock(socket_ops::socket(protocol.family(), - protocol.type(), protocol.protocol(), ec)); - if (sock.get() == invalid_socket) - return ec; - - if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) - { - ec = boost::system::error_code(err, - boost::asio::error::get_system_category()); - return ec; - } - - impl.socket_ = sock.release(); - impl.flags_ = 0; - impl.protocol_ = protocol; - ec = boost::system::error_code(); + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + impl.protocol_ = protocol; return ec; } @@ -184,56 +93,8 @@ public: const protocol_type& protocol, const native_type& native_socket, boost::system::error_code& ec) { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } - - if (int err = reactor_.register_descriptor( - native_socket, impl.reactor_data_)) - { - ec = boost::system::error_code(err, - boost::asio::error::get_system_category()); - return ec; - } - - impl.socket_ = native_socket; - impl.flags_ = 0; - impl.protocol_ = protocol; - ec = boost::system::error_code(); - return ec; - } - - // Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return impl.socket_ != invalid_socket; - } - - // Destroy a socket implementation. - boost::system::error_code close(implementation_type& impl, - boost::system::error_code& ec) - { - if (is_open(impl)) - { - reactor_.close_descriptor(impl.socket_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::non_blocking) - { - ioctl_arg_type non_blocking = 0; - boost::system::error_code ignored_ec; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::non_blocking; - } - - if (socket_ops::close(impl.socket_, ec) == socket_error_retval) - return ec; - - impl.socket_ = invalid_socket; - } - - ec = boost::system::error_code(); + if (!do_assign(impl, protocol.type(), native_socket, ec)) + impl.protocol_ = protocol; return ec; } @@ -243,153 +104,23 @@ public: return impl.socket_; } - // Cancel all operations associated with the socket. - boost::system::error_code cancel(implementation_type& impl, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - reactor_.cancel_ops(impl.socket_, impl.reactor_data_); - ec = boost::system::error_code(); - return ec; - } - - // Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - boost::system::error_code& ec) const - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return false; - } - -#if defined(SIOCATMARK) - boost::asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec); -# if defined(ENOTTY) - if (ec.value() == ENOTTY) - ec = boost::asio::error::not_socket; -# endif // defined(ENOTTY) -#else // defined(SIOCATMARK) - int value = sockatmark(impl.socket_); - if (value == -1) - ec = boost::system::error_code(errno, - boost::asio::error::get_system_category()); - else - ec = boost::system::error_code(); -#endif // defined(SIOCATMARK) - return ec ? false : value != 0; - } - - // Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - boost::system::error_code& ec) const - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - boost::asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec); -#if defined(ENOTTY) - if (ec.value() == ENOTTY) - ec = boost::asio::error::not_socket; -#endif // defined(ENOTTY) - return ec ? static_cast(0) : static_cast(value); - } - // Bind the socket to the specified local endpoint. boost::system::error_code bind(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); return ec; } - // Place the socket into the state where it will listen for new connections. - boost::system::error_code listen(implementation_type& impl, int backlog, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::listen(impl.socket_, backlog, ec); - return ec; - } - // Set a socket option. template boost::system::error_code set_option(implementation_type& impl, const Option& option, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = boost::asio::error::invalid_argument; - } - else - { - if (*reinterpret_cast(option.data(impl.protocol_))) - impl.flags_ |= implementation_type::enable_connection_aborted; - else - impl.flags_ &= ~implementation_type::enable_connection_aborted; - ec = boost::system::error_code(); - } - return ec; - } - else - { - if (option.level(impl.protocol_) == SOL_SOCKET - && option.name(impl.protocol_) == SO_LINGER) - { - impl.flags_ |= implementation_type::user_set_linger; - } - - socket_ops::setsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), option.size(impl.protocol_), ec); - -#if defined(__MACH__) && defined(__APPLE__) \ -|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - // To implement portable behaviour for SO_REUSEADDR with UDP sockets we - // need to also set SO_REUSEPORT on BSD-based platforms. - if (!ec && impl.protocol_.type() == SOCK_DGRAM - && option.level(impl.protocol_) == SOL_SOCKET - && option.name(impl.protocol_) == SO_REUSEADDR) - { - boost::system::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT, - option.data(impl.protocol_), option.size(impl.protocol_), - ignored_ec); - } -#endif - - return ec; - } + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; } // Set a socket option. @@ -397,78 +128,12 @@ public: boost::system::error_code get_option(const implementation_type& impl, Option& option, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = boost::asio::error::invalid_argument; - } - else - { - int* target = reinterpret_cast(option.data(impl.protocol_)); - if (impl.flags_ & implementation_type::enable_connection_aborted) - *target = 1; - else - *target = 0; - option.resize(impl.protocol_, sizeof(int)); - ec = boost::system::error_code(); - } - return ec; - } - else - { - size_t size = option.size(impl.protocol_); - socket_ops::getsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), &size, ec); - if (!ec) - option.resize(impl.protocol_, size); - return ec; - } - } - - // Perform an IO control command on the socket. - template - boost::system::error_code io_control(implementation_type& impl, - IO_Control_Command& command, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::ioctl(impl.socket_, command.name(), - static_cast(command.data()), ec); - - // When updating the non-blocking mode we always perform the ioctl - // syscall, even if the flags would otherwise indicate that the socket is - // already in the correct state. This ensures that the underlying socket - // is put into the state that has been requested by the user. If the ioctl - // syscall was successful then we need to update the flags to match. - if (!ec && command.name() == static_cast(FIONBIO)) - { - if (*static_cast(command.data())) - { - impl.flags_ |= implementation_type::user_set_non_blocking; - } - else - { - // Clearing the non-blocking mode always overrides any internally-set - // non-blocking flag. Any subsequent asynchronous operations will need - // to re-enable non-blocking I/O. - impl.flags_ &= ~(implementation_type::user_set_non_blocking - | implementation_type::internal_non_blocking); - } - } - + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); return ec; } @@ -476,12 +141,6 @@ public: endpoint_type local_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return endpoint_type(); - } - endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) @@ -494,218 +153,15 @@ public: endpoint_type remote_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return endpoint_type(); - } - endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); - if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) + if (socket_ops::getpeername(impl.socket_, + endpoint.data(), &addr_len, false, ec)) return endpoint_type(); endpoint.resize(addr_len); return endpoint; } - /// Disable sends or receives on the socket. - boost::system::error_code shutdown(implementation_type& impl, - socket_base::shutdown_type what, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::shutdown(impl.socket_, what, ec); - return ec; - } - - // Send the given data to the peer. - template - size_t send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Send the data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_sent = socket_ops::send(impl.socket_, - bufs.buffers(), bufs.count(), flags, ec); - - // Check if operation succeeded. - if (bytes_sent >= 0) - return bytes_sent; - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_write(impl.socket_, ec) < 0) - return 0; - } - } - - // Wait until data can be sent without blocking. - size_t send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, ec); - - return 0; - } - - template - class send_op_base : public reactor_op - { - public: - send_op_base(socket_type socket, const ConstBufferSequence& buffers, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&send_op_base::do_perform, complete_func), - socket_(socket), - buffers_(buffers), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - send_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Send the data. - boost::system::error_code ec; - int bytes = socket_ops::send(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, ec); - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - ConstBufferSequence buffers_; - socket_base::message_flags flags_; - }; - - template - class send_op : public send_op_base - { - public: - send_op(socket_type socket, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - : send_op_base(socket, - buffers, flags, &send_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - send_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - - // Start an asynchronous send. The data being sent must be valid for the - // lifetime of the asynchronous operation. - template - void async_send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef send_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl.socket_, buffers, flags, handler); - - start_op(impl, reactor::write_op, ptr.get(), true, - (impl.protocol_.type() == SOCK_STREAM - && buffer_sequence_adapter::all_empty(buffers))); - ptr.release(); - } - - // Start an asynchronous wait until data can be sent without blocking. - template - void async_send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - start_op(impl, reactor::write_op, ptr.get(), false, false); - ptr.release(); - } - // Send a datagram to the specified endpoint. Returns the number of bytes // sent. template @@ -713,148 +169,25 @@ public: const endpoint_type& destination, socket_base::message_flags flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // Send the data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_sent = socket_ops::sendto(impl.socket_, bufs.buffers(), - bufs.count(), flags, destination.data(), destination.size(), ec); - - // Check if operation succeeded. - if (bytes_sent >= 0) - return bytes_sent; - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_write(impl.socket_, ec) < 0) - return 0; - } + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); } // 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&, + const endpoint_type&, socket_base::message_flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } - template - class send_to_op_base : public reactor_op - { - public: - send_to_op_base(socket_type socket, const ConstBufferSequence& buffers, - const endpoint_type& endpoint, socket_base::message_flags flags, - func_type complete_func) - : reactor_op(&send_to_op_base::do_perform, complete_func), - socket_(socket), - buffers_(buffers), - destination_(endpoint), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - send_to_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Send the data. - boost::system::error_code ec; - int bytes = socket_ops::sendto(o->socket_, bufs.buffers(), bufs.count(), - o->flags_, o->destination_.data(), o->destination_.size(), ec); - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - ConstBufferSequence buffers_; - endpoint_type destination_; - socket_base::message_flags flags_; - }; - - template - class send_to_op : public send_to_op_base - { - public: - send_to_op(socket_type socket, const ConstBufferSequence& buffers, - const endpoint_type& endpoint, socket_base::message_flags flags, - Handler handler) - : send_to_op_base(socket, - buffers, endpoint, flags, &send_to_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - send_to_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template @@ -864,235 +197,31 @@ public: Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef send_to_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, impl.socket_, - buffers, destination, flags, handler); + typedef reactive_socket_sendto_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler); - start_op(impl, reactor::write_op, ptr.get(), true, false); - ptr.release(); + start_op(impl, reactor::write_op, p.p, true, false); + p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template void async_send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, Handler handler) + const endpoint_type&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); - start_op(impl, reactor::write_op, ptr.get(), false, false); - ptr.release(); - } - - // Receive some data from the peer. Returns the number of bytes received. - template - size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Receive some data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_recvd = socket_ops::recv(impl.socket_, - bufs.buffers(), bufs.count(), flags, ec); - - // Check if operation succeeded. - if (bytes_recvd > 0) - return bytes_recvd; - - // Check for EOF. - if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = boost::asio::error::eof; - return 0; - } - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_, ec) < 0) - return 0; - } - } - - // Wait until data can be received without blocking. - size_t receive(implementation_type& impl, const null_buffers&, - socket_base::message_flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, ec); - - return 0; - } - - template - class receive_op_base : public reactor_op - { - public: - receive_op_base(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&receive_op_base::do_perform, complete_func), - socket_(socket), - protocol_type_(protocol_type), - buffers_(buffers), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - receive_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Receive some data. - boost::system::error_code ec; - int bytes = socket_ops::recv(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, ec); - if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) - ec = boost::asio::error::eof; - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - int protocol_type_; - MutableBufferSequence buffers_; - socket_base::message_flags flags_; - }; - - template - class receive_op : public receive_op_base - { - public: - receive_op(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - : receive_op_base(socket, - protocol_type, buffers, flags, &receive_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - receive_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - - // Start an asynchronous receive. The buffer for the data being received - // must be valid for the lifetime of the asynchronous operation. - template - void async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef receive_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, impl.socket_, - protocol_type, buffers, flags, handler); - - start_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get(), (flags & socket_base::message_out_of_band) == 0, - (impl.protocol_.type() == SOCK_STREAM - && buffer_sequence_adapter::all_empty(buffers))); - ptr.release(); - } - - // Wait until data can be received without blocking. - template - void async_receive(implementation_type& impl, const null_buffers&, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - start_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get(), false, false); - ptr.release(); + start_op(impl, reactor::write_op, p.p, false, false); + p.v = p.p = 0; } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -1103,47 +232,18 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // Receive some data. - for (;;) - { - // Try to complete the operation without blocking. - std::size_t addr_len = sender_endpoint.capacity(); - int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs.buffers(), - bufs.count(), flags, sender_endpoint.data(), &addr_len, ec); + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); - // Check if operation succeeded. - if (bytes_recvd > 0) - { - sender_endpoint.resize(addr_len); - return bytes_recvd; - } + if (!ec) + sender_endpoint.resize(addr_len); - // Check for EOF. - if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = boost::asio::error::eof; - return 0; - } - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_, ec) < 0) - return 0; - } + return bytes_recvd; } // Wait until data can be received without blocking. @@ -1151,12 +251,6 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); @@ -1166,105 +260,6 @@ public: return 0; } - template - class receive_from_op_base : public reactor_op - { - public: - receive_from_op_base(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, endpoint_type& endpoint, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&receive_from_op_base::do_perform, complete_func), - socket_(socket), - protocol_type_(protocol_type), - buffers_(buffers), - sender_endpoint_(endpoint), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - receive_from_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Receive some data. - boost::system::error_code ec; - std::size_t addr_len = o->sender_endpoint_.capacity(); - int bytes = socket_ops::recvfrom(o->socket_, bufs.buffers(), - bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, ec); - if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) - ec = boost::asio::error::eof; - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->sender_endpoint_.resize(addr_len); - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - int protocol_type_; - MutableBufferSequence buffers_; - endpoint_type& sender_endpoint_; - socket_base::message_flags flags_; - }; - - template - class receive_from_op : public receive_from_op_base - { - public: - receive_from_op(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, endpoint_type& endpoint, - socket_base::message_flags flags, Handler handler) - : receive_from_op_base(socket, protocol_type, - buffers, endpoint, flags, &receive_from_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - receive_from_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. @@ -1274,18 +269,20 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef receive_from_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); + typedef reactive_socket_recvfrom_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, impl.socket_, - protocol_type, buffers, sender_endpoint, flags, handler); + p.p = new (p.v) op(impl.socket_, protocol_type, + buffers, sender_endpoint, flags, handler); start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - ptr.get(), true, false); - ptr.release(); + p.p, true, false); + p.v = p.p = 0; } // Wait until data can be received without blocking. @@ -1295,10 +292,11 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); @@ -1306,8 +304,8 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - ptr.get(), false, false); - ptr.release(); + p.p, false, false); + p.v = p.p = 0; } // Accept a new connection. @@ -1315,12 +313,6 @@ public: boost::system::error_code accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - // We cannot accept a socket that is already open. if (peer.is_open()) { @@ -1328,182 +320,23 @@ public: return ec; } - // Accept a socket. - for (;;) + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() >= 0) { - // Try to complete the operation without blocking. - socket_holder new_socket; - std::size_t addr_len = 0; if (peer_endpoint) - { - addr_len = peer_endpoint->capacity(); - new_socket.reset(socket_ops::accept(impl.socket_, - peer_endpoint->data(), &addr_len, ec)); - } - else - { - new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec)); - } - - // Check if operation succeeded. - if (new_socket.get() >= 0) - { - if (peer_endpoint) - peer_endpoint->resize(addr_len); - peer.assign(impl.protocol_, new_socket.get(), ec); - if (!ec) - new_socket.release(); - return ec; - } - - // Operation failed. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - { - if (impl.flags_ & implementation_type::user_set_non_blocking) - return ec; - // Fall through to retry operation. - } - else if (ec == boost::asio::error::connection_aborted) - { - if (impl.flags_ & implementation_type::enable_connection_aborted) - return ec; - // Fall through to retry operation. - } -#if defined(EPROTO) - else if (ec.value() == EPROTO) - { - if (impl.flags_ & implementation_type::enable_connection_aborted) - return ec; - // Fall through to retry operation. - } -#endif // defined(EPROTO) - else - return ec; - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_, ec) < 0) - return ec; + peer_endpoint->resize(addr_len); + if (!peer.assign(impl.protocol_, new_socket.get(), ec)) + new_socket.release(); } + + return ec; } - template - class accept_op_base : public reactor_op - { - public: - accept_op_base(socket_type socket, Socket& peer, - const protocol_type& protocol, endpoint_type* peer_endpoint, - bool enable_connection_aborted, func_type complete_func) - : reactor_op(&accept_op_base::do_perform, complete_func), - socket_(socket), - peer_(peer), - protocol_(protocol), - peer_endpoint_(peer_endpoint), - enable_connection_aborted_(enable_connection_aborted) - { - } - - static bool do_perform(reactor_op* base) - { - accept_op_base* o(static_cast(base)); - - for (;;) - { - // Accept the waiting connection. - boost::system::error_code ec; - socket_holder new_socket; - std::size_t addr_len = 0; - std::size_t* addr_len_p = 0; - socket_addr_type* addr = 0; - if (o->peer_endpoint_) - { - addr_len = o->peer_endpoint_->capacity(); - addr_len_p = &addr_len; - addr = o->peer_endpoint_->data(); - } - new_socket.reset(socket_ops::accept(o->socket_, addr, addr_len_p, ec)); - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - if (ec == boost::asio::error::connection_aborted - && !o->enable_connection_aborted_) - return false; -#if defined(EPROTO) - if (ec.value() == EPROTO && !o->enable_connection_aborted_) - return false; -#endif // defined(EPROTO) - - // Transfer ownership of the new socket to the peer object. - if (!ec) - { - if (o->peer_endpoint_) - o->peer_endpoint_->resize(addr_len); - o->peer_.assign(o->protocol_, new_socket.get(), ec); - if (!ec) - new_socket.release(); - } - - o->ec_ = ec; - return true; - } - } - - private: - socket_type socket_; - Socket& peer_; - protocol_type protocol_; - endpoint_type* peer_endpoint_; - bool enable_connection_aborted_; - }; - - template - class accept_op : public accept_op_base - { - public: - accept_op(socket_type socket, Socket& peer, const protocol_type& protocol, - endpoint_type* peer_endpoint, bool enable_connection_aborted, - Handler handler) - : accept_op_base(socket, peer, protocol, peer_endpoint, - enable_connection_aborted, &accept_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - accept_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder1 - handler(o->handler_, o->ec_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template @@ -1511,230 +344,41 @@ public: endpoint_type* peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef accept_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - bool enable_connection_aborted = - (impl.flags_ & implementation_type::enable_connection_aborted) != 0; - handler_ptr ptr(raw_ptr, impl.socket_, peer, - impl.protocol_, peer_endpoint, enable_connection_aborted, handler); + typedef reactive_socket_accept_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, peer, + impl.protocol_, peer_endpoint, handler); - start_accept_op(impl, ptr.get(), peer.is_open()); - ptr.release(); + start_accept_op(impl, p.p, peer.is_open()); + p.v = p.p = 0; } // Connect the socket to the specified endpoint. boost::system::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - // Perform the connect operation. - socket_ops::connect(impl.socket_, + socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); - if (ec != boost::asio::error::in_progress - && ec != boost::asio::error::would_block) - { - // The connect operation finished immediately. - return ec; - } - - // Wait for socket to become ready. - if (socket_ops::poll_connect(impl.socket_, ec) < 0) - return ec; - - // Get the error code from the connect operation. - int connect_error = 0; - size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, ec) == socket_error_retval) - return ec; - - // Return the result of the connect operation. - ec = boost::system::error_code(connect_error, - boost::asio::error::get_system_category()); return ec; } - class connect_op_base : public reactor_op - { - public: - connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&connect_op_base::do_perform, complete_func), - socket_(socket) - { - } - - static bool do_perform(reactor_op* base) - { - connect_op_base* o(static_cast(base)); - - // Get the error code from the connect operation. - int connect_error = 0; - size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, o->ec_) == socket_error_retval) - return true; - - // The connection failed so the handler will be posted with an error code. - if (connect_error) - { - o->ec_ = boost::system::error_code(connect_error, - boost::asio::error::get_system_category()); - } - - return true; - } - - private: - socket_type socket_; - }; - - template - class connect_op : public connect_op_base - { - public: - connect_op(socket_type socket, Handler handler) - : connect_op_base(socket, &connect_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - connect_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder1 - handler(o->handler_, o->ec_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous connect. template void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef connect_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, impl.socket_, handler); + typedef reactive_socket_connect_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler); - start_connect_op(impl, ptr.get(), peer_endpoint); - ptr.release(); + start_connect_op(impl, p.p, peer_endpoint.data(), peer_endpoint.size()); + p.v = p.p = 0; } - -private: - // Start the asynchronous read or write operation. - void start_op(implementation_type& impl, int op_type, - reactor_op* op, bool non_blocking, bool noop) - { - if (!noop) - { - if (is_open(impl)) - { - if (!non_blocking || is_non_blocking(impl) - || set_non_blocking(impl, op->ec_)) - { - reactor_.start_op(op_type, impl.socket_, - impl.reactor_data_, op, non_blocking); - return; - } - } - else - op->ec_ = boost::asio::error::bad_descriptor; - } - - io_service_impl_.post_immediate_completion(op); - } - - // Start the asynchronous accept operation. - void start_accept_op(implementation_type& impl, - reactor_op* op, bool peer_is_open) - { - if (!peer_is_open) - start_op(impl, reactor::read_op, op, true, false); - else - { - op->ec_ = boost::asio::error::already_open; - io_service_impl_.post_immediate_completion(op); - } - } - - // Start the asynchronous connect operation. - void start_connect_op(implementation_type& impl, - reactor_op* op, const endpoint_type& peer_endpoint) - { - if (is_open(impl)) - { - if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) - { - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), op->ec_) != 0) - { - if (op->ec_ == boost::asio::error::in_progress - || op->ec_ == boost::asio::error::would_block) - { - op->ec_ = boost::system::error_code(); - reactor_.start_op(reactor::connect_op, - impl.socket_, impl.reactor_data_, op, false); - return; - } - } - } - } - else - op->ec_ = boost::asio::error::bad_descriptor; - - io_service_impl_.post_immediate_completion(op); - } - - // Determine whether the socket has been set non-blocking. - bool is_non_blocking(implementation_type& impl) const - { - return (impl.flags_ & implementation_type::non_blocking); - } - - // Set the internal non-blocking flag. - bool set_non_blocking(implementation_type& impl, - boost::system::error_code& ec) - { - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - return false; - impl.flags_ |= implementation_type::internal_non_blocking; - return true; - } - - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; - - // The selector that performs event demultiplexing for the service. - reactor& reactor_; }; } // namespace detail @@ -1743,4 +387,6 @@ private: #include +#endif // !defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP diff --git a/include/boost/asio/detail/reactive_socket_service_base.hpp b/include/boost/asio/detail/reactive_socket_service_base.hpp new file mode 100644 index 00000000..1733ce10 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_service_base.hpp @@ -0,0 +1,300 @@ +// +// detail/reactive_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactive_socket_service_base +{ +public: + // The native type of a socket. + typedef socket_type native_type; + + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + }; + + // Constructor. + BOOST_ASIO_DECL reactive_socket_service_base( + boost::asio::io_service& io_service); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown_service(); + + // Construct a new socket implementation. + BOOST_ASIO_DECL void construct(base_implementation_type& impl); + + // Destroy a socket implementation. + BOOST_ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + BOOST_ASIO_DECL boost::system::error_code close( + base_implementation_type& impl, boost::system::error_code& ec); + + // Get the native socket representation. + native_type native(base_implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + BOOST_ASIO_DECL boost::system::error_code cancel( + base_implementation_type& impl, boost::system::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + boost::system::error_code listen(base_implementation_type& impl, + int backlog, boost::system::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template + boost::system::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, boost::system::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast(command.data()), ec); + return ec; + } + + /// Disable sends or receives on the socket. + boost::system::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, boost::system::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send the given data to the peer. + template + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_send_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, flags, handler); + + start_op(impl, reactor::write_op, p.p, true, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter::all_empty(buffers))); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + start_op(impl, reactor::write_op, p.p, false, false); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recv_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, (flags & socket_base::message_out_of_band) == 0, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter::all_empty(buffers))); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, false, false); + p.v = p.p = 0; + } + +protected: + // Open a new socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_open( + base_implementation_type& impl, int af, + int type, int protocol, boost::system::error_code& ec); + + // Assign a native socket to a socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_assign( + base_implementation_type& impl, int type, + const native_type& native_socket, boost::system::error_code& ec); + + // Start the asynchronous read or write operation. + BOOST_ASIO_DECL void start_op(base_implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop); + + // Start the asynchronous accept operation. + BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl, + reactor_op* op, bool peer_is_open); + + // Start the asynchronous connect operation. + BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, size_t addrlen); + + // The selector that performs event demultiplexing for the service. + reactor& reactor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP diff --git a/include/boost/asio/detail/reactor.hpp b/include/boost/asio/detail/reactor.hpp index 43e432b8..468276d7 100644 --- a/include/boost/asio/detail/reactor.hpp +++ b/include/boost/asio/detail/reactor.hpp @@ -1,6 +1,6 @@ // -// reactor.hpp -// ~~~~~~~~~~~ +// detail/reactor.hpp +// ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include #if defined(BOOST_ASIO_HAS_EPOLL) @@ -29,6 +27,4 @@ # include #endif -#include - #endif // BOOST_ASIO_DETAIL_REACTOR_HPP diff --git a/include/boost/asio/detail/reactor_fwd.hpp b/include/boost/asio/detail/reactor_fwd.hpp index 9ff05eb5..3fae83c7 100644 --- a/include/boost/asio/detail/reactor_fwd.hpp +++ b/include/boost/asio/detail/reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// reactor_fwd.hpp -// ~~~~~~~~~~~~~~~ +// detail/reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,20 +15,26 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#elif defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#else +# include +#endif namespace boost { namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_IOCP) -typedef select_reactor reactor; +typedef select_reactor reactor; #elif defined(BOOST_ASIO_HAS_EPOLL) typedef epoll_reactor reactor; #elif defined(BOOST_ASIO_HAS_KQUEUE) @@ -36,13 +42,11 @@ typedef kqueue_reactor reactor; #elif defined(BOOST_ASIO_HAS_DEV_POLL) typedef dev_poll_reactor reactor; #else -typedef select_reactor reactor; +typedef select_reactor reactor; #endif } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/reactor_op.hpp b/include/boost/asio/detail/reactor_op.hpp index 40647ec8..ed4a33d9 100644 --- a/include/boost/asio/detail/reactor_op.hpp +++ b/include/boost/asio/detail/reactor_op.hpp @@ -1,6 +1,6 @@ // -// reactor_op.hpp -// ~~~~~~~~~~~~ +// detail/reactor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/reactor_op_queue.hpp b/include/boost/asio/detail/reactor_op_queue.hpp index 0dd56540..830e9b35 100644 --- a/include/boost/asio/detail/reactor_op_queue.hpp +++ b/include/boost/asio/detail/reactor_op_queue.hpp @@ -1,6 +1,6 @@ // -// reactor_op_queue.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/reactor_op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/regex_fwd.hpp b/include/boost/asio/detail/regex_fwd.hpp new file mode 100644 index 00000000..7847b8d8 --- /dev/null +++ b/include/boost/asio/detail/regex_fwd.hpp @@ -0,0 +1,31 @@ +// +// detail/regex_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REGEX_FWD_HPP +#define BOOST_ASIO_DETAIL_REGEX_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +namespace boost { + +template +class sub_match; + +template +class match_results; + +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_REGEX_FWD_HPP diff --git a/include/boost/asio/detail/resolve_endpoint_op.hpp b/include/boost/asio/detail/resolve_endpoint_op.hpp new file mode 100644 index 00000000..ccf5f532 --- /dev/null +++ b/include/boost/asio/detail/resolve_endpoint_op.hpp @@ -0,0 +1,118 @@ +// +// detail/resolve_endpoint_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP +#define BOOST_ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class resolve_endpoint_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op); + + typedef typename Protocol::endpoint endpoint_type; + typedef boost::asio::ip::basic_resolver_iterator iterator_type; + + resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token, + const endpoint_type& endpoint, io_service_impl& ios, Handler handler) + : operation(&resolve_endpoint_op::do_complete), + cancel_token_(cancel_token), + endpoint_(endpoint), + io_service_impl_(ios), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_endpoint_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + if (owner && owner != &o->io_service_impl_) + { + // The operation is being run on the worker io_service. Time to perform + // the resolver operation. + + // Perform the blocking endpoint resolution operation. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(), + o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV, + o->endpoint_.protocol().type(), o->ec_); + o->iter_ = iterator_type::create(o->endpoint_, host_name, service_name); + + // Pass operation back to main io_service for completion. + o->io_service_impl_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_service. The completion + // handler is ready to be delivered. + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an upcall, + // 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. + detail::binder2 + handler(o->handler_, o->ec_, o->iter_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + endpoint_type endpoint_; + io_service_impl& io_service_impl_; + Handler handler_; + boost::system::error_code ec_; + iterator_type iter_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP diff --git a/include/boost/asio/detail/resolve_op.hpp b/include/boost/asio/detail/resolve_op.hpp new file mode 100644 index 00000000..aff61040 --- /dev/null +++ b/include/boost/asio/detail/resolve_op.hpp @@ -0,0 +1,128 @@ +// +// detail/resolve_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_RESOLVE_OP_HPP +#define BOOST_ASIO_DETAIL_RESOLVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class resolve_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_op); + + typedef boost::asio::ip::basic_resolver_query query_type; + typedef boost::asio::ip::basic_resolver_iterator iterator_type; + + resolve_op(socket_ops::weak_cancel_token_type cancel_token, + const query_type& query, io_service_impl& ios, Handler handler) + : operation(&resolve_op::do_complete), + cancel_token_(cancel_token), + query_(query), + io_service_impl_(ios), + handler_(handler), + addrinfo_(0) + { + } + + ~resolve_op() + { + if (addrinfo_) + socket_ops::freeaddrinfo(addrinfo_); + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + if (owner && owner != &o->io_service_impl_) + { + // The operation is being run on the worker io_service. Time to perform + // the resolver operation. + + // Perform the blocking host resolution operation. + socket_ops::background_getaddrinfo(o->cancel_token_, + o->query_.host_name().c_str(), o->query_.service_name().c_str(), + o->query_.hints(), &o->addrinfo_, o->ec_); + + // Pass operation back to main io_service for completion. + o->io_service_impl_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_service. The completion + // handler is ready to be delivered. + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an upcall, + // 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. + detail::binder2 + handler(o->handler_, o->ec_, iterator_type()); + p.h = boost::addressof(handler.handler_); + if (o->addrinfo_) + { + handler.arg2_ = iterator_type::create(o->addrinfo_, + o->query_.host_name(), o->query_.service_name()); + } + p.reset(); + + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + query_type query_; + io_service_impl& io_service_impl_; + Handler handler_; + boost::system::error_code ec_; + boost::asio::detail::addrinfo_type* addrinfo_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_RESOLVE_OP_HPP diff --git a/include/boost/asio/detail/resolver_service.hpp b/include/boost/asio/detail/resolver_service.hpp index f9b7a98a..1b734a0e 100644 --- a/include/boost/asio/detail/resolver_service.hpp +++ b/include/boost/asio/detail/resolver_service.hpp @@ -1,6 +1,6 @@ // -// resolver_service.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,69 +15,26 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include -#include - -#include -#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include + +#include namespace boost { namespace asio { namespace detail { template -class resolver_service - : public boost::asio::detail::service_base > +class resolver_service : public resolver_service_base { -private: - // Helper class to perform exception-safe cleanup of addrinfo objects. - class auto_addrinfo - : private boost::asio::detail::noncopyable - { - public: - explicit auto_addrinfo(boost::asio::detail::addrinfo_type* ai) - : ai_(ai) - { - } - - ~auto_addrinfo() - { - if (ai_) - socket_ops::freeaddrinfo(ai_); - } - - operator boost::asio::detail::addrinfo_type*() - { - return ai_; - } - - private: - boost::asio::detail::addrinfo_type* ai_; - }; - public: - // The implementation type of the resolver. The shared pointer is used as a - // cancellation token to indicate to the background thread that the operation - // has been cancelled. - typedef boost::shared_ptr implementation_type; - struct noop_deleter { void operator()(void*) {} }; + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; // The endpoint type. typedef typename Protocol::endpoint endpoint_type; @@ -90,349 +47,69 @@ public: // Constructor. resolver_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - resolver_service >(io_service), - mutex_(), - io_service_impl_(boost::asio::use_service(io_service)), - work_io_service_(new boost::asio::io_service), - work_io_service_impl_(boost::asio::use_service< - io_service_impl>(*work_io_service_)), - work_(new boost::asio::io_service::work(*work_io_service_)), - work_thread_(0) + : resolver_service_base(io_service) { } - // Destructor. - ~resolver_service() - { - shutdown_service(); - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - work_.reset(); - if (work_io_service_) - { - work_io_service_->stop(); - if (work_thread_) - { - work_thread_->join(); - work_thread_.reset(); - } - work_io_service_.reset(); - } - } - - // Construct a new resolver implementation. - void construct(implementation_type& impl) - { - impl.reset(static_cast(0), noop_deleter()); - } - - // Destroy a resolver implementation. - void destroy(implementation_type&) - { - } - - // Cancel pending asynchronous operations. - void cancel(implementation_type& impl) - { - impl.reset(static_cast(0), noop_deleter()); - } - // Resolve a query to a list of entries. iterator_type resolve(implementation_type&, const query_type& query, boost::system::error_code& ec) { boost::asio::detail::addrinfo_type* address_info = 0; - std::string host_name = query.host_name(); - std::string service_name = query.service_name(); - boost::asio::detail::addrinfo_type hints = query.hints(); - socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info, ec); + socket_ops::getaddrinfo(query.host_name().c_str(), + query.service_name().c_str(), query.hints(), &address_info, ec); auto_addrinfo auto_address_info(address_info); - if (ec) - return iterator_type(); - - return iterator_type::create(address_info, host_name, service_name); + return ec ? iterator_type() : iterator_type::create( + address_info, query.host_name(), query.service_name()); } - template - class resolve_op - : public operation - { - public: - resolve_op(implementation_type impl, const query_type& query, - io_service_impl& io_service_impl, Handler handler) - : operation(&resolve_op::do_complete), - impl_(impl), - query_(query), - io_service_impl_(io_service_impl), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the operation object. - resolve_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - if (owner) - { - if (owner != &o->io_service_impl_) - { - // The operation is being run on the worker io_service. Time to - // perform the resolver operation. - - if (o->impl_.expired()) - { - // THe operation has been cancelled. - o->ec_ = boost::asio::error::operation_aborted; - } - else - { - // Perform the blocking host resolution operation. - boost::asio::detail::addrinfo_type* address_info = 0; - std::string host_name = o->query_.host_name(); - std::string service_name = o->query_.service_name(); - boost::asio::detail::addrinfo_type hints = o->query_.hints(); - socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info, o->ec_); - auto_addrinfo auto_address_info(address_info); - o->iter_ = iterator_type::create( - address_info, host_name, service_name); - } - - o->io_service_impl_.post_deferred_completion(o); - ptr.release(); - } - else - { - // The operation has been returned to the main io_serice. The - // completion handler is ready to be delivered. - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, o->ec_, o->iter_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - } - - private: - boost::weak_ptr impl_; - query_type query_; - io_service_impl& io_service_impl_; - Handler handler_; - boost::system::error_code ec_; - iterator_type iter_; - }; - // Asynchronously resolve a query to a list of entries. template void async_resolve(implementation_type& impl, const query_type& query, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef resolve_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl, query, io_service_impl_, handler); + typedef resolve_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl, query, io_service_impl_, handler); - if (work_io_service_) - { - start_work_thread(); - io_service_impl_.work_started(); - work_io_service_impl_.post_immediate_completion(ptr.get()); - ptr.release(); - } + start_resolve_op(p.p); + p.v = p.p = 0; } // Resolve an endpoint to a list of entries. iterator_type resolve(implementation_type&, const endpoint_type& endpoint, boost::system::error_code& ec) { - // First try resolving with the service name. If that fails try resolving - // but allow the service to be returned as a number. char host_name[NI_MAXHOST]; char service_name[NI_MAXSERV]; - int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - socket_ops::getnameinfo(endpoint.data(), endpoint.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); - if (ec) - { - flags |= NI_NUMERICSERV; - socket_ops::getnameinfo(endpoint.data(), endpoint.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); - } + socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, + endpoint.protocol().type(), ec); - if (ec) - return iterator_type(); - - return iterator_type::create(endpoint, host_name, service_name); + return ec ? iterator_type() : iterator_type::create( + endpoint, host_name, service_name); } - template - class resolve_endpoint_op - : public operation - { - public: - resolve_endpoint_op(implementation_type impl, const endpoint_type& ep, - io_service_impl& io_service_impl, Handler handler) - : operation(&resolve_endpoint_op::do_complete), - impl_(impl), - ep_(ep), - io_service_impl_(io_service_impl), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the operation object. - resolve_endpoint_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - if (owner) - { - if (owner != &o->io_service_impl_) - { - // The operation is being run on the worker io_service. Time to - // perform the resolver operation. - - if (o->impl_.expired()) - { - // THe operation has been cancelled. - o->ec_ = boost::asio::error::operation_aborted; - } - else - { - // Perform the blocking endoint resolution operation. - char host_name[NI_MAXHOST]; - char service_name[NI_MAXSERV]; - int flags = o->ep_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), - host_name, NI_MAXHOST, service_name, - NI_MAXSERV, flags, o->ec_); - if (o->ec_) - { - flags |= NI_NUMERICSERV; - socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), - host_name, NI_MAXHOST, service_name, - NI_MAXSERV, flags, o->ec_); - } - o->iter_ = iterator_type::create(o->ep_, host_name, service_name); - } - - o->io_service_impl_.post_deferred_completion(o); - ptr.release(); - } - else - { - // The operation has been returned to the main io_serice. The - // completion handler is ready to be delivered. - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, o->ec_, o->iter_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - } - - private: - boost::weak_ptr impl_; - endpoint_type ep_; - io_service_impl& io_service_impl_; - Handler handler_; - boost::system::error_code ec_; - iterator_type iter_; - }; - // Asynchronously resolve an endpoint to a list of entries. template void async_resolve(implementation_type& impl, const endpoint_type& endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef resolve_endpoint_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl, endpoint, io_service_impl_, handler); + typedef resolve_endpoint_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl, endpoint, io_service_impl_, handler); - if (work_io_service_) - { - start_work_thread(); - io_service_impl_.work_started(); - work_io_service_impl_.post_immediate_completion(ptr.get()); - ptr.release(); - } + start_resolve_op(p.p); + p.v = p.p = 0; } - -private: - // Helper class to run the work io_service in a thread. - class work_io_service_runner - { - public: - work_io_service_runner(boost::asio::io_service& io_service) - : io_service_(io_service) {} - void operator()() { io_service_.run(); } - private: - boost::asio::io_service& io_service_; - }; - - // Start the work thread if it's not already running. - void start_work_thread() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!work_thread_) - { - work_thread_.reset(new boost::asio::detail::thread( - work_io_service_runner(*work_io_service_))); - } - } - - // Mutex to protect access to internal data. - boost::asio::detail::mutex mutex_; - - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; - - // Private io_service used for performing asynchronous host resolution. - boost::scoped_ptr work_io_service_; - - // The work io_service implementation used to post completions. - io_service_impl& work_io_service_impl_; - - // Work for the private io_service to perform. - boost::scoped_ptr work_; - - // Thread used for running the work io_service's run loop. - boost::scoped_ptr work_thread_; }; } // namespace detail diff --git a/include/boost/asio/detail/resolver_service_base.hpp b/include/boost/asio/detail/resolver_service_base.hpp new file mode 100644 index 00000000..cc6ede6d --- /dev/null +++ b/include/boost/asio/detail/resolver_service_base.hpp @@ -0,0 +1,125 @@ +// +// detail/resolver_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class resolver_service_base +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // Constructor. + BOOST_ASIO_DECL resolver_service_base(boost::asio::io_service& io_service); + + // Destructor. + BOOST_ASIO_DECL ~resolver_service_base(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown_service(); + + // Construct a new resolver implementation. + BOOST_ASIO_DECL void construct(implementation_type& impl); + + // Destroy a resolver implementation. + BOOST_ASIO_DECL void destroy(implementation_type&); + + // Cancel pending asynchronous operations. + BOOST_ASIO_DECL void cancel(implementation_type& impl); + +protected: + // Helper function to start an asynchronous resolve operation. + BOOST_ASIO_DECL void start_resolve_op(operation* op); + + // Helper class to perform exception-safe cleanup of addrinfo objects. + class auto_addrinfo + : private boost::asio::detail::noncopyable + { + public: + explicit auto_addrinfo(boost::asio::detail::addrinfo_type* ai) + : ai_(ai) + { + } + + ~auto_addrinfo() + { + if (ai_) + socket_ops::freeaddrinfo(ai_); + } + + operator boost::asio::detail::addrinfo_type*() + { + return ai_; + } + + private: + boost::asio::detail::addrinfo_type* ai_; + }; + + // Helper class to run the work io_service in a thread. + class work_io_service_runner; + + // Start the work thread if it's not already running. + BOOST_ASIO_DECL void start_work_thread(); + + // The io_service implementation used to post completions. + io_service_impl& io_service_impl_; + +private: + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // Private io_service used for performing asynchronous host resolution. + boost::scoped_ptr work_io_service_; + + // The work io_service implementation used to post completions. + io_service_impl& work_io_service_impl_; + + // Work for the private io_service to perform. + boost::scoped_ptr work_; + + // Thread used for running the work io_service's run loop. + boost::scoped_ptr work_thread_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP diff --git a/include/boost/asio/detail/scoped_lock.hpp b/include/boost/asio/detail/scoped_lock.hpp index c3192631..247411e1 100644 --- a/include/boost/asio/detail/scoped_lock.hpp +++ b/include/boost/asio/detail/scoped_lock.hpp @@ -1,6 +1,6 @@ // -// scoped_lock.hpp -// ~~~~~~~~~~~~~~~ +// detail/scoped_lock.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/select_interrupter.hpp b/include/boost/asio/detail/select_interrupter.hpp index f8448815..9683e636 100644 --- a/include/boost/asio/detail/select_interrupter.hpp +++ b/include/boost/asio/detail/select_interrupter.hpp @@ -1,6 +1,6 @@ // -// select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include - -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) # include -#else +#elif defined(BOOST_ASIO_HAS_EVENTFD) # include +#else # include #endif @@ -32,7 +29,7 @@ namespace boost { namespace asio { namespace detail { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) typedef socket_select_interrupter select_interrupter; #elif defined(BOOST_ASIO_HAS_EVENTFD) typedef eventfd_select_interrupter select_interrupter; @@ -44,6 +41,4 @@ typedef pipe_select_interrupter select_interrupter; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP diff --git a/include/boost/asio/detail/select_reactor.hpp b/include/boost/asio/detail/select_reactor.hpp index 91030e91..c453c598 100644 --- a/include/boost/asio/detail/select_reactor.hpp +++ b/include/boost/asio/detail/select_reactor.hpp @@ -1,6 +1,6 @@ // -// select_reactor.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,42 +15,39 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include // Must come before posix_time. +#if defined(BOOST_ASIO_HAS_IOCP) \ + || (!defined(BOOST_ASIO_HAS_DEV_POLL) \ + && !defined(BOOST_ASIO_HAS_EPOLL) \ + && !defined(BOOST_ASIO_HAS_KQUEUE)) -#include #include -#include -#include - -#include -#include -#include #include -#include #include #include #include #include #include -#include -#include -#include #include -#include #include #include #include #include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include namespace boost { namespace asio { namespace detail { -template class select_reactor - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -67,280 +64,89 @@ public: }; // Constructor. - select_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - select_reactor >(io_service), - io_service_(use_service(io_service)), - mutex_(), - interrupter_(), - stop_thread_(false), - thread_(0), - shutdown_(false) - { - if (Own_Thread) - { - boost::asio::detail::signal_blocker sb; - thread_ = new boost::asio::detail::thread( - bind_handler(&select_reactor::call_run_thread, this)); - } - } + BOOST_ASIO_DECL select_reactor(boost::asio::io_service& io_service); // Destructor. - ~select_reactor() - { - shutdown_service(); - } + BOOST_ASIO_DECL ~select_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - shutdown_ = true; - stop_thread_ = true; - lock.unlock(); - - if (Own_Thread) - { - if (thread_) - { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; - } - } - - op_queue ops; - - for (int i = 0; i < max_ops; ++i) - op_queue_[i].get_all_operations(ops); - - timer_queues_.get_all_timers(ops); - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task, but only if the reactor is not in its own thread. - void init_task() - { - io_service_.init_task(); - } + BOOST_ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type, per_descriptor_data&) + BOOST_ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, - per_descriptor_data&, reactor_op* op, bool) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool first = op_queue_[op_type].enqueue_operation(descriptor, op); - io_service_.work_started(); - if (first) - interrupter_.interrupt(); - } - } + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool); // 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, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); - } + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); - } + BOOST_ASIO_DECL void close_descriptor(socket_type descriptor, + per_descriptor_data&); // Add a new timer queue to the reactor. template - void add_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& queue); // Remove a timer queue from the reactor. template - void remove_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template - void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - interrupter_.interrupt(); - } - } + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue& queue, void* token); // Run select once until interrupted or events are ready to be dispatched. - void run(bool block, op_queue& ops) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Check if the thread is supposed to stop. - if (Own_Thread) - if (stop_thread_) - return; - - // Set up the descriptor sets. - fd_set_adapter fds[max_select_ops]; - fds[read_op].set(interrupter_.read_descriptor()); - socket_type max_fd = 0; - bool have_work_to_do = !timer_queues_.all_empty(); - for (int i = 0; i < max_select_ops; ++i) - { - have_work_to_do = have_work_to_do || !op_queue_[i].empty(); - op_queue_[i].get_descriptors(fds[i], ops); - if (fds[i].max_descriptor() > max_fd) - max_fd = fds[i].max_descriptor(); - } - -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Connection operations on Windows use both except and write fd_sets. - have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); - op_queue_[connect_op].get_descriptors(fds[write_op], ops); - if (fds[write_op].max_descriptor() > max_fd) - max_fd = fds[write_op].max_descriptor(); - op_queue_[connect_op].get_descriptors(fds[except_op], ops); - if (fds[except_op].max_descriptor() > max_fd) - max_fd = fds[except_op].max_descriptor(); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - - // We can return immediately if there's no work to do and the reactor is - // not supposed to block. - if (!block && !have_work_to_do) - return; - - // Determine how long to block while waiting for events. - timeval tv_buf = { 0, 0 }; - timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; - - lock.unlock(); - - // Block on the select call until descriptors become ready. - boost::system::error_code ec; - int retval = socket_ops::select(static_cast(max_fd + 1), - fds[read_op], fds[write_op], fds[except_op], tv, ec); - - // Reset the interrupter. - if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor())) - interrupter_.reset(); - - lock.lock(); - - // Dispatch all ready operations. - if (retval > 0) - { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Connection operations on Windows use both except and write fd_sets. - op_queue_[connect_op].perform_operations_for_descriptors( - fds[except_op], ops); - op_queue_[connect_op].perform_operations_for_descriptors( - fds[write_op], ops); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - for (int i = max_select_ops - 1; i >= 0; --i) - op_queue_[i].perform_operations_for_descriptors(fds[i], ops); - } - timer_queues_.get_ready_timers(ops); - } + BOOST_ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the select loop. - void interrupt() - { - interrupter_.interrupt(); - } + BOOST_ASIO_DECL void interrupt(); private: +#if defined(BOOST_ASIO_HAS_IOCP) // Run the select loop in the thread. - void run_thread() - { - if (Own_Thread) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) - { - lock.unlock(); - op_queue ops; - run(true, ops); - io_service_.post_deferred_completions(ops); - lock.lock(); - } - } - } + BOOST_ASIO_DECL void run_thread(); // Entry point for the select loop thread. - static void call_run_thread(select_reactor* reactor) - { - if (Own_Thread) - { - reactor->run_thread(); - } - } + BOOST_ASIO_DECL static void call_run_thread(select_reactor* reactor); +#endif // defined(BOOST_ASIO_HAS_IOCP) + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the select call. - timeval* get_timeout(timeval& tv) - { - // By default we will wait no longer than 5 minutes. This will ensure that - // any changes to the system clock are detected after no longer than this. - long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); - tv.tv_sec = usec / 1000000; - tv.tv_usec = usec % 1000000; - return &tv; - } + BOOST_ASIO_DECL timeval* get_timeout(timeval& tv); // Cancel all operations associated with the given descriptor. This function // does not acquire the select_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor, - const boost::system::error_code& ec) - { - bool need_interrupt = false; - op_queue ops; - for (int i = 0; i < max_ops; ++i) - need_interrupt = op_queue_[i].cancel_operations( - descriptor, ops, ec) || need_interrupt; - io_service_.post_deferred_completions(ops); - if (need_interrupt) - interrupter_.interrupt(); - } + BOOST_ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -357,11 +163,13 @@ private: // The timer queues. timer_queue_set timer_queues_; +#if defined(BOOST_ASIO_HAS_IOCP) // Does the reactor loop thread need to stop. bool stop_thread_; // The thread that is running the reactor loop. boost::asio::detail::thread* thread_; +#endif // defined(BOOST_ASIO_HAS_IOCP) // Whether the service has been shut down. bool shutdown_; @@ -373,4 +181,14 @@ private: #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || (!defined(BOOST_ASIO_HAS_DEV_POLL) + // && !defined(BOOST_ASIO_HAS_EPOLL) + // && !defined(BOOST_ASIO_HAS_KQUEUE)) + #endif // BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP diff --git a/include/boost/asio/detail/select_reactor_fwd.hpp b/include/boost/asio/detail/select_reactor_fwd.hpp index b48e0f01..f4f9f65a 100644 --- a/include/boost/asio/detail/select_reactor_fwd.hpp +++ b/include/boost/asio/detail/select_reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// select_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/select_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { namespace detail { -template class select_reactor; } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_SELECT_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/service_base.hpp b/include/boost/asio/detail/service_base.hpp deleted file mode 100644 index 66c2af38..00000000 --- a/include/boost/asio/detail/service_base.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// -// service_base.hpp -// ~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_ASIO_DETAIL_SERVICE_BASE_HPP -#define BOOST_ASIO_DETAIL_SERVICE_BASE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -// Special service base class to keep classes header-file only. -template -class service_base - : public boost::asio::io_service::service -{ -public: - static boost::asio::detail::service_id id; - - // Constructor. - service_base(boost::asio::io_service& io_service) - : boost::asio::io_service::service(io_service) - { - } -}; - -template -boost::asio::detail::service_id service_base::id; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_SERVICE_BASE_HPP diff --git a/include/boost/asio/detail/service_registry.hpp b/include/boost/asio/detail/service_registry.hpp index e640ec86..9fd0c5af 100644 --- a/include/boost/asio/detail/service_registry.hpp +++ b/include/boost/asio/detail/service_registry.hpp @@ -1,6 +1,6 @@ // -// service_registry.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include - -#include #include #include -#include +#include #if defined(BOOST_NO_TYPEID) # if !defined(BOOST_ASIO_NO_TYPEID) @@ -32,6 +27,8 @@ # endif // !defined(BOOST_ASIO_NO_TYPEID) #endif // defined(BOOST_NO_TYPEID) +#include + namespace boost { namespace asio { namespace detail { @@ -56,98 +53,42 @@ class service_registry { public: // Constructor. - service_registry(boost::asio::io_service& o) - : owner_(o), - first_service_(0) - { - } + BOOST_ASIO_DECL service_registry(boost::asio::io_service& o); // Destructor. - ~service_registry() - { - // Shutdown all services. This must be done in a separate loop before the - // services are destroyed since the destructors of user-defined handler - // objects may try to access other service objects. - boost::asio::io_service::service* service = first_service_; - while (service) - { - service->shutdown_service(); - service = service->next_; - } - - // Destroy all services. - while (first_service_) - { - boost::asio::io_service::service* next_service = first_service_->next_; - destroy(first_service_); - first_service_ = next_service; - } - } + BOOST_ASIO_DECL ~service_registry(); // Get the service object corresponding to the specified service type. Will // create a new service object automatically if no such object already // exists. Ownership of the service object is not transferred to the caller. template - Service& use_service() - { - boost::asio::io_service::service::key key; - init_key(key, Service::id); - factory_type factory = &service_registry::create; - return *static_cast(do_use_service(key, factory)); - } + Service& use_service(); - // Add a service object. Returns false on error, in which case ownership of - // the object is retained by the caller. + // Add a service object. Throws on error, in which case ownership of the + // object is retained by the caller. template - bool add_service(Service* new_service) - { - boost::asio::io_service::service::key key; - init_key(key, Service::id); - return do_add_service(key, new_service); - } + void add_service(Service* new_service); // Check whether a service object of the specified type already exists. template - bool has_service() const - { - boost::asio::io_service::service::key key; - init_key(key, Service::id); - return do_has_service(key); - } + bool has_service() const; private: // Initialise a service's key based on its id. - void init_key(boost::asio::io_service::service::key& key, - const boost::asio::io_service::id& id) - { - key.type_info_ = 0; - key.id_ = &id; - } + BOOST_ASIO_DECL void init_key(boost::asio::io_service::service::key& key, + const boost::asio::io_service::id& id); #if !defined(BOOST_ASIO_NO_TYPEID) // Initialise a service's key based on its id. template void init_key(boost::asio::io_service::service::key& key, - const boost::asio::detail::service_id& /*id*/) - { - key.type_info_ = &typeid(typeid_wrapper); - key.id_ = 0; - } + const boost::asio::detail::service_id& /*id*/); #endif // !defined(BOOST_ASIO_NO_TYPEID) // Check if a service matches the given id. - static bool keys_match( + BOOST_ASIO_DECL static bool keys_match( const boost::asio::io_service::service::key& key1, - const boost::asio::io_service::service::key& key2) - { - if (key1.id_ && key2.id_) - if (key1.id_ == key2.id_) - return true; - if (key1.type_info_ && key2.type_info_) - if (*key1.type_info_ == *key2.type_info_) - return true; - return false; - } + const boost::asio::io_service::service::key& key2); // The type of a factory function used for creating a service instance. typedef boost::asio::io_service::service* @@ -156,18 +97,15 @@ private: // Factory function for creating a service instance. template static boost::asio::io_service::service* create( - boost::asio::io_service& owner) - { - return new Service(owner); - } + boost::asio::io_service& owner); // Destroy a service instance. - static void destroy(boost::asio::io_service::service* service) - { - delete service; - } + BOOST_ASIO_DECL static void destroy( + boost::asio::io_service::service* service); // Helper class to manage service pointers. + struct auto_service_ptr; + friend struct auto_service_ptr; struct auto_service_ptr { boost::asio::io_service::service* ptr_; @@ -177,86 +115,19 @@ private: // Get the service object corresponding to the specified service key. Will // create a new service object automatically if no such object already // exists. Ownership of the service object is not transferred to the caller. - boost::asio::io_service::service* do_use_service( + BOOST_ASIO_DECL boost::asio::io_service::service* do_use_service( const boost::asio::io_service::service::key& key, - factory_type factory) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // First see if there is an existing service object with the given key. - boost::asio::io_service::service* service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return service; - service = service->next_; - } - - // Create a new service object. The service registry's mutex is not locked - // at this time to allow for nested calls into this function from the new - // service's constructor. - lock.unlock(); - auto_service_ptr new_service = { factory(owner_) }; - new_service.ptr_->key_ = key; - lock.lock(); - - // Check that nobody else created another service object of the same type - // while the lock was released. - service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return service; - service = service->next_; - } - - // Service was successfully initialised, pass ownership to registry. - new_service.ptr_->next_ = first_service_; - first_service_ = new_service.ptr_; - new_service.ptr_ = 0; - return first_service_; - } + factory_type factory); // Add a service object. Returns false on error, in which case ownership of // the object is retained by the caller. - bool do_add_service( + BOOST_ASIO_DECL void do_add_service( const boost::asio::io_service::service::key& key, - boost::asio::io_service::service* new_service) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Check if there is an existing service object with the given key. - boost::asio::io_service::service* service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return false; - service = service->next_; - } - - // Take ownership of the service object. - new_service->key_ = key; - new_service->next_ = first_service_; - first_service_ = new_service; - - return true; - } + boost::asio::io_service::service* new_service); // Check whether a service object with the specified key already exists. - bool do_has_service(const boost::asio::io_service::service::key& key) const - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - boost::asio::io_service::service* service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return true; - service = service->next_; - } - - return false; - } + BOOST_ASIO_DECL bool do_has_service( + const boost::asio::io_service::service::key& key) const; // Mutex to protect access to internal data. mutable boost::asio::detail::mutex mutex_; @@ -274,4 +145,9 @@ private: #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP diff --git a/include/boost/asio/detail/service_registry_fwd.hpp b/include/boost/asio/detail/service_registry_fwd.hpp index 4031b1a1..8713a30b 100644 --- a/include/boost/asio/detail/service_registry_fwd.hpp +++ b/include/boost/asio/detail/service_registry_fwd.hpp @@ -1,6 +1,6 @@ // -// service_registry_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/service_registry_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { namespace detail { @@ -27,6 +25,4 @@ class service_registry; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP diff --git a/include/boost/asio/detail/service_id.hpp b/include/boost/asio/detail/shared_ptr.hpp similarity index 51% rename from include/boost/asio/detail/service_id.hpp rename to include/boost/asio/detail/shared_ptr.hpp index ac0f4d13..0c5586e2 100644 --- a/include/boost/asio/detail/service_id.hpp +++ b/include/boost/asio/detail/shared_ptr.hpp @@ -1,6 +1,6 @@ // -// service_id.hpp -// ~~~~~~~~~~~~~~ +// detail/shared_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,32 +8,33 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_SERVICE_ID_HPP -#define BOOST_ASIO_DETAIL_SERVICE_ID_HPP +#ifndef BOOST_ASIO_DETAIL_SHARED_PTR_HPP +#define BOOST_ASIO_DETAIL_SHARED_PTR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# include +#else +# include +#endif namespace boost { namespace asio { namespace detail { -// Special derived service id type to keep classes header-file only. -template -class service_id - : public boost::asio::io_service::id -{ -}; +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +using std::shared_ptr; +#else +using boost::shared_ptr; +#endif } // namespace detail } // namespace asio } // namespace boost -#include - -#endif // BOOST_ASIO_DETAIL_SERVICE_ID_HPP +#endif // BOOST_ASIO_DETAIL_SHARED_PTR_HPP diff --git a/include/boost/asio/detail/signal_blocker.hpp b/include/boost/asio/detail/signal_blocker.hpp index 0197e04d..67eaac0a 100644 --- a/include/boost/asio/detail/signal_blocker.hpp +++ b/include/boost/asio/detail/signal_blocker.hpp @@ -1,6 +1,6 @@ // -// signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include - -#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) \ + || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) # include -#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# include #elif defined(BOOST_HAS_PTHREADS) # include #else @@ -35,10 +30,9 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) \ + || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) typedef null_signal_blocker signal_blocker; -#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) -typedef win_signal_blocker signal_blocker; #elif defined(BOOST_HAS_PTHREADS) typedef posix_signal_blocker signal_blocker; #endif @@ -47,6 +41,4 @@ typedef posix_signal_blocker signal_blocker; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP diff --git a/include/boost/asio/detail/signal_init.hpp b/include/boost/asio/detail/signal_init.hpp index 50e06b85..76d21bff 100644 --- a/include/boost/asio/detail/signal_init.hpp +++ b/include/boost/asio/detail/signal_init.hpp @@ -1,6 +1,6 @@ // -// signal_init.hpp -// ~~~~~~~~~~~~~~~ +// detail/signal_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#include #include -#include + +#include namespace boost { namespace asio { @@ -46,8 +42,8 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP diff --git a/include/boost/asio/detail/socket_holder.hpp b/include/boost/asio/detail/socket_holder.hpp index 5d6012b0..7815accc 100644 --- a/include/boost/asio/detail/socket_holder.hpp +++ b/include/boost/asio/detail/socket_holder.hpp @@ -1,6 +1,6 @@ // -// socket_holder.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/socket_holder.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -47,7 +48,8 @@ public: if (socket_ != invalid_socket) { boost::system::error_code ec; - socket_ops::close(socket_, ec); + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); } } @@ -63,7 +65,8 @@ public: if (socket_ != invalid_socket) { boost::system::error_code ec; - socket_ops::close(socket_, ec); + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); socket_ = invalid_socket; } } diff --git a/include/boost/asio/detail/socket_ops.hpp b/include/boost/asio/detail/socket_ops.hpp index 475162a3..bbdba385 100644 --- a/include/boost/asio/detail/socket_ops.hpp +++ b/include/boost/asio/detail/socket_ops.hpp @@ -1,6 +1,6 @@ // -// socket_ops.hpp -// ~~~~~~~~~~~~~~ +// detail/socket_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,194 +15,103 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include #include +#include + +#include namespace boost { namespace asio { namespace detail { namespace socket_ops { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -struct msghdr { int msg_namelen; }; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - -#if defined(__hpux) -// HP-UX doesn't declare these functions extern "C", so they are declared again -// here to avoid linker errors about undefined symbols. -extern "C" char* if_indextoname(unsigned int, char*); -extern "C" unsigned int if_nametoindex(const char*); -#endif // defined(__hpux) - -inline void clear_error(boost::system::error_code& ec) +// Socket state bits. +enum { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - WSASetLastError(0); -#else - errno = 0; -#endif - ec = boost::system::error_code(); -} + // The user wants a non-blocking socket. + user_set_non_blocking = 1, -template -inline ReturnType error_wrapper(ReturnType return_value, - boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - ec = boost::system::error_code(WSAGetLastError(), - boost::asio::error::get_system_category()); -#else - ec = boost::system::error_code(errno, - boost::asio::error::get_system_category()); -#endif - return return_value; -} + // The socket has been set non-blocking. + internal_non_blocking = 2, -template -inline socket_type call_accept(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) -{ - SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; - socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); - if (addrlen) - *addrlen = (std::size_t)tmp_addrlen; - return result; -} + // Helper "state" used to determine whether the socket is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, -inline socket_type accept(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, boost::system::error_code& ec) -{ - clear_error(ec); + // User wants connection_aborted errors, which are disabled by default. + enable_connection_aborted = 4, - socket_type new_s = error_wrapper(call_accept( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (new_s == invalid_socket) - return new_s; + // The user set the linger option. Needs to be checked when closing. + user_set_linger = 8, -#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - int optval = 1; - int result = error_wrapper(::setsockopt(new_s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); - if (result != 0) - { - ::close(new_s); - return invalid_socket; - } -#endif + // The socket is stream-oriented. + stream_oriented = 16, - clear_error(ec); - return new_s; -} + // The socket is datagram-oriented. + datagram_oriented = 32 +}; -template -inline int call_bind(SockLenType msghdr::*, - socket_type s, const socket_addr_type* addr, std::size_t addrlen) -{ - return ::bind(s, addr, (SockLenType)addrlen); -} +typedef unsigned char state_type; -inline int bind(socket_type s, const socket_addr_type* addr, - std::size_t addrlen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_bind( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} +struct noop_deleter { void operator()(void*) {} }; +typedef shared_ptr shared_cancel_token_type; +typedef weak_ptr weak_cancel_token_type; -inline int close(socket_type s, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::closesocket(s), ec); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::close(s), ec); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); -inline int shutdown(socket_type s, int what, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::shutdown(s, what), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL socket_type sync_accept(socket_type s, + state_type state, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); -template -inline int call_connect(SockLenType msghdr::*, - socket_type s, const socket_addr_type* addr, std::size_t addrlen) -{ - return ::connect(s, addr, (SockLenType)addrlen); -} +#if defined(BOOST_ASIO_HAS_IOCP) -inline int connect(socket_type s, const socket_addr_type* addr, - std::size_t addrlen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_connect( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, boost::system::error_code& ec); -inline int socketpair(int af, int type, int protocol, - socket_type sv[2], boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - (void)(af); - (void)(type); - (void)(protocol); - (void)(sv); - ec = boost::asio::error::operation_not_supported; - return -1; -#else - clear_error(ec); - int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); - if (result == 0) - clear_error(ec); - return result; -#endif -} +#else // defined(BOOST_ASIO_HAS_IOCP) -inline int listen(socket_type s, int backlog, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::listen(s, backlog), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, socket_type& new_socket); -inline void init_buf_iov_base(void*& base, void* addr) -{ - base = addr; -} +#endif // defined(BOOST_ASIO_HAS_IOCP) -template -inline void init_buf_iov_base(T& base, void* addr) -{ - base = static_cast(addr); -} +BOOST_ASIO_DECL int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL int close(socket_type s, state_type& state, + bool destruction, boost::system::error_code& ec); + +BOOST_ASIO_DECL bool set_internal_non_blocking(socket_type s, + state_type& state, boost::system::error_code& ec); + +BOOST_ASIO_DECL int shutdown(socket_type s, + int what, boost::system::error_code& ec); + +BOOST_ASIO_DECL int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL bool non_blocking_connect( + socket_type s, boost::system::error_code& ec); + +BOOST_ASIO_DECL int socketpair(int af, int type, int protocol, + socket_type sv[2], boost::system::error_code& ec); + +BOOST_ASIO_DECL bool sockatmark(socket_type s, boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t available(socket_type s, boost::system::error_code& ec); + +BOOST_ASIO_DECL int listen(socket_type s, + int backlog, boost::system::error_code& ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef WSABUF buf; @@ -210,1699 +119,163 @@ typedef WSABUF buf; typedef iovec buf; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -inline void init_buf(buf& b, void* data, size_t size) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - b.buf = static_cast(data); - b.len = static_cast(size); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - init_buf_iov_base(b.iov_base, data); - b.iov_len = size; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL void init_buf(buf& b, void* data, size_t size); -inline void init_buf(buf& b, const void* data, size_t size) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - b.buf = static_cast(const_cast(data)); - b.len = static_cast(size); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - init_buf_iov_base(b.iov_base, const_cast(data)); - b.iov_len = size; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL void init_buf(buf& b, const void* data, size_t size); -inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) -{ - name = addr; -} +BOOST_ASIO_DECL int recv(socket_type s, buf* bufs, size_t count, int flags, + boost::system::error_code& ec); -inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) -{ - name = const_cast(addr); -} +BOOST_ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, boost::system::error_code& ec); -template -inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) -{ - name = reinterpret_cast(addr); -} +#if defined(BOOST_ASIO_HAS_IOCP) -template -inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) -{ - name = reinterpret_cast(const_cast(addr)); -} +BOOST_ASIO_DECL void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + boost::system::error_code& ec, size_t bytes_transferred); -inline int recv(socket_type s, buf* bufs, size_t count, int flags, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Receive some data. - DWORD recv_buf_count = static_cast(count); - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = error_wrapper(::WSARecv(s, bufs, - recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - msg.msg_iov = bufs; - msg.msg_iovlen = count; - int result = error_wrapper(::recvmsg(s, &msg, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +#else // defined(BOOST_ASIO_HAS_IOCP) -inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, +BOOST_ASIO_DECL bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL int recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Receive some data. - DWORD recv_buf_count = static_cast(count); - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int tmp_addrlen = (int)*addrlen; - int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, - &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); - *addrlen = (std::size_t)tmp_addrlen; - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - init_msghdr_msg_name(msg.msg_name, addr); - msg.msg_namelen = *addrlen; - msg.msg_iov = bufs; - msg.msg_iovlen = count; - int result = error_wrapper(::recvmsg(s, &msg, flags), ec); - *addrlen = msg.msg_namelen; - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} + boost::system::error_code& ec); -inline int send(socket_type s, const buf* bufs, size_t count, int flags, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Send the data. - DWORD send_buf_count = static_cast(count); - DWORD bytes_transferred = 0; - DWORD send_flags = flags; - int result = error_wrapper(::WSASend(s, const_cast(bufs), - send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - msg.msg_iov = const_cast(bufs); - msg.msg_iovlen = count; -#if defined(__linux__) - flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - int result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state, + buf* bufs, size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); -inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec); + +#else // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL int send(socket_type s, const buf* bufs, + size_t count, int flags, boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t sync_send(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, + bool all_empty, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec); + +#else // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL int sendto(socket_type s, const buf* bufs, size_t count, + int flags, const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t sync_sendto(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +#if !defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Send the data. - DWORD send_buf_count = static_cast(count); - DWORD bytes_transferred = 0; - int result = error_wrapper(::WSASendTo(s, const_cast(bufs), - send_buf_count, &bytes_transferred, flags, addr, - static_cast(addrlen), 0, 0), ec); - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - init_msghdr_msg_name(msg.msg_name, addr); - msg.msg_namelen = addrlen; - msg.msg_iov = const_cast(bufs); - msg.msg_iovlen = count; -#if defined(__linux__) - flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - int result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} + boost::system::error_code& ec, size_t& bytes_transferred); -inline socket_type socket(int af, int type, int protocol, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, - WSA_FLAG_OVERLAPPED), ec); - if (s == invalid_socket) - return s; +#endif // !defined(BOOST_ASIO_HAS_IOCP) - if (af == AF_INET6) - { - // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to - // false. This will only succeed on Windows Vista and later versions of - // Windows, where a dual-stack IPv4/v6 implementation is available. - DWORD optval = 0; - ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, - reinterpret_cast(&optval), sizeof(optval)); - } +BOOST_ASIO_DECL socket_type socket(int af, int type, int protocol, + boost::system::error_code& ec); - clear_error(ec); +BOOST_ASIO_DECL int setsockopt(socket_type s, state_type& state, + int level, int optname, const void* optval, + std::size_t optlen, boost::system::error_code& ec); - return s; -#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - socket_type s = error_wrapper(::socket(af, type, protocol), ec); - if (s == invalid_socket) - return s; +BOOST_ASIO_DECL int getsockopt(socket_type s, state_type state, + int level, int optname, void* optval, + size_t* optlen, boost::system::error_code& ec); - int optval = 1; - int result = error_wrapper(::setsockopt(s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); - if (result != 0) - { - ::close(s); - return invalid_socket; - } +BOOST_ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, boost::system::error_code& ec); - return s; -#else - int s = error_wrapper(::socket(af, type, protocol), ec); - if (s >= 0) - clear_error(ec); - return s; -#endif -} +BOOST_ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); -template -inline int call_setsockopt(SockLenType msghdr::*, - socket_type s, int level, int optname, - const void* optval, std::size_t optlen) -{ - return ::setsockopt(s, level, optname, - (const char*)optval, (SockLenType)optlen); -} +BOOST_ASIO_DECL int ioctl(socket_type s, state_type& state, + long cmd, ioctl_arg_type* arg, boost::system::error_code& ec); -inline int setsockopt(socket_type s, int level, int optname, - const void* optval, std::size_t optlen, boost::system::error_code& ec) -{ - if (level == custom_socket_option_level && optname == always_fail_option) - { - ec = boost::asio::error::invalid_argument; - return -1; - } +BOOST_ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec); -#if defined(__BORLANDC__) - // Mysteriously, using the getsockopt and setsockopt functions directly with - // Borland C++ results in incorrect values being set and read. The bug can be - // worked around by using function addresses resolved with GetProcAddress. - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); - if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) - { - clear_error(ec); - return error_wrapper(sso(s, level, optname, - reinterpret_cast(optval), - static_cast(optlen)), ec); - } - } - ec = boost::asio::error::fault; - return -1; -#else // defined(__BORLANDC__) - clear_error(ec); - int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); - if (result == 0) - clear_error(ec); - return result; -#endif // defined(__BORLANDC__) -} +BOOST_ASIO_DECL int poll_read(socket_type s, boost::system::error_code& ec); -template -inline int call_getsockopt(SockLenType msghdr::*, - socket_type s, int level, int optname, - void* optval, std::size_t* optlen) -{ - SockLenType tmp_optlen = (SockLenType)*optlen; - int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); - *optlen = (std::size_t)tmp_optlen; - return result; -} +BOOST_ASIO_DECL int poll_write(socket_type s, boost::system::error_code& ec); -inline int getsockopt(socket_type s, int level, int optname, void* optval, - size_t* optlen, boost::system::error_code& ec) -{ - if (level == custom_socket_option_level && optname == always_fail_option) - { - ec = boost::asio::error::invalid_argument; - return -1; - } +BOOST_ASIO_DECL int poll_connect(socket_type s, boost::system::error_code& ec); -#if defined(__BORLANDC__) - // Mysteriously, using the getsockopt and setsockopt functions directly with - // Borland C++ results in incorrect values being set and read. The bug can be - // worked around by using function addresses resolved with GetProcAddress. - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); - if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) - { - clear_error(ec); - int tmp_optlen = static_cast(*optlen); - int result = error_wrapper(gso(s, level, optname, - reinterpret_cast(optval), &tmp_optlen), ec); - *optlen = static_cast(tmp_optlen); - if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY - && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) - { - // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are - // only supported on Windows Vista and later. To simplify program logic - // we will fake success of getting this option and specify that the - // value is non-zero (i.e. true). This corresponds to the behavior of - // IPv6 sockets on Windows platforms pre-Vista. - *static_cast(optval) = 1; - clear_error(ec); - } - return result; - } - } - ec = boost::asio::error::fault; - return -1; -#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) - clear_error(ec); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); - if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY - && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) - { - // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only - // supported on Windows Vista and later. To simplify program logic we will - // fake success of getting this option and specify that the value is - // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets - // on Windows platforms pre-Vista. - *static_cast(optval) = 1; - clear_error(ec); - } - if (result == 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - clear_error(ec); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); -#if defined(__linux__) - if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) - && (optname == SO_SNDBUF || optname == SO_RCVBUF)) - { - // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel - // to set the buffer size to N*2. Linux puts additional stuff into the - // buffers so that only about half is actually available to the application. - // The retrieved value is divided by 2 here to make it appear as though the - // correct value has been set. - *static_cast(optval) /= 2; - } -#endif // defined(__linux__) - if (result == 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest, + size_t length, unsigned long scope_id, boost::system::error_code& ec); -template -inline int call_getpeername(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) -{ - SockLenType tmp_addrlen = (SockLenType)*addrlen; - int result = ::getpeername(s, addr, &tmp_addrlen); - *addrlen = (std::size_t)tmp_addrlen; - return result; -} +BOOST_ASIO_DECL int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, boost::system::error_code& ec); -inline int getpeername(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_getpeername( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int gethostname(char* name, + int namelen, boost::system::error_code& ec); -template -inline int call_getsockname(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) -{ - SockLenType tmp_addrlen = (SockLenType)*addrlen; - int result = ::getsockname(s, addr, &tmp_addrlen); - *addrlen = (std::size_t)tmp_addrlen; - return result; -} +BOOST_ASIO_DECL boost::system::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec); -inline int getsockname(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_getsockname( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL boost::system::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec); -inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctl(s, cmd, arg), ec); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL void freeaddrinfo(addrinfo_type* ai); -inline int select(int nfds, fd_set* readfds, fd_set* writefds, - fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - if (!readfds && !writefds && !exceptfds && timeout) - { - DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; - if (milliseconds == 0) - milliseconds = 1; // Force context switch. - ::Sleep(milliseconds); - ec = boost::system::error_code(); - return 0; - } +BOOST_ASIO_DECL boost::system::error_code getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int flags, boost::system::error_code& ec); - // The select() call allows timeout values measured in microseconds, but the - // system clock (as wrapped by boost::posix_time::microsec_clock) typically - // has a resolution of 10 milliseconds. This can lead to a spinning select - // reactor, meaning increased CPU usage, when waiting for the earliest - // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight - // spin we'll use a minimum timeout of 1 millisecond. - if (timeout && timeout->tv_sec == 0 - && timeout->tv_usec > 0 && timeout->tv_usec < 1000) - timeout->tv_usec = 1000; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +BOOST_ASIO_DECL boost::system::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec); -#if defined(__hpux) && defined(__HP_aCC) - timespec ts; - ts.tv_sec = timeout ? timeout->tv_sec : 0; - ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; - return error_wrapper(::pselect(nfds, readfds, - writefds, exceptfds, timeout ? &ts : 0, 0), ec); -#else - int result = error_wrapper(::select(nfds, readfds, - writefds, exceptfds, timeout), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif -} +BOOST_ASIO_DECL boost::system::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec); -inline int poll_read(socket_type s, boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - FD_SET fds; - FD_ZERO(&fds); - FD_SET(s, &fds); - clear_error(ec); - int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); - if (result >= 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - pollfd fds; - fds.fd = s; - fds.events = POLLIN; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL u_long_type network_to_host_long(u_long_type value); -inline int poll_write(socket_type s, boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - FD_SET fds; - FD_ZERO(&fds); - FD_SET(s, &fds); - clear_error(ec); - int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); - if (result >= 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - pollfd fds; - fds.fd = s; - fds.events = POLLOUT; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL u_long_type host_to_network_long(u_long_type value); -inline int poll_connect(socket_type s, boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - FD_SET write_fds; - FD_ZERO(&write_fds); - FD_SET(s, &write_fds); - FD_SET except_fds; - FD_ZERO(&except_fds); - FD_SET(s, &except_fds); - clear_error(ec); - int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec); - if (result >= 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - pollfd fds; - fds.fd = s; - fds.events = POLLOUT; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL u_short_type network_to_host_short(u_short_type value); -inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, - unsigned long scope_id, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - using namespace std; // For memcpy. - - if (af != AF_INET && af != AF_INET6) - { - ec = boost::asio::error::address_family_not_supported; - return 0; - } - - union - { - socket_addr_type base; - sockaddr_storage_type storage; - sockaddr_in4_type v4; - sockaddr_in6_type v6; - } address; - DWORD address_length; - if (af == AF_INET) - { - address_length = sizeof(sockaddr_in4_type); - address.v4.sin_family = AF_INET; - address.v4.sin_port = 0; - memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); - } - else // AF_INET6 - { - address_length = sizeof(sockaddr_in6_type); - address.v6.sin6_family = AF_INET6; - address.v6.sin6_port = 0; - address.v6.sin6_flowinfo = 0; - address.v6.sin6_scope_id = scope_id; - memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); - } - - DWORD string_length = static_cast(length); -#if defined(BOOST_NO_ANSI_APIS) - LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); - int result = error_wrapper(::WSAAddressToStringW(&address.base, - address_length, 0, string_buffer, &string_length), ec); - ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); -#else - int result = error_wrapper(::WSAAddressToStringA( - &address.base, address_length, 0, dest, &string_length), ec); -#endif - - // Windows may set error code on success. - if (result != socket_error_retval) - clear_error(ec); - - // Windows may not set an error code on failure. - else if (result == socket_error_retval && !ec) - ec = boost::asio::error::invalid_argument; - - return result == socket_error_retval ? 0 : dest; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); - if (result == 0 && !ec) - ec = boost::asio::error::invalid_argument; - if (result != 0 && af == AF_INET6 && scope_id != 0) - { - using namespace std; // For strcat and sprintf. - char if_name[IF_NAMESIZE + 1] = "%"; - const in6_addr_type* ipv6_address = static_cast(src); - bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); - if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) - sprintf(if_name + 1, "%lu", scope_id); - strcat(dest, if_name); - } - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} - -inline int inet_pton(int af, const char* src, void* dest, - unsigned long* scope_id, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - using namespace std; // For memcpy and strcmp. - - if (af != AF_INET && af != AF_INET6) - { - ec = boost::asio::error::address_family_not_supported; - return -1; - } - - union - { - socket_addr_type base; - sockaddr_storage_type storage; - sockaddr_in4_type v4; - sockaddr_in6_type v6; - } address; - int address_length = sizeof(sockaddr_storage_type); -#if defined(BOOST_NO_ANSI_APIS) - int num_wide_chars = strlen(src) + 1; - LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); - ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); - int result = error_wrapper(::WSAStringToAddressW( - wide_buffer, af, 0, &address.base, &address_length), ec); -#else - int result = error_wrapper(::WSAStringToAddressA( - const_cast(src), af, 0, &address.base, &address_length), ec); -#endif - - if (af == AF_INET) - { - if (result != socket_error_retval) - { - memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); - clear_error(ec); - } - else if (strcmp(src, "255.255.255.255") == 0) - { - static_cast(dest)->s_addr = INADDR_NONE; - clear_error(ec); - } - } - else // AF_INET6 - { - if (result != socket_error_retval) - { - memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); - if (scope_id) - *scope_id = address.v6.sin6_scope_id; - clear_error(ec); - } - } - - // Windows may not set an error code on failure. - if (result == socket_error_retval && !ec) - ec = boost::asio::error::invalid_argument; - - if (result != socket_error_retval) - clear_error(ec); - - return result == socket_error_retval ? -1 : 1; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::inet_pton(af, src, dest), ec); - if (result <= 0 && !ec) - ec = boost::asio::error::invalid_argument; - if (result > 0 && af == AF_INET6 && scope_id) - { - using namespace std; // For strchr and atoi. - *scope_id = 0; - if (const char* if_name = strchr(src, '%')) - { - in6_addr_type* ipv6_address = static_cast(dest); - bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); - if (is_link_local) - *scope_id = if_nametoindex(if_name + 1); - if (*scope_id == 0) - *scope_id = atoi(if_name + 1); - } - } - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} - -inline int gethostname(char* name, int namelen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::gethostname(name, namelen), ec); -#if defined(BOOST_WINDOWS) - if (result == 0) - clear_error(ec); -#endif - return result; -} - -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ - || defined(__MACH__) && defined(__APPLE__) - -// The following functions are only needed for emulation of getaddrinfo and -// getnameinfo. - -inline boost::system::error_code translate_netdb_error(int error) -{ - switch (error) - { - case 0: - return boost::system::error_code(); - case HOST_NOT_FOUND: - return boost::asio::error::host_not_found; - case TRY_AGAIN: - return boost::asio::error::host_not_found_try_again; - case NO_RECOVERY: - return boost::asio::error::no_recovery; - case NO_DATA: - return boost::asio::error::no_data; - default: - BOOST_ASSERT(false); - return boost::asio::error::invalid_argument; - } -} - -inline hostent* gethostbyaddr(const char* addr, int length, int af, - hostent* result, char* buffer, int buflength, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - (void)(buffer); - (void)(buflength); - hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); - if (!retval) - return 0; - clear_error(ec); - *result = *retval; - return retval; -#elif defined(__sun) || defined(__QNX__) - int error = 0; - hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, - buffer, buflength, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#elif defined(__MACH__) && defined(__APPLE__) - (void)(buffer); - (void)(buflength); - int error = 0; - hostent* retval = error_wrapper(::getipnodebyaddr( - addr, length, af, &error), ec); - if (error) - ec = translate_netdb_error(error); - if (!retval) - return 0; - *result = *retval; - return retval; -#else - hostent* retval = 0; - int error = 0; - error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, - buflength, &retval, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#endif -} - -inline hostent* gethostbyname(const char* name, int af, struct hostent* result, - char* buffer, int buflength, int ai_flags, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - (void)(buffer); - (void)(buflength); - (void)(ai_flags); - if (af != AF_INET) - { - ec = boost::asio::error::address_family_not_supported; - return 0; - } - hostent* retval = error_wrapper(::gethostbyname(name), ec); - if (!retval) - return 0; - clear_error(ec); - *result = *retval; - return result; -#elif defined(__sun) || defined(__QNX__) - (void)(ai_flags); - if (af != AF_INET) - { - ec = boost::asio::error::address_family_not_supported; - return 0; - } - int error = 0; - hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, - buflength, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#elif defined(__MACH__) && defined(__APPLE__) - (void)(buffer); - (void)(buflength); - int error = 0; - hostent* retval = error_wrapper(::getipnodebyname( - name, af, ai_flags, &error), ec); - if (error) - ec = translate_netdb_error(error); - if (!retval) - return 0; - *result = *retval; - return retval; -#else - (void)(ai_flags); - if (af != AF_INET) - { - ec = boost::asio::error::address_family_not_supported; - return 0; - } - hostent* retval = 0; - int error = 0; - error_wrapper(::gethostbyname_r(name, result, - buffer, buflength, &retval, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#endif -} - -inline void freehostent(hostent* h) -{ -#if defined(__MACH__) && defined(__APPLE__) - if (h) - ::freehostent(h); -#else - (void)(h); -#endif -} - -// Emulation of getaddrinfo based on implementation in: -// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. - -struct gai_search -{ - const char* host; - int family; -}; - -inline int gai_nsearch(const char* host, - const addrinfo_type* hints, gai_search (&search)[2]) -{ - int search_count = 0; - if (host == 0 || host[0] == '\0') - { - if (hints->ai_flags & AI_PASSIVE) - { - // No host and AI_PASSIVE implies wildcard bind. - switch (hints->ai_family) - { - case AF_INET: - search[search_count].host = "0.0.0.0"; - search[search_count].family = AF_INET; - ++search_count; - break; - case AF_INET6: - search[search_count].host = "0::0"; - search[search_count].family = AF_INET6; - ++search_count; - break; - case AF_UNSPEC: - search[search_count].host = "0::0"; - search[search_count].family = AF_INET6; - ++search_count; - search[search_count].host = "0.0.0.0"; - search[search_count].family = AF_INET; - ++search_count; - break; - default: - break; - } - } - else - { - // No host and not AI_PASSIVE means connect to local host. - switch (hints->ai_family) - { - case AF_INET: - search[search_count].host = "localhost"; - search[search_count].family = AF_INET; - ++search_count; - break; - case AF_INET6: - search[search_count].host = "localhost"; - search[search_count].family = AF_INET6; - ++search_count; - break; - case AF_UNSPEC: - search[search_count].host = "localhost"; - search[search_count].family = AF_INET6; - ++search_count; - search[search_count].host = "localhost"; - search[search_count].family = AF_INET; - ++search_count; - break; - default: - break; - } - } - } - else - { - // Host is specified. - switch (hints->ai_family) - { - case AF_INET: - search[search_count].host = host; - search[search_count].family = AF_INET; - ++search_count; - break; - case AF_INET6: - search[search_count].host = host; - search[search_count].family = AF_INET6; - ++search_count; - break; - case AF_UNSPEC: - search[search_count].host = host; - search[search_count].family = AF_INET6; - ++search_count; - search[search_count].host = host; - search[search_count].family = AF_INET; - ++search_count; - break; - default: - break; - } - } - return search_count; -} - -template -inline T* gai_alloc(std::size_t size = sizeof(T)) -{ - using namespace std; - T* p = static_cast(::operator new(size, std::nothrow)); - if (p) - memset(p, 0, size); - return p; -} - -inline void gai_free(void* p) -{ - ::operator delete(p); -} - -inline void gai_strcpy(char* target, const char* source, std::size_t max_size) -{ - using namespace std; -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) - strcpy_s(target, max_size, source); -#else - *target = 0; - strncat(target, source, max_size); -#endif -} - -enum { gai_clone_flag = 1 << 30 }; - -inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, - const void* addr, int family) -{ - using namespace std; - - addrinfo_type* ai = gai_alloc(); - if (ai == 0) - return EAI_MEMORY; - - ai->ai_next = 0; - **next = ai; - *next = &ai->ai_next; - - ai->ai_canonname = 0; - ai->ai_socktype = hints->ai_socktype; - if (ai->ai_socktype == 0) - ai->ai_flags |= gai_clone_flag; - ai->ai_protocol = hints->ai_protocol; - ai->ai_family = family; - - switch (ai->ai_family) - { - case AF_INET: - { - sockaddr_in4_type* sinptr = gai_alloc(); - if (sinptr == 0) - return EAI_MEMORY; - sinptr->sin_family = AF_INET; - memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); - ai->ai_addr = reinterpret_cast(sinptr); - ai->ai_addrlen = sizeof(sockaddr_in4_type); - break; - } - case AF_INET6: - { - sockaddr_in6_type* sin6ptr = gai_alloc(); - if (sin6ptr == 0) - return EAI_MEMORY; - sin6ptr->sin6_family = AF_INET6; - memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); - ai->ai_addr = reinterpret_cast(sin6ptr); - ai->ai_addrlen = sizeof(sockaddr_in6_type); - break; - } - default: - break; - } - - return 0; -} - -inline addrinfo_type* gai_clone(addrinfo_type* ai) -{ - using namespace std; - - addrinfo_type* new_ai = gai_alloc(); - if (new_ai == 0) - return new_ai; - - new_ai->ai_next = ai->ai_next; - ai->ai_next = new_ai; - - new_ai->ai_flags = 0; - new_ai->ai_family = ai->ai_family; - new_ai->ai_socktype = ai->ai_socktype; - new_ai->ai_protocol = ai->ai_protocol; - new_ai->ai_canonname = 0; - new_ai->ai_addrlen = ai->ai_addrlen; - new_ai->ai_addr = gai_alloc(ai->ai_addrlen); - memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); - - return new_ai; -} - -inline int gai_port(addrinfo_type* aihead, int port, int socktype) -{ - int num_found = 0; - - for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) - { - if (ai->ai_flags & gai_clone_flag) - { - if (ai->ai_socktype != 0) - { - ai = gai_clone(ai); - if (ai == 0) - return -1; - // ai now points to newly cloned entry. - } - } - else if (ai->ai_socktype != socktype) - { - // Ignore if mismatch on socket type. - continue; - } - - ai->ai_socktype = socktype; - - switch (ai->ai_family) - { - case AF_INET: - { - sockaddr_in4_type* sinptr = - reinterpret_cast(ai->ai_addr); - sinptr->sin_port = port; - ++num_found; - break; - } - case AF_INET6: - { - sockaddr_in6_type* sin6ptr = - reinterpret_cast(ai->ai_addr); - sin6ptr->sin6_port = port; - ++num_found; - break; - } - default: - break; - } - } - - return num_found; -} - -inline int gai_serv(addrinfo_type* aihead, - const addrinfo_type* hints, const char* serv) -{ - using namespace std; - - int num_found = 0; - - if ( -#if defined(AI_NUMERICSERV) - (hints->ai_flags & AI_NUMERICSERV) || -#endif - isdigit(serv[0])) - { - int port = htons(atoi(serv)); - if (hints->ai_socktype) - { - // Caller specifies socket type. - int rc = gai_port(aihead, port, hints->ai_socktype); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - else - { - // Caller does not specify socket type. - int rc = gai_port(aihead, port, SOCK_STREAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - rc = gai_port(aihead, port, SOCK_DGRAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - } - else - { - // Try service name with TCP first, then UDP. - if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) - { - servent* sptr = getservbyname(serv, "tcp"); - if (sptr != 0) - { - int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - } - if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) - { - servent* sptr = getservbyname(serv, "udp"); - if (sptr != 0) - { - int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - } - } - - if (num_found == 0) - { - if (hints->ai_socktype == 0) - { - // All calls to getservbyname() failed. - return EAI_NONAME; - } - else - { - // Service not supported for socket type. - return EAI_SERVICE; - } - } - - return 0; -} - -inline int gai_echeck(const char* host, const char* service, - int flags, int family, int socktype, int protocol) -{ - (void)(flags); - (void)(protocol); - - // Host or service must be specified. - if (host == 0 || host[0] == '\0') - if (service == 0 || service[0] == '\0') - return EAI_NONAME; - - // Check combination of family and socket type. - switch (family) - { - case AF_UNSPEC: - break; - case AF_INET: - case AF_INET6: - if (service != 0 && service[0] != '\0') - if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) - return EAI_SOCKTYPE; - break; - default: - return EAI_FAMILY; - } - - return 0; -} - -inline void freeaddrinfo_emulation(addrinfo_type* aihead) -{ - addrinfo_type* ai = aihead; - while (ai) - { - gai_free(ai->ai_addr); - gai_free(ai->ai_canonname); - addrinfo_type* ainext = ai->ai_next; - gai_free(ai); - ai = ainext; - } -} - -inline int getaddrinfo_emulation(const char* host, const char* service, - const addrinfo_type* hintsp, addrinfo_type** result) -{ - // Set up linked list of addrinfo structures. - addrinfo_type* aihead = 0; - addrinfo_type** ainext = &aihead; - char* canon = 0; - - // Supply default hints if not specified by caller. - addrinfo_type hints = addrinfo_type(); - hints.ai_family = AF_UNSPEC; - if (hintsp) - hints = *hintsp; - - // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED - // and AI_ALL flags. -#if defined(AI_V4MAPPED) - if (hints.ai_family != AF_INET6) - hints.ai_flags &= ~AI_V4MAPPED; -#endif -#if defined(AI_ALL) - if (hints.ai_family != AF_INET6) - hints.ai_flags &= ~AI_ALL; -#endif - - // Basic error checking. - int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, - hints.ai_socktype, hints.ai_protocol); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - return rc; - } - - gai_search search[2]; - int search_count = gai_nsearch(host, &hints, search); - for (gai_search* sptr = search; sptr < search + search_count; ++sptr) - { - // Check for IPv4 dotted decimal string. - in4_addr_type inaddr; - boost::system::error_code ec; - if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) - { - if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return EAI_FAMILY; - } - if (sptr->family == AF_INET) - { - rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return rc; - } - } - continue; - } - - // Check for IPv6 hex string. - in6_addr_type in6addr; - if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) - { - if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return EAI_FAMILY; - } - if (sptr->family == AF_INET6) - { - rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return rc; - } - } - continue; - } - - // Look up hostname. - hostent hent; - char hbuf[8192] = ""; - hostent* hptr = socket_ops::gethostbyname(sptr->host, - sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); - if (hptr == 0) - { - if (search_count == 2) - { - // Failure is OK if there are multiple searches. - continue; - } - freeaddrinfo_emulation(aihead); - gai_free(canon); - if (ec == boost::asio::error::host_not_found) - return EAI_NONAME; - if (ec == boost::asio::error::host_not_found_try_again) - return EAI_AGAIN; - if (ec == boost::asio::error::no_recovery) - return EAI_FAIL; - if (ec == boost::asio::error::no_data) - return EAI_NONAME; - return EAI_NONAME; - } - - // Check for address family mismatch if one was specified. - if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - socket_ops::freehostent(hptr); - return EAI_FAMILY; - } - - // Save canonical name first time. - if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] - && (hints.ai_flags & AI_CANONNAME) && canon == 0) - { - std::size_t canon_len = strlen(hptr->h_name) + 1; - canon = gai_alloc(canon_len); - if (canon == 0) - { - freeaddrinfo_emulation(aihead); - socket_ops::freehostent(hptr); - return EAI_MEMORY; - } - gai_strcpy(canon, hptr->h_name, canon_len); - } - - // Create an addrinfo structure for each returned address. - for (char** ap = hptr->h_addr_list; *ap; ++ap) - { - rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - socket_ops::freehostent(hptr); - return EAI_FAMILY; - } - } - - socket_ops::freehostent(hptr); - } - - // Check if we found anything. - if (aihead == 0) - { - gai_free(canon); - return EAI_NONAME; - } - - // Return canonical name in first entry. - if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) - { - if (canon) - { - aihead->ai_canonname = canon; - canon = 0; - } - else - { - std::size_t canonname_len = strlen(search[0].host) + 1; - aihead->ai_canonname = gai_alloc(canonname_len); - if (aihead->ai_canonname == 0) - { - freeaddrinfo_emulation(aihead); - return EAI_MEMORY; - } - gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); - } - } - gai_free(canon); - - // Process the service name. - if (service != 0 && service[0] != '\0') - { - rc = gai_serv(aihead, &hints, service); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - return rc; - } - } - - // Return result to caller. - *result = aihead; - return 0; -} - -inline boost::system::error_code getnameinfo_emulation( - const socket_addr_type* sa, std::size_t salen, char* host, - std::size_t hostlen, char* serv, std::size_t servlen, int flags, - boost::system::error_code& ec) -{ - using namespace std; - - const char* addr; - size_t addr_len; - unsigned short port; - switch (sa->sa_family) - { - case AF_INET: - if (salen != sizeof(sockaddr_in4_type)) - { - return ec = boost::asio::error::invalid_argument; - } - addr = reinterpret_cast( - &reinterpret_cast(sa)->sin_addr); - addr_len = sizeof(in4_addr_type); - port = reinterpret_cast(sa)->sin_port; - break; - case AF_INET6: - if (salen != sizeof(sockaddr_in6_type)) - { - return ec = boost::asio::error::invalid_argument; - } - addr = reinterpret_cast( - &reinterpret_cast(sa)->sin6_addr); - addr_len = sizeof(in6_addr_type); - port = reinterpret_cast(sa)->sin6_port; - break; - default: - return ec = boost::asio::error::address_family_not_supported; - } - - if (host && hostlen > 0) - { - if (flags & NI_NUMERICHOST) - { - if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) - { - return ec; - } - } - else - { - hostent hent; - char hbuf[8192] = ""; - hostent* hptr = socket_ops::gethostbyaddr(addr, - static_cast(addr_len), sa->sa_family, - &hent, hbuf, sizeof(hbuf), ec); - if (hptr && hptr->h_name && hptr->h_name[0] != '\0') - { - if (flags & NI_NOFQDN) - { - char* dot = strchr(hptr->h_name, '.'); - if (dot) - { - *dot = 0; - } - } - gai_strcpy(host, hptr->h_name, hostlen); - socket_ops::freehostent(hptr); - } - else - { - socket_ops::freehostent(hptr); - if (flags & NI_NAMEREQD) - { - return ec = boost::asio::error::host_not_found; - } - if (socket_ops::inet_ntop(sa->sa_family, - addr, host, hostlen, 0, ec) == 0) - { - return ec; - } - } - } - } - - if (serv && servlen > 0) - { - if (flags & NI_NUMERICSERV) - { - if (servlen < 6) - { - return ec = boost::asio::error::no_buffer_space; - } -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) - sprintf_s(serv, servlen, "%u", ntohs(port)); -#else - sprintf(serv, "%u", ntohs(port)); -#endif - } - else - { -#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - ::pthread_mutex_lock(&mutex); -#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); - if (sptr && sptr->s_name && sptr->s_name[0] != '\0') - { - gai_strcpy(serv, sptr->s_name, servlen); - } - else - { - if (servlen < 6) - { - return ec = boost::asio::error::no_buffer_space; - } -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) - sprintf_s(serv, servlen, "%u", ntohs(port)); -#else - sprintf(serv, "%u", ntohs(port)); -#endif - } -#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - ::pthread_mutex_unlock(&mutex); -#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - } - } - - clear_error(ec); - return ec; -} - -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // || defined(__MACH__) && defined(__APPLE__) - -inline boost::system::error_code translate_addrinfo_error(int error) -{ - switch (error) - { - case 0: - return boost::system::error_code(); - case EAI_AGAIN: - return boost::asio::error::host_not_found_try_again; - case EAI_BADFLAGS: - return boost::asio::error::invalid_argument; - case EAI_FAIL: - return boost::asio::error::no_recovery; - case EAI_FAMILY: - return boost::asio::error::address_family_not_supported; - case EAI_MEMORY: - return boost::asio::error::no_memory; - case EAI_NONAME: -#if defined(EAI_ADDRFAMILY) - case EAI_ADDRFAMILY: -#endif -#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) - case EAI_NODATA: -#endif - return boost::asio::error::host_not_found; - case EAI_SERVICE: - return boost::asio::error::service_not_found; - case EAI_SOCKTYPE: - return boost::asio::error::socket_type_not_supported; - default: // Possibly the non-portable EAI_SYSTEM. -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return boost::system::error_code( - WSAGetLastError(), boost::asio::error::get_system_category()); -#else - return boost::system::error_code( - errno, boost::asio::error::get_system_category()); -#endif - } -} - -inline boost::system::error_code getaddrinfo(const char* host, - const char* service, const addrinfo_type* hints, addrinfo_type** result, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) - // Building for Windows XP, Windows Server 2003, or later. - int error = ::getaddrinfo(host, service, hints, result); - return ec = translate_addrinfo_error(error); -# else - // Building for Windows 2000 or earlier. - typedef int (WSAAPI *gai_t)(const char*, - const char*, const addrinfo_type*, addrinfo_type**); - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) - { - int error = gai(host, service, hints, result); - return ec = translate_addrinfo_error(error); - } - } - int error = getaddrinfo_emulation(host, service, hints, result); - return ec = translate_addrinfo_error(error); -# endif -#elif defined(__MACH__) && defined(__APPLE__) - int error = getaddrinfo_emulation(host, service, hints, result); - return ec = translate_addrinfo_error(error); -#else - int error = ::getaddrinfo(host, service, hints, result); - return ec = translate_addrinfo_error(error); -#endif -} - -inline void freeaddrinfo(addrinfo_type* ai) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) - // Building for Windows XP, Windows Server 2003, or later. - ::freeaddrinfo(ai); -# else - // Building for Windows 2000 or earlier. - typedef int (WSAAPI *fai_t)(addrinfo_type*); - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) - { - fai(ai); - return; - } - } - freeaddrinfo_emulation(ai); -# endif -#elif defined(__MACH__) && defined(__APPLE__) - freeaddrinfo_emulation(ai); -#else - ::freeaddrinfo(ai); -#endif -} - -inline boost::system::error_code getnameinfo(const socket_addr_type* addr, - std::size_t addrlen, char* host, std::size_t hostlen, - char* serv, std::size_t servlen, int flags, boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) - // Building for Windows XP, Windows Server 2003, or later. - clear_error(ec); - int error = ::getnameinfo(addr, static_cast(addrlen), - host, static_cast(hostlen), - serv, static_cast(servlen), flags); - return ec = translate_addrinfo_error(error); -# else - // Building for Windows 2000 or earlier. - typedef int (WSAAPI *gni_t)(const socket_addr_type*, - int, char*, DWORD, char*, DWORD, int); - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) - { - clear_error(ec); - int error = gni(addr, static_cast(addrlen), - host, static_cast(hostlen), - serv, static_cast(servlen), flags); - return ec = translate_addrinfo_error(error); - } - } - clear_error(ec); - return getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags, ec); -# endif -#elif defined(__MACH__) && defined(__APPLE__) - using namespace std; // For memcpy. - sockaddr_storage_type tmp_addr; - memcpy(&tmp_addr, addr, addrlen); - tmp_addr.ss_len = addrlen; - addr = reinterpret_cast(&tmp_addr); - clear_error(ec); - return getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags, ec); -#else - clear_error(ec); - int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); - return ec = translate_addrinfo_error(error); -#endif -} - -inline u_long_type network_to_host_long(u_long_type value) -{ - return ntohl(value); -} - -inline u_long_type host_to_network_long(u_long_type value) -{ - return htonl(value); -} - -inline u_short_type network_to_host_short(u_short_type value) -{ - return ntohs(value); -} - -inline u_short_type host_to_network_short(u_short_type value) -{ - return htons(value); -} +BOOST_ASIO_DECL u_short_type host_to_network_short(u_short_type value); } // namespace socket_ops } // namespace detail @@ -1911,4 +284,8 @@ inline u_short_type host_to_network_short(u_short_type value) #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_SOCKET_OPS_HPP diff --git a/include/boost/asio/detail/socket_option.hpp b/include/boost/asio/detail/socket_option.hpp index e31aae40..37efa834 100644 --- a/include/boost/asio/detail/socket_option.hpp +++ b/include/boost/asio/detail/socket_option.hpp @@ -1,6 +1,6 @@ // -// socket_option.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include #include -#include - #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/socket_select_interrupter.hpp b/include/boost/asio/detail/socket_select_interrupter.hpp index a538ae55..b674514a 100644 --- a/include/boost/asio/detail/socket_select_interrupter.hpp +++ b/include/boost/asio/detail/socket_select_interrupter.hpp @@ -1,6 +1,6 @@ // -// socket_select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/socket_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include -#include +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) -#include -#include -#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -36,135 +33,16 @@ class socket_select_interrupter { public: // Constructor. - socket_select_interrupter() - { - boost::system::error_code ec; - socket_holder acceptor(socket_ops::socket( - AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); - if (acceptor.get() == invalid_socket) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - int opt = 1; - socket_ops::setsockopt(acceptor.get(), - SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); - - using namespace std; // For memset. - sockaddr_in4_type addr; - std::size_t addr_len = sizeof(addr); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - addr.sin_port = 0; - if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, - addr_len, ec) == socket_error_retval) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, - &addr_len, ec) == socket_error_retval) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - // Some broken firewalls on Windows will intermittently cause getsockname to - // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We - // explicitly specify the target address here to work around this problem. - addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - - if (socket_ops::listen(acceptor.get(), - SOMAXCONN, ec) == socket_error_retval) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - socket_holder client(socket_ops::socket( - AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); - if (client.get() == invalid_socket) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, - addr_len, ec) == socket_error_retval) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); - if (server.get() == invalid_socket) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec)) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - opt = 1; - socket_ops::setsockopt(client.get(), - IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); - - non_blocking = 1; - if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec)) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - opt = 1; - socket_ops::setsockopt(server.get(), - IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); - - read_descriptor_ = server.release(); - write_descriptor_ = client.release(); - } + BOOST_ASIO_DECL socket_select_interrupter(); // Destructor. - ~socket_select_interrupter() - { - boost::system::error_code ec; - if (read_descriptor_ != invalid_socket) - socket_ops::close(read_descriptor_, ec); - if (write_descriptor_ != invalid_socket) - socket_ops::close(write_descriptor_, ec); - } + BOOST_ASIO_DECL ~socket_select_interrupter(); // Interrupt the select call. - void interrupt() - { - char byte = 0; - socket_ops::buf b; - socket_ops::init_buf(b, &byte, 1); - boost::system::error_code ec; - socket_ops::send(write_descriptor_, &b, 1, 0, ec); - } + BOOST_ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. - bool reset() - { - char data[1024]; - socket_ops::buf b; - socket_ops::init_buf(b, data, sizeof(data)); - boost::system::error_code ec; - int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); - return was_interrupted; - } + BOOST_ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. socket_type read_descriptor() const @@ -191,4 +69,12 @@ private: #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + #endif // BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP diff --git a/include/boost/asio/detail/socket_types.hpp b/include/boost/asio/detail/socket_types.hpp index 10091649..04540efe 100644 --- a/include/boost/asio/detail/socket_types.hpp +++ b/include/boost/asio/detail/socket_types.hpp @@ -1,6 +1,6 @@ // -// socket_types.hpp -// ~~~~~~~~~~~~~~~~ +// detail/socket_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,69 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include - -#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) # error WinSock.h has already been included # endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) -# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) -# if defined(_MSC_VER) || defined(__BORLANDC__) -# pragma message( \ - "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ - "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ - "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ - "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") -# else // defined(_MSC_VER) || defined(__BORLANDC__) -# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. -# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. -# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). -# endif // defined(_MSC_VER) || defined(__BORLANDC__) -# define _WIN32_WINNT 0x0501 -# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) -# if defined(_MSC_VER) -# if defined(_WIN32) && !defined(WIN32) -# if !defined(_WINSOCK2API_) -# define WIN32 // Needed for correct types in winsock2.h -# else // !defined(_WINSOCK2API_) -# error Please define the macro WIN32 in your compiler options -# endif // !defined(_WINSOCK2API_) -# endif // defined(_WIN32) && !defined(WIN32) -# endif // defined(_MSC_VER) # if defined(__BORLANDC__) # include // Needed for __errno -# if defined(__WIN32__) && !defined(WIN32) -# if !defined(_WINSOCK2API_) -# define WIN32 // Needed for correct types in winsock2.h -# else // !defined(_WINSOCK2API_) -# error Please define the macro WIN32 in your compiler options -# endif // !defined(_WINSOCK2API_) -# endif // defined(__WIN32__) && !defined(WIN32) # if !defined(_WSPIAPI_H_) # define _WSPIAPI_H_ # define BOOST_ASIO_WSPIAPI_H_DEFINED # endif // !defined(_WSPIAPI_H_) # endif // defined(__BORLANDC__) -# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) -# if !defined(WIN32_LEAN_AND_MEAN) -# define WIN32_LEAN_AND_MEAN -# endif // !defined(WIN32_LEAN_AND_MEAN) -# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) -# if !defined(BOOST_ASIO_NO_NOMINMAX) -# if !defined(NOMINMAX) -# define NOMINMAX 1 -# endif // !defined(NOMINMAX) -# endif // !defined(BOOST_ASIO_NO_NOMINMAX) -# if defined(__CYGWIN__) -# if !defined(__USE_W32_SOCKETS) -# error You must add -D__USE_W32_SOCKETS to your compiler options. -# endif // !defined(__USE_W32_SOCKETS) -# endif // defined(__CYGWIN__) # include # include # include @@ -96,8 +46,12 @@ # include #else # include -# include +# if !defined(__SYMBIAN32__) +# include +# endif # include +# include +# include # if defined(__hpux) && !defined(__HP_aCC) # include # else @@ -107,7 +61,9 @@ # include # include # include -# include +# if !defined(__SYMBIAN32__) +# include +# endif # include # include # include @@ -117,7 +73,8 @@ # include # endif #endif -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/solaris_fenced_block.hpp b/include/boost/asio/detail/solaris_fenced_block.hpp index be9803e7..db6cb980 100644 --- a/include/boost/asio/detail/solaris_fenced_block.hpp +++ b/include/boost/asio/detail/solaris_fenced_block.hpp @@ -1,6 +1,6 @@ // -// solaris_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/solaris_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(__sun) -#include #include -#include + +#include namespace boost { namespace asio { @@ -52,8 +48,8 @@ public: } // namespace asio } // namespace boost -#endif // defined(__sun) - #include +#endif // defined(__sun) + #endif // BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/strand_service.hpp b/include/boost/asio/detail/strand_service.hpp index d6b45b1a..24bec7c9 100644 --- a/include/boost/asio/detail/strand_service.hpp +++ b/include/boost/asio/detail/strand_service.hpp @@ -1,6 +1,6 @@ // -// strand_service.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,23 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include -#include -#include -#include -#include -#include #include #include #include -#include + +#include namespace boost { namespace asio { @@ -42,7 +33,10 @@ class strand_service : public boost::asio::detail::service_base { private: + // Helper class to re-post the strand on exit. struct on_do_complete_exit; + + // Helper class to re-post the strand on exit. struct on_dispatch_exit; public: @@ -52,11 +46,7 @@ public: : public operation { public: - strand_impl() - : operation(&strand_service::do_complete), - count_(0) - { - } + strand_impl(); private: // Only this service will have access to the internal values. @@ -77,180 +67,29 @@ public: typedef strand_impl* implementation_type; // Construct a new strand service for the specified io_service. - explicit strand_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - io_service_(boost::asio::use_service(io_service)), - mutex_(), - salt_(0) - { - } + BOOST_ASIO_DECL explicit strand_service(boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - op_queue ops; - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - for (std::size_t i = 0; i < num_implementations; ++i) - if (strand_impl* impl = implementations_[i].get()) - ops.push(impl->queue_); - } + BOOST_ASIO_DECL void shutdown_service(); // Construct a new strand implementation. - void construct(implementation_type& impl) - { - std::size_t index = boost::hash_value(&impl); - boost::hash_combine(index, salt_++); - index = index % num_implementations; - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (!implementations_[index]) - implementations_[index].reset(new strand_impl); - impl = implementations_[index].get(); - } + BOOST_ASIO_DECL void construct(implementation_type& impl); // Destroy a strand implementation. - void destroy(implementation_type& impl) - { - impl = 0; - } + void destroy(implementation_type& impl); // Request the io_service to invoke the given handler. template - void dispatch(implementation_type& impl, Handler handler) - { - // If we are already in the strand then the handler can run immediately. - if (call_stack::contains(impl)) - { - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - return; - } - - // Allocate and construct an object to wrap the handler. - typedef completion_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - // If we are running inside the io_service, and no other handler is queued - // or running, then the handler can run immediately. - bool can_dispatch = call_stack::contains(&io_service_); - impl->mutex_.lock(); - bool first = (++impl->count_ == 1); - if (can_dispatch && first) - { - // Immediate invocation is allowed. - impl->mutex_.unlock(); - - // Memory must be releaesed before any upcall is made. - ptr.reset(); - - // Indicate that this strand is executing on the current thread. - call_stack::context ctx(impl); - - // Ensure the next handler, if any, is scheduled on block exit. - on_dispatch_exit on_exit = { &io_service_, impl }; - (void)on_exit; - - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - return; - } - - // Immediate invocation is not allowed, so enqueue for later. - impl->queue_.push(ptr.get()); - impl->mutex_.unlock(); - ptr.release(); - - // The first handler to be enqueued is responsible for scheduling the - // strand. - if (first) - io_service_.post_immediate_completion(impl); - } + void dispatch(implementation_type& impl, Handler handler); // Request the io_service to invoke the given handler and return immediately. template - void post(implementation_type& impl, Handler handler) - { - // Allocate and construct an object to wrap the handler. - typedef completion_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - // Add the handler to the queue. - impl->mutex_.lock(); - bool first = (++impl->count_ == 1); - impl->queue_.push(ptr.get()); - impl->mutex_.unlock(); - ptr.release(); - - // The first handler to be enqueue is responsible for scheduling the strand. - if (first) - io_service_.post_immediate_completion(impl); - } + void post(implementation_type& impl, Handler handler); private: - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - if (owner) - { - strand_impl* impl = static_cast(base); - - // Get the next handler to be executed. - impl->mutex_.lock(); - operation* o = impl->queue_.front(); - impl->queue_.pop(); - impl->mutex_.unlock(); - - // Indicate that this strand is executing on the current thread. - call_stack::context ctx(impl); - - // Ensure the next handler, if any, is scheduled on block exit. - on_do_complete_exit on_exit = { owner, impl }; - (void)on_exit; - - o->complete(*owner); - } - } - - // Helper class to re-post the strand on exit. - struct on_do_complete_exit - { - io_service_impl* owner_; - strand_impl* impl_; - - ~on_do_complete_exit() - { - impl_->mutex_.lock(); - bool more_handlers = (--impl_->count_ > 0); - impl_->mutex_.unlock(); - - if (more_handlers) - owner_->post_immediate_completion(impl_); - } - }; - - // Helper class to re-post the strand on exit. - struct on_dispatch_exit - { - io_service_impl* io_service_; - strand_impl* impl_; - - ~on_dispatch_exit() - { - impl_->mutex_.lock(); - bool more_handlers = (--impl_->count_ > 0); - impl_->mutex_.unlock(); - - if (more_handlers) - io_service_->post_immediate_completion(impl_); - } - }; + BOOST_ASIO_DECL static void do_complete(io_service_impl* owner, + operation* base, boost::system::error_code ec, + std::size_t bytes_transferred); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -275,4 +114,9 @@ private: #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP diff --git a/include/boost/asio/detail/task_io_service.hpp b/include/boost/asio/detail/task_io_service.hpp index f6de3706..a9a7053b 100644 --- a/include/boost/asio/detail/task_io_service.hpp +++ b/include/boost/asio/detail/task_io_service.hpp @@ -1,6 +1,6 @@ // -// task_io_service.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/task_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,181 +15,60 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include +#include #include -#include -#include -#include -#include -#include -#include #include #include -#include +#include #include #include #include -#include -#include -#include namespace boost { namespace asio { namespace detail { -template class task_io_service - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: - typedef task_io_service_operation operation; + typedef task_io_service_operation operation; // Constructor. - task_io_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base >(io_service), - mutex_(), - task_(0), - task_interrupted_(true), - outstanding_work_(0), - stopped_(false), - shutdown_(false), - first_idle_thread_(0) - { - } + BOOST_ASIO_DECL task_io_service(boost::asio::io_service& io_service); - void init(size_t /*concurrency_hint*/) - { - } + // How many concurrent threads are likely to run the io_service. + BOOST_ASIO_DECL void init(std::size_t concurrency_hint); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - // Destroy handler objects. - while (!op_queue_.empty()) - { - operation* o = op_queue_.front(); - op_queue_.pop(); - if (o != &task_operation_) - o->destroy(); - } - - // Reset to initial state. - task_ = 0; - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task, if required. - void init_task() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_ && !task_) - { - task_ = &use_service(this->get_io_service()); - op_queue_.push(&task_operation_); - wake_one_thread_and_unlock(lock); - } - } + BOOST_ASIO_DECL void init_task(); // Run the event loop until interrupted or no more work. - size_t run(boost::system::error_code& ec) - { - ec = boost::system::error_code(); - if (outstanding_work_ == 0) - { - stop(); - return 0; - } - - typename call_stack::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - size_t n = 0; - for (; do_one(lock, &this_idle_thread); lock.lock()) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } + BOOST_ASIO_DECL std::size_t run(boost::system::error_code& ec); // Run until interrupted or one operation is performed. - size_t run_one(boost::system::error_code& ec) - { - ec = boost::system::error_code(); - if (outstanding_work_ == 0) - { - stop(); - return 0; - } - - typename call_stack::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - return do_one(lock, &this_idle_thread); - } + BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec); // Poll for operations without blocking. - size_t poll(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - size_t n = 0; - for (; do_one(lock, 0); lock.lock()) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } + BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec); // Poll for one operation without blocking. - size_t poll_one(boost::system::error_code& ec) - { - ec = boost::system::error_code(); - if (outstanding_work_ == 0) - { - stop(); - return 0; - } - - typename call_stack::context ctx(this); - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - return do_one(lock, 0); - } + BOOST_ASIO_DECL std::size_t poll_one(boost::system::error_code& ec); // Interrupt the event processing loop. - void stop() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - stop_all_threads(lock); - } + BOOST_ASIO_DECL void stop(); // Reset in preparation for a subsequent run invocation. - void reset() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - stopped_ = false; - } + BOOST_ASIO_DECL void reset(); // Notify that some work has started. void work_started() @@ -206,228 +85,60 @@ public: // Request invocation of the given handler. template - void dispatch(Handler handler) - { - if (call_stack::contains(this)) - { - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - else - post(handler); - } + void dispatch(Handler handler); // Request invocation of the given handler and return immediately. template - void post(Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef completion_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - post_immediate_completion(ptr.get()); - ptr.release(); - } + void post(Handler handler); // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. - void post_immediate_completion(operation* op) - { - work_started(); - post_deferred_completion(op); - } + BOOST_ASIO_DECL void post_immediate_completion(operation* op); // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operation. - void post_deferred_completion(operation* op) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - op_queue_.push(op); - wake_one_thread_and_unlock(lock); - } + BOOST_ASIO_DECL void post_deferred_completion(operation* op); // Request invocation of the given operations and return immediately. Assumes // that work_started() was previously called for each operation. - void post_deferred_completions(op_queue& ops) - { - if (!ops.empty()) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - op_queue_.push(ops); - wake_one_thread_and_unlock(lock); - } - } + BOOST_ASIO_DECL void post_deferred_completions(op_queue& ops); private: + // Structure containing information about an idle thread. struct idle_thread_info; - size_t do_one(boost::asio::detail::mutex::scoped_lock& lock, - idle_thread_info* this_idle_thread) - { - bool polling = !this_idle_thread; - bool task_has_run = false; - while (!stopped_) - { - if (!op_queue_.empty()) - { - // Prepare to execute first handler from queue. - operation* o = op_queue_.front(); - op_queue_.pop(); - bool more_handlers = (!op_queue_.empty()); - - if (o == &task_operation_) - { - task_interrupted_ = more_handlers || polling; - - // If the task has already run and we're polling then we're done. - if (task_has_run && polling) - { - task_interrupted_ = true; - op_queue_.push(&task_operation_); - return 0; - } - task_has_run = true; - - if (!more_handlers || !wake_one_idle_thread_and_unlock(lock)) - lock.unlock(); - - op_queue completed_ops; - task_cleanup c = { this, &lock, &completed_ops }; - (void)c; - - // Run the task. May throw an exception. Only block if the operation - // queue is empty and we're not polling, otherwise we want to return - // as soon as possible. - task_->run(!more_handlers && !polling, completed_ops); - } - else - { - if (more_handlers) - wake_one_thread_and_unlock(lock); - else - lock.unlock(); - - // Ensure the count of outstanding work is decremented on block exit. - work_finished_on_block_exit on_exit = { this }; - (void)on_exit; - - // Complete the operation. May throw an exception. - o->complete(*this); // deletes the operation object - - return 1; - } - } - else if (this_idle_thread) - { - // Nothing to run right now, so just wait for work to do. - this_idle_thread->next = first_idle_thread_; - first_idle_thread_ = this_idle_thread; - this_idle_thread->wakeup_event.clear(lock); - this_idle_thread->wakeup_event.wait(lock); - } - else - { - return 0; - } - } - - return 0; - } + // Run at most one operation. Blocks only if this_idle_thread is non-null. + BOOST_ASIO_DECL std::size_t do_one(mutex::scoped_lock& lock, + idle_thread_info* this_idle_thread); // Stop the task and all idle threads. - void stop_all_threads( - boost::asio::detail::mutex::scoped_lock& lock) - { - stopped_ = true; - - while (first_idle_thread_) - { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(lock); - } - - if (!task_interrupted_ && task_) - { - task_interrupted_ = true; - task_->interrupt(); - } - } + BOOST_ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock); // Wakes a single idle thread and unlocks the mutex. Returns true if an idle // thread was found. If there is no idle thread, returns false and leaves the // mutex locked. - bool wake_one_idle_thread_and_unlock( - boost::asio::detail::mutex::scoped_lock& lock) - { - if (first_idle_thread_) - { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal_and_unlock(lock); - return true; - } - return false; - } + BOOST_ASIO_DECL bool wake_one_idle_thread_and_unlock( + mutex::scoped_lock& lock); // Wake a single idle thread, or the task, and always unlock the mutex. - void wake_one_thread_and_unlock( - boost::asio::detail::mutex::scoped_lock& lock) - { - if (!wake_one_idle_thread_and_unlock(lock)) - { - if (!task_interrupted_ && task_) - { - task_interrupted_ = true; - task_->interrupt(); - } - lock.unlock(); - } - } + BOOST_ASIO_DECL void wake_one_thread_and_unlock( + mutex::scoped_lock& lock); // Helper class to perform task-related operations on block exit. struct task_cleanup; friend struct task_cleanup; - struct task_cleanup - { - ~task_cleanup() - { - // Enqueue the completed operations and reinsert the task at the end of - // the operation queue. - lock_->lock(); - task_io_service_->task_interrupted_ = true; - task_io_service_->op_queue_.push(*ops_); - task_io_service_->op_queue_.push(&task_io_service_->task_operation_); - } - - task_io_service* task_io_service_; - boost::asio::detail::mutex::scoped_lock* lock_; - op_queue* ops_; - }; // Helper class to call work_finished() on block exit. - struct work_finished_on_block_exit - { - ~work_finished_on_block_exit() - { - task_io_service_->work_finished(); - } - - task_io_service* task_io_service_; - }; + struct work_finished_on_block_exit; // Mutex to protect access to internal data. - boost::asio::detail::mutex mutex_; + mutex mutex_; // The task to be run by this service. - Task* task_; + reactor* task_; // Operation object to represent the position of the task in the queue. - struct task_operation : public operation + struct task_operation : operation { task_operation() : operation(0) {} } task_operation_; @@ -447,13 +158,6 @@ private: // Flag to indicate that the dispatcher has been shut down. bool shutdown_; - // Structure containing information about an idle thread. - struct idle_thread_info - { - event wakeup_event; - idle_thread_info* next; - }; - // The threads that are currently idle. idle_thread_info* first_idle_thread_; }; @@ -464,4 +168,11 @@ private: #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP diff --git a/include/boost/asio/detail/task_io_service_fwd.hpp b/include/boost/asio/detail/task_io_service_fwd.hpp index 60a07900..24dd11bd 100644 --- a/include/boost/asio/detail/task_io_service_fwd.hpp +++ b/include/boost/asio/detail/task_io_service_fwd.hpp @@ -1,6 +1,6 @@ // -// task_io_service_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/task_io_service_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { namespace detail { -template class task_io_service; } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP diff --git a/include/boost/asio/detail/task_io_service_operation.hpp b/include/boost/asio/detail/task_io_service_operation.hpp index 557f6732..e234c07d 100644 --- a/include/boost/asio/detail/task_io_service_operation.hpp +++ b/include/boost/asio/detail/task_io_service_operation.hpp @@ -1,6 +1,6 @@ // -// task_io_service_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/task_io_service_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,22 +15,22 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include + namespace boost { namespace asio { namespace detail { // Base class for all operations. A function pointer is used instead of virtual // functions to avoid the associated overhead. -template class task_io_service_operation { public: - void complete(task_io_service& owner) + void complete(task_io_service& owner) { func_(&owner, this, boost::system::error_code(), 0); } @@ -41,8 +41,9 @@ public: } protected: - typedef void (*func_type)(task_io_service*, - task_io_service_operation*, boost::system::error_code, std::size_t); + typedef void (*func_type)(task_io_service*, + task_io_service_operation*, + boost::system::error_code, std::size_t); task_io_service_operation(func_type func) : next_(0), @@ -65,7 +66,6 @@ private: } // namespace asio } // namespace boost -#include #include #endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP diff --git a/include/boost/asio/detail/thread.hpp b/include/boost/asio/detail/thread.hpp index 3e2e2159..8848cd06 100644 --- a/include/boost/asio/detail/thread.hpp +++ b/include/boost/asio/detail/thread.hpp @@ -1,6 +1,6 @@ // -// thread.hpp -// ~~~~~~~~~~ +// detail/thread.hpp +// ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -55,6 +51,4 @@ typedef posix_thread thread; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_THREAD_HPP diff --git a/include/boost/asio/detail/throw_error.hpp b/include/boost/asio/detail/throw_error.hpp index e9406a72..713a1963 100644 --- a/include/boost/asio/detail/throw_error.hpp +++ b/include/boost/asio/detail/throw_error.hpp @@ -1,6 +1,6 @@ // -// throw_error.hpp -// ~~~~~~~~~~~~~~~ +// detail/throw_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,26 +15,31 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include -#include +#include namespace boost { namespace asio { namespace detail { +BOOST_ASIO_DECL void do_throw_error(const boost::system::error_code& err); + +BOOST_ASIO_DECL void do_throw_error(const boost::system::error_code& err, + const char* location); + inline void throw_error(const boost::system::error_code& err) { if (err) - { - boost::system::system_error e(err); - boost::throw_exception(e); - } + do_throw_error(err); +} + +inline void throw_error(const boost::system::error_code& err, + const char* location) +{ + if (err) + do_throw_error(err, location); } } // namespace detail @@ -43,4 +48,8 @@ inline void throw_error(const boost::system::error_code& err) #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_THROW_ERROR_HPP diff --git a/include/boost/asio/detail/timer_op.hpp b/include/boost/asio/detail/timer_op.hpp index 9973d893..8f82339e 100644 --- a/include/boost/asio/detail/timer_op.hpp +++ b/include/boost/asio/detail/timer_op.hpp @@ -1,6 +1,6 @@ // -// timer_op.hpp -// ~~~~~~~~~~~~ +// detail/timer_op.hpp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/timer_queue.hpp b/include/boost/asio/detail/timer_queue.hpp index 164b3420..4e49ae91 100644 --- a/include/boost/asio/detail/timer_queue.hpp +++ b/include/boost/asio/detail/timer_queue.hpp @@ -1,6 +1,6 @@ // -// timer_queue.hpp -// ~~~~~~~~~~~~~~~ +// detail/timer_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include #include #include -#include - -#include #include #include #include #include +#include +#include + +#include +#include +#include + +#include namespace boost { namespace asio { @@ -98,8 +101,10 @@ public: if (duration > boost::posix_time::milliseconds(max_duration)) duration = boost::posix_time::milliseconds(max_duration); - else if (duration < boost::posix_time::milliseconds(0)) + else if (duration <= boost::posix_time::milliseconds(0)) duration = boost::posix_time::milliseconds(0); + else if (duration < boost::posix_time::milliseconds(1)) + duration = boost::posix_time::milliseconds(1); return duration.total_milliseconds(); } @@ -115,8 +120,10 @@ public: if (duration > boost::posix_time::microseconds(max_duration)) duration = boost::posix_time::microseconds(max_duration); - else if (duration < boost::posix_time::microseconds(0)) + else if (duration <= boost::posix_time::microseconds(0)) duration = boost::posix_time::microseconds(0); + else if (duration < boost::posix_time::microseconds(1)) + duration = boost::posix_time::microseconds(1); return duration.total_microseconds(); } @@ -269,6 +276,59 @@ private: std::vector heap_; }; +#if !defined(BOOST_ASIO_HEADER_ONLY) + +struct forwarding_posix_time_traits : time_traits {}; + +// Template specialisation for the commonly used instantation. +template <> +class timer_queue > + : public timer_queue_base +{ +public: + // The time type. + typedef boost::posix_time::ptime time_type; + + // The duration type. + typedef boost::posix_time::time_duration duration_type; + + // Constructor. + BOOST_ASIO_DECL timer_queue(); + + // Destructor. + BOOST_ASIO_DECL virtual ~timer_queue(); + + // Add a new timer to the queue. Returns true if this is the timer that is + // earliest in the queue, in which case the reactor's event demultiplexing + // function call may need to be interrupted and restarted. + BOOST_ASIO_DECL bool enqueue_timer(const time_type& time, + timer_op* op, void* token); + + // Whether there are no timers in the queue. + BOOST_ASIO_DECL virtual bool empty() const; + + // Get the time for the timer that is earliest in the queue. + BOOST_ASIO_DECL virtual long wait_duration_msec(long max_duration) const; + + // Get the time for the timer that is earliest in the queue. + BOOST_ASIO_DECL virtual long wait_duration_usec(long max_duration) const; + + // Dequeue all timers not later than the current time. + BOOST_ASIO_DECL virtual void get_ready_timers(op_queue& ops); + + // Dequeue all timers. + BOOST_ASIO_DECL virtual void get_all_timers(op_queue& ops); + + // Cancel and dequeue the timers with the given token. + BOOST_ASIO_DECL std::size_t cancel_timer( + void* timer_token, op_queue& ops); + +private: + timer_queue impl_; +}; + +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + } // namespace detail } // namespace asio } // namespace boost diff --git a/include/boost/asio/detail/timer_queue_base.hpp b/include/boost/asio/detail/timer_queue_base.hpp index 074c2e15..02903085 100644 --- a/include/boost/asio/detail/timer_queue_base.hpp +++ b/include/boost/asio/detail/timer_queue_base.hpp @@ -1,6 +1,6 @@ // -// timer_queue_base.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/timer_queue_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,12 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/timer_queue_fwd.hpp b/include/boost/asio/detail/timer_queue_fwd.hpp index b8bc5f2e..0a62a44d 100644 --- a/include/boost/asio/detail/timer_queue_fwd.hpp +++ b/include/boost/asio/detail/timer_queue_fwd.hpp @@ -1,6 +1,6 @@ // -// timer_queue_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/timer_queue_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { namespace detail { @@ -28,6 +26,4 @@ class timer_queue; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_FWD_HPP diff --git a/include/boost/asio/detail/timer_queue_set.hpp b/include/boost/asio/detail/timer_queue_set.hpp index a92a6b90..c2cea662 100644 --- a/include/boost/asio/detail/timer_queue_set.hpp +++ b/include/boost/asio/detail/timer_queue_set.hpp @@ -1,6 +1,6 @@ // -// timer_queue_set.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/timer_queue_set.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -27,82 +28,28 @@ class timer_queue_set { public: // Constructor. - timer_queue_set() - : first_(0) - { - } + BOOST_ASIO_DECL timer_queue_set(); // Add a timer queue to the set. - void insert(timer_queue_base* q) - { - q->next_ = first_; - first_ = q; - } + BOOST_ASIO_DECL void insert(timer_queue_base* q); // Remove a timer queue from the set. - void erase(timer_queue_base* q) - { - if (first_) - { - if (q == first_) - { - first_ = q->next_; - q->next_ = 0; - return; - } - - for (timer_queue_base* p = first_; p->next_; p = p->next_) - { - if (p->next_ == q) - { - p->next_ = q->next_; - q->next_ = 0; - return; - } - } - } - } + BOOST_ASIO_DECL void erase(timer_queue_base* q); // Determine whether all queues are empty. - bool all_empty() const - { - for (timer_queue_base* p = first_; p; p = p->next_) - if (!p->empty()) - return false; - return true; - } + BOOST_ASIO_DECL bool all_empty() const; // Get the wait duration in milliseconds. - long wait_duration_msec(long max_duration) const - { - long min_duration = max_duration; - for (timer_queue_base* p = first_; p; p = p->next_) - min_duration = p->wait_duration_msec(min_duration); - return min_duration; - } + BOOST_ASIO_DECL long wait_duration_msec(long max_duration) const; // Get the wait duration in microseconds. - long wait_duration_usec(long max_duration) const - { - long min_duration = max_duration; - for (timer_queue_base* p = first_; p; p = p->next_) - min_duration = p->wait_duration_usec(min_duration); - return min_duration; - } + BOOST_ASIO_DECL long wait_duration_usec(long max_duration) const; // Dequeue all ready timers. - void get_ready_timers(op_queue& ops) - { - for (timer_queue_base* p = first_; p; p = p->next_) - p->get_ready_timers(ops); - } + BOOST_ASIO_DECL void get_ready_timers(op_queue& ops); // Dequeue all timers. - void get_all_timers(op_queue& ops) - { - for (timer_queue_base* p = first_; p; p = p->next_) - p->get_all_timers(ops); - } + BOOST_ASIO_DECL void get_all_timers(op_queue& ops); private: timer_queue_base* first_; @@ -114,4 +61,8 @@ private: #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP diff --git a/include/boost/asio/detail/timer_scheduler.hpp b/include/boost/asio/detail/timer_scheduler.hpp index bc837ee0..ec80f407 100644 --- a/include/boost/asio/detail/timer_scheduler.hpp +++ b/include/boost/asio/detail/timer_scheduler.hpp @@ -1,6 +1,6 @@ // -// timer_scheduler.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,8 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #if defined(BOOST_ASIO_HAS_IOCP) @@ -31,6 +30,4 @@ # include #endif -#include - #endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP diff --git a/include/boost/asio/detail/timer_scheduler_fwd.hpp b/include/boost/asio/detail/timer_scheduler_fwd.hpp index 9d0b1e63..77d6c99e 100644 --- a/include/boost/asio/detail/timer_scheduler_fwd.hpp +++ b/include/boost/asio/detail/timer_scheduler_fwd.hpp @@ -1,6 +1,6 @@ // -// timer_scheduler_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/timer_scheduler_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#elif defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#else +# include +#endif namespace boost { namespace asio { @@ -36,13 +42,11 @@ typedef kqueue_reactor timer_scheduler; #elif defined(BOOST_ASIO_HAS_DEV_POLL) typedef dev_poll_reactor timer_scheduler; #else -typedef select_reactor timer_scheduler; +typedef select_reactor timer_scheduler; #endif } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP diff --git a/include/boost/asio/detail/tss_ptr.hpp b/include/boost/asio/detail/tss_ptr.hpp index 7ccfcf32..8edf15bb 100644 --- a/include/boost/asio/detail/tss_ptr.hpp +++ b/include/boost/asio/detail/tss_ptr.hpp @@ -1,6 +1,6 @@ // -// tss_ptr.hpp -// ~~~~~~~~~~~ +// detail/tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -31,6 +27,8 @@ # error Only Windows and POSIX are supported! #endif +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/wait_handler.hpp b/include/boost/asio/detail/wait_handler.hpp new file mode 100644 index 00000000..e451f196 --- /dev/null +++ b/include/boost/asio/detail/wait_handler.hpp @@ -0,0 +1,78 @@ +// +// detail/wait_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WAIT_HANDLER_HPP +#define BOOST_ASIO_DETAIL_WAIT_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class wait_handler : public timer_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(wait_handler); + + wait_handler(Handler h) + : timer_op(&wait_handler::do_complete), + handler_(h) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + wait_handler* h(static_cast(base)); + ptr p = { boost::addressof(h->handler_), h, h }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder1 + handler(h->handler_, h->ec_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_WAIT_HANDLER_HPP diff --git a/include/boost/asio/detail/weak_ptr.hpp b/include/boost/asio/detail/weak_ptr.hpp new file mode 100644 index 00000000..9a14297f --- /dev/null +++ b/include/boost/asio/detail/weak_ptr.hpp @@ -0,0 +1,41 @@ +// +// detail/weak_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WEAK_PTR_HPP +#define BOOST_ASIO_DETAIL_WEAK_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# include +#else +# include +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +using std::weak_ptr; +#else +using boost::weak_ptr; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_WEAK_PTR_HPP diff --git a/include/boost/asio/detail/win_event.hpp b/include/boost/asio/detail/win_event.hpp index bddf09d6..736ebb2d 100644 --- a/include/boost/asio/detail/win_event.hpp +++ b/include/boost/asio/detail/win_event.hpp @@ -1,6 +1,6 @@ // -// win_event.hpp -// ~~~~~~~~~~~~~ +// detail/win_event.hpp +// ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,23 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) -#include +#include #include #include #include -#include -#include -#include namespace boost { namespace asio { @@ -42,19 +34,7 @@ class win_event { public: // Constructor. - win_event() - : event_(::CreateEvent(0, true, false, 0)) - { - if (!event_) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "event"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL win_event(); // Destructor. ~win_event() @@ -107,8 +87,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + #endif // BOOST_ASIO_DETAIL_WIN_EVENT_HPP diff --git a/include/boost/asio/detail/win_fd_set_adapter.hpp b/include/boost/asio/detail/win_fd_set_adapter.hpp index 11c1e153..4a5d7faa 100644 --- a/include/boost/asio/detail/win_fd_set_adapter.hpp +++ b/include/boost/asio/detail/win_fd_set_adapter.hpp @@ -1,6 +1,6 @@ // -// win_fd_set_adapter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#include namespace boost { namespace asio { @@ -83,8 +85,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP diff --git a/include/boost/asio/detail/win_fenced_block.hpp b/include/boost/asio/detail/win_fenced_block.hpp index ff4a21cb..b23ee02f 100644 --- a/include/boost/asio/detail/win_fenced_block.hpp +++ b/include/boost/asio/detail/win_fenced_block.hpp @@ -1,6 +1,6 @@ // -// win_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/win_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include +#include + namespace boost { namespace asio { namespace detail { @@ -64,14 +62,22 @@ public: MemoryBarrier(); #endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) } + +#if defined(__BORLANDC__) + static void MemoryBarrier() + { + LONG barrier = 0; + ::InterlockedExchange(&barrier, 1); + } +#endif // defined(__BORLANDC__) }; } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) - #include +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + #endif // BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/win_iocp_handle_read_op.hpp b/include/boost/asio/detail/win_iocp_handle_read_op.hpp new file mode 100644 index 00000000..f1a9b1f6 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_handle_read_op.hpp @@ -0,0 +1,103 @@ +// +// detail/win_iocp_handle_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_handle_read_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op); + + win_iocp_handle_read_op(const MutableBufferSequence& buffers, Handler handler) + : operation(&win_iocp_handle_read_op::do_complete), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_handle_read_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_HANDLE_EOF) + ec = boost::asio::error::eof; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_handle_service.hpp b/include/boost/asio/detail/win_iocp_handle_service.hpp index a6d65990..291a06ff 100644 --- a/include/boost/asio/detail/win_iocp_handle_service.hpp +++ b/include/boost/asio/detail/win_iocp_handle_service.hpp @@ -1,6 +1,6 @@ // -// win_iocp_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) @@ -16,26 +16,23 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) -#include #include -#include - #include #include -#include #include #include -#include #include #include +#include +#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -77,75 +74,20 @@ public: implementation_type* prev_; }; - win_iocp_handle_service(boost::asio::io_service& io_service) - : iocp_service_(boost::asio::use_service(io_service)), - mutex_(), - impl_list_(0) - { - } + BOOST_ASIO_DECL win_iocp_handle_service(boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - // Close all implementations, causing all operations to complete. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - implementation_type* impl = impl_list_; - while (impl) - { - close_for_destruction(*impl); - impl = impl->next_; - } - } + BOOST_ASIO_DECL void shutdown_service(); // 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. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - impl.next_ = impl_list_; - impl.prev_ = 0; - if (impl_list_) - impl_list_->prev_ = &impl; - impl_list_ = &impl; - } + BOOST_ASIO_DECL void construct(implementation_type& impl); // Destroy a handle implementation. - void destroy(implementation_type& impl) - { - close_for_destruction(impl); - - // Remove implementation from linked list of all implementations. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (impl_list_ == &impl) - impl_list_ = impl.next_; - if (impl.prev_) - impl.prev_->next_ = impl.next_; - if (impl.next_) - impl.next_->prev_= impl.prev_; - impl.next_ = 0; - impl.prev_ = 0; - } + BOOST_ASIO_DECL void destroy(implementation_type& impl); // Assign a native handle to a handle implementation. - boost::system::error_code assign(implementation_type& impl, - const native_type& native_handle, boost::system::error_code& ec) - { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } - - if (iocp_service_.register_handle(native_handle, ec)) - return ec; - - impl.handle_ = native_handle; - ec = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl, + const native_type& native_handle, boost::system::error_code& ec); // Determine whether the handle is open. bool is_open(const implementation_type& impl) const @@ -154,26 +96,8 @@ public: } // Destroy a handle implementation. - boost::system::error_code close(implementation_type& impl, - boost::system::error_code& ec) - { - if (is_open(impl)) - { - if (!::CloseHandle(impl.handle_)) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - impl.handle_ = INVALID_HANDLE_VALUE; - impl.safe_cancellation_thread_id_ = 0; - } - - ec = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec); // Get the native handle representation. native_type native(const implementation_type& impl) const @@ -182,106 +106,8 @@ public: } // Cancel all operations associated with the handle. - boost::system::error_code cancel(implementation_type& impl, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::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 = boost::system::error_code(); - } - else - { - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - } - else - { - ec = boost::system::error_code(); - } - } - else if (impl.safe_cancellation_thread_id_ == 0) - { - // No operations have been started, so there's nothing to cancel. - ec = boost::system::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 = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - else - { - ec = boost::system::error_code(); - } - } - else - { - // Asynchronous operations have been started from more than one thread, - // so cancellation is not safe. - ec = boost::asio::error::operation_not_supported; - } - - return ec; - } - - class overlapped_wrapper - : public OVERLAPPED - { - public: - explicit overlapped_wrapper(boost::system::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(&hEvent) |= 1; - } - else - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - } - - ~overlapped_wrapper() - { - if (hEvent) - { - ::CloseHandle(hEvent); - } - } - }; + BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec); // Write the given data. Returns the number of bytes written. template @@ -297,109 +123,13 @@ public: size_t write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - boost::asio::const_buffer buffer = buffer_sequence_adapter::first(buffers); - // A request to write 0 bytes on a handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) - { - ec = boost::system::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_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), 0, &overlapped); - if (!ok) - { - DWORD last_error = ::GetLastError(); - if (last_error != ERROR_IO_PENDING) - { - ec = boost::system::error_code(last_error, - boost::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 = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; + return do_write(impl, offset, buffer, ec); } - template - class write_op : public operation - { - public: - write_op(const ConstBufferSequence& buffers, Handler handler) - : operation(&write_op::do_complete), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - write_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - ConstBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. template @@ -416,15 +146,16 @@ public: const ConstBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef write_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, buffers, handler); + typedef win_iocp_handle_write_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(buffers, handler); start_write_op(impl, offset, buffer_sequence_adapter::first(buffers), ptr.get()); - ptr.release(); + ConstBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; } // Read some data. Returns the number of bytes received. @@ -440,129 +171,13 @@ public: size_t read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - boost::asio::mutable_buffer buffer = buffer_sequence_adapter::first(buffers); - // A request to read 0 bytes on a stream handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) - { - ec = boost::system::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_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), 0, &overlapped); - if (!ok) - { - DWORD last_error = ::GetLastError(); - if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) - { - if (last_error == ERROR_HANDLE_EOF) - { - ec = boost::asio::error::eof; - } - else - { - ec = boost::system::error_code(last_error, - boost::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 = boost::asio::error::eof; - } - else - { - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; + return do_read(impl, offset, buffer, ec); } - template - class read_op : public operation - { - public: - read_op(const MutableBufferSequence& buffers, Handler handler) - : operation(&read_op::do_complete), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - read_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_HANDLE_EOF) - { - ec = boost::asio::error::eof; - } - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - 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 @@ -580,15 +195,16 @@ public: const MutableBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef read_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, buffers, handler); + typedef win_iocp_handle_read_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(buffers, handler); start_read_op(impl, offset, buffer_sequence_adapter::first(buffers), ptr.get()); - ptr.release(); + MutableBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; } private: @@ -614,113 +230,42 @@ private: void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, Handler handler); - // Helper function to start a write operation. - void start_write_op(implementation_type& impl, boost::uint64_t offset, - const boost::asio::const_buffer& buffer, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); + // Helper class for waiting for synchronous operations to complete. + class overlapped_wrapper; - if (!is_open(impl)) - { - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - } - else if (boost::asio::buffer_size(buffer) == 0) - { - // A request to write 0 bytes on a handle is a no-op. - iocp_service_.on_completion(op); - } - else - { - DWORD bytes_transferred = 0; - op->Offset = offset & 0xFFFFFFFF; - op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::WriteFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), - &bytes_transferred, op); - DWORD last_error = ::GetLastError(); - if (!ok && last_error != ERROR_IO_PENDING - && last_error != ERROR_MORE_DATA) - { - iocp_service_.on_completion(op, last_error, bytes_transferred); - } - else - { - iocp_service_.on_pending(op); - } - } - } + // Helper function to perform a synchronous write operation. + BOOST_ASIO_DECL size_t do_write(implementation_type& impl, + boost::uint64_t offset, const boost::asio::const_buffer& buffer, + boost::system::error_code& ec); + + // Helper function to start a write operation. + BOOST_ASIO_DECL void start_write_op(implementation_type& impl, + boost::uint64_t offset, const boost::asio::const_buffer& buffer, + operation* op); + + // Helper function to perform a synchronous write operation. + BOOST_ASIO_DECL size_t do_read(implementation_type& impl, + boost::uint64_t offset, const boost::asio::mutable_buffer& buffer, + boost::system::error_code& ec); // Helper function to start a read operation. - void start_read_op(implementation_type& impl, boost::uint64_t offset, - const boost::asio::mutable_buffer& buffer, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - { - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - } - else if (boost::asio::buffer_size(buffer) == 0) - { - // A request to read 0 bytes on a handle is a no-op. - iocp_service_.on_completion(op); - } - else - { - DWORD bytes_transferred = 0; - op->Offset = offset & 0xFFFFFFFF; - op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::ReadFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), - &bytes_transferred, op); - DWORD last_error = ::GetLastError(); - if (!ok && last_error != ERROR_IO_PENDING - && last_error != ERROR_MORE_DATA) - { - iocp_service_.on_completion(op, last_error, bytes_transferred); - } - else - { - iocp_service_.on_pending(op); - } - } - } + BOOST_ASIO_DECL void start_read_op(implementation_type& impl, + boost::uint64_t offset, const boost::asio::mutable_buffer& buffer, + operation* op); // Update the ID of the thread from which cancellation is safe. - void update_cancellation_thread_id(implementation_type& impl) - { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - 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); -#else // defined(BOOST_ASIO_ENABLE_CANCELIO) - (void)impl; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - } + BOOST_ASIO_DECL void update_cancellation_thread_id(implementation_type& impl); // 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; - } - } + BOOST_ASIO_DECL void close_for_destruction(implementation_type& impl); // 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. - boost::asio::detail::mutex mutex_; + mutex mutex_; // The head of a linked list of all implementations. implementation_type* impl_list_; @@ -730,8 +275,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP diff --git a/include/boost/asio/detail/win_iocp_handle_write_op.hpp b/include/boost/asio/detail/win_iocp_handle_write_op.hpp new file mode 100644 index 00000000..971f1746 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_handle_write_op.hpp @@ -0,0 +1,99 @@ +// +// detail/win_iocp_handle_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_handle_write_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op); + + win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler handler) + : operation(&win_iocp_handle_write_op::do_complete), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_handle_write_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + ConstBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_io_service.hpp b/include/boost/asio/detail/win_iocp_io_service.hpp index 83b16bf8..e7420192 100644 --- a/include/boost/asio/detail/win_iocp_io_service.hpp +++ b/include/boost/asio/detail/win_iocp_io_service.hpp @@ -1,6 +1,6 @@ // -// win_iocp_io_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,33 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) -#include -#include -#include -#include -#include - +#include #include -#include -#include -#include -#include -#include #include #include -#include #include #include #include #include #include +#include #include +#include + +#include namespace boost { namespace asio { @@ -53,69 +44,13 @@ class win_iocp_io_service : public boost::asio::detail::service_base { public: - typedef win_iocp_operation operation; - // Constructor. - win_iocp_io_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - iocp_(), - outstanding_work_(0), - stopped_(0), - shutdown_(0), - timer_thread_(0), - timer_interrupt_issued_(false) - { - } + BOOST_ASIO_DECL win_iocp_io_service(boost::asio::io_service& io_service); - void init(size_t concurrency_hint) - { - iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, - static_cast((std::min)(concurrency_hint, DWORD(~0)))); - if (!iocp_.handle) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "iocp"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL void init(size_t concurrency_hint); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - ::InterlockedExchange(&shutdown_, 1); - - while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) - { - op_queue ops; - timer_queues_.get_all_timers(ops); - ops.push(completed_ops_); - if (!ops.empty()) - { - while (operation* op = ops.front()) - { - ops.pop(); - ::InterlockedDecrement(&outstanding_work_); - op->destroy(); - } - } - else - { - DWORD bytes_transferred = 0; - dword_ptr_t completion_key = 0; - LPOVERLAPPED overlapped = 0; - ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, max_timeout); - if (overlapped) - { - ::InterlockedDecrement(&outstanding_work_); - static_cast(overlapped)->destroy(); - } - } - } - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task. Nothing to do here. void init_task() @@ -123,106 +58,23 @@ public: } // Register a handle with the IO completion port. - boost::system::error_code register_handle( - HANDLE handle, boost::system::error_code& ec) - { - if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - else - { - ec = boost::system::error_code(); - } - return ec; - } + BOOST_ASIO_DECL boost::system::error_code register_handle( + HANDLE handle, boost::system::error_code& ec); // Run the event loop until stopped or no more work. - size_t run(boost::system::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - call_stack::context ctx(this); - - size_t n = 0; - while (do_one(true, ec)) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } + BOOST_ASIO_DECL size_t run(boost::system::error_code& ec); // Run until stopped or one operation is performed. - size_t run_one(boost::system::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - call_stack::context ctx(this); - - return do_one(true, ec); - } + BOOST_ASIO_DECL size_t run_one(boost::system::error_code& ec); // Poll for operations without blocking. - size_t poll(boost::system::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - call_stack::context ctx(this); - - size_t n = 0; - while (do_one(false, ec)) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } + BOOST_ASIO_DECL size_t poll(boost::system::error_code& ec); // Poll for one operation without blocking. - size_t poll_one(boost::system::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - call_stack::context ctx(this); - - return do_one(false, ec); - } + BOOST_ASIO_DECL size_t poll_one(boost::system::error_code& ec); // Stop the event processing loop. - void stop() - { - if (::InterlockedExchange(&stopped_, 1) == 0) - { - if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "pqcs"); - boost::throw_exception(e); - } - } - } + BOOST_ASIO_DECL void stop(); // Reset in preparation for a subsequent run invocation. void reset() @@ -245,34 +97,15 @@ public: // Request invocation of the given handler. template - void dispatch(Handler handler) - { - if (call_stack::contains(this)) - { - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - else - post(handler); - } + void dispatch(Handler handler); // Request invocation of the given handler and return immediately. template - void post(Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef completion_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - post_immediate_completion(ptr.get()); - ptr.release(); - } + void post(Handler handler); // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. - void post_immediate_completion(operation* op) + void post_immediate_completion(win_iocp_operation* op) { work_started(); post_deferred_completion(op); @@ -280,171 +113,48 @@ public: // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operation. - void post_deferred_completion(operation* op) - { - // Flag the operation as ready. - op->ready_ = 1; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } + BOOST_ASIO_DECL void post_deferred_completion(win_iocp_operation* op); // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operations. - void post_deferred_completions(op_queue& ops) - { - while (operation* op = ops.front()) - { - ops.pop(); - - // Flag the operation as ready. - op->ready_ = 1; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - completed_ops_.push(ops); - } - } - } + BOOST_ASIO_DECL void post_deferred_completions( + op_queue& ops); // Called after starting an overlapped I/O operation that did not complete // immediately. The caller must have already called work_started() prior to // starting the operation. - void on_pending(operation* op) - { - if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) - { - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } - } + BOOST_ASIO_DECL void on_pending(win_iocp_operation* op); // Called after starting an overlapped I/O operation that completed // immediately. The caller must have already called work_started() prior to // starting the operation. - void on_completion(operation* op, - DWORD last_error = 0, DWORD bytes_transferred = 0) - { - // Flag that the operation is ready for invocation. - op->ready_ = 1; - - // Store results in the OVERLAPPED structure. - op->Internal = reinterpret_cast( - &boost::asio::error::get_system_category()); - op->Offset = last_error; - op->OffsetHigh = bytes_transferred; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } + BOOST_ASIO_DECL void on_completion(win_iocp_operation* op, + DWORD last_error = 0, DWORD bytes_transferred = 0); // Called after starting an overlapped I/O operation that completed // immediately. The caller must have already called work_started() prior to // starting the operation. - void on_completion(operation* op, - const boost::system::error_code& ec, DWORD bytes_transferred = 0) - { - // Flag that the operation is ready for invocation. - op->ready_ = 1; - - // Store results in the OVERLAPPED structure. - op->Internal = reinterpret_cast(&ec.category()); - op->Offset = ec.value(); - op->OffsetHigh = bytes_transferred; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } + BOOST_ASIO_DECL void on_completion(win_iocp_operation* op, + const boost::system::error_code& ec, DWORD bytes_transferred = 0); // Add a new timer queue to the service. template - void add_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& timer_queue); // Remove a timer queue from the service. template - void remove_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - // If the service has been shut down we silently discard the timer. - if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) - return; - - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - bool interrupt = timer_queue.enqueue_timer(time, op, token); - work_started(); - if (interrupt && !timer_interrupt_issued_) - { - timer_interrupt_issued_ = true; - lock.unlock(); - ::PostQueuedCompletionStatus(iocp_.handle, - 0, steal_timer_dispatching, 0); - } - } + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer associated with the given token. Returns the number of // handlers that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - // If the service has been shut down we silently ignore the cancellation. - if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) - return 0; - - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - post_deferred_completions(ops); - if (n > 0 && !timer_interrupt_issued_) - { - timer_interrupt_issued_ = true; - lock.unlock(); - ::PostQueuedCompletionStatus(iocp_.handle, - 0, steal_timer_dispatching, 0); - } - return n; - } + std::size_t cancel_timer(timer_queue& timer_queue, void* token); private: #if defined(WINVER) && (WINVER < 0x0500) @@ -458,181 +168,30 @@ private: // Dequeues at most one operation from the I/O completion port, and then // executes it. Returns the number of operations that were dequeued (i.e. // either 0 or 1). - size_t do_one(bool block, boost::system::error_code& ec) - { - long this_thread_id = static_cast(::GetCurrentThreadId()); + BOOST_ASIO_DECL size_t do_one(bool block, boost::system::error_code& ec); - for (;;) - { - // Try to acquire responsibility for dispatching timers. - bool dispatching_timers = (::InterlockedCompareExchange( - &timer_thread_, this_thread_id, 0) == 0); + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); - // Calculate timeout for GetQueuedCompletionStatus call. - DWORD timeout = max_timeout; - if (dispatching_timers) - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_interrupt_issued_ = false; - timeout = get_timeout(); - } + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); - // Get the next operation from the queue. - DWORD bytes_transferred = 0; - dword_ptr_t completion_key = 0; - LPOVERLAPPED overlapped = 0; - ::SetLastError(0); - BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, block ? timeout : 0); - DWORD last_error = ::GetLastError(); - - // Dispatch any pending timers. - if (dispatching_timers) - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - op_queue ops; - ops.push(completed_ops_); - timer_queues_.get_ready_timers(ops); - post_deferred_completions(ops); - } - - if (!ok && overlapped == 0) - { - if (block && last_error == WAIT_TIMEOUT) - { - // Relinquish responsibility for dispatching timers. - if (dispatching_timers) - { - ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); - } - - continue; - } - - // Transfer responsibility for dispatching timers to another thread. - if (dispatching_timers && ::InterlockedCompareExchange( - &timer_thread_, 0, this_thread_id) == this_thread_id) - { - ::PostQueuedCompletionStatus(iocp_.handle, - 0, transfer_timer_dispatching, 0); - } - - ec = boost::system::error_code(); - return 0; - } - else if (overlapped) - { - operation* op = static_cast(overlapped); - boost::system::error_code result_ec(last_error, - boost::asio::error::get_system_category()); - - // Transfer responsibility for dispatching timers to another thread. - if (dispatching_timers && ::InterlockedCompareExchange( - &timer_thread_, 0, this_thread_id) == this_thread_id) - { - ::PostQueuedCompletionStatus(iocp_.handle, - 0, transfer_timer_dispatching, 0); - } - - // We may have been passed the last_error and bytes_transferred in the - // OVERLAPPED structure itself. - if (completion_key == overlapped_contains_result) - { - result_ec = boost::system::error_code(static_cast(op->Offset), - *reinterpret_cast(op->Internal)); - bytes_transferred = op->OffsetHigh; - } - - // Otherwise ensure any result has been saved into the OVERLAPPED - // structure. - else - { - op->Internal = reinterpret_cast(&result_ec.category()); - op->Offset = result_ec.value(); - op->OffsetHigh = bytes_transferred; - } - - // Dispatch the operation only if ready. The operation may not be ready - // if the initiating function (e.g. a call to WSARecv) has not yet - // returned. This is because the initiating function still wants access - // to the operation's OVERLAPPED structure. - if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) - { - // Ensure the count of outstanding work is decremented on block exit. - work_finished_on_block_exit on_exit = { this }; - (void)on_exit; - - op->complete(*this, result_ec, bytes_transferred); - ec = boost::system::error_code(); - return 1; - } - } - else if (completion_key == transfer_timer_dispatching) - { - // Woken up to try to acquire responsibility for dispatching timers. - ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); - } - else if (completion_key == steal_timer_dispatching) - { - // Woken up to steal responsibility for dispatching timers. - ::InterlockedExchange(&timer_thread_, 0); - } - else - { - // 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) - { - // Wake up next thread that is blocked on GetQueuedCompletionStatus. - if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) - { - last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - - ec = boost::system::error_code(); - return 0; - } - } - } - } - - // Get the timeout value for the GetQueuedCompletionStatus call. The timeout - // value is returned as a number of milliseconds. We will wait no longer than - // 1000 milliseconds. - DWORD get_timeout() - { - return timer_queues_.wait_duration_msec(max_timeout); - } + // Called to recalculate and update the timeout. + BOOST_ASIO_DECL void update_timeout(); // Helper class to call work_finished() on block exit. - struct work_finished_on_block_exit - { - ~work_finished_on_block_exit() - { - io_service_->work_finished(); - } + struct work_finished_on_block_exit; - win_iocp_io_service* io_service_; + // Helper class for managing a HANDLE. + struct auto_handle + { + HANDLE handle; + auto_handle() : handle(0) {} + ~auto_handle() { if (handle) ::CloseHandle(handle); } }; // The IO completion port used for queueing operations. - struct iocp_holder - { - HANDLE handle; - iocp_holder() : handle(0) {} - ~iocp_holder() { if (handle) ::CloseHandle(handle); } - } iocp_; + auto_handle iocp_; // The count of unfinished work. long outstanding_work_; @@ -645,45 +204,62 @@ private: enum { - // Maximum GetQueuedCompletionStatus timeout, in milliseconds. - max_timeout = 500, + // Timeout to use with GetQueuedCompletionStatus. Some versions of windows + // have a "bug" where a call to GetQueuedCompletionStatus can appear stuck + // even though there are events waiting on the queue. Using a timeout helps + // to work around the issue. + gqcs_timeout = 500, - // Completion key value to indicate that responsibility for dispatching - // timers is being cooperatively transferred from one thread to another. - transfer_timer_dispatching = 1, + // Maximum waitable timer timeout, in milliseconds. + max_timeout_msec = 5 * 60 * 1000, - // Completion key value to indicate that responsibility for dispatching - // timers should be stolen from another thread. - steal_timer_dispatching = 2, + // Maximum waitable timer timeout, in microseconds. + max_timeout_usec = max_timeout_msec * 1000, + + // Completion key value used to wake up a thread to dispatch timers or + // completed operations. + wake_for_dispatch = 1, // Completion key value to indicate that an operation has posted with the // original last_error and bytes_transferred values stored in the fields of // the OVERLAPPED structure. - overlapped_contains_result = 3 + overlapped_contains_result = 2 }; - // The thread that's currently in charge of dispatching timers. - long timer_thread_; + // Function object for processing timeouts in a background thread. + struct timer_thread_function; + friend struct timer_thread_function; - // Mutex for protecting access to the timer queues. - mutex timer_mutex_; + // Background thread used for processing timeouts. + boost::scoped_ptr timer_thread_; - // Whether a thread has been interrupted to process a new timeout. - bool timer_interrupt_issued_; + // A waitable timer object used for waiting for timeouts. + auto_handle waitable_timer_; + + // Non-zero if timers or completed operations need to be dispatched. + long dispatch_required_; + + // Mutex for protecting access to the timer queues and completed operations. + mutex dispatch_mutex_; // The timer queues. timer_queue_set timer_queues_; // The operations that are ready to dispatch. - op_queue completed_ops_; + op_queue completed_ops_; }; } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP diff --git a/include/boost/asio/detail/win_iocp_io_service_fwd.hpp b/include/boost/asio/detail/win_iocp_io_service_fwd.hpp index be413ec9..1357603b 100644 --- a/include/boost/asio/detail/win_iocp_io_service_fwd.hpp +++ b/include/boost/asio/detail/win_iocp_io_service_fwd.hpp @@ -1,6 +1,6 @@ // -// win_iocp_io_service_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_io_service_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,22 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include - -#include - -// This service is only supported on Win32 (NT4 and later). -#if !defined(BOOST_ASIO_DISABLE_IOCP) -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) -#if !defined(UNDER_CE) - -// Define this to indicate that IOCP is supported on the target platform. -#define BOOST_ASIO_HAS_IOCP 1 +#if defined(BOOST_ASIO_HAS_IOCP) namespace boost { namespace asio { @@ -43,11 +30,6 @@ class win_iocp_overlapped_ptr; } // namespace asio } // namespace boost -#endif // !defined(UNDER_CE) -#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#endif // !defined(BOOST_ASIO_DISABLE_IOCP) - -#include +#endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP diff --git a/include/boost/asio/detail/win_iocp_null_buffers_op.hpp b/include/boost/asio/detail/win_iocp_null_buffers_op.hpp new file mode 100644 index 00000000..ed1c28f8 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_null_buffers_op.hpp @@ -0,0 +1,114 @@ +// +// detail/win_iocp_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_null_buffers_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op); + + win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token, + Handler handler) + : reactor_op(&win_iocp_null_buffers_op::do_perform, + &win_iocp_null_buffers_op::do_complete), + cancel_token_(cancel_token), + handler_(handler) + { + } + + static bool do_perform(reactor_op*) + { + return true; + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_null_buffers_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // The reactor may have stored a result in the operation object. + if (o->ec_) + ec = o->ec_; + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_operation.hpp b/include/boost/asio/detail/win_iocp_operation.hpp index d7d5723b..c9b30412 100644 --- a/include/boost/asio/detail/win_iocp_operation.hpp +++ b/include/boost/asio/detail/win_iocp_operation.hpp @@ -1,6 +1,6 @@ // -// win_iocp_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) #include +#include +#include + +#include namespace boost { namespace asio { @@ -83,9 +85,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - -#include #include +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP diff --git a/include/boost/asio/detail/win_iocp_overlapped_op.hpp b/include/boost/asio/detail/win_iocp_overlapped_op.hpp new file mode 100644 index 00000000..911449d3 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_overlapped_op.hpp @@ -0,0 +1,86 @@ +// +// detail/win_iocp_overlapped_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_overlapped_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op); + + win_iocp_overlapped_op(Handler handler) + : operation(&win_iocp_overlapped_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_overlapped_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp index 082a5b1b..5589c110 100644 --- a/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp +++ b/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp @@ -1,6 +1,6 @@ // -// win_iocp_overlapped_ptr.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) -#include +#include +#include +#include #include +#include #include -#include + +#include namespace boost { namespace asio { @@ -75,13 +77,15 @@ public: template void reset(boost::asio::io_service& io_service, Handler handler) { - typedef overlapped_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef win_iocp_overlapped_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); io_service.impl_.work_started(); reset(); - ptr_ = ptr.release(); + ptr_ = p.p; + p.v = p.p = 0; iocp_service_ = &io_service.impl_; } @@ -123,44 +127,6 @@ public: } private: - template - struct overlapped_op : public win_iocp_operation - { - overlapped_op(Handler handler) - : win_iocp_operation(&overlapped_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - overlapped_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - win_iocp_operation* ptr_; win_iocp_io_service* iocp_service_; }; @@ -169,8 +135,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP diff --git a/include/boost/asio/detail/win_iocp_serial_port_service.hpp b/include/boost/asio/detail/win_iocp_serial_port_service.hpp index 288287c2..a0caa691 100644 --- a/include/boost/asio/detail/win_iocp_serial_port_service.hpp +++ b/include/boost/asio/detail/win_iocp_serial_port_service.hpp @@ -1,6 +1,6 @@ // -// win_iocp_serial_port_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) @@ -16,21 +16,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) -#include -#include #include -#include - -#include - -#if defined(BOOST_ASIO_HAS_IOCP) - #include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -39,133 +35,56 @@ namespace detail { class win_iocp_serial_port_service { public: - // The native type of a stream handle. + // The native type of a serial port. typedef win_iocp_handle_service::native_type native_type; - // The implementation type of the stream handle. + // The implementation type of the serial port. typedef win_iocp_handle_service::implementation_type implementation_type; - win_iocp_serial_port_service(boost::asio::io_service& io_service) - : handle_service_(io_service) - { - } + // Constructor. + BOOST_ASIO_DECL win_iocp_serial_port_service( + boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } + BOOST_ASIO_DECL void shutdown_service(); - // Construct a new handle implementation. + // Construct a new serial port implementation. void construct(implementation_type& impl) { handle_service_.construct(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. void destroy(implementation_type& impl) { handle_service_.destroy(impl); } // Open the serial port using the specified device name. - boost::system::error_code open(implementation_type& impl, - const std::string& device, boost::system::error_code& ec) - { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } + BOOST_ASIO_DECL boost::system::error_code open(implementation_type& impl, + const std::string& device, boost::system::error_code& 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 = boost::system::error_code(last_error, - boost::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 = boost::system::error_code(last_error, - boost::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 = boost::system::error_code(last_error, - boost::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 = boost::system::error_code(last_error, - boost::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. + // Assign a native handle to a serial port implementation. boost::system::error_code assign(implementation_type& impl, const native_type& native_handle, boost::system::error_code& ec) { return handle_service_.assign(impl, native_handle, ec); } - // Determine whether the handle is open. + // Determine whether the serial port is open. bool is_open(const implementation_type& impl) const { return handle_service_.is_open(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. boost::system::error_code close(implementation_type& impl, boost::system::error_code& ec) { return handle_service_.close(impl, ec); } - // Get the native handle representation. + // Get the native serial port representation. native_type native(implementation_type& impl) { return handle_service_.native(impl); @@ -183,32 +102,9 @@ public: boost::system::error_code set_option(implementation_type& impl, const SettableSerialPortOption& option, boost::system::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 = boost::system::error_code(last_error, - boost::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 = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - ec = boost::system::error_code(); - return ec; + return do_set_option(impl, + &win_iocp_serial_port_service::store_option, + &option, ec); } // Get an option from the serial port. @@ -216,20 +112,9 @@ public: boost::system::error_code get_option(const implementation_type& impl, GettableSerialPortOption& option, boost::system::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 = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - return option.load(dcb, ec); + return do_get_option(impl, + &win_iocp_serial_port_service::load_option, + &option, ec); } // Send a break sequence to the serial port. @@ -275,6 +160,41 @@ public: } private: + // Function pointer type for storing a serial port option. + typedef boost::system::error_code (*store_function_type)( + const void*, ::DCB&, boost::system::error_code&); + + // Helper function template to store a serial port option. + template + static boost::system::error_code store_option(const void* option, + ::DCB& storage, boost::system::error_code& ec) + { + return static_cast(option)->store( + storage, ec); + } + + // Helper function to set a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, boost::system::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef boost::system::error_code (*load_function_type)( + void*, const ::DCB&, boost::system::error_code&); + + // Helper function template to load a serial port option. + template + static boost::system::error_code load_option(void* option, + const ::DCB& storage, boost::system::error_code& ec) + { + return static_cast(option)->load(storage, ec); + } + + // Helper function to get a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, boost::system::error_code& ec) const; + // The implementation used for initiating asynchronous operations. win_iocp_handle_service handle_service_; }; @@ -283,8 +203,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_accept_op.hpp b/include/boost/asio/detail/win_iocp_socket_accept_op.hpp new file mode 100644 index 00000000..89dff0c6 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_accept_op.hpp @@ -0,0 +1,160 @@ +// +// detail/win_iocp_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_accept_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op); + + win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service, + socket_type socket, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler handler) + : operation(&win_iocp_socket_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(handler) + { + } + + socket_holder& new_socket() + { + return new_socket_; + } + + void* output_buffer() + { + return output_buffer_; + } + + DWORD address_length() + { + return sizeof(sockaddr_storage_type) + 16; + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + win_iocp_socket_accept_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + if (owner) + { + typename Protocol::endpoint peer_endpoint; + std::size_t addr_len = peer_endpoint.capacity(); + socket_ops::complete_iocp_accept(o->socket_, + o->output_buffer(), o->address_length(), + peer_endpoint.data(), &addr_len, + o->new_socket_.get(), ec); + + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == boost::asio::error::connection_aborted + && !o->enable_connection_aborted_) + { + o->reset(); + o->socket_service_.restart_accept_op(o->socket_, + o->new_socket_, o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), + o->output_buffer(), o->address_length(), o); + p.v = p.p = 0; + return; + } + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) + { + o->peer_.assign(o->protocol_, + typename Socket::native_type( + o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); + } + + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder1 + handler(o->handler_, ec); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; + bool enable_connection_aborted_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_recv_op.hpp b/include/boost/asio/detail/win_iocp_socket_recv_op.hpp new file mode 100644 index 00000000..98d7e99e --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_recv_op.hpp @@ -0,0 +1,110 @@ +// +// detail/win_iocp_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_recv_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op); + + win_iocp_socket_recv_op(socket_ops::state_type state, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler handler) + : operation(&win_iocp_socket_recv_op::do_complete), + state_(state), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_socket_recv_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recv(o->state_, o->cancel_token_, + buffer_sequence_adapter::all_empty(o->buffers_), + ec, bytes_transferred); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + socket_ops::state_type state_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp b/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp new file mode 100644 index 00000000..eca34df7 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp @@ -0,0 +1,118 @@ +// +// detail/win_iocp_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_recvfrom_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op); + + win_iocp_socket_recvfrom_op(Endpoint& endpoint, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler handler) + : operation(&win_iocp_socket_recvfrom_op::do_complete), + endpoint_(endpoint), + endpoint_size_(static_cast(endpoint.capacity())), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(handler) + { + } + + int& endpoint_size() + { + return endpoint_size_; + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_socket_recvfrom_op* o( + static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec); + + // Record the size of the endpoint returned by the operation. + o->endpoint_.resize(o->endpoint_size_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Endpoint& endpoint_; + int endpoint_size_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_send_op.hpp b/include/boost/asio/detail/win_iocp_socket_send_op.hpp new file mode 100644 index 00000000..2dcb4af4 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_send_op.hpp @@ -0,0 +1,104 @@ +// +// detail/win_iocp_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_send_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op); + + win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token, + const ConstBufferSequence& buffers, Handler handler) + : operation(&win_iocp_socket_send_op::do_complete), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_socket_send_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_send(o->cancel_token_, ec); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + ConstBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_service.hpp b/include/boost/asio/detail/win_iocp_socket_service.hpp index 5d545a87..6f1f2bd4 100644 --- a/include/boost/asio/detail/win_iocp_socket_service.hpp +++ b/include/boost/asio/detail/win_iocp_socket_service.hpp @@ -1,6 +1,6 @@ // -// win_iocp_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) -#include #include -#include -#include -#include -#include - +#include #include #include #include @@ -37,21 +30,28 @@ #include #include #include -#include #include +#include #include #include #include #include #include #include +#include +#include +#include +#include +#include + +#include namespace boost { namespace asio { namespace detail { template -class win_iocp_socket_service +class win_iocp_socket_service : public win_iocp_socket_service_base { public: // The protocol type. @@ -60,10 +60,6 @@ public: // The endpoint type. typedef typename Protocol::endpoint endpoint_type; - struct noop_deleter { void operator()(void*) {} }; - typedef boost::shared_ptr shared_cancel_token_type; - typedef boost::weak_ptr weak_cancel_token_type; - // The native type of a socket. class native_type { @@ -93,11 +89,6 @@ public: return socket_; } - HANDLE as_handle() const - { - return reinterpret_cast(socket_); - } - bool have_remote_endpoint() const { return have_remote_endpoint_; @@ -115,148 +106,44 @@ public: }; // The implementation type of the socket. - class implementation_type + struct implementation_type : + win_iocp_socket_service_base::base_implementation_type { - public: // Default constructor. implementation_type() - : socket_(invalid_socket), - flags_(0), - cancel_token_(), - protocol_(endpoint_type().protocol()), - next_(0), - prev_(0) + : protocol_(endpoint_type().protocol()), + have_remote_endpoint_(false), + remote_endpoint_() { } - private: - // Only this service will have access to the internal values. - friend class win_iocp_socket_service; - - // The native socket representation. - native_type socket_; - - enum - { - enable_connection_aborted = 1, // User wants connection_aborted errors. - close_might_block = 2, // User set linger option for blocking close. - user_set_non_blocking = 4 // The user wants a non-blocking socket. - }; - - // Flags indicating the current state of the socket. - unsigned char flags_; - - // We use a shared pointer as a cancellation token here to work around the - // broken Windows support for cancellation. MSDN says that when you call - // closesocket any outstanding WSARecv or WSASend operations will complete - // with the error ERROR_OPERATION_ABORTED. In practice they complete with - // ERROR_NETNAME_DELETED, which means you can't tell the difference between - // a local cancellation and the socket being hard-closed by the peer. - shared_cancel_token_type cancel_token_; - // The protocol associated with the socket. protocol_type protocol_; - // Per-descriptor data used by the reactor. - reactor::per_descriptor_data reactor_data_; + // Whether we have a cached remote endpoint. + bool have_remote_endpoint_; -#if defined(BOOST_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. - // ~0 means asynchronous operations have been started from more than one - // thread, and cancellation is not supported for the socket. - DWORD safe_cancellation_thread_id_; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - - // Pointers to adjacent socket implementations in linked list. - implementation_type* next_; - implementation_type* prev_; + // A cached remote endpoint. + endpoint_type remote_endpoint_; }; // Constructor. win_iocp_socket_service(boost::asio::io_service& io_service) - : io_service_(io_service), - iocp_service_(use_service(io_service)), - reactor_(0), - mutex_(), - impl_list_(0) + : win_iocp_socket_service_base(io_service) { } - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - // Close all implementations, causing all operations to complete. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - implementation_type* impl = impl_list_; - while (impl) - { - boost::system::error_code ignored_ec; - close_for_destruction(*impl); - impl = impl->next_; - } - } - - // Construct a new socket implementation. - void construct(implementation_type& impl) - { - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - impl.safe_cancellation_thread_id_ = 0; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - - // Insert implementation into linked list of all implementations. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - impl.next_ = impl_list_; - impl.prev_ = 0; - if (impl_list_) - impl_list_->prev_ = &impl; - impl_list_ = &impl; - } - - // Destroy a socket implementation. - void destroy(implementation_type& impl) - { - close_for_destruction(impl); - - // Remove implementation from linked list of all implementations. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (impl_list_ == &impl) - impl_list_ = impl.next_; - if (impl.prev_) - impl.prev_->next_ = impl.next_; - if (impl.next_) - impl.next_->prev_= impl.prev_; - impl.next_ = 0; - impl.prev_ = 0; - } - // Open a new socket implementation. boost::system::error_code open(implementation_type& impl, const protocol_type& protocol, boost::system::error_code& ec) { - if (is_open(impl)) + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) { - ec = boost::asio::error::already_open; - return ec; + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = false; + impl.remote_endpoint_ = endpoint_type(); } - - socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(), - protocol.protocol(), ec)); - if (sock.get() == invalid_socket) - return ec; - - HANDLE sock_as_handle = reinterpret_cast(sock.get()); - if (iocp_service_.register_handle(sock_as_handle, ec)) - return ec; - - impl.socket_ = sock.release(); - impl.flags_ = 0; - impl.cancel_token_.reset(static_cast(0), noop_deleter()); - impl.protocol_ = protocol; - ec = boost::system::error_code(); return ec; } @@ -265,247 +152,40 @@ public: const protocol_type& protocol, const native_type& native_socket, boost::system::error_code& ec) { - if (is_open(impl)) + if (!do_assign(impl, protocol.type(), native_socket, ec)) { - ec = boost::asio::error::already_open; - return ec; + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = native_socket.have_remote_endpoint(); + impl.remote_endpoint_ = native_socket.remote_endpoint(); } - - if (iocp_service_.register_handle(native_socket.as_handle(), ec)) - return ec; - - impl.socket_ = native_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(static_cast(0), noop_deleter()); - impl.protocol_ = protocol; - ec = boost::system::error_code(); - return ec; - } - - // Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return impl.socket_ != invalid_socket; - } - - // Destroy a socket implementation. - boost::system::error_code close(implementation_type& impl, - boost::system::error_code& ec) - { - if (is_open(impl)) - { - // Check if the reactor was created, in which case we need to close the - // socket on the reactor as well to cancel any operations that might be - // running there. - reactor* r = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (r) - r->close_descriptor(impl.socket_, impl.reactor_data_); - - if (socket_ops::close(impl.socket_, ec) == socket_error_retval) - return ec; - - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - impl.safe_cancellation_thread_id_ = 0; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - } - - ec = boost::system::error_code(); return ec; } // Get the native socket representation. native_type native(implementation_type& impl) { - return impl.socket_; - } - - // Cancel all operations associated with the socket. - boost::system::error_code cancel(implementation_type& impl, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - 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; - socket_type sock = impl.socket_; - HANDLE sock_as_handle = reinterpret_cast(sock); - if (!cancel_io_ex(sock_as_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 = boost::system::error_code(); - } - else - { - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - } - else - { - ec = boost::system::error_code(); - } - } -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - else if (impl.safe_cancellation_thread_id_ == 0) - { - // No operations have been started, so there's nothing to cancel. - ec = boost::system::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. - socket_type sock = impl.socket_; - HANDLE sock_as_handle = reinterpret_cast(sock); - if (!::CancelIo(sock_as_handle)) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - else - { - ec = boost::system::error_code(); - } - } - else - { - // Asynchronous operations have been started from more than one thread, - // so cancellation is not safe. - ec = boost::asio::error::operation_not_supported; - } -#else // defined(BOOST_ASIO_ENABLE_CANCELIO) - else - { - // Cancellation is not supported as CancelIo may not be used. - ec = boost::asio::error::operation_not_supported; - } -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - - return ec; - } - - // Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - boost::system::error_code& ec) const - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return false; - } - - boost::asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec); - return ec ? false : value != 0; - } - - // Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - boost::system::error_code& ec) const - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - boost::asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec); - return ec ? static_cast(0) : static_cast(value); + if (impl.have_remote_endpoint_) + return native_type(impl.socket_, impl.remote_endpoint_); + return native_type(impl.socket_); } // Bind the socket to the specified local endpoint. boost::system::error_code bind(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); return ec; } - // Place the socket into the state where it will listen for new connections. - boost::system::error_code listen(implementation_type& impl, int backlog, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::listen(impl.socket_, backlog, ec); - return ec; - } - // Set a socket option. template boost::system::error_code set_option(implementation_type& impl, const Option& option, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = boost::asio::error::invalid_argument; - } - else - { - if (*reinterpret_cast(option.data(impl.protocol_))) - impl.flags_ |= implementation_type::enable_connection_aborted; - else - impl.flags_ &= ~implementation_type::enable_connection_aborted; - ec = boost::system::error_code(); - } - return ec; - } - else - { - if (option.level(impl.protocol_) == SOL_SOCKET - && option.name(impl.protocol_) == SO_LINGER) - { - const ::linger* linger_option = - reinterpret_cast(option.data(impl.protocol_)); - if (linger_option->l_onoff != 0 && linger_option->l_linger != 0) - impl.flags_ |= implementation_type::close_might_block; - else - impl.flags_ &= ~implementation_type::close_might_block; - } - - socket_ops::setsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), option.size(impl.protocol_), ec); - return ec; - } + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; } // Set a socket option. @@ -513,65 +193,12 @@ public: boost::system::error_code get_option(const implementation_type& impl, Option& option, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = boost::asio::error::invalid_argument; - } - else - { - int* target = reinterpret_cast(option.data(impl.protocol_)); - if (impl.flags_ & implementation_type::enable_connection_aborted) - *target = 1; - else - *target = 0; - option.resize(impl.protocol_, sizeof(int)); - ec = boost::system::error_code(); - } - return ec; - } - else - { - size_t size = option.size(impl.protocol_); - socket_ops::getsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), &size, ec); - if (!ec) - option.resize(impl.protocol_, size); - return ec; - } - } - - // Perform an IO control command on the socket. - template - boost::system::error_code io_control(implementation_type& impl, - IO_Control_Command& command, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::ioctl(impl.socket_, command.name(), - static_cast(command.data()), ec); - - if (!ec && command.name() == static_cast(FIONBIO)) - { - if (*static_cast(command.data())) - impl.flags_ |= implementation_type::user_set_non_blocking; - else - impl.flags_ &= ~implementation_type::user_set_non_blocking; - } - + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); return ec; } @@ -579,12 +206,6 @@ public: endpoint_type local_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return endpoint_type(); - } - endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) @@ -597,210 +218,13 @@ public: endpoint_type remote_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; + endpoint_type endpoint = impl.remote_endpoint_; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, endpoint.data(), + &addr_len, impl.have_remote_endpoint_, ec)) return endpoint_type(); - } - - if (impl.socket_.have_remote_endpoint()) - { - // Check if socket is still connected. - DWORD connect_time = 0; - size_t connect_time_len = sizeof(connect_time); - if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME, - &connect_time, &connect_time_len, ec) == socket_error_retval) - { - return endpoint_type(); - } - if (connect_time == 0xFFFFFFFF) - { - ec = boost::asio::error::not_connected; - return endpoint_type(); - } - - ec = boost::system::error_code(); - return impl.socket_.remote_endpoint(); - } - else - { - endpoint_type endpoint; - std::size_t addr_len = endpoint.capacity(); - if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) - return endpoint_type(); - endpoint.resize(addr_len); - return endpoint; - } - } - - /// Disable sends or receives on the socket. - boost::system::error_code shutdown(implementation_type& impl, - socket_base::shutdown_type what, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::shutdown(impl.socket_, what, ec); - return ec; - } - - // Send the given data to the peer. Returns the number of bytes sent. - template - size_t send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, bufs.buffers(), - bufs.count(), &bytes_transferred, flags, 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_NETNAME_DELETED) - last_error = WSAECONNRESET; - else if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; - } - - // Wait until data can be sent without blocking. - size_t send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, ec); - - return 0; - } - - template - class send_op : public operation - { - public: - send_op(weak_cancel_token_type cancel_token, - const ConstBufferSequence& buffers, Handler handler) - : operation(&send_op::do_complete), - cancel_token_(cancel_token), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - send_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_NETNAME_DELETED) - { - if (o->cancel_token_.expired()) - ec = boost::asio::error::operation_aborted; - else - ec = boost::asio::error::connection_reset; - } - else if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - weak_cancel_token_type cancel_token_; - ConstBufferSequence buffers_; - Handler handler_; - }; - - // Start an asynchronous send. The data being sent must be valid for the - // lifetime of the asynchronous operation. - template - void async_send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef send_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl.cancel_token_, buffers, handler); - - buffer_sequence_adapter bufs(buffers); - - start_send_op(impl, bufs.buffers(), bufs.count(), flags, - impl.protocol_.type() == SOCK_STREAM && bufs.all_empty(), ptr.get()); - ptr.release(); - } - - // Start an asynchronous wait until data can be sent without blocking. - template - void async_send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - start_reactor_op(impl, reactor::write_op, ptr.get()); - ptr.release(); + endpoint.resize(addr_len); + return endpoint; } // Send a datagram to the specified endpoint. Returns the number of bytes @@ -810,107 +234,25 @@ public: const endpoint_type& destination, socket_base::message_flags flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, bufs.buffers(), bufs.count(), - &bytes_transferred, flags, destination.data(), - static_cast(destination.size()), 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); } // 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&, + const endpoint_type&, socket_base::message_flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } - template - class send_to_op : public operation - { - public: - send_to_op(weak_cancel_token_type cancel_token, - const ConstBufferSequence& buffers, Handler handler) - : operation(&send_to_op::do_complete), - cancel_token_(cancel_token), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - send_to_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - weak_cancel_token_type cancel_token_; - ConstBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template @@ -919,233 +261,35 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef send_to_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl.cancel_token_, buffers, handler); + typedef win_iocp_socket_send_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler); buffer_sequence_adapter bufs(buffers); - start_send_to_op(impl, bufs.buffers(), - bufs.count(), destination, flags, ptr.get()); - ptr.release(); + start_send_to_op(impl, bufs.buffers(), bufs.count(), + destination.data(), static_cast(destination.size()), + flags, p.p); + p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template void async_send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, Handler handler) + const endpoint_type&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); - start_reactor_op(impl, reactor::write_op, ptr.get()); - ptr.release(); - } - - // Receive some data from the peer. Returns the number of bytes received. - template - size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, bufs.buffers(), - bufs.count(), &bytes_transferred, &recv_flags, 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_NETNAME_DELETED) - last_error = WSAECONNRESET; - else if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = boost::asio::error::eof; - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; - } - - // Wait until data can be received without blocking. - size_t receive(implementation_type& impl, const null_buffers&, - socket_base::message_flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, ec); - - return 0; - } - - template - class receive_op : public operation - { - public: - receive_op(int protocol_type, weak_cancel_token_type cancel_token, - const MutableBufferSequence& buffers, Handler handler) - : operation(&receive_op::do_complete), - protocol_type_(protocol_type), - cancel_token_(cancel_token), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - receive_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_NETNAME_DELETED) - { - if (o->cancel_token_.expired()) - ec = boost::asio::error::operation_aborted; - else - ec = boost::asio::error::connection_reset; - } - else if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } - - // Check for connection closed. - else if (!ec && bytes_transferred == 0 - && o->protocol_type_ == SOCK_STREAM - && !buffer_sequence_adapter::all_empty(o->buffers_) - && !boost::is_same::value) - { - ec = boost::asio::error::eof; - } - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - int protocol_type_; - weak_cancel_token_type cancel_token_; - MutableBufferSequence buffers_; - Handler handler_; - }; - - // Start an asynchronous receive. The buffer for the data being received - // must be valid for the lifetime of the asynchronous operation. - template - void async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef receive_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, protocol_type, - impl.cancel_token_, buffers, handler); - - buffer_sequence_adapter bufs(buffers); - - start_receive_op(impl, bufs.buffers(), bufs.count(), flags, - protocol_type == SOCK_STREAM && bufs.all_empty(), ptr.get()); - ptr.release(); - } - - // Wait until data can be received without blocking. - template - void async_receive(implementation_type& impl, const null_buffers& buffers, - socket_base::message_flags flags, Handler handler) - { - 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. - - // Allocate and construct an operation to wrap the handler. - typedef receive_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, protocol_type, - impl.cancel_token_, buffers, handler); - - ::WSABUF buf = { 0, 0 }; - start_receive_op(impl, &buf, 1, flags, false, ptr.get()); - ptr.release(); - } - else - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - start_reactor_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get()); - ptr.release(); - } + start_reactor_op(impl, reactor::write_op, p.p); + p.v = p.p = 0; } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -1156,41 +300,18 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int endpoint_size = static_cast(sender_endpoint.capacity()); - int result = ::WSARecvFrom(impl.socket_, bufs.buffers(), - bufs.count(), &bytes_transferred, &recv_flags, - sender_endpoint.data(), &endpoint_size, 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = boost::asio::error::eof; - return 0; - } + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); - sender_endpoint.resize(static_cast(endpoint_size)); + if (!ec) + sender_endpoint.resize(addr_len); - ec = boost::system::error_code(); - return bytes_transferred; + return bytes_recvd; } // Wait until data can be received without blocking. @@ -1198,12 +319,6 @@ public: const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); @@ -1213,75 +328,6 @@ public: return 0; } - template - class receive_from_op : public operation - { - public: - receive_from_op(int protocol_type, endpoint_type& endpoint, - const MutableBufferSequence& buffers, Handler handler) - : operation(&receive_from_op::do_complete), - protocol_type_(protocol_type), - endpoint_(endpoint), - endpoint_size_(static_cast(endpoint.capacity())), - buffers_(buffers), - handler_(handler) - { - } - - int& endpoint_size() - { - return endpoint_size_; - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - receive_from_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } - - // Record the size of the endpoint returned by the operation. - o->endpoint_.resize(o->endpoint_size_); - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder2 - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - int protocol_type_; - endpoint_type& endpoint_; - int endpoint_size_; - weak_cancel_token_type cancel_token_; - MutableBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. @@ -1291,19 +337,19 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef receive_from_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, - protocol_type, sender_endp, buffers, handler); + typedef win_iocp_socket_recvfrom_op< + MutableBufferSequence, endpoint_type, Handler> op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler); buffer_sequence_adapter bufs(buffers); start_receive_from_op(impl, bufs.buffers(), bufs.count(), - sender_endp, flags, &ptr.get()->endpoint_size(), ptr.get()); - ptr.release(); + sender_endp.data(), flags, &p.p->endpoint_size(), p.p); + p.v = p.p = 0; } // Wait until data can be received without blocking. @@ -1313,19 +359,17 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); - start_reactor_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get()); - ptr.release(); + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; } // Accept a new connection. @@ -1333,12 +377,6 @@ public: boost::system::error_code accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - // We cannot accept a socket that is already open. if (peer.is_open()) { @@ -1346,223 +384,23 @@ public: return ec; } - for (;;) + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() >= 0) { - socket_holder new_socket; - std::size_t addr_len = 0; - if (peer_endpoint) - { - addr_len = peer_endpoint->capacity(); - new_socket.reset(socket_ops::accept(impl.socket_, - peer_endpoint->data(), &addr_len, ec)); - } - else - { - new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec)); - } - - if (ec) - { - if (ec == boost::asio::error::connection_aborted - && !(impl.flags_ & implementation_type::enable_connection_aborted)) - { - // Retry accept operation. - continue; - } - else - { - return ec; - } - } - if (peer_endpoint) peer_endpoint->resize(addr_len); - - peer.assign(impl.protocol_, new_socket.get(), ec); - if (!ec) + if (!peer.assign(impl.protocol_, new_socket.get(), ec)) new_socket.release(); - return ec; } + + return ec; } - template - class accept_op : public operation - { - public: - accept_op(win_iocp_io_service& iocp_service, socket_type socket, - Socket& peer, const protocol_type& protocol, - endpoint_type* peer_endpoint, bool enable_connection_aborted, - Handler handler) - : operation(&accept_op::do_complete), - iocp_service_(iocp_service), - socket_(socket), - peer_(peer), - protocol_(protocol), - peer_endpoint_(peer_endpoint), - enable_connection_aborted_(enable_connection_aborted), - handler_(handler) - { - } - - socket_holder& new_socket() - { - return new_socket_; - } - - void* output_buffer() - { - return output_buffer_; - } - - DWORD address_length() - { - return sizeof(sockaddr_storage_type) + 16; - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - accept_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Map Windows error ERROR_NETNAME_DELETED to connection_aborted. - if (ec.value() == ERROR_NETNAME_DELETED) - { - ec = boost::asio::error::connection_aborted; - } - - // Restart the accept operation if we got the connection_aborted error - // and the enable_connection_aborted socket option is not set. - if (ec == boost::asio::error::connection_aborted - && !o->enable_connection_aborted_) - { - // Reset OVERLAPPED structure. - o->reset(); - - // Create a new socket for the next connection, since the AcceptEx - // call fails with WSAEINVAL if we try to reuse the same socket. - o->new_socket_.reset(); - o->new_socket_.reset(socket_ops::socket(o->protocol_.family(), - o->protocol_.type(), o->protocol_.protocol(), ec)); - if (o->new_socket_.get() != invalid_socket) - { - // Accept a connection. - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(o->socket_, o->new_socket_.get(), - o->output_buffer(), 0, o->address_length(), - o->address_length(), &bytes_read, o); - DWORD last_error = ::WSAGetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - - // Check if the operation completed immediately. - if (!result && last_error != WSA_IO_PENDING) - { - if (last_error == ERROR_NETNAME_DELETED - || last_error == WSAECONNABORTED) - { - // Post this handler so that operation will be restarted again. - o->iocp_service_.work_started(); - o->iocp_service_.on_completion(o, ec); - ptr.release(); - return; - } - else - { - // Operation already complete. Continue with rest of this - // handler. - } - } - else - { - // Asynchronous operation has been successfully restarted. - o->iocp_service_.work_started(); - o->iocp_service_.on_pending(o); - ptr.release(); - return; - } - } - } - - // Get the address of the peer. - endpoint_type peer_endpoint; - if (!ec) - { - LPSOCKADDR local_addr = 0; - int local_addr_length = 0; - LPSOCKADDR remote_addr = 0; - int remote_addr_length = 0; - GetAcceptExSockaddrs(o->output_buffer(), 0, o->address_length(), - o->address_length(), &local_addr, &local_addr_length, - &remote_addr, &remote_addr_length); - if (static_cast(remote_addr_length) - > peer_endpoint.capacity()) - { - ec = boost::asio::error::invalid_argument; - } - else - { - using namespace std; // For memcpy. - memcpy(peer_endpoint.data(), remote_addr, remote_addr_length); - peer_endpoint.resize(static_cast(remote_addr_length)); - } - } - - // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname - // and getpeername will work on the accepted socket. - if (!ec) - { - SOCKET update_ctx_param = o->socket_; - socket_ops::setsockopt(o->new_socket_.get(), - SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - &update_ctx_param, sizeof(SOCKET), ec); - } - - // If the socket was successfully accepted, transfer ownership of the - // socket to the peer object. - if (!ec) - { - o->peer_.assign(o->protocol_, - native_type(o->new_socket_.get(), peer_endpoint), ec); - if (!ec) - o->new_socket_.release(); - } - - // Pass endpoint back to caller. - if (o->peer_endpoint_) - *o->peer_endpoint_ = peer_endpoint; - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder1 - handler(o->handler_, ec); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - win_iocp_io_service& iocp_service_; - socket_type socket_; - socket_holder new_socket_; - Socket& peer_; - protocol_type protocol_; - endpoint_type* peer_endpoint_; - unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; - bool enable_connection_aborted_; - Handler handler_; - }; - // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template @@ -1570,443 +408,55 @@ public: endpoint_type* peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef accept_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); + typedef win_iocp_socket_accept_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; bool enable_connection_aborted = - (impl.flags_ & implementation_type::enable_connection_aborted); - handler_ptr ptr(raw_ptr, iocp_service_, impl.socket_, peer, - impl.protocol_, peer_endpoint, enable_connection_aborted, handler); + (impl.state_ & socket_ops::enable_connection_aborted) != 0; + p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, + peer_endpoint, enable_connection_aborted, handler); - start_accept_op(impl, peer.is_open(), ptr.get()->new_socket(), - ptr.get()->output_buffer(), ptr.get()->address_length(), ptr.get()); - ptr.release(); + start_accept_op(impl, peer.is_open(), p.p->new_socket(), + impl.protocol_.family(), impl.protocol_.type(), + impl.protocol_.protocol(), p.p->output_buffer(), + p.p->address_length(), p.p); + p.v = p.p = 0; } // Connect the socket to the specified endpoint. boost::system::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - // Perform the connect operation. - socket_ops::connect(impl.socket_, + socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); return ec; } - class connect_op_base : public reactor_op - { - public: - connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&connect_op_base::do_perform, complete_func), - socket_(socket) - { - } - - static bool do_perform(reactor_op* base) - { - connect_op_base* o(static_cast(base)); - - // Get the error code from the connect operation. - int connect_error = 0; - size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, o->ec_) == socket_error_retval) - return true; - - // The connection failed so the handler will be posted with an error code. - if (connect_error) - { - o->ec_ = boost::system::error_code(connect_error, - boost::asio::error::get_system_category()); - } - - return true; - } - - private: - socket_type socket_; - }; - - template - class connect_op : public connect_op_base - { - public: - connect_op(socket_type socket, Handler handler) - : connect_op_base(socket, &connect_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - connect_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, 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. - detail::binder1 - handler(o->handler_, o->ec_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous connect. template void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef connect_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, impl.socket_, handler); + typedef reactive_socket_connect_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler); - start_connect_op(impl, ptr.get(), peer_endpoint); - ptr.release(); + start_connect_op(impl, p.p, peer_endpoint.data(), + static_cast(peer_endpoint.size())); + p.v = p.p = 0; } - -private: - // Helper function to start an asynchronous send operation. - void start_send_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, socket_base::message_flags flags, - bool noop, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (noop) - iocp_service_.on_completion(op); - else if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, buffers, - buffer_count, &bytes_transferred, flags, op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous send_to operation. - void start_send_to_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, const endpoint_type& destination, - socket_base::message_flags flags, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, buffers, buffer_count, - &bytes_transferred, flags, destination.data(), - static_cast(destination.size()), op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous receive operation. - void start_receive_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, socket_base::message_flags flags, - bool noop, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (noop) - iocp_service_.on_completion(op); - else if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, buffers, buffer_count, - &bytes_transferred, &recv_flags, op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_NETNAME_DELETED) - last_error = WSAECONNRESET; - else if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous receive_from operation. - void start_receive_from_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, endpoint_type& sender_endpoint, - socket_base::message_flags flags, int* endpoint_size, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecvFrom(impl.socket_, buffers, - buffer_count, &bytes_transferred, &recv_flags, - sender_endpoint.data(), endpoint_size, op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous receive_from operation. - void start_accept_op(implementation_type& impl, - bool peer_is_open, socket_holder& new_socket, - void* output_buffer, DWORD address_length, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else if (peer_is_open) - iocp_service_.on_completion(op, boost::asio::error::already_open); - else - { - boost::system::error_code ec; - new_socket.reset(socket_ops::socket(impl.protocol_.family(), - impl.protocol_.type(), impl.protocol_.protocol(), ec)); - if (new_socket.get() == invalid_socket) - iocp_service_.on_completion(op, ec); - else - { - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, - 0, address_length, address_length, &bytes_read, op); - DWORD last_error = ::WSAGetLastError(); - if (!result && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error); - else - iocp_service_.on_pending(op); - } - } - } - - // Start an asynchronous read or write operation using the the reactor. - void start_reactor_op(implementation_type& impl, int op_type, reactor_op* op) - { - reactor& r = get_reactor(); - update_cancellation_thread_id(impl); - - if (is_open(impl)) - { - r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false); - return; - } - else - op->ec_ = boost::asio::error::bad_descriptor; - - iocp_service_.post_immediate_completion(op); - } - - // Start the asynchronous connect operation using the reactor. - void start_connect_op(implementation_type& impl, - reactor_op* op, const endpoint_type& peer_endpoint) - { - reactor& r = get_reactor(); - update_cancellation_thread_id(impl); - - if (is_open(impl)) - { - ioctl_arg_type non_blocking = 1; - if (!socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_)) - { - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), op->ec_) != 0) - { - if (!op->ec_ - && !(impl.flags_ & implementation_type::user_set_non_blocking)) - { - non_blocking = 0; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_); - } - - if (op->ec_ == boost::asio::error::in_progress - || op->ec_ == boost::asio::error::would_block) - { - op->ec_ = boost::system::error_code(); - r.start_op(reactor::connect_op, impl.socket_, - impl.reactor_data_, op, true); - return; - } - } - } - } - else - op->ec_ = boost::asio::error::bad_descriptor; - - iocp_service_.post_immediate_completion(op); - } - - // Helper function to close a socket when the associated object is being - // destroyed. - void close_for_destruction(implementation_type& impl) - { - if (is_open(impl)) - { - // Check if the reactor was created, in which case we need to close the - // socket on the reactor as well to cancel any operations that might be - // running there. - reactor* r = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (r) - r->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 - // default so that the closure is performed in the background. - if (impl.flags_ & implementation_type::close_might_block) - { - ::linger opt; - opt.l_onoff = 0; - opt.l_linger = 0; - boost::system::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); - } - - boost::system::error_code ignored_ec; - socket_ops::close(impl.socket_, ignored_ec); - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - impl.safe_cancellation_thread_id_ = 0; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - } - } - - // Update the ID of the thread from which cancellation is safe. - void update_cancellation_thread_id(implementation_type& impl) - { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - 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); -#else // defined(BOOST_ASIO_ENABLE_CANCELIO) - (void)impl; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - } - - // Helper function to get the reactor. If no reactor has been created yet, a - // new one is obtained from the io_service and a pointer to it is cached in - // this service. - reactor& get_reactor() - { - reactor* r = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!r) - { - r = &(use_service(io_service_)); - interlocked_exchange_pointer(reinterpret_cast(&reactor_), r); - } - return *r; - } - - // Helper function to emulate InterlockedCompareExchangePointer functionality - // for: - // - very old Platform SDKs; and - // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. - void* interlocked_compare_exchange_pointer(void** dest, void* exch, void* cmp) - { -#if defined(_M_IX86) - return reinterpret_cast(InterlockedCompareExchange( - reinterpret_cast(dest), reinterpret_cast(exch), - reinterpret_cast(cmp))); -#else - return InterlockedCompareExchangePointer(dest, exch, cmp); -#endif - } - - // Helper function to emulate InterlockedExchangePointer functionality for: - // - very old Platform SDKs; and - // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. - void* interlocked_exchange_pointer(void** dest, void* val) - { -#if defined(_M_IX86) - return reinterpret_cast(InterlockedExchange( - reinterpret_cast(dest), reinterpret_cast(val))); -#else - return InterlockedExchangePointer(dest, val); -#endif - } - - // The io_service used to obtain the reactor, if required. - boost::asio::io_service& io_service_; - - // The IOCP service used for running asynchronous operations and dispatching - // handlers. - win_iocp_io_service& iocp_service_; - - // The reactor used for performing connect operations. This object is created - // only if needed. - reactor* reactor_; - - // Mutex to protect access to the linked list of implementations. - boost::asio::detail::mutex mutex_; - - // The head of a linked list of all implementations. - implementation_type* impl_list_; }; } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_service_base.hpp b/include/boost/asio/detail/win_iocp_socket_service_base.hpp new file mode 100644 index 00000000..2dd3ba35 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_service_base.hpp @@ -0,0 +1,387 @@ +// +// detail/win_iocp_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_socket_service_base +{ +public: + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // We use a shared pointer as a cancellation token here to work around the + // broken Windows support for cancellation. MSDN says that when you call + // closesocket any outstanding WSARecv or WSASend operations will complete + // with the error ERROR_OPERATION_ABORTED. In practice they complete with + // ERROR_NETNAME_DELETED, which means you can't tell the difference between + // a local cancellation and the socket being hard-closed by the peer. + socket_ops::shared_cancel_token_type cancel_token_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + +#if defined(BOOST_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. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the socket. + DWORD safe_cancellation_thread_id_; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + // Pointers to adjacent socket implementations in linked list. + base_implementation_type* next_; + base_implementation_type* prev_; + }; + + // Constructor. + BOOST_ASIO_DECL win_iocp_socket_service_base( + boost::asio::io_service& io_service); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown_service(); + + // Construct a new socket implementation. + BOOST_ASIO_DECL void construct(base_implementation_type& impl); + + // Destroy a socket implementation. + BOOST_ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + BOOST_ASIO_DECL boost::system::error_code close( + base_implementation_type& impl, boost::system::error_code& ec); + + // Cancel all operations associated with the socket. + BOOST_ASIO_DECL boost::system::error_code cancel( + base_implementation_type& impl, boost::system::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + boost::system::error_code listen(base_implementation_type& impl, + int backlog, boost::system::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template + boost::system::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, boost::system::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast(command.data()), ec); + return ec; + } + + /// Disable sends or receives on the socket. + boost::system::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, boost::system::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send the given data to the peer. Returns the number of bytes sent. + template + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_send_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler); + + buffer_sequence_adapter bufs(buffers); + + start_send_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + start_reactor_op(impl, reactor::write_op, p.p); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recv_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler); + + buffer_sequence_adapter bufs(buffers); + + start_receive_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; + } + + // Helper function to restart an asynchronous accept operation. + BOOST_ASIO_DECL void restart_accept_op(socket_type s, + socket_holder& new_socket, int family, int type, int protocol, + void* output_buffer, DWORD address_length, operation* op); + +protected: + // Open a new socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_open( + base_implementation_type& impl, int family, int type, + int protocol, boost::system::error_code& ec); + + // Assign a native socket to a socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_assign( + base_implementation_type& impl, int type, + socket_type native_socket, boost::system::error_code& ec); + + // Helper function to start an asynchronous send operation. + BOOST_ASIO_DECL void start_send_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous send_to operation. + BOOST_ASIO_DECL void start_send_to_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op); + + // Helper function to start an asynchronous receive operation. + BOOST_ASIO_DECL void start_receive_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous null_buffers receive operation. + BOOST_ASIO_DECL void start_null_buffers_receive_op( + base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op); + + // Helper function to start an asynchronous receive_from operation. + BOOST_ASIO_DECL void start_receive_from_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op); + + // Helper function to start an asynchronous accept operation. + BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op); + + // Start an asynchronous read or write operation using the the reactor. + BOOST_ASIO_DECL void start_reactor_op(base_implementation_type& impl, + int op_type, reactor_op* op); + + // Start the asynchronous connect operation using the reactor. + BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, std::size_t addrlen); + + // Helper function to close a socket when the associated object is being + // destroyed. + BOOST_ASIO_DECL void close_for_destruction(base_implementation_type& impl); + + // Update the ID of the thread from which cancellation is safe. + BOOST_ASIO_DECL void update_cancellation_thread_id( + base_implementation_type& impl); + + // Helper function to get the reactor. If no reactor has been created yet, a + // new one is obtained from the io_service and a pointer to it is cached in + // this service. + BOOST_ASIO_DECL reactor& get_reactor(); + + // Helper function to emulate InterlockedCompareExchangePointer functionality + // for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + BOOST_ASIO_DECL void* interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp); + + // Helper function to emulate InterlockedExchangePointer functionality for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + BOOST_ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val); + + // The io_service used to obtain the reactor, if required. + boost::asio::io_service& io_service_; + + // The IOCP service used for running asynchronous operations and dispatching + // handlers. + win_iocp_io_service& iocp_service_; + + // The reactor used for performing connect operations. This object is created + // only if needed. + reactor* reactor_; + + // Mutex to protect access to the linked list of implementations. + boost::asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + base_implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP diff --git a/include/boost/asio/detail/win_mutex.hpp b/include/boost/asio/detail/win_mutex.hpp index 176a5fd9..3f6dadbe 100644 --- a/include/boost/asio/detail/win_mutex.hpp +++ b/include/boost/asio/detail/win_mutex.hpp @@ -1,6 +1,6 @@ // -// win_mutex.hpp -// ~~~~~~~~~~~~~ +// detail/win_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,23 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) -#include #include -#include #include +#include #include -#include -#include namespace boost { namespace asio { @@ -44,18 +36,7 @@ public: typedef boost::asio::detail::scoped_lock scoped_lock; // Constructor. - win_mutex() - { - int error = do_init(); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL win_mutex(); // Destructor. ~win_mutex() @@ -79,35 +60,7 @@ private: // Initialisation must be performed in a separate function to the constructor // since the compiler does not support the use of structured exceptions and // C++ exceptions in the same function. - int do_init() - { -#if defined(__MINGW32__) - // Not sure if MinGW supports structured exception handling, so for now - // we'll just call the Windows API and hope. -# if defined(UNDER_CE) - ::InitializeCriticalSection(&crit_section_); -# else - ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); -# endif - return 0; -#else - __try - { -# if defined(UNDER_CE) - ::InitializeCriticalSection(&crit_section_); -# else - ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); -# endif - } - __except(GetExceptionCode() == STATUS_NO_MEMORY - ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - return ERROR_OUTOFMEMORY; - } - - return 0; -#endif - } + BOOST_ASIO_DECL int do_init(); ::CRITICAL_SECTION crit_section_; }; @@ -116,8 +69,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + #endif // BOOST_ASIO_DETAIL_WIN_MUTEX_HPP diff --git a/include/boost/asio/detail/win_signal_blocker.hpp b/include/boost/asio/detail/win_signal_blocker.hpp deleted file mode 100644 index 6d70a16c..00000000 --- a/include/boost/asio/detail/win_signal_blocker.hpp +++ /dev/null @@ -1,69 +0,0 @@ -// -// win_signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP -#define BOOST_ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include - -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - -#include - -namespace boost { -namespace asio { -namespace detail { - -class win_signal_blocker - : private noncopyable -{ -public: - // Constructor blocks all signals for the calling thread. - win_signal_blocker() - { - // No-op. - } - - // Destructor restores the previous signal mask. - ~win_signal_blocker() - { - // No-op. - } - - // Block all signals for the calling thread. - void block() - { - // No-op. - } - - // Restore the previous signal mask. - void unblock() - { - // No-op. - } -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - -#include - -#endif // BOOST_ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP diff --git a/include/boost/asio/detail/win_thread.hpp b/include/boost/asio/detail/win_thread.hpp index 61c9b8a9..cba546f6 100644 --- a/include/boost/asio/detail/win_thread.hpp +++ b/include/boost/asio/detail/win_thread.hpp @@ -1,6 +1,6 @@ // -// win_thread.hpp -// ~~~~~~~~~~~~~~ +// detail/win_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,35 +15,25 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) -#include #include #include #include -#include -#include -#include -#include namespace boost { namespace asio { namespace detail { -unsigned int __stdcall win_thread_function(void* arg); +BOOST_ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); #if defined(WINVER) && (WINVER < 0x0500) -void __stdcall apc_function(ULONG data); +BOOST_ASIO_DECL void __stdcall apc_function(ULONG data); #else -void __stdcall apc_function(ULONG_PTR data); +BOOST_ASIO_DECL void __stdcall apc_function(ULONG_PTR data); #endif template @@ -74,92 +64,26 @@ class win_thread public: // Constructor. template - win_thread(Function f) - : exit_event_(0) + win_thread(Function f, unsigned int stack_size = 0) + : thread_(0), + exit_event_(0) { - std::auto_ptr arg(new func(f)); - - ::HANDLE entry_event = 0; - arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); - if (!entry_event) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::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); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "thread.exit_event"); - boost::throw_exception(e); - } - - unsigned int thread_id = 0; - thread_ = reinterpret_cast(::_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_); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "thread"); - boost::throw_exception(e); - } - arg.release(); - - if (entry_event) - { - ::WaitForSingleObject(entry_event, INFINITE); - ::CloseHandle(entry_event); - } + start_thread(new func(f), stack_size); } // 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. - } + BOOST_ASIO_DECL ~win_thread(); // Wait for the thread to exit. - void join() - { - ::WaitForSingleObject(exit_event_, INFINITE); - ::CloseHandle(exit_event_); - if (terminate_threads()) - { - ::TerminateThread(thread_, 0); - } - else - { - ::QueueUserAPC(apc_function, thread_, 0); - ::WaitForSingleObject(thread_, INFINITE); - } - } + BOOST_ASIO_DECL void join(); private: - friend unsigned int __stdcall win_thread_function(void* arg); + friend BOOST_ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); #if defined(WINVER) && (WINVER < 0x0500) - friend void __stdcall apc_function(ULONG); + friend BOOST_ASIO_DECL void __stdcall apc_function(ULONG); #else - friend void __stdcall apc_function(ULONG_PTR); + friend BOOST_ASIO_DECL void __stdcall apc_function(ULONG_PTR); #endif class func_base @@ -171,6 +95,12 @@ private: ::HANDLE exit_event_; }; + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + template class func : public func_base @@ -190,45 +120,22 @@ private: Function f_; }; + BOOST_ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size); + ::HANDLE thread_; ::HANDLE exit_event_; }; -inline unsigned int __stdcall win_thread_function(void* arg) -{ - std::auto_ptr func( - static_cast(arg)); - - ::SetEvent(func->entry_event_); - - func->run(); - - // Signal that the thread has finished its work, but rather than returning go - // to sleep to put the thread into a well known state. If the thread is being - // joined during global object destruction then it may be killed using - // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx - // call will be interrupted using QueueUserAPC and the thread will shut down - // cleanly. - HANDLE exit_event = func->exit_event_; - func.reset(); - ::SetEvent(exit_event); - ::SleepEx(INFINITE, TRUE); - - return 0; -} - -#if defined(WINVER) && (WINVER < 0x0500) -inline void __stdcall apc_function(ULONG) {} -#else -inline void __stdcall apc_function(ULONG_PTR) {} -#endif - } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + #endif // BOOST_ASIO_DETAIL_WIN_THREAD_HPP diff --git a/include/boost/asio/detail/win_tss_ptr.hpp b/include/boost/asio/detail/win_tss_ptr.hpp index fa04613c..2c5ee3bd 100644 --- a/include/boost/asio/detail/win_tss_ptr.hpp +++ b/include/boost/asio/detail/win_tss_ptr.hpp @@ -1,6 +1,6 @@ // -// win_tss_ptr.hpp -// ~~~~~~~~~~~~~~~ +// detail/win_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,51 +15,31 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) -#include #include #include #include -#include -#include namespace boost { namespace asio { namespace detail { +// Helper function to create thread-specific storage. +BOOST_ASIO_DECL DWORD win_tss_ptr_create(); + template class win_tss_ptr : private noncopyable { public: -#if defined(UNDER_CE) - enum { out_of_indexes = 0xFFFFFFFF }; -#else - enum { out_of_indexes = TLS_OUT_OF_INDEXES }; -#endif - // Constructor. win_tss_ptr() + : tss_key_(win_tss_ptr_create()) { - tss_key_ = ::TlsAlloc(); - if (tss_key_ == out_of_indexes) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "tss"); - boost::throw_exception(e); - } } // Destructor. @@ -90,8 +70,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + #endif // BOOST_ASIO_DETAIL_WIN_TSS_PTR_HPP diff --git a/include/boost/asio/detail/wince_thread.hpp b/include/boost/asio/detail/wince_thread.hpp index 1cb9a7ae..82ca544b 100644 --- a/include/boost/asio/detail/wince_thread.hpp +++ b/include/boost/asio/detail/wince_thread.hpp @@ -1,6 +1,6 @@ // -// wince_thread.hpp -// ~~~~~~~~~~~~~~~~ +// detail/wince_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,23 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) && defined(UNDER_CE) -#include +#include #include #include +#include +#include #include -#include -#include -#include namespace boost { namespace asio { @@ -54,11 +48,9 @@ public: if (!thread_) { DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "thread"); - boost::throw_exception(e); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); } arg.release(); } @@ -119,8 +111,8 @@ inline DWORD WINAPI wince_thread_function(LPVOID arg) } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE) - #include +#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE) + #endif // BOOST_ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/include/boost/asio/detail/winsock_init.hpp b/include/boost/asio/detail/winsock_init.hpp index 186a8b5c..ac24b0dc 100644 --- a/include/boost/asio/detail/winsock_init.hpp +++ b/include/boost/asio/detail/winsock_init.hpp @@ -1,6 +1,6 @@ // -// winsock_init.hpp -// ~~~~~~~~~~~~~~~~ +// detail/winsock_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,108 +15,78 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include -#include -#include -#include - -#include -#include -#include namespace boost { namespace asio { namespace detail { -template -class winsock_init - : private noncopyable +class winsock_init_base { -private: - // Structure to perform the actual initialisation. - struct do_init +protected: + // Structure to track result of initialisation and number of uses. POD is used + // to ensure that the values are zero-initialised prior to any code being run. + struct data { - do_init() - { - WSADATA wsa_data; - result_ = ::WSAStartup(MAKEWORD(Major, Minor), &wsa_data); - } - - ~do_init() - { - ::WSACleanup(); - } - - int result() const - { - return result_; - } - - // Helper function to manage a do_init singleton. The static instance of the - // winsock_init object ensures that this function is always called before - // main, and therefore before any other threads can get started. The do_init - // instance must be static in this function to ensure that it gets - // initialised before any other global objects try to use it. - static boost::shared_ptr instance() - { - static boost::shared_ptr init(new do_init); - return init; - } - - private: - int result_; + long init_count_; + long result_; }; + BOOST_ASIO_DECL static void startup(data& d, + unsigned char major, unsigned char minor); + + BOOST_ASIO_DECL static void cleanup(data& d); + + BOOST_ASIO_DECL static void throw_on_error(data& d); +}; + +template +class winsock_init : private winsock_init_base +{ public: - // Constructor. - winsock_init() - : ref_(do_init::instance()) + winsock_init(bool allow_throw = true) { - // Check whether winsock was successfully initialised. This check is not - // performed for the global instance since there will be nobody around to - // catch the exception. - if (this != &instance_ && ref_->result() != 0) - { - boost::system::system_error e( - boost::system::error_code(ref_->result(), - boost::asio::error::get_system_category()), - "winsock"); - boost::throw_exception(e); - } + startup(data_, Major, Minor); + if (allow_throw) + throw_on_error(data_); + } + + winsock_init(const winsock_init&) + { + startup(data_, Major, Minor); + throw_on_error(data_); } - // Destructor. ~winsock_init() { + cleanup(data_); } private: - // Instance to force initialisation of winsock at global scope. - static winsock_init instance_; - - // Reference to singleton do_init object to ensure that winsock does not get - // cleaned up until the last user has finished with it. - boost::shared_ptr ref_; + static data data_; }; template -winsock_init winsock_init::instance_; +winsock_init_base::data winsock_init::data_; + +// Static variable to ensure that winsock is initialised before main, and +// therefore before any other threads can get started. +static const winsock_init<>& winsock_init_instance = winsock_init<>(false); } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP diff --git a/include/boost/asio/detail/wrapped_handler.hpp b/include/boost/asio/detail/wrapped_handler.hpp index 8f2f6252..9645b64f 100644 --- a/include/boost/asio/detail/wrapped_handler.hpp +++ b/include/boost/asio/detail/wrapped_handler.hpp @@ -1,6 +1,6 @@ // -// wrapped_handler.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/wrapped_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - #include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -35,9 +31,7 @@ class wrapped_handler public: typedef void result_type; - wrapped_handler( - typename boost::add_reference::type dispatcher, - Handler handler) + wrapped_handler(Dispatcher dispatcher, Handler handler) : dispatcher_(dispatcher), handler_(handler) { diff --git a/include/boost/asio/error.hpp b/include/boost/asio/error.hpp index 0dcb3dcd..5663b694 100644 --- a/include/boost/asio/error.hpp +++ b/include/boost/asio/error.hpp @@ -15,15 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include #include -#include - -#include +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include +#else +# include +# include +#endif #if defined(GENERATING_DOCUMENTATION) /// INTERNAL ONLY. @@ -50,6 +50,8 @@ # define BOOST_ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix #endif +#include + namespace boost { namespace asio { namespace error { @@ -220,65 +222,11 @@ inline const boost::system::error_category& get_system_category() #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -namespace detail { +extern BOOST_ASIO_DECL +const boost::system::error_category& get_netdb_category(); -class netdb_category : public boost::system::error_category -{ -public: - const char* name() const - { - return "asio.netdb"; - } - - std::string message(int value) const - { - if (value == error::host_not_found) - return "Host not found (authoritative)"; - if (value == error::host_not_found_try_again) - return "Host not found (non-authoritative), try again later"; - if (value == error::no_data) - return "The query is valid, but it does not have associated data"; - if (value == error::no_recovery) - return "A non-recoverable error occurred during database lookup"; - return "asio.netdb error"; - } -}; - -} // namespace detail - -inline const boost::system::error_category& get_netdb_category() -{ - static detail::netdb_category instance; - return instance; -} - -namespace detail { - -class addrinfo_category : public boost::system::error_category -{ -public: - const char* name() const - { - return "asio.addrinfo"; - } - - std::string message(int value) const - { - if (value == error::service_not_found) - return "Service not found"; - if (value == error::socket_type_not_supported) - return "Socket type not supported"; - return "asio.addrinfo error"; - } -}; - -} // namespace detail - -inline const boost::system::error_category& get_addrinfo_category() -{ - static detail::addrinfo_category instance; - return instance; -} +extern BOOST_ASIO_DECL +const boost::system::error_category& get_addrinfo_category(); #else // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) @@ -294,61 +242,11 @@ inline const boost::system::error_category& get_addrinfo_category() #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -namespace detail { +extern BOOST_ASIO_DECL +const boost::system::error_category& get_misc_category(); -class misc_category : public boost::system::error_category -{ -public: - const char* name() const - { - return "asio.misc"; - } - - std::string message(int value) const - { - if (value == error::already_open) - return "Already open"; - if (value == error::eof) - return "End of file"; - if (value == error::not_found) - return "Element not found"; - if (value == error::fd_set_failure) - return "The descriptor does not fit into the select call's fd_set"; - return "asio.misc error"; - } -}; - -} // namespace detail - -inline const boost::system::error_category& get_misc_category() -{ - static detail::misc_category instance; - return instance; -} - -namespace detail { - -class ssl_category : public boost::system::error_category -{ -public: - const char* name() const - { - return "asio.ssl"; - } - - std::string message(int) const - { - return "asio.ssl error"; - } -}; - -} // namespace detail - -inline const boost::system::error_category& get_ssl_category() -{ - static detail::ssl_category instance; - return instance; -} +extern BOOST_ASIO_DECL +const boost::system::error_category& get_ssl_category(); static const boost::system::error_category& system_category = boost::asio::error::get_system_category(); @@ -430,13 +328,16 @@ inline boost::system::error_code make_error_code(ssl_errors e) } // namespace asio } // namespace boost +#include + #undef BOOST_ASIO_NATIVE_ERROR #undef BOOST_ASIO_SOCKET_ERROR #undef BOOST_ASIO_NETDB_ERROR #undef BOOST_ASIO_GETADDRINFO_ERROR #undef BOOST_ASIO_WIN_OR_POSIX - -#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_ERROR_HPP diff --git a/include/boost/asio/handler_alloc_hook.hpp b/include/boost/asio/handler_alloc_hook.hpp index 5dada4e7..179f75e6 100644 --- a/include/boost/asio/handler_alloc_hook.hpp +++ b/include/boost/asio/handler_alloc_hook.hpp @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/handler_invoke_hook.hpp b/include/boost/asio/handler_invoke_hook.hpp index 184f4495..f997f110 100644 --- a/include/boost/asio/handler_invoke_hook.hpp +++ b/include/boost/asio/handler_invoke_hook.hpp @@ -15,6 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include + #include namespace boost { diff --git a/include/boost/asio/impl/error.ipp b/include/boost/asio/impl/error.ipp new file mode 100644 index 00000000..708654e4 --- /dev/null +++ b/include/boost/asio/impl/error.ipp @@ -0,0 +1,155 @@ +// +// impl/error.ipp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_ERROR_IPP +#define BOOST_ASIO_IMPL_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace error { + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +namespace detail { + +class netdb_category : public boost::system::error_category +{ +public: + const char* name() const + { + return "asio.netdb"; + } + + std::string message(int value) const + { + if (value == error::host_not_found) + return "Host not found (authoritative)"; + if (value == error::host_not_found_try_again) + return "Host not found (non-authoritative), try again later"; + if (value == error::no_data) + return "The query is valid, but it does not have associated data"; + if (value == error::no_recovery) + return "A non-recoverable error occurred during database lookup"; + return "asio.netdb error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_netdb_category() +{ + static detail::netdb_category instance; + return instance; +} + +namespace detail { + +class addrinfo_category : public boost::system::error_category +{ +public: + const char* name() const + { + return "asio.addrinfo"; + } + + std::string message(int value) const + { + if (value == error::service_not_found) + return "Service not found"; + if (value == error::socket_type_not_supported) + return "Socket type not supported"; + return "asio.addrinfo error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_addrinfo_category() +{ + static detail::addrinfo_category instance; + return instance; +} + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +namespace detail { + +class misc_category : public boost::system::error_category +{ +public: + const char* name() const + { + return "asio.misc"; + } + + std::string message(int value) const + { + if (value == error::already_open) + return "Already open"; + if (value == error::eof) + return "End of file"; + if (value == error::not_found) + return "Element not found"; + if (value == error::fd_set_failure) + return "The descriptor does not fit into the select call's fd_set"; + return "asio.misc error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_misc_category() +{ + static detail::misc_category instance; + return instance; +} + +namespace detail { + +class ssl_category : public boost::system::error_category +{ +public: + const char* name() const + { + return "asio.ssl"; + } + + std::string message(int) const + { + return "asio.ssl error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_ssl_category() +{ + static detail::ssl_category instance; + return instance; +} + +} // namespace error +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_ERROR_IPP diff --git a/include/boost/asio/impl/io_service.hpp b/include/boost/asio/impl/io_service.hpp new file mode 100644 index 00000000..3c082cb9 --- /dev/null +++ b/include/boost/asio/impl/io_service.hpp @@ -0,0 +1,136 @@ +// +// impl/io_service.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_IO_SERVICE_HPP +#define BOOST_ASIO_IMPL_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { + +template +inline Service& use_service(io_service& ios) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + + return ios.service_registry_->template use_service(); +} + +template +inline void add_service(io_service& ios, Service* svc) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + + ios.service_registry_->template add_service(svc); +} + +template +inline bool has_service(io_service& ios) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + + return ios.service_registry_->template has_service(); +} + +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +#include + +namespace boost { +namespace asio { + +template +inline void io_service::dispatch(Handler handler) +{ + impl_.dispatch(handler); +} + +template +inline void io_service::post(Handler handler) +{ + impl_.post(handler); +} + +template +#if defined(GENERATING_DOCUMENTATION) +unspecified +#else +inline detail::wrapped_handler +#endif +io_service::wrap(Handler handler) +{ + return detail::wrapped_handler(*this, handler); +} + +inline io_service::work::work(boost::asio::io_service& io_service) + : io_service_(io_service) +{ + io_service_.impl_.work_started(); +} + +inline io_service::work::work(const work& other) + : io_service_(other.io_service_) +{ + io_service_.impl_.work_started(); +} + +inline io_service::work::~work() +{ + io_service_.impl_.work_finished(); +} + +inline boost::asio::io_service& io_service::work::io_service() +{ + return io_service_; +} + +inline boost::asio::io_service& io_service::work::get_io_service() +{ + return io_service_; +} + +inline boost::asio::io_service& io_service::service::io_service() +{ + return owner_; +} + +inline boost::asio::io_service& io_service::service::get_io_service() +{ + return owner_; +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_IO_SERVICE_HPP diff --git a/include/boost/asio/impl/io_service.ipp b/include/boost/asio/impl/io_service.ipp index 20f868d2..731adb87 100644 --- a/include/boost/asio/impl/io_service.ipp +++ b/include/boost/asio/impl/io_service.ipp @@ -1,6 +1,6 @@ // -// io_service.ipp -// ~~~~~~~~~~~~~~ +// impl/io_service.ipp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,19 +8,16 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_IO_SERVICE_IPP -#define BOOST_ASIO_IO_SERVICE_IPP +#ifndef BOOST_ASIO_IMPL_IO_SERVICE_IPP +#define BOOST_ASIO_IMPL_IO_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include - +#include #include #include @@ -28,32 +25,33 @@ # include #else # include -# include #endif +#include + namespace boost { namespace asio { -inline io_service::io_service() +io_service::io_service() : service_registry_(new boost::asio::detail::service_registry(*this)), impl_(service_registry_->use_service()) { impl_.init((std::numeric_limits::max)()); } -inline io_service::io_service(std::size_t concurrency_hint) +io_service::io_service(std::size_t concurrency_hint) : service_registry_(new boost::asio::detail::service_registry(*this)), impl_(service_registry_->use_service()) { impl_.init(concurrency_hint); } -inline io_service::~io_service() +io_service::~io_service() { delete service_registry_; } -inline std::size_t io_service::run() +std::size_t io_service::run() { boost::system::error_code ec; std::size_t s = impl_.run(ec); @@ -61,12 +59,12 @@ inline std::size_t io_service::run() return s; } -inline std::size_t io_service::run(boost::system::error_code& ec) +std::size_t io_service::run(boost::system::error_code& ec) { return impl_.run(ec); } -inline std::size_t io_service::run_one() +std::size_t io_service::run_one() { boost::system::error_code ec; std::size_t s = impl_.run_one(ec); @@ -74,12 +72,12 @@ inline std::size_t io_service::run_one() return s; } -inline std::size_t io_service::run_one(boost::system::error_code& ec) +std::size_t io_service::run_one(boost::system::error_code& ec) { return impl_.run_one(ec); } -inline std::size_t io_service::poll() +std::size_t io_service::poll() { boost::system::error_code ec; std::size_t s = impl_.poll(ec); @@ -87,12 +85,12 @@ inline std::size_t io_service::poll() return s; } -inline std::size_t io_service::poll(boost::system::error_code& ec) +std::size_t io_service::poll(boost::system::error_code& ec) { return impl_.poll(ec); } -inline std::size_t io_service::poll_one() +std::size_t io_service::poll_one() { boost::system::error_code ec; std::size_t s = impl_.poll_one(ec); @@ -100,122 +98,39 @@ inline std::size_t io_service::poll_one() return s; } -inline std::size_t io_service::poll_one(boost::system::error_code& ec) +std::size_t io_service::poll_one(boost::system::error_code& ec) { return impl_.poll_one(ec); } -inline void io_service::stop() +void io_service::stop() { impl_.stop(); } -inline void io_service::reset() +void io_service::reset() { impl_.reset(); } -template -inline void io_service::dispatch(Handler handler) -{ - impl_.dispatch(handler); -} - -template -inline void io_service::post(Handler handler) -{ - impl_.post(handler); -} - -template -#if defined(GENERATING_DOCUMENTATION) -unspecified -#else -inline detail::wrapped_handler -#endif -io_service::wrap(Handler handler) -{ - return detail::wrapped_handler(*this, handler); -} - -inline io_service::work::work(boost::asio::io_service& io_service) - : io_service_(io_service) -{ - io_service_.impl_.work_started(); -} - -inline io_service::work::work(const work& other) - : io_service_(other.io_service_) -{ - io_service_.impl_.work_started(); -} - -inline io_service::work::~work() -{ - io_service_.impl_.work_finished(); -} - -inline boost::asio::io_service& io_service::work::io_service() -{ - return io_service_; -} - -inline boost::asio::io_service& io_service::work::get_io_service() -{ - return io_service_; -} - -inline io_service::service::service(boost::asio::io_service& owner) +io_service::service::service(boost::asio::io_service& owner) : owner_(owner), next_(0) { } -inline io_service::service::~service() +io_service::service::~service() { } -inline boost::asio::io_service& io_service::service::io_service() +service_already_exists::service_already_exists() + : std::logic_error("Service already exists.") { - return owner_; } -inline boost::asio::io_service& io_service::service::get_io_service() +invalid_service_owner::invalid_service_owner() + : std::logic_error("Invalid service owner.") { - return owner_; -} - -template -inline Service& use_service(io_service& ios) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast(static_cast(0)); - (void)static_cast(&Service::id); - - return ios.service_registry_->template use_service(); -} - -template -void add_service(io_service& ios, Service* svc) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast(static_cast(0)); - (void)static_cast(&Service::id); - - if (&ios != &svc->io_service()) - boost::throw_exception(invalid_service_owner()); - if (!ios.service_registry_->template add_service(svc)) - boost::throw_exception(service_already_exists()); -} - -template -bool has_service(io_service& ios) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast(static_cast(0)); - (void)static_cast(&Service::id); - - return ios.service_registry_->template has_service(); } } // namespace asio @@ -223,4 +138,4 @@ bool has_service(io_service& ios) #include -#endif // BOOST_ASIO_IO_SERVICE_IPP +#endif // BOOST_ASIO_IMPL_IO_SERVICE_IPP diff --git a/include/boost/asio/impl/read.ipp b/include/boost/asio/impl/read.hpp similarity index 87% rename from include/boost/asio/impl/read.ipp rename to include/boost/asio/impl/read.hpp index 772c06bc..e51210ee 100644 --- a/include/boost/asio/impl/read.ipp +++ b/include/boost/asio/impl/read.hpp @@ -1,6 +1,6 @@ // -// read.ipp -// ~~~~~~~~ +// impl/read.hpp +// ~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,28 +8,25 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_READ_IPP -#define BOOST_ASIO_READ_IPP +#ifndef BOOST_ASIO_IMPL_READ_HPP +#define BOOST_ASIO_IMPL_READ_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include #include -#include - #include #include -#include #include #include #include #include #include #include +#include + +#include namespace boost { namespace asio { @@ -88,8 +85,7 @@ std::size_t read(SyncReadStream& s, std::size_t total_transferred = 0; std::size_t max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); - std::size_t bytes_available = std::min(512, - std::min(max_size, b.max_size() - b.size())); + std::size_t bytes_available = read_size_helper(b, max_size); while (bytes_available > 0) { std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); @@ -97,8 +93,7 @@ std::size_t read(SyncReadStream& s, total_transferred += bytes_transferred; max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); - bytes_available = std::min(512, - std::min(max_size, b.max_size() - b.size())); + bytes_available = read_size_helper(b, max_size); } return total_transferred; } @@ -142,25 +137,24 @@ namespace detail stream_(stream), buffers_(buffers), total_transferred_(0), - handler_(handler), - start_(true) + handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - switch (start_) + switch (start) { - case true: start_ = false; - buffers_.prepare(this->check(ec, total_transferred_)); + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); for (;;) { stream_.async_read_some(buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.prepare(this->check(ec, total_transferred_)); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; @@ -176,7 +170,6 @@ namespace detail mutable_buffer, MutableBufferSequence> buffers_; std::size_t total_transferred_; ReadHandler handler_; - bool start_; }; template check(ec, total_transferred_); + case 1: + n = this->check_for_completion(ec, total_transferred_); for (;;) { stream_.async_read_some(boost::asio::buffer( @@ -215,7 +207,7 @@ namespace detail return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) - || (n = this->check(ec, total_transferred_)) == 0 + || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == boost::asio::buffer_size(buffer_)) break; } @@ -229,7 +221,6 @@ namespace detail boost::asio::mutable_buffer buffer_; std::size_t total_transferred_; ReadHandler handler_; - bool start_; }; template ( s, buffers, completion_condition, handler)( - boost::system::error_code(), 0); + boost::system::error_code(), 0, 1); } template check(ec, total_transferred_); - bytes_available = std::min(512, - std::min(max_size, - streambuf_.max_size() - streambuf_.size())); + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); for (;;) { stream_.async_read_some(streambuf_.prepare(bytes_available), *this); return; default: total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); - max_size = this->check(ec, total_transferred_); - bytes_available = std::min(512, - std::min(max_size, - streambuf_.max_size() - streambuf_.size())); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; } @@ -340,7 +326,6 @@ namespace detail boost::asio::basic_streambuf& streambuf_; std::size_t total_transferred_; ReadHandler handler_; - bool start_; }; template ( s, b, completion_condition, handler)( - boost::system::error_code(), 0); + boost::system::error_code(), 0, 1); } template @@ -400,4 +385,4 @@ inline void async_read(AsyncReadStream& s, #include -#endif // BOOST_ASIO_READ_IPP +#endif // BOOST_ASIO_IMPL_READ_HPP diff --git a/include/boost/asio/impl/read_at.ipp b/include/boost/asio/impl/read_at.hpp similarity index 63% rename from include/boost/asio/impl/read_at.ipp rename to include/boost/asio/impl/read_at.hpp index eb3c3f89..0eb064b5 100644 --- a/include/boost/asio/impl/read_at.ipp +++ b/include/boost/asio/impl/read_at.hpp @@ -1,6 +1,6 @@ // -// read_at.ipp -// ~~~~~~~~~~~ +// impl/read_at.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,27 +8,25 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_READ_AT_IPP -#define BOOST_ASIO_READ_AT_IPP +#ifndef BOOST_ASIO_IMPL_READ_AT_HPP +#define BOOST_ASIO_IMPL_READ_AT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include #include -#include - #include #include -#include +#include #include #include #include #include #include +#include + +#include namespace boost { namespace asio { @@ -89,19 +87,22 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, boost::asio::basic_streambuf& b, CompletionCondition completion_condition, boost::system::error_code& ec) { + ec = boost::system::error_code(); std::size_t total_transferred = 0; - for (;;) + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = read_size_helper(b, max_size); + while (bytes_available > 0) { - std::size_t bytes_available = - std::min(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; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = read_size_helper(b, max_size); } + return total_transferred; } template @@ -135,48 +136,105 @@ namespace detail template - class read_at_handler + class read_at_op + : detail::base_from_completion_cond { public: - typedef boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> buffers_type; - - read_at_handler(AsyncRandomAccessReadDevice& stream, - boost::uint64_t offset, const buffers_type& buffers, + read_at_op(AsyncRandomAccessReadDevice& device, + boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), offset_(offset), buffers_(buffers), total_transferred_(0), - completion_condition_(completion_condition), handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - total_transferred_ += bytes_transferred; - buffers_.consume(bytes_transferred); - buffers_.prepare(detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_))); - if (buffers_.begin() == buffers_.end()) + switch (start) { + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + for (;;) + { + device_.async_read_some_at( + offset_ + total_transferred_, buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + handler_(ec, total_transferred_); } - else - { - stream_.async_read_some_at( - offset_ + total_transferred_, buffers_, *this); - } } //private: - AsyncRandomAccessReadDevice& stream_; + AsyncRandomAccessReadDevice& device_; boost::uint64_t offset_; - buffers_type buffers_; + boost::asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> buffers_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template + class read_at_op + : detail::base_from_completion_cond + { + public: + read_at_op(AsyncRandomAccessReadDevice& device, + boost::uint64_t offset, const boost::asio::mutable_buffers_1& buffers, + CompletionCondition completion_condition, ReadHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffer_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (start) + { + case 1: + n = this->check_for_completion(ec, total_transferred_); + for (;;) + { + device_.async_read_some_at(offset_ + total_transferred_, + boost::asio::buffer(buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check_for_completion(ec, total_transferred_)) == 0 + || total_transferred_ == boost::asio::buffer_size(buffer_)) + break; + } + + handler_(ec, total_transferred_); + } + } + + //private: + AsyncRandomAccessReadDevice& device_; + boost::uint64_t offset_; + boost::asio::mutable_buffer buffer_; std::size_t total_transferred_; - CompletionCondition completion_condition_; ReadHandler handler_; }; @@ -184,7 +242,7 @@ namespace detail typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_at_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -195,7 +253,7 @@ namespace detail typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_at_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -206,7 +264,7 @@ namespace detail typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_at_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -220,24 +278,10 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) { - boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> tmp(buffers); - - boost::system::error_code ec; - std::size_t total_transferred = 0; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - if (tmp.begin() == tmp.end()) - { - d.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - d.async_read_some_at(offset, tmp, - detail::read_at_handler( - d, offset, tmp, completion_condition, handler)); + detail::read_at_op( + d, offset, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); } template - class read_at_streambuf_handler + class read_at_streambuf_op + : detail::base_from_completion_cond { public: - read_at_streambuf_handler(AsyncRandomAccessReadDevice& stream, + read_at_streambuf_op(AsyncRandomAccessReadDevice& device, boost::uint64_t offset, basic_streambuf& streambuf, CompletionCondition completion_condition, ReadHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), offset_(offset), streambuf_(streambuf), total_transferred_(0), - completion_condition_(completion_condition), handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - total_transferred_ += bytes_transferred; - streambuf_.commit(bytes_transferred); - std::size_t max_size = detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_)); - std::size_t bytes_available = std::min(512, - std::min(max_size, - streambuf_.max_size() - streambuf_.size())); - if (bytes_available == 0) + std::size_t max_size, bytes_available; + switch (start) { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + for (;;) + { + device_.async_read_some_at(offset_ + total_transferred_, + streambuf_.prepare(bytes_available), *this); + return; default: + total_transferred_ += bytes_transferred; + streambuf_.commit(bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + if ((!ec && bytes_transferred == 0) || bytes_available == 0) + break; + } + handler_(ec, total_transferred_); } - else - { - stream_.async_read_some_at(offset_ + total_transferred_, - streambuf_.prepare(bytes_available), *this); - } } //private: - AsyncRandomAccessReadDevice& stream_; + AsyncRandomAccessReadDevice& device_; boost::uint64_t offset_; boost::asio::basic_streambuf& streambuf_; std::size_t total_transferred_; - CompletionCondition completion_condition_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, - read_at_streambuf_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -313,7 +363,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_at_streambuf_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -323,7 +373,7 @@ namespace detail template inline void asio_handler_invoke(const Function& function, - read_at_streambuf_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -337,23 +387,10 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, boost::asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { - boost::system::error_code ec; - std::size_t total_transferred = 0; - std::size_t max_size = detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred)); - std::size_t bytes_available = std::min(512, - std::min(max_size, b.max_size() - b.size())); - if (bytes_available == 0) - { - d.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - d.async_read_some_at(offset, b.prepare(bytes_available), - detail::read_at_streambuf_handler( - d, offset, b, completion_condition, handler)); + detail::read_at_streambuf_op( + d, offset, b, completion_condition, handler)( + boost::system::error_code(), 0, 1); } template -#endif // BOOST_ASIO_READ_AT_IPP +#endif // BOOST_ASIO_IMPL_READ_AT_HPP diff --git a/include/boost/asio/impl/read_until.hpp b/include/boost/asio/impl/read_until.hpp new file mode 100644 index 00000000..f3d8819e --- /dev/null +++ b/include/boost/asio/impl/read_until.hpp @@ -0,0 +1,876 @@ +// +// impl/read_until.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP +#define BOOST_ASIO_IMPL_READ_UNTIL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, char delim) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, b, delim, ec); + boost::asio::detail::throw_error(ec); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, char delim, + boost::system::error_code& ec) +{ + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename boost::asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef boost::asio::buffers_iterator iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + iterator iter = std::find(start, end, delim); + if (iter != end) + { + // Found a match. We're done. + ec = boost::system::error_code(); + return iter - begin + 1; + } + else + { + // No match. Next search can start with the new data. + search_position = 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_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const std::string& delim) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, b, delim, ec); + boost::asio::detail::throw_error(ec); + return bytes_transferred; +} + +namespace detail +{ + // Algorithm that finds a subsequence of equal values in a sequence. Returns + // (iterator,true) if a full match was found, in which case the iterator + // points to the beginning of the match. Returns (iterator,false) if a + // partial match was found at the end of the first sequence, in which case + // the iterator points to the beginning of the partial match. Returns + // (last1,false) if no full or partial match was found. + template + std::pair partial_search( + Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) + { + for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) + { + Iterator1 test_iter1 = iter1; + Iterator2 test_iter2 = first2; + for (;; ++test_iter1, ++test_iter2) + { + if (test_iter2 == last2) + return std::make_pair(iter1, true); + if (test_iter1 == last1) + { + if (test_iter2 != first2) + return std::make_pair(iter1, false); + else + break; + } + if (*test_iter1 != *test_iter2) + break; + } + } + return std::make_pair(last1, false); + } +} // namespace detail + +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const std::string& delim, + boost::system::error_code& ec) +{ + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename boost::asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef boost::asio::buffers_iterator iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair result = detail::partial_search( + start, end, delim.begin(), delim.end()); + if (result.first != end) + { + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin + delim.length(); + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = 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_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, b, expr, ec); + boost::asio::detail::throw_error(ec); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr, + boost::system::error_code& ec) +{ + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename boost::asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef boost::asio::buffers_iterator iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + boost::match_results >::allocator_type> + match_results; + if (regex_search(start, end, match_results, expr, + boost::match_default | boost::match_partial)) + { + if (match_results[0].matched) + { + // Full match. We're done. + ec = boost::system::error_code(); + return match_results[0].second - begin; + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = match_results[0].first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = 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_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, + MatchCondition match_condition, boost::system::error_code& ec, + typename boost::enable_if >::type*) +{ + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename boost::asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef boost::asio::buffers_iterator iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair result = match_condition(start, end); + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + else + { + // No match. Next search can start with the new data. + search_position = 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_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, MatchCondition match_condition, + typename boost::enable_if >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, b, match_condition, ec); + boost::asio::detail::throw_error(ec); + return bytes_transferred; +} + +namespace detail +{ + template + class read_until_delim_op + { + public: + read_until_delim_op(AsyncReadStream& stream, + boost::asio::basic_streambuf& streambuf, + char delim, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + delim_(delim), + search_position_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename boost::asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef boost::asio::buffers_iterator iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + iterator iter = std::find(start, end, delim_); + if (iter != end) + { + // Found a match. We're done. + search_position_ = iter - begin + 1; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + // Next search can start with the new data. + search_position_ = end - begin; + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + handler_(search_position_ == not_found ? error::not_found : ec, + ec || search_position_ == not_found ? 0 : search_position_); + } + } + + //private: + AsyncReadStream& stream_; + boost::asio::basic_streambuf& streambuf_; + char delim_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_delim_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template +void async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, char delim, ReadHandler handler) +{ + detail::read_until_delim_op< + AsyncReadStream, Allocator, ReadHandler>( + s, b, delim, handler)( + boost::system::error_code(), 0, 1); +} + +namespace detail +{ + template + class read_until_delim_string_op + { + public: + read_until_delim_string_op(AsyncReadStream& stream, + boost::asio::basic_streambuf& streambuf, + const std::string& delim, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + delim_(delim), + search_position_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename boost::asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef boost::asio::buffers_iterator iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair result = detail::partial_search( + start, end, delim_.begin(), delim_.end()); + if (result.first != end && result.second) + { + // Full match. We're done. + search_position_ = result.first - begin + delim_.length(); + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + handler_(search_position_ == not_found ? error::not_found : ec, + ec || search_position_ == not_found ? 0 : search_position_); + } + } + + //private: + AsyncReadStream& stream_; + boost::asio::basic_streambuf& streambuf_; + std::string delim_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_string_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_string_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_delim_string_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template +void async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, const std::string& delim, + ReadHandler handler) +{ + detail::read_until_delim_string_op< + AsyncReadStream, Allocator, ReadHandler>( + s, b, delim, handler)( + boost::system::error_code(), 0, 1); +} + +namespace detail +{ + template + class read_until_expr_op + { + public: + read_until_expr_op(AsyncReadStream& stream, + boost::asio::basic_streambuf& streambuf, + const boost::regex& expr, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + expr_(expr), + search_position_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename boost::asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef boost::asio::buffers_iterator iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + boost::match_results >::allocator_type> + match_results; + bool match = regex_search(start, end, match_results, expr_, + boost::match_default | boost::match_partial); + if (match && match_results[0].matched) + { + // Full match. We're done. + search_position_ = match_results[0].second - begin; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (match) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = match_results[0].first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + handler_(search_position_ == not_found ? error::not_found : ec, + ec || search_position_ == not_found ? 0 : search_position_); + } + } + + //private: + AsyncReadStream& stream_; + boost::asio::basic_streambuf& streambuf_; + RegEx expr_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_expr_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_expr_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_expr_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template +void async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr, + ReadHandler handler) +{ + detail::read_until_expr_op( + s, b, expr, handler)( + boost::system::error_code(), 0, 1); +} + +namespace detail +{ + template + class read_until_match_op + { + public: + read_until_match_op(AsyncReadStream& stream, + boost::asio::basic_streambuf& streambuf, + MatchCondition match_condition, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + match_condition_(match_condition), + search_position_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename boost::asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef boost::asio::buffers_iterator iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair result = match_condition_(start, end); + if (result.second) + { + // Full match. We're done. + search_position_ = result.first - begin; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + handler_(search_position_ == not_found ? error::not_found : ec, + ec || search_position_ == not_found ? 0 : search_position_); + } + } + + //private: + AsyncReadStream& stream_; + boost::asio::basic_streambuf& streambuf_; + MatchCondition match_condition_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_match_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_match_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_match_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template +void async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, + MatchCondition match_condition, ReadHandler handler, + typename boost::enable_if >::type*) +{ + detail::read_until_match_op< + AsyncReadStream, Allocator, MatchCondition, ReadHandler>( + s, b, match_condition, handler)( + boost::system::error_code(), 0, 1); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP diff --git a/include/boost/asio/impl/read_until.ipp b/include/boost/asio/impl/read_until.ipp deleted file mode 100644 index 0ee0de0d..00000000 --- a/include/boost/asio/impl/read_until.ipp +++ /dev/null @@ -1,989 +0,0 @@ -// -// read_until.ipp -// ~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_ASIO_READ_UNTIL_IPP -#define BOOST_ASIO_READ_UNTIL_IPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace asio { - -template -inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, char delim) -{ - boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, delim, ec); - boost::asio::detail::throw_error(ec); - return bytes_transferred; -} - -template -std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, char delim, - boost::system::error_code& ec) -{ - std::size_t next_search_start = 0; - for (;;) - { - // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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. - iterator iter = std::find(start, end, delim); - if (iter != end) - { - // Found a match. We're done. - ec = boost::system::error_code(); - return iter - begin + 1; - } - 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(512, b.max_size() - b.size()); - b.commit(s.read_some(b.prepare(bytes_available), ec)); - if (ec) - return 0; - } -} - -template -inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, const std::string& delim) -{ - boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, delim, ec); - boost::asio::detail::throw_error(ec); - return bytes_transferred; -} - -namespace detail -{ - // Algorithm that finds a subsequence of equal values in a sequence. Returns - // (iterator,true) if a full match was found, in which case the iterator - // points to the beginning of the match. Returns (iterator,false) if a - // partial match was found at the end of the first sequence, in which case - // the iterator points to the beginning of the partial match. Returns - // (last1,false) if no full or partial match was found. - template - std::pair partial_search( - Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) - { - for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) - { - Iterator1 test_iter1 = iter1; - Iterator2 test_iter2 = first2; - for (;; ++test_iter1, ++test_iter2) - { - if (test_iter2 == last2) - return std::make_pair(iter1, true); - if (test_iter1 == last1) - { - if (test_iter2 != first2) - return std::make_pair(iter1, false); - else - break; - } - if (*test_iter1 != *test_iter2) - break; - } - } - return std::make_pair(last1, false); - } -} // namespace detail - -template -std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, const std::string& delim, - boost::system::error_code& ec) -{ - std::size_t next_search_start = 0; - for (;;) - { - // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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 result = boost::asio::detail::partial_search( - start, end, delim.begin(), delim.end()); - if (result.first != end) - { - if (result.second) - { - // Full match. We're done. - ec = boost::system::error_code(); - return result.first - begin + delim.length(); - } - 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(512, b.max_size() - b.size()); - b.commit(s.read_some(b.prepare(bytes_available), ec)); - if (ec) - return 0; - } -} - -template -inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, const boost::regex& expr) -{ - boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, expr, ec); - boost::asio::detail::throw_error(ec); - return bytes_transferred; -} - -template -std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, const boost::regex& expr, - boost::system::error_code& ec) -{ - std::size_t next_search_start = 0; - for (;;) - { - // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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. - boost::match_results match_results; - 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 = boost::system::error_code(); - 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 - 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(512, b.max_size() - b.size()); - b.commit(s.read_some(b.prepare(bytes_available), ec)); - if (ec) - return 0; - } -} - -template -std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, - MatchCondition match_condition, boost::system::error_code& ec, - typename boost::enable_if >::type*) -{ - std::size_t next_search_start = 0; - for (;;) - { - // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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 result = match_condition(start, end); - if (result.second) - { - // Full match. We're done. - ec = boost::system::error_code(); - return result.first - begin; - } - else if (result.first != end) - { - // 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(512, b.max_size() - b.size()); - b.commit(s.read_some(b.prepare(bytes_available), ec)); - if (ec) - return 0; - } -} - -template -inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, MatchCondition match_condition, - typename boost::enable_if >::type*) -{ - boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, match_condition, ec); - boost::asio::detail::throw_error(ec); - return bytes_transferred; -} - -namespace detail -{ - template - class read_until_delim_handler - { - public: - read_until_delim_handler(AsyncReadStream& stream, - boost::asio::basic_streambuf& streambuf, char delim, - std::size_t next_search_start, ReadHandler handler) - : stream_(stream), - streambuf_(streambuf), - delim_(delim), - next_search_start_(next_search_start), - handler_(handler) - { - } - - void operator()(const boost::system::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 boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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. - iterator iter = std::find(start, end, delim_); - if (iter != end) - { - // Found a match. We're done. - std::size_t bytes = iter - begin + 1; - handler_(ec, bytes); - return; - } - - // No match. Check if buffer is full. - if (streambuf_.size() == streambuf_.max_size()) - { - std::size_t bytes = 0; - boost::system::error_code ec(error::not_found); - handler_(ec, bytes); - return; - } - - // Next search can start with the new data. - next_search_start_ = end - begin; - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, streambuf_.max_size() - streambuf_.size()); - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } - - //private: - AsyncReadStream& stream_; - boost::asio::basic_streambuf& streambuf_; - char delim_; - std::size_t next_search_start_; - ReadHandler handler_; - }; - - template - inline void* asio_handler_allocate(std::size_t size, - read_until_delim_handler* this_handler) - { - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_handler* this_handler) - { - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template - inline void asio_handler_invoke(const Function& function, - read_until_delim_handler* this_handler) - { - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } -} // namespace detail - -template -void async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf& b, char delim, ReadHandler handler) -{ - // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); - iterator end = iterator::end(buffers); - - // Look for a match. - iterator iter = std::find(begin, end, delim); - if (iter != end) - { - // Found a match. We're done. - boost::system::error_code ec; - std::size_t bytes = iter - begin + 1; - s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); - return; - } - - // No match. Check if buffer is full. - if (b.size() == b.max_size()) - { - boost::system::error_code ec(error::not_found); - s.get_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(512, b.max_size() - b.size()); - s.async_read_some(b.prepare(bytes_available), - detail::read_until_delim_handler( - s, b, delim, end - begin, handler)); -} - -namespace detail -{ - template - class read_until_delim_string_handler - { - public: - read_until_delim_string_handler(AsyncReadStream& stream, - boost::asio::basic_streambuf& streambuf, - const std::string& delim, std::size_t next_search_start, - ReadHandler handler) - : stream_(stream), - streambuf_(streambuf), - delim_(delim), - next_search_start_(next_search_start), - handler_(handler) - { - } - - void operator()(const boost::system::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 boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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 result = boost::asio::detail::partial_search( - start, end, delim_.begin(), delim_.end()); - if (result.first != end) - { - if (result.second) - { - // Full match. We're done. - 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 - 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; - boost::system::error_code ec2(error::not_found); - handler_(ec2, bytes); - return; - } - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, streambuf_.max_size() - streambuf_.size()); - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } - - //private: - AsyncReadStream& stream_; - boost::asio::basic_streambuf& streambuf_; - std::string delim_; - std::size_t next_search_start_; - ReadHandler handler_; - }; - - template - inline void* asio_handler_allocate(std::size_t size, - read_until_delim_string_handler* this_handler) - { - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_string_handler* this_handler) - { - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template - inline void asio_handler_invoke(const Function& function, - read_until_delim_string_handler* this_handler) - { - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } -} // namespace detail - -template -void async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf& b, const std::string& delim, - ReadHandler handler) -{ - // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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 result = boost::asio::detail::partial_search( - begin, end, delim.begin(), delim.end()); - if (result.first != end) - { - if (result.second) - { - // Full match. We're done. - boost::system::error_code ec; - std::size_t bytes = result.first - begin + delim.length(); - s.get_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()) - { - boost::system::error_code ec(error::not_found); - s.get_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(512, b.max_size() - b.size()); - s.async_read_some(b.prepare(bytes_available), - detail::read_until_delim_string_handler< - AsyncReadStream, Allocator, ReadHandler>( - s, b, delim, next_search_start, handler)); -} - -namespace detail -{ - template - class read_until_expr_handler - { - public: - read_until_expr_handler(AsyncReadStream& stream, - boost::asio::basic_streambuf& streambuf, - const boost::regex& expr, std::size_t next_search_start, - ReadHandler handler) - : stream_(stream), - streambuf_(streambuf), - expr_(expr), - next_search_start_(next_search_start), - handler_(handler) - { - } - - void operator()(const boost::system::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 boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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. - boost::match_results match_results; - 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 - begin; - handler_(ec, bytes); - return; - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start_ = match_results[0].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; - boost::system::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(512, streambuf_.max_size() - streambuf_.size()); - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } - - //private: - AsyncReadStream& stream_; - boost::asio::basic_streambuf& streambuf_; - boost::regex expr_; - std::size_t next_search_start_; - ReadHandler handler_; - }; - - template - inline void* asio_handler_allocate(std::size_t size, - read_until_expr_handler* this_handler) - { - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_expr_handler* this_handler) - { - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template - inline void asio_handler_invoke(const Function& function, - read_until_expr_handler* this_handler) - { - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } -} // namespace detail - -template -void async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf& b, const boost::regex& expr, - ReadHandler handler) -{ - // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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; - boost::match_results match_results; - if (boost::regex_search(begin, end, match_results, expr, - boost::match_default | boost::match_partial)) - { - if (match_results[0].matched) - { - // Full match. We're done. - boost::system::error_code ec; - std::size_t bytes = match_results[0].second - begin; - s.get_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 - 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()) - { - boost::system::error_code ec(error::not_found); - s.get_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(512, b.max_size() - b.size()); - s.async_read_some(b.prepare(bytes_available), - detail::read_until_expr_handler( - s, b, expr, next_search_start, handler)); -} - -namespace detail -{ - template - class read_until_match_handler - { - public: - read_until_match_handler(AsyncReadStream& stream, - boost::asio::basic_streambuf& 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 boost::system::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 boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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 result = match_condition_(start, end); - if (result.second) - { - // Full match. We're done. - std::size_t bytes = result.first - begin; - handler_(ec, bytes); - return; - } - else if (result.first != end) - { - // 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; - boost::system::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(512, streambuf_.max_size() - streambuf_.size()); - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } - - //private: - AsyncReadStream& stream_; - boost::asio::basic_streambuf& streambuf_; - MatchCondition match_condition_; - std::size_t next_search_start_; - ReadHandler handler_; - }; - - template - inline void* asio_handler_allocate(std::size_t size, - read_until_match_handler* this_handler) - { - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_match_handler* this_handler) - { - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template - inline void asio_handler_invoke(const Function& function, - read_until_match_handler* this_handler) - { - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } -} // namespace detail - -template -void async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf& b, - MatchCondition match_condition, ReadHandler handler, - typename boost::enable_if >::type*) -{ - // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator 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 result = match_condition(begin, end); - if (result.second) - { - // Full match. We're done. - boost::system::error_code ec; - std::size_t bytes = result.first - begin; - s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); - return; - } - else if (result.first != end) - { - // 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()) - { - boost::system::error_code ec(error::not_found); - s.get_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(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 -} // namespace boost - -#include - -#endif // BOOST_ASIO_READ_UNTIL_IPP diff --git a/include/boost/asio/impl/serial_port_base.hpp b/include/boost/asio/impl/serial_port_base.hpp new file mode 100644 index 00000000..2b291f39 --- /dev/null +++ b/include/boost/asio/impl/serial_port_base.hpp @@ -0,0 +1,61 @@ +// +// impl/serial_port_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 BOOST_ASIO_IMPL_SERIAL_PORT_BASE_HPP +#define BOOST_ASIO_IMPL_SERIAL_PORT_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +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 serial_port_base::flow_control::type +serial_port_base::flow_control::value() const +{ + return value_; +} + +inline serial_port_base::parity::type serial_port_base::parity::value() const +{ + return value_; +} + +inline serial_port_base::stop_bits::type +serial_port_base::stop_bits::value() const +{ + return value_; +} + +inline unsigned int serial_port_base::character_size::value() const +{ + return value_; +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_HPP diff --git a/include/boost/asio/impl/serial_port_base.ipp b/include/boost/asio/impl/serial_port_base.ipp index 2775a02b..1eb96b02 100644 --- a/include/boost/asio/impl/serial_port_base.ipp +++ b/include/boost/asio/impl/serial_port_base.ipp @@ -1,6 +1,6 @@ // -// serial_port_base.ipp -// ~~~~~~~~~~~~~~~~~~~~ +// impl/serial_port_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) @@ -9,33 +9,36 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_SERIAL_PORT_BASE_IPP -#define BOOST_ASIO_SERIAL_PORT_BASE_IPP +#ifndef BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP +#define BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#include +#include +#include +#include + +#if defined(GENERATING_DOCUMENTATION) +# define BOOST_ASIO_OPTION_STORAGE implementation_defined +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# define BOOST_ASIO_OPTION_STORAGE DCB +#else +# define BOOST_ASIO_OPTION_STORAGE termios +#endif #include -#include -#include namespace boost { 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 boost::system::error_code serial_port_base::baud_rate::store( +boost::system::error_code serial_port_base::baud_rate::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -123,7 +126,7 @@ inline boost::system::error_code serial_port_base::baud_rate::store( return ec; } -inline boost::system::error_code serial_port_base::baud_rate::load( +boost::system::error_code serial_port_base::baud_rate::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -205,7 +208,7 @@ inline boost::system::error_code serial_port_base::baud_rate::load( return ec; } -inline serial_port_base::flow_control::flow_control( +serial_port_base::flow_control::flow_control( serial_port_base::flow_control::type t) : value_(t) { @@ -216,13 +219,7 @@ inline serial_port_base::flow_control::flow_control( } } -inline serial_port_base::flow_control::type -serial_port_base::flow_control::value() const -{ - return value_; -} - -inline boost::system::error_code serial_port_base::flow_control::store( +boost::system::error_code serial_port_base::flow_control::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -281,7 +278,7 @@ inline boost::system::error_code serial_port_base::flow_control::store( return ec; } -inline boost::system::error_code serial_port_base::flow_control::load( +boost::system::error_code serial_port_base::flow_control::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -317,7 +314,7 @@ inline boost::system::error_code serial_port_base::flow_control::load( return ec; } -inline serial_port_base::parity::parity(serial_port_base::parity::type t) +serial_port_base::parity::parity(serial_port_base::parity::type t) : value_(t) { if (t != none && t != odd && t != even) @@ -327,12 +324,7 @@ inline serial_port_base::parity::parity(serial_port_base::parity::type t) } } -inline serial_port_base::parity::type serial_port_base::parity::value() const -{ - return value_; -} - -inline boost::system::error_code serial_port_base::parity::store( +boost::system::error_code serial_port_base::parity::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -379,7 +371,7 @@ inline boost::system::error_code serial_port_base::parity::store( return ec; } -inline boost::system::error_code serial_port_base::parity::load( +boost::system::error_code serial_port_base::parity::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -416,7 +408,7 @@ inline boost::system::error_code serial_port_base::parity::load( return ec; } -inline serial_port_base::stop_bits::stop_bits( +serial_port_base::stop_bits::stop_bits( serial_port_base::stop_bits::type t) : value_(t) { @@ -427,13 +419,7 @@ inline serial_port_base::stop_bits::stop_bits( } } -inline serial_port_base::stop_bits::type -serial_port_base::stop_bits::value() const -{ - return value_; -} - -inline boost::system::error_code serial_port_base::stop_bits::store( +boost::system::error_code serial_port_base::stop_bits::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -469,7 +455,7 @@ inline boost::system::error_code serial_port_base::stop_bits::store( return ec; } -inline boost::system::error_code serial_port_base::stop_bits::load( +boost::system::error_code serial_port_base::stop_bits::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -496,7 +482,7 @@ inline boost::system::error_code serial_port_base::stop_bits::load( return ec; } -inline serial_port_base::character_size::character_size(unsigned int t) +serial_port_base::character_size::character_size(unsigned int t) : value_(t) { if (t < 5 || t > 8) @@ -506,12 +492,7 @@ inline serial_port_base::character_size::character_size(unsigned int t) } } -inline unsigned int serial_port_base::character_size::value() const -{ - return value_; -} - -inline boost::system::error_code serial_port_base::character_size::store( +boost::system::error_code serial_port_base::character_size::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -531,7 +512,7 @@ inline boost::system::error_code serial_port_base::character_size::store( return ec; } -inline boost::system::error_code serial_port_base::character_size::load( +boost::system::error_code serial_port_base::character_size::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -556,4 +537,8 @@ inline boost::system::error_code serial_port_base::character_size::load( #include -#endif // BOOST_ASIO_SERIAL_PORT_BASE_IPP +#undef BOOST_ASIO_OPTION_STORAGE + +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP diff --git a/include/boost/asio/impl/src.cpp b/include/boost/asio/impl/src.cpp new file mode 100644 index 00000000..59a10c95 --- /dev/null +++ b/include/boost/asio/impl/src.cpp @@ -0,0 +1,59 @@ +// +// impl/src.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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) +// + +#define BOOST_ASIO_SOURCE + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# error Do not compile Asio library source with BOOST_ASIO_HEADER_ONLY defined +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/include/boost/asio/impl/write.ipp b/include/boost/asio/impl/write.hpp similarity index 92% rename from include/boost/asio/impl/write.ipp rename to include/boost/asio/impl/write.hpp index 28a5273c..0792f2cb 100644 --- a/include/boost/asio/impl/write.ipp +++ b/include/boost/asio/impl/write.hpp @@ -1,6 +1,6 @@ // -// write.ipp -// ~~~~~~~~~ +// impl/write.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,15 +8,13 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_WRITE_IPP -#define BOOST_ASIO_WRITE_IPP +#ifndef BOOST_ASIO_IMPL_WRITE_HPP +#define BOOST_ASIO_IMPL_WRITE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include #include #include @@ -26,6 +24,8 @@ #include #include +#include + namespace boost { namespace asio { @@ -123,25 +123,24 @@ namespace detail stream_(stream), buffers_(buffers), total_transferred_(0), - handler_(handler), - start_(true) + handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - switch (start_) + switch (start) { - case true: start_ = false; - buffers_.prepare(this->check(ec, total_transferred_)); + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); for (;;) { stream_.async_write_some(buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.prepare(this->check(ec, total_transferred_)); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; @@ -157,7 +156,6 @@ namespace detail const_buffer, ConstBufferSequence> buffers_; std::size_t total_transferred_; WriteHandler handler_; - bool start_; }; template check(ec, total_transferred_); + case 1: + n = this->check_for_completion(ec, total_transferred_); for (;;) { stream_.async_write_some(boost::asio::buffer( @@ -196,7 +193,7 @@ namespace detail return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) - || (n = this->check(ec, total_transferred_)) == 0 + || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == boost::asio::buffer_size(buffer_)) break; } @@ -210,7 +207,6 @@ namespace detail boost::asio::mutable_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; - bool start_; }; template check(ec, total_transferred_); + case 1: + n = this->check_for_completion(ec, total_transferred_); for (;;) { stream_.async_write_some(boost::asio::buffer( @@ -249,7 +244,7 @@ namespace detail return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) - || (n = this->check(ec, total_transferred_)) == 0 + || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == boost::asio::buffer_size(buffer_)) break; } @@ -263,7 +258,6 @@ namespace detail boost::asio::const_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; - bool start_; }; template ( s, buffers, completion_condition, handler)( - boost::system::error_code(), 0); + boost::system::error_code(), 0, 1); } template -#endif // BOOST_ASIO_WRITE_IPP +#endif // BOOST_ASIO_IMPL_WRITE_HPP diff --git a/include/boost/asio/impl/write_at.ipp b/include/boost/asio/impl/write_at.hpp similarity index 61% rename from include/boost/asio/impl/write_at.ipp rename to include/boost/asio/impl/write_at.hpp index 3d1a1128..daa14420 100644 --- a/include/boost/asio/impl/write_at.ipp +++ b/include/boost/asio/impl/write_at.hpp @@ -1,6 +1,6 @@ // -// write_at.ipp -// ~~~~~~~~~~~~ +// impl/write_at.hpp +// ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,23 +8,24 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_WRITE_AT_IPP -#define BOOST_ASIO_WRITE_AT_IPP +#ifndef BOOST_ASIO_IMPL_WRITE_AT_HPP +#define BOOST_ASIO_IMPL_WRITE_AT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include #include +#include #include #include #include #include #include +#include + namespace boost { namespace asio { @@ -119,55 +120,166 @@ namespace detail { template - class write_at_handler + class write_at_op + : detail::base_from_completion_cond { public: - typedef boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> buffers_type; - - write_at_handler(AsyncRandomAccessWriteDevice& stream, - boost::uint64_t offset, const buffers_type& buffers, + write_at_op(AsyncRandomAccessWriteDevice& device, + boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) - : stream_(stream), - buffers_(buffers), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), offset_(offset), + buffers_(buffers), total_transferred_(0), - completion_condition_(completion_condition), handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - total_transferred_ += bytes_transferred; - buffers_.consume(bytes_transferred); - buffers_.prepare(detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_))); - if (buffers_.begin() == buffers_.end()) + switch (start) { + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + for (;;) + { + device_.async_write_some_at( + offset_ + total_transferred_, buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + handler_(ec, total_transferred_); } - else - { - stream_.async_write_some_at( - offset_ + total_transferred_, buffers_, *this); - } } //private: - AsyncRandomAccessWriteDevice& stream_; - buffers_type buffers_; + AsyncRandomAccessWriteDevice& device_; boost::uint64_t offset_; + boost::asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> buffers_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template + class write_at_op + : detail::base_from_completion_cond + { + public: + write_at_op(AsyncRandomAccessWriteDevice& device, + boost::uint64_t offset, const boost::asio::mutable_buffers_1& buffers, + CompletionCondition completion_condition, + WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffer_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (start) + { + case 1: + n = this->check_for_completion(ec, total_transferred_); + for (;;) + { + device_.async_write_some_at(offset_ + total_transferred_, + boost::asio::buffer(buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check_for_completion(ec, total_transferred_)) == 0 + || total_transferred_ == boost::asio::buffer_size(buffer_)) + break; + } + + handler_(ec, total_transferred_); + } + } + + //private: + AsyncRandomAccessWriteDevice& device_; + boost::uint64_t offset_; + boost::asio::mutable_buffer buffer_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template + class write_at_op + : detail::base_from_completion_cond + { + public: + write_at_op(AsyncRandomAccessWriteDevice& device, + boost::uint64_t offset, const boost::asio::const_buffers_1& buffers, + CompletionCondition completion_condition, + WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffer_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (start) + { + case 1: + n = this->check_for_completion(ec, total_transferred_); + for (;;) + { + device_.async_write_some_at(offset_ + total_transferred_, + boost::asio::buffer(buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check_for_completion(ec, total_transferred_)) == 0 + || total_transferred_ == boost::asio::buffer_size(buffer_)) + break; + } + + handler_(ec, total_transferred_); + } + } + + //private: + AsyncRandomAccessWriteDevice& device_; + boost::uint64_t offset_; + boost::asio::const_buffer buffer_; std::size_t total_transferred_; - CompletionCondition completion_condition_; WriteHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, - write_at_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -177,7 +289,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_at_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -188,7 +300,7 @@ namespace detail typename ConstBufferSequence, typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(const Function& function, - write_at_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -202,24 +314,10 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) { - boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> tmp(buffers); - - boost::system::error_code ec; - std::size_t total_transferred = 0; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - if (tmp.begin() == tmp.end()) - { - d.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - d.async_write_some_at(offset, tmp, - detail::write_at_handler( - d, offset, tmp, completion_condition, handler)); + detail::write_at_op( + d, offset, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); } template - class write_at_streambuf_handler + template + class write_at_streambuf_op { public: - write_at_streambuf_handler( + write_at_streambuf_op( boost::asio::basic_streambuf& streambuf, WriteHandler handler) : streambuf_(streambuf), @@ -263,7 +361,7 @@ namespace detail template inline void* asio_handler_allocate(std::size_t size, - write_at_streambuf_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -273,7 +371,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_at_streambuf_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -283,7 +381,7 @@ namespace detail template inline void asio_handler_invoke(const Function& function, - write_at_streambuf_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -298,7 +396,7 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d, CompletionCondition completion_condition, WriteHandler handler) { async_write_at(d, offset, b.data(), completion_condition, - detail::write_at_streambuf_handler< + detail::write_at_streambuf_op< AsyncRandomAccessWriteDevice, Allocator, WriteHandler>(b, handler)); } @@ -318,4 +416,4 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d, #include -#endif // BOOST_ASIO_WRITE_AT_IPP +#endif // BOOST_ASIO_IMPL_WRITE_AT_HPP diff --git a/include/boost/asio/io_service.hpp b/include/boost/asio/io_service.hpp index 3863e96f..9350a84a 100644 --- a/include/boost/asio/io_service.hpp +++ b/include/boost/asio/io_service.hpp @@ -15,25 +15,29 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include -#include -#include -#include - #include -#include #include -#include -#include -#include -#include #include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) +# include +#endif + +#include namespace boost { namespace asio { @@ -46,7 +50,7 @@ template bool has_service(io_service& ios); #if defined(BOOST_ASIO_HAS_IOCP) namespace detail { typedef win_iocp_io_service io_service_impl; } #else -namespace detail { typedef task_io_service io_service_impl; } +namespace detail { typedef task_io_service io_service_impl; } #endif /// Provides core I/O functionality. @@ -197,7 +201,7 @@ public: class strand; /// Constructor. - io_service(); + BOOST_ASIO_DECL io_service(); /// Constructor. /** @@ -206,7 +210,7 @@ public: * @param concurrency_hint A suggestion to the implementation on how many * threads it should allow to run simultaneously. */ - explicit io_service(std::size_t concurrency_hint); + BOOST_ASIO_DECL explicit io_service(std::size_t concurrency_hint); /// Destructor. /** @@ -240,7 +244,7 @@ public: * destructor defined above destroys all handlers, causing all @c shared_ptr * references to all connection objects to be destroyed. */ - ~io_service(); + BOOST_ASIO_DECL ~io_service(); /// Run the io_service object's event processing loop. /** @@ -266,7 +270,7 @@ public: * The poll() function may also be used to dispatch ready handlers, but * without blocking. */ - std::size_t run(); + BOOST_ASIO_DECL std::size_t run(); /// Run the io_service object's event processing loop. /** @@ -292,7 +296,7 @@ public: * The poll() function may also be used to dispatch ready handlers, but * without blocking. */ - std::size_t run(boost::system::error_code& ec); + BOOST_ASIO_DECL std::size_t run(boost::system::error_code& ec); /// Run the io_service object's event processing loop to execute at most one /// handler. @@ -304,7 +308,7 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - std::size_t run_one(); + BOOST_ASIO_DECL std::size_t run_one(); /// Run the io_service object's event processing loop to execute at most one /// handler. @@ -316,7 +320,7 @@ public: * * @return The number of handlers that were executed. */ - std::size_t run_one(boost::system::error_code& ec); + BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec); /// Run the io_service object's event processing loop to execute ready /// handlers. @@ -328,7 +332,7 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - std::size_t poll(); + BOOST_ASIO_DECL std::size_t poll(); /// Run the io_service object's event processing loop to execute ready /// handlers. @@ -340,7 +344,7 @@ public: * * @return The number of handlers that were executed. */ - std::size_t poll(boost::system::error_code& ec); + BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec); /// Run the io_service object's event processing loop to execute one ready /// handler. @@ -352,7 +356,7 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - std::size_t poll_one(); + BOOST_ASIO_DECL std::size_t poll_one(); /// Run the io_service object's event processing loop to execute one ready /// handler. @@ -364,7 +368,7 @@ public: * * @return The number of handlers that were executed. */ - std::size_t poll_one(boost::system::error_code& ec); + BOOST_ASIO_DECL std::size_t poll_one(boost::system::error_code& ec); /// Stop the io_service object's event processing loop. /** @@ -373,7 +377,7 @@ public: * return as soon as possible. Subsequent calls to run(), run_one(), poll() * or poll_one() will return immediately until reset() is called. */ - void stop(); + BOOST_ASIO_DECL void stop(); /// Reset the io_service in preparation for a subsequent run() invocation. /** @@ -386,7 +390,7 @@ public: * This function must not be called while there are any unfinished calls to * the run(), run_one(), poll() or poll_one() functions. */ - void reset(); + BOOST_ASIO_DECL void reset(); /// Request the io_service to invoke the given handler. /** @@ -606,10 +610,10 @@ protected: /** * @param owner The io_service object that owns the service. */ - service(boost::asio::io_service& owner); + BOOST_ASIO_DECL service(boost::asio::io_service& owner); /// Destructor. - virtual ~service(); + BOOST_ASIO_DECL virtual ~service(); private: /// Destroy all user-defined handler objects owned by the service. @@ -632,10 +636,7 @@ class service_already_exists : public std::logic_error { public: - service_already_exists() - : std::logic_error("Service already exists.") - { - } + BOOST_ASIO_DECL service_already_exists(); }; /// Exception thrown when trying to add a service object to an io_service where @@ -644,17 +645,45 @@ class invalid_service_owner : public std::logic_error { public: - invalid_service_owner() - : std::logic_error("Invalid service owner.") + BOOST_ASIO_DECL invalid_service_owner(); +}; + +namespace detail { + +// Special derived service id type to keep classes header-file only. +template +class service_id + : public boost::asio::io_service::id +{ +}; + +// Special service base class to keep classes header-file only. +template +class service_base + : public boost::asio::io_service::service +{ +public: + static boost::asio::detail::service_id id; + + // Constructor. + service_base(boost::asio::io_service& io_service) + : boost::asio::io_service::service(io_service) { } }; +template +boost::asio::detail::service_id service_base::id; + +} // namespace detail } // namespace asio } // namespace boost -#include - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IO_SERVICE_HPP diff --git a/include/boost/asio/ip/address.hpp b/include/boost/asio/ip/address.hpp index 16113f00..8cc3a4b4 100644 --- a/include/boost/asio/ip/address.hpp +++ b/include/boost/asio/ip/address.hpp @@ -1,6 +1,6 @@ // -// address.hpp -// ~~~~~~~~~~~ +// ip/address.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include +#include +#include +#include -#include -#include #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace asio { @@ -48,63 +44,27 @@ class address { public: /// Default constructor. - address() - : type_(ipv4), - ipv4_address_(), - ipv6_address_() - { - } + BOOST_ASIO_DECL address(); /// Construct an address from an IPv4 address. - address(const boost::asio::ip::address_v4& ipv4_address) - : type_(ipv4), - ipv4_address_(ipv4_address), - ipv6_address_() - { - } + BOOST_ASIO_DECL address(const boost::asio::ip::address_v4& ipv4_address); /// Construct an address from an IPv6 address. - address(const boost::asio::ip::address_v6& ipv6_address) - : type_(ipv6), - ipv4_address_(), - ipv6_address_(ipv6_address) - { - } + BOOST_ASIO_DECL address(const boost::asio::ip::address_v6& ipv6_address); /// Copy constructor. - address(const address& other) - : type_(other.type_), - ipv4_address_(other.ipv4_address_), - ipv6_address_(other.ipv6_address_) - { - } + BOOST_ASIO_DECL address(const address& other); /// Assign from another address. - address& operator=(const address& other) - { - type_ = other.type_; - ipv4_address_ = other.ipv4_address_; - ipv6_address_ = other.ipv6_address_; - return *this; - } + BOOST_ASIO_DECL address& operator=(const address& other); /// Assign from an IPv4 address. - address& operator=(const boost::asio::ip::address_v4& ipv4_address) - { - type_ = ipv4; - ipv4_address_ = ipv4_address; - ipv6_address_ = boost::asio::ip::address_v6(); - return *this; - } + BOOST_ASIO_DECL address& operator=( + const boost::asio::ip::address_v4& ipv4_address); /// Assign from an IPv6 address. - address& operator=(const boost::asio::ip::address_v6& ipv6_address) - { - type_ = ipv6; - ipv4_address_ = boost::asio::ip::address_v4(); - ipv6_address_ = ipv6_address; - return *this; - } + BOOST_ASIO_DECL address& operator=( + const boost::asio::ip::address_v6& ipv6_address); /// Get whether the address is an IP version 4 address. bool is_v4() const @@ -119,127 +79,63 @@ public: } /// Get the address as an IP version 4 address. - boost::asio::ip::address_v4 to_v4() const - { - if (type_ != ipv4) - { - boost::system::system_error e( - boost::asio::error::address_family_not_supported); - boost::throw_exception(e); - } - return ipv4_address_; - } + BOOST_ASIO_DECL boost::asio::ip::address_v4 to_v4() const; /// Get the address as an IP version 6 address. - boost::asio::ip::address_v6 to_v6() const - { - if (type_ != ipv6) - { - boost::system::system_error e( - boost::asio::error::address_family_not_supported); - boost::throw_exception(e); - } - return ipv6_address_; - } + BOOST_ASIO_DECL boost::asio::ip::address_v6 to_v6() const; /// Get the address as a string in dotted decimal format. - std::string to_string() const - { - if (type_ == ipv6) - return ipv6_address_.to_string(); - return ipv4_address_.to_string(); - } + BOOST_ASIO_DECL std::string to_string() const; /// Get the address as a string in dotted decimal format. - std::string to_string(boost::system::error_code& ec) const - { - if (type_ == ipv6) - return ipv6_address_.to_string(ec); - return ipv4_address_.to_string(ec); - } + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - static address from_string(const char* str) - { - boost::system::error_code ec; - address addr = from_string(str, ec); - boost::asio::detail::throw_error(ec); - return addr; - } + BOOST_ASIO_DECL static address from_string(const char* str); /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - static address from_string(const char* str, boost::system::error_code& ec) - { - boost::asio::ip::address_v6 ipv6_address = - boost::asio::ip::address_v6::from_string(str, ec); - if (!ec) - { - address tmp; - tmp.type_ = ipv6; - tmp.ipv6_address_ = ipv6_address; - return tmp; - } - - boost::asio::ip::address_v4 ipv4_address = - boost::asio::ip::address_v4::from_string(str, ec); - if (!ec) - { - address tmp; - tmp.type_ = ipv4; - tmp.ipv4_address_ = ipv4_address; - return tmp; - } - - return address(); - } + BOOST_ASIO_DECL static address from_string( + const char* str, boost::system::error_code& ec); /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - static address from_string(const std::string& str) - { - return from_string(str.c_str()); - } + BOOST_ASIO_DECL static address from_string(const std::string& str); /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - static address from_string(const std::string& str, - boost::system::error_code& ec) - { - return from_string(str.c_str(), ec); - } + BOOST_ASIO_DECL static address from_string( + const std::string& str, boost::system::error_code& ec); /// Compare two addresses for equality. - friend bool operator==(const address& a1, const address& a2) - { - if (a1.type_ != a2.type_) - return false; - if (a1.type_ == ipv6) - return a1.ipv6_address_ == a2.ipv6_address_; - return a1.ipv4_address_ == a2.ipv4_address_; - } + BOOST_ASIO_DECL friend bool operator==(const address& a1, const address& a2); /// Compare two addresses for inequality. friend bool operator!=(const address& a1, const address& a2) { - if (a1.type_ != a2.type_) - return true; - if (a1.type_ == ipv6) - return a1.ipv6_address_ != a2.ipv6_address_; - return a1.ipv4_address_ != a2.ipv4_address_; + return !(a1 == a2); } /// Compare addresses for ordering. - friend bool operator<(const address& a1, const address& a2) + BOOST_ASIO_DECL friend bool operator<(const address& a1, const address& a2); + + /// Compare addresses for ordering. + friend bool operator>(const address& a1, const address& a2) { - if (a1.type_ < a2.type_) - return true; - if (a1.type_ > a2.type_) - return false; - if (a1.type_ == ipv6) - return a1.ipv6_address_ < a2.ipv6_address_; - return a1.ipv4_address_ < a2.ipv4_address_; + return a2 < a1; + } + + /// Compare addresses for ordering. + friend bool operator<=(const address& a1, const address& a2) + { + return !(a2 < a1); + } + + /// Compare addresses for ordering. + friend bool operator>=(const address& a1, const address& a2) + { + return !(a1 < a2); } private: @@ -269,11 +165,7 @@ private: */ template std::basic_ostream& operator<<( - std::basic_ostream& os, const address& addr) -{ - os << addr.to_string(); - return os; -} + std::basic_ostream& os, const address& addr); #endif // !defined(BOOST_NO_IOSTREAM) @@ -283,4 +175,9 @@ std::basic_ostream& operator<<( #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IP_ADDRESS_HPP diff --git a/include/boost/asio/ip/address_v4.hpp b/include/boost/asio/ip/address_v4.hpp index 47d36b5d..21c1a7ff 100644 --- a/include/boost/asio/ip/address_v4.hpp +++ b/include/boost/asio/ip/address_v4.hpp @@ -1,6 +1,6 @@ // -// address_v4.hpp -// ~~~~~~~~~~~~~~ +// ip/address_v4.hpp +// ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,24 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include +#include +#include +#include +#include -#include -#include #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace asio { @@ -60,34 +54,10 @@ public: } /// Construct an address from raw bytes. - explicit address_v4(const bytes_type& bytes) - { -#if UCHAR_MAX > 0xFF - if (bytes[0] > 0xFF || bytes[1] > 0xFF - || bytes[2] > 0xFF || bytes[3] > 0xFF) - { - std::out_of_range ex("address_v4 from bytes_type"); - boost::throw_exception(ex); - } -#endif // UCHAR_MAX > 0xFF - - using namespace std; // For memcpy. - memcpy(&addr_.s_addr, bytes.elems, 4); - } + BOOST_ASIO_DECL explicit address_v4(const bytes_type& bytes); /// Construct an address from a unsigned long in host byte order. - explicit address_v4(unsigned long addr) - { -#if ULONG_MAX > 0xFFFFFFFF - if (addr > 0xFFFFFFFF) - { - std::out_of_range ex("address_v4 from unsigned long"); - boost::throw_exception(ex); - } -#endif // ULONG_MAX > 0xFFFFFFFF - - addr_.s_addr = boost::asio::detail::socket_ops::host_to_network_long(addr); - } + BOOST_ASIO_DECL explicit address_v4(unsigned long addr); /// Copy constructor. address_v4(const address_v4& other) @@ -103,96 +73,42 @@ public: } /// Get the address in bytes, in network byte order. - bytes_type to_bytes() const - { - using namespace std; // For memcpy. - bytes_type bytes; - memcpy(bytes.elems, &addr_.s_addr, 4); - return bytes; - } + BOOST_ASIO_DECL bytes_type to_bytes() const; /// Get the address as an unsigned long in host byte order - unsigned long to_ulong() const - { - return boost::asio::detail::socket_ops::network_to_host_long(addr_.s_addr); - } + BOOST_ASIO_DECL unsigned long to_ulong() const; /// Get the address as a string in dotted decimal format. - std::string to_string() const - { - boost::system::error_code ec; - std::string addr = to_string(ec); - boost::asio::detail::throw_error(ec); - return addr; - } + BOOST_ASIO_DECL std::string to_string() const; /// Get the address as a string in dotted decimal format. - std::string to_string(boost::system::error_code& ec) const - { - char addr_str[boost::asio::detail::max_addr_v4_str_len]; - const char* addr = - boost::asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str, - boost::asio::detail::max_addr_v4_str_len, 0, ec); - if (addr == 0) - return std::string(); - return addr; - } + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; /// Create an address from an IP address string in dotted decimal form. - static address_v4 from_string(const char* str) - { - boost::system::error_code ec; - address_v4 addr = from_string(str, ec); - boost::asio::detail::throw_error(ec); - return addr; - } + BOOST_ASIO_DECL static address_v4 from_string(const char* str); /// Create an address from an IP address string in dotted decimal form. - static address_v4 from_string(const char* str, boost::system::error_code& ec) - { - address_v4 tmp; - if (boost::asio::detail::socket_ops::inet_pton( - AF_INET, str, &tmp.addr_, 0, ec) <= 0) - return address_v4(); - return tmp; - } + BOOST_ASIO_DECL static address_v4 from_string( + const char* str, boost::system::error_code& ec); /// Create an address from an IP address string in dotted decimal form. - static address_v4 from_string(const std::string& str) - { - return from_string(str.c_str()); - } + BOOST_ASIO_DECL static address_v4 from_string(const std::string& str); /// Create an address from an IP address string in dotted decimal form. - static address_v4 from_string(const std::string& str, - boost::system::error_code& ec) - { - return from_string(str.c_str(), ec); - } + BOOST_ASIO_DECL static address_v4 from_string( + const std::string& str, boost::system::error_code& ec); /// Determine whether the address is a class A address. - bool is_class_a() const - { - return IN_CLASSA(to_ulong()); - } + BOOST_ASIO_DECL bool is_class_a() const; /// Determine whether the address is a class B address. - bool is_class_b() const - { - return IN_CLASSB(to_ulong()); - } + BOOST_ASIO_DECL bool is_class_b() const; /// Determine whether the address is a class C address. - bool is_class_c() const - { - return IN_CLASSC(to_ulong()); - } + BOOST_ASIO_DECL bool is_class_c() const; /// Determine whether the address is a multicast address. - bool is_multicast() const - { - return IN_MULTICAST(to_ulong()); - } + BOOST_ASIO_DECL bool is_multicast() const; /// Compare two addresses for equality. friend bool operator==(const address_v4& a1, const address_v4& a2) @@ -250,23 +166,12 @@ public: /// Obtain an address object that represents the broadcast address that /// corresponds to the specified address and netmask. - static address_v4 broadcast(const address_v4& addr, const address_v4& mask) - { - return address_v4(addr.to_ulong() | ~mask.to_ulong()); - } + BOOST_ASIO_DECL static address_v4 broadcast( + const address_v4& addr, const address_v4& mask); /// Obtain the netmask that corresponds to the address, based on its address /// class. - static address_v4 netmask(const address_v4& addr) - { - if (addr.is_class_a()) - return address_v4(0xFF000000); - if (addr.is_class_b()) - return address_v4(0xFFFF0000); - if (addr.is_class_c()) - return address_v4(0xFFFFFF00); - return address_v4(0xFFFFFFFF); - } + BOOST_ASIO_DECL static address_v4 netmask(const address_v4& addr); private: // The underlying IPv4 address. @@ -289,22 +194,7 @@ private: */ template std::basic_ostream& operator<<( - std::basic_ostream& os, const address_v4& addr) -{ - boost::system::error_code ec; - std::string s = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; -} + std::basic_ostream& os, const address_v4& addr); #endif // !defined(BOOST_NO_IOSTREAM) @@ -314,4 +204,9 @@ std::basic_ostream& operator<<( #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IP_ADDRESS_V4_HPP diff --git a/include/boost/asio/ip/address_v6.hpp b/include/boost/asio/ip/address_v6.hpp index 5685f082..7165eac2 100644 --- a/include/boost/asio/ip/address_v6.hpp +++ b/include/boost/asio/ip/address_v6.hpp @@ -1,6 +1,6 @@ // -// address_v6.hpp -// ~~~~~~~~~~~~~~ +// ip/address_v6.hpp +// ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,26 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include +#include +#include +#include +#include +#include -#include -#include #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace asio { @@ -56,46 +49,17 @@ public: typedef boost::array bytes_type; /// Default constructor. - address_v6() - : scope_id_(0) - { - boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; - addr_ = tmp_addr; - } + BOOST_ASIO_DECL address_v6(); /// Construct an address from raw bytes and scope ID. - explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0) - : scope_id_(scope_id) - { -#if UCHAR_MAX > 0xFF - for (std::size_t i = 0; i < bytes.size(); ++i) - { - if (bytes[i] > 0xFF) - { - std::out_of_range ex("address_v6 from bytes_type"); - boost::throw_exception(ex); - } - } -#endif // UCHAR_MAX > 0xFF - - using namespace std; // For memcpy. - memcpy(addr_.s6_addr, bytes.elems, 16); - } + BOOST_ASIO_DECL explicit address_v6(const bytes_type& bytes, + unsigned long scope_id = 0); /// Copy constructor. - address_v6(const address_v6& other) - : addr_(other.addr_), - scope_id_(other.scope_id_) - { - } + BOOST_ASIO_DECL address_v6(const address_v6& other); /// Assign from another address. - address_v6& operator=(const address_v6& other) - { - addr_ = other.addr_; - scope_id_ = other.scope_id_; - return *this; - } + BOOST_ASIO_DECL address_v6& operator=(const address_v6& other); /// The scope ID of the address. /** @@ -116,217 +80,80 @@ public: } /// Get the address in bytes, in network byte order. - bytes_type to_bytes() const - { - using namespace std; // For memcpy. - bytes_type bytes; - memcpy(bytes.elems, addr_.s6_addr, 16); - return bytes; - } + BOOST_ASIO_DECL bytes_type to_bytes() const; /// Get the address as a string. - std::string to_string() const - { - boost::system::error_code ec; - std::string addr = to_string(ec); - boost::asio::detail::throw_error(ec); - return addr; - } + BOOST_ASIO_DECL std::string to_string() const; /// Get the address as a string. - std::string to_string(boost::system::error_code& ec) const - { - char addr_str[boost::asio::detail::max_addr_v6_str_len]; - const char* addr = - boost::asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str, - boost::asio::detail::max_addr_v6_str_len, scope_id_, ec); - if (addr == 0) - return std::string(); - return addr; - } + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; /// Create an address from an IP address string. - static address_v6 from_string(const char* str) - { - boost::system::error_code ec; - address_v6 addr = from_string(str, ec); - boost::asio::detail::throw_error(ec); - return addr; - } + BOOST_ASIO_DECL static address_v6 from_string(const char* str); /// Create an address from an IP address string. - static address_v6 from_string(const char* str, boost::system::error_code& ec) - { - address_v6 tmp; - if (boost::asio::detail::socket_ops::inet_pton( - AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0) - return address_v6(); - return tmp; - } + BOOST_ASIO_DECL static address_v6 from_string( + const char* str, boost::system::error_code& ec); /// Create an address from an IP address string. - static address_v6 from_string(const std::string& str) - { - return from_string(str.c_str()); - } + BOOST_ASIO_DECL static address_v6 from_string(const std::string& str); /// Create an address from an IP address string. - static address_v6 from_string(const std::string& str, - boost::system::error_code& ec) - { - return from_string(str.c_str(), ec); - } + BOOST_ASIO_DECL static address_v6 from_string( + const std::string& str, boost::system::error_code& ec); /// Converts an IPv4-mapped or IPv4-compatible address to an IPv4 address. - address_v4 to_v4() const - { - if (!is_v4_mapped() && !is_v4_compatible()) - { - std::bad_cast ex; - boost::throw_exception(ex); - } - - address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], - addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; - return address_v4(v4_bytes); - } + BOOST_ASIO_DECL address_v4 to_v4() const; /// Determine whether the address is a loopback address. - bool is_loopback() const - { -#if defined(__BORLANDC__) - return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) - && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) - && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) - && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) - && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) - && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) - && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) - && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); -#else - using namespace boost::asio::detail; - return IN6_IS_ADDR_LOOPBACK(&addr_) != 0; -#endif - } + BOOST_ASIO_DECL bool is_loopback() const; /// Determine whether the address is unspecified. - bool is_unspecified() const - { -#if defined(__BORLANDC__) - return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) - && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) - && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) - && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) - && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) - && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) - && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) - && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); -#else - using namespace boost::asio::detail; - return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0; -#endif - } + BOOST_ASIO_DECL bool is_unspecified() const; /// Determine whether the address is link local. - bool is_link_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_link_local() const; /// Determine whether the address is site local. - bool is_site_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_SITELOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_site_local() const; /// Determine whether the address is a mapped IPv4 address. - bool is_v4_mapped() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_V4MAPPED(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_v4_mapped() const; /// Determine whether the address is an IPv4-compatible address. - bool is_v4_compatible() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_V4COMPAT(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_v4_compatible() const; /// Determine whether the address is a multicast address. - bool is_multicast() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MULTICAST(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast() const; /// Determine whether the address is a global multicast address. - bool is_multicast_global() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_global() const; /// Determine whether the address is a link-local multicast address. - bool is_multicast_link_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_link_local() const; /// Determine whether the address is a node-local multicast address. - bool is_multicast_node_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_node_local() const; /// Determine whether the address is a org-local multicast address. - bool is_multicast_org_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_org_local() const; /// Determine whether the address is a site-local multicast address. - bool is_multicast_site_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_site_local() const; /// Compare two addresses for equality. - friend bool operator==(const address_v6& a1, const address_v6& a2) - { - using namespace std; // For memcmp. - return memcmp(&a1.addr_, &a2.addr_, - sizeof(boost::asio::detail::in6_addr_type)) == 0 - && a1.scope_id_ == a2.scope_id_; - } + BOOST_ASIO_DECL friend bool operator==( + const address_v6& a1, const address_v6& a2); /// Compare two addresses for inequality. friend bool operator!=(const address_v6& a1, const address_v6& a2) { - using namespace std; // For memcmp. - return memcmp(&a1.addr_, &a2.addr_, - sizeof(boost::asio::detail::in6_addr_type)) != 0 - || a1.scope_id_ != a2.scope_id_; + return !(a1 == a2); } /// Compare addresses for ordering. - friend bool operator<(const address_v6& a1, const address_v6& a2) - { - using namespace std; // For memcmp. - int memcmp_result = memcmp(&a1.addr_, &a2.addr_, - sizeof(boost::asio::detail::in6_addr_type)); - if (memcmp_result < 0) - return true; - if (memcmp_result > 0) - return false; - return a1.scope_id_ < a2.scope_id_; - } + BOOST_ASIO_DECL friend bool operator<( + const address_v6& a1, const address_v6& a2); /// Compare addresses for ordering. friend bool operator>(const address_v6& a1, const address_v6& a2) @@ -353,31 +180,13 @@ public: } /// Obtain an address object that represents the loopback address. - static address_v6 loopback() - { - address_v6 tmp; - boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT; - tmp.addr_ = tmp_addr; - return tmp; - } + BOOST_ASIO_DECL static address_v6 loopback(); /// Create an IPv4-mapped IPv6 address. - static address_v6 v4_mapped(const address_v4& addr) - { - address_v4::bytes_type v4_bytes = addr.to_bytes(); - bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, - v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; - return address_v6(v6_bytes); - } + BOOST_ASIO_DECL static address_v6 v4_mapped(const address_v4& addr); /// Create an IPv4-compatible IPv6 address. - static address_v6 v4_compatible(const address_v4& addr) - { - address_v4::bytes_type v4_bytes = addr.to_bytes(); - bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; - return address_v6(v6_bytes); - } + BOOST_ASIO_DECL static address_v6 v4_compatible(const address_v4& addr); private: // The underlying IPv6 address. @@ -403,22 +212,7 @@ private: */ template std::basic_ostream& operator<<( - std::basic_ostream& os, const address_v6& addr) -{ - boost::system::error_code ec; - std::string s = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; -} + std::basic_ostream& os, const address_v6& addr); #endif // !defined(BOOST_NO_IOSTREAM) @@ -428,4 +222,9 @@ std::basic_ostream& operator<<( #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IP_ADDRESS_V6_HPP diff --git a/include/boost/asio/ip/basic_endpoint.hpp b/include/boost/asio/ip/basic_endpoint.hpp index f191a4ca..10459c41 100644 --- a/include/boost/asio/ip/basic_endpoint.hpp +++ b/include/boost/asio/ip/basic_endpoint.hpp @@ -1,6 +1,6 @@ // -// basic_endpoint.hpp -// ~~~~~~~~~~~~~~~~~~ +// ip/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,25 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include -#if !defined(BOOST_NO_IOSTREAM) -# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -# include -# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -# include -#endif // !defined(BOOST_NO_IOSTREAM) -#include - -#include +#include #include -#include -#include +#include + +#if !defined(BOOST_NO_IOSTREAM) +# include +#endif // !defined(BOOST_NO_IOSTREAM) + +#include namespace boost { namespace asio { @@ -68,11 +58,8 @@ public: /// Default constructor. basic_endpoint() - : data_() + : impl_() { - data_.v4.sin_family = AF_INET; - data_.v4.sin_port = 0; - data_.v4.sin_addr.s_addr = INADDR_ANY; } /// Construct an endpoint using a port number, specified in the host's byte @@ -92,74 +79,35 @@ public: * @endcode */ basic_endpoint(const InternetProtocol& protocol, unsigned short port_num) - : data_() + : impl_(protocol.family(), port_num) { - using namespace std; // For memcpy. - if (protocol.family() == PF_INET) - { - data_.v4.sin_family = AF_INET; - data_.v4.sin_port = - boost::asio::detail::socket_ops::host_to_network_short(port_num); - data_.v4.sin_addr.s_addr = INADDR_ANY; - } - else - { - data_.v6.sin6_family = AF_INET6; - data_.v6.sin6_port = - boost::asio::detail::socket_ops::host_to_network_short(port_num); - data_.v6.sin6_flowinfo = 0; - boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; - data_.v6.sin6_addr = tmp_addr; - data_.v6.sin6_scope_id = 0; - } } /// Construct an endpoint using a port number and an IP address. This /// constructor may be used for accepting connections on a specific interface /// or for making a connection to a remote endpoint. basic_endpoint(const boost::asio::ip::address& addr, unsigned short port_num) - : data_() + : impl_(addr, port_num) { - using namespace std; // For memcpy. - if (addr.is_v4()) - { - data_.v4.sin_family = AF_INET; - data_.v4.sin_port = - boost::asio::detail::socket_ops::host_to_network_short(port_num); - data_.v4.sin_addr.s_addr = - boost::asio::detail::socket_ops::host_to_network_long( - addr.to_v4().to_ulong()); - } - else - { - data_.v6.sin6_family = AF_INET6; - data_.v6.sin6_port = - boost::asio::detail::socket_ops::host_to_network_short(port_num); - data_.v6.sin6_flowinfo = 0; - boost::asio::ip::address_v6 v6_addr = addr.to_v6(); - boost::asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes(); - memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16); - data_.v6.sin6_scope_id = v6_addr.scope_id(); - } } /// Copy constructor. basic_endpoint(const basic_endpoint& other) - : data_(other.data_) + : impl_(other.impl_) { } /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) { - data_ = other.data_; + impl_ = other.impl_; return *this; } /// The protocol associated with the endpoint. protocol_type protocol() const { - if (is_v4()) + if (impl_.is_v4()) return InternetProtocol::v4(); return InternetProtocol::v6(); } @@ -167,137 +115,104 @@ public: /// Get the underlying endpoint in the native type. data_type* data() { - return &data_.base; + return impl_.data(); } /// Get the underlying endpoint in the native type. const data_type* data() const { - return &data_.base; + return impl_.data(); } /// Get the underlying size of the endpoint in the native type. std::size_t size() const { - if (is_v4()) - return sizeof(boost::asio::detail::sockaddr_in4_type); - else - return sizeof(boost::asio::detail::sockaddr_in6_type); + return impl_.size(); } /// Set the underlying size of the endpoint in the native type. void resize(std::size_t size) { - if (size > sizeof(boost::asio::detail::sockaddr_storage_type)) - { - boost::system::system_error e(boost::asio::error::invalid_argument); - boost::throw_exception(e); - } + impl_.resize(size); } /// Get the capacity of the endpoint in the native type. std::size_t capacity() const { - return sizeof(boost::asio::detail::sockaddr_storage_type); + return impl_.capacity(); } /// Get the port associated with the endpoint. The port number is always in /// the host's byte order. unsigned short port() const { - if (is_v4()) - { - return boost::asio::detail::socket_ops::network_to_host_short( - data_.v4.sin_port); - } - else - { - return boost::asio::detail::socket_ops::network_to_host_short( - data_.v6.sin6_port); - } + return impl_.port(); } /// Set the port associated with the endpoint. The port number is always in /// the host's byte order. void port(unsigned short port_num) { - if (is_v4()) - { - data_.v4.sin_port - = boost::asio::detail::socket_ops::host_to_network_short(port_num); - } - else - { - data_.v6.sin6_port - = boost::asio::detail::socket_ops::host_to_network_short(port_num); - } + impl_.port(port_num); } /// Get the IP address associated with the endpoint. boost::asio::ip::address address() const { - using namespace std; // For memcpy. - if (is_v4()) - { - return boost::asio::ip::address_v4( - boost::asio::detail::socket_ops::network_to_host_long( - data_.v4.sin_addr.s_addr)); - } - else - { - boost::asio::ip::address_v6::bytes_type bytes; - memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16); - return boost::asio::ip::address_v6(bytes, data_.v6.sin6_scope_id); - } + return impl_.address(); } /// Set the IP address associated with the endpoint. void address(const boost::asio::ip::address& addr) { - basic_endpoint tmp_endpoint(addr, port()); - data_ = tmp_endpoint.data_; + impl_.address(addr); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.address() == e2.address() && e1.port() == e2.port(); + return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.address() != e2.address() || e1.port() != e2.port(); + return !(e1 == e2); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint& e1, const basic_endpoint& e2) { - if (e1.address() < e2.address()) - return true; - if (e1.address() != e2.address()) - return false; - return e1.port() < e2.port(); + return e1.impl_ < e2.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator>(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e2.impl_ < e1.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator<=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e2 < e1); + } + + /// Compare endpoints for ordering. + friend bool operator>=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e1 < e2); } private: - // Helper function to determine whether the endpoint is IPv4. - bool is_v4() const - { - return data_.base.sa_family == AF_INET; - } - - // The underlying IP socket address. - union data_union - { - boost::asio::detail::socket_addr_type base; - boost::asio::detail::sockaddr_storage_type storage; - boost::asio::detail::sockaddr_in4_type v4; - boost::asio::detail::sockaddr_in6_type v6; - } data_; + // The underlying IP endpoint. + boost::asio::ip::detail::endpoint impl_; }; #if !defined(BOOST_NO_IOSTREAM) @@ -314,64 +229,10 @@ private: * * @relates boost::asio::ip::basic_endpoint */ -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -template -std::ostream& operator<<(std::ostream& os, - const basic_endpoint& endpoint) -{ - const address& addr = endpoint.address(); - boost::system::error_code ec; - std::string a = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - { - std::ostringstream tmp_os; - tmp_os.imbue(std::locale::classic()); - if (addr.is_v4()) - tmp_os << a; - else - tmp_os << '[' << a << ']'; - tmp_os << ':' << endpoint.port(); - os << tmp_os.str(); - } - return os; -} -#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) template std::basic_ostream& operator<<( std::basic_ostream& os, - const basic_endpoint& endpoint) -{ - const address& addr = endpoint.address(); - boost::system::error_code ec; - std::string a = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - { - std::ostringstream tmp_os; - tmp_os.imbue(std::locale::classic()); - if (addr.is_v4()) - tmp_os << a; - else - tmp_os << '[' << a << ']'; - tmp_os << ':' << endpoint.port(); - os << tmp_os.str(); - } - return os; -} -#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + const basic_endpoint& endpoint); #endif // !defined(BOOST_NO_IOSTREAM) @@ -381,4 +242,6 @@ std::basic_ostream& operator<<( #include +#include + #endif // BOOST_ASIO_IP_BASIC_ENDPOINT_HPP diff --git a/include/boost/asio/ip/basic_resolver.hpp b/include/boost/asio/ip/basic_resolver.hpp index 0660ce58..21b83da9 100644 --- a/include/boost/asio/ip/basic_resolver.hpp +++ b/include/boost/asio/ip/basic_resolver.hpp @@ -1,6 +1,6 @@ // -// basic_resolver.hpp -// ~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/basic_resolver_entry.hpp b/include/boost/asio/ip/basic_resolver_entry.hpp index f2ac5957..84589b5b 100644 --- a/include/boost/asio/ip/basic_resolver_entry.hpp +++ b/include/boost/asio/ip/basic_resolver_entry.hpp @@ -1,6 +1,6 @@ // -// basic_resolver_entry.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver_entry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/basic_resolver_iterator.hpp b/include/boost/asio/ip/basic_resolver_iterator.hpp index 5f4937bf..de426993 100644 --- a/include/boost/asio/ip/basic_resolver_iterator.hpp +++ b/include/boost/asio/ip/basic_resolver_iterator.hpp @@ -1,6 +1,6 @@ // -// basic_resolver_iterator.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,20 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include #include #include -#include - +#include #include #include #include +#include + namespace boost { namespace asio { namespace ip { @@ -177,7 +175,7 @@ private: } typedef std::vector > values_type; - boost::shared_ptr values_; + boost::asio::detail::shared_ptr values_; std::size_t index_; }; diff --git a/include/boost/asio/ip/basic_resolver_query.hpp b/include/boost/asio/ip/basic_resolver_query.hpp index 75d3c477..38cba015 100644 --- a/include/boost/asio/ip/basic_resolver_query.hpp +++ b/include/boost/asio/ip/basic_resolver_query.hpp @@ -1,6 +1,6 @@ // -// basic_resolver_query.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver_query.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/ip/detail/endpoint.hpp b/include/boost/asio/ip/detail/endpoint.hpp new file mode 100644 index 00000000..9823e720 --- /dev/null +++ b/include/boost/asio/ip/detail/endpoint.hpp @@ -0,0 +1,142 @@ +// +// ip/detail/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_DETAIL_ENDPOINT_HPP +#define BOOST_ASIO_IP_DETAIL_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { +namespace detail { + +// Helper class for implementating an IP endpoint. +class endpoint +{ +public: + // Default constructor. + BOOST_ASIO_DECL endpoint(); + + // Construct an endpoint using a family and port number. + BOOST_ASIO_DECL endpoint(int family, unsigned short port_num); + + // Construct an endpoint using an address and port number. + BOOST_ASIO_DECL endpoint(const boost::asio::ip::address& addr, + unsigned short port_num); + + // Copy constructor. + endpoint(const endpoint& other) + : data_(other.data_) + { + } + + // Assign from another endpoint. + endpoint& operator=(const endpoint& other) + { + data_ = other.data_; + return *this; + } + + // Get the underlying endpoint in the native type. + boost::asio::detail::socket_addr_type* data() + { + return &data_.base; + } + + // Get the underlying endpoint in the native type. + const boost::asio::detail::socket_addr_type* data() const + { + return &data_.base; + } + + // Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + if (is_v4()) + return sizeof(boost::asio::detail::sockaddr_in4_type); + else + return sizeof(boost::asio::detail::sockaddr_in6_type); + } + + // Set the underlying size of the endpoint in the native type. + BOOST_ASIO_DECL void resize(std::size_t size); + + // Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return sizeof(boost::asio::detail::sockaddr_storage_type); + } + + // Get the port associated with the endpoint. + BOOST_ASIO_DECL unsigned short port() const; + + // Set the port associated with the endpoint. + BOOST_ASIO_DECL void port(unsigned short port_num); + + // Get the IP address associated with the endpoint. + BOOST_ASIO_DECL boost::asio::ip::address address() const; + + // Set the IP address associated with the endpoint. + BOOST_ASIO_DECL void address(const boost::asio::ip::address& addr); + + // Compare two endpoints for equality. + BOOST_ASIO_DECL friend bool operator==( + const endpoint& e1, const endpoint& e2); + + // Compare endpoints for ordering. + BOOST_ASIO_DECL friend bool operator<( + const endpoint& e1, const endpoint& e2); + + // Determine whether the endpoint is IPv4. + bool is_v4() const + { + return data_.base.sa_family == AF_INET; + } + +#if !defined(BOOST_NO_IOSTREAM) + // Convert to a string. + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; +#endif // !defined(BOOST_NO_IOSTREAM) + +private: + // The underlying IP socket address. + union data_union + { + boost::asio::detail::socket_addr_type base; + boost::asio::detail::sockaddr_storage_type storage; + boost::asio::detail::sockaddr_in4_type v4; + boost::asio::detail::sockaddr_in6_type v6; + } data_; +}; + +} // namespace detail +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_DETAIL_ENDPOINT_HPP diff --git a/include/boost/asio/ip/detail/impl/endpoint.ipp b/include/boost/asio/ip/detail/impl/endpoint.ipp new file mode 100644 index 00000000..4a6e3954 --- /dev/null +++ b/include/boost/asio/ip/detail/impl/endpoint.ipp @@ -0,0 +1,193 @@ +// +// ip/detail/impl/endpoint.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP +#define BOOST_ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#if !defined(BOOST_NO_IOSTREAM) +# include +#endif // !defined(BOOST_NO_IOSTREAM) +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { +namespace detail { + +endpoint::endpoint() + : data_() +{ + data_.v4.sin_family = AF_INET; + data_.v4.sin_port = 0; + data_.v4.sin_addr.s_addr = INADDR_ANY; +} + +endpoint::endpoint(int family, unsigned short port_num) + : data_() +{ + using namespace std; // For memcpy. + if (family == PF_INET) + { + data_.v4.sin_family = AF_INET; + data_.v4.sin_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v4.sin_addr.s_addr = INADDR_ANY; + } + else + { + data_.v6.sin6_family = AF_INET6; + data_.v6.sin6_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v6.sin6_flowinfo = 0; + boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; + data_.v6.sin6_addr = tmp_addr; + data_.v6.sin6_scope_id = 0; + } +} + +endpoint::endpoint(const boost::asio::ip::address& addr, + unsigned short port_num) + : data_() +{ + using namespace std; // For memcpy. + if (addr.is_v4()) + { + data_.v4.sin_family = AF_INET; + data_.v4.sin_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v4.sin_addr.s_addr = + boost::asio::detail::socket_ops::host_to_network_long( + addr.to_v4().to_ulong()); + } + else + { + data_.v6.sin6_family = AF_INET6; + data_.v6.sin6_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v6.sin6_flowinfo = 0; + boost::asio::ip::address_v6 v6_addr = addr.to_v6(); + boost::asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes(); + memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16); + data_.v6.sin6_scope_id = v6_addr.scope_id(); + } +} + +void endpoint::resize(std::size_t size) +{ + if (size > sizeof(boost::asio::detail::sockaddr_storage_type)) + { + boost::system::error_code ec(boost::asio::error::invalid_argument); + boost::asio::detail::throw_error(ec); + } +} + +unsigned short endpoint::port() const +{ + if (is_v4()) + { + return boost::asio::detail::socket_ops::network_to_host_short( + data_.v4.sin_port); + } + else + { + return boost::asio::detail::socket_ops::network_to_host_short( + data_.v6.sin6_port); + } +} + +void endpoint::port(unsigned short port_num) +{ + if (is_v4()) + { + data_.v4.sin_port + = boost::asio::detail::socket_ops::host_to_network_short(port_num); + } + else + { + data_.v6.sin6_port + = boost::asio::detail::socket_ops::host_to_network_short(port_num); + } +} + +boost::asio::ip::address endpoint::address() const +{ + using namespace std; // For memcpy. + if (is_v4()) + { + return boost::asio::ip::address_v4( + boost::asio::detail::socket_ops::network_to_host_long( + data_.v4.sin_addr.s_addr)); + } + else + { + boost::asio::ip::address_v6::bytes_type bytes; + memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16); + return boost::asio::ip::address_v6(bytes, data_.v6.sin6_scope_id); + } +} + +void endpoint::address(const boost::asio::ip::address& addr) +{ + endpoint tmp_endpoint(addr, port()); + data_ = tmp_endpoint.data_; +} + +bool operator==(const endpoint& e1, const endpoint& e2) +{ + return e1.address() == e2.address() && e1.port() == e2.port(); +} + +bool operator<(const endpoint& e1, const endpoint& e2) +{ + if (e1.address() < e2.address()) + return true; + if (e1.address() != e2.address()) + return false; + return e1.port() < e2.port(); +} + +#if !defined(BOOST_NO_IOSTREAM) +std::string endpoint::to_string(boost::system::error_code& ec) const +{ + std::string a = address().to_string(ec); + if (ec) + return std::string(); + + std::ostringstream tmp_os; + tmp_os.imbue(std::locale::classic()); + if (is_v4()) + tmp_os << a; + else + tmp_os << '[' << a << ']'; + tmp_os << ':' << port(); + + return tmp_os.str(); +} +#endif // !defined(BOOST_NO_IOSTREAM) + +} // namespace detail +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP diff --git a/include/boost/asio/ip/detail/socket_option.hpp b/include/boost/asio/ip/detail/socket_option.hpp index 0c268648..59ce6c37 100644 --- a/include/boost/asio/ip/detail/socket_option.hpp +++ b/include/boost/asio/ip/detail/socket_option.hpp @@ -1,6 +1,6 @@ // -// socket_option.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,18 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include #include -#include - -#include #include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/host_name.hpp b/include/boost/asio/ip/host_name.hpp index fee245b7..f40a9df6 100644 --- a/include/boost/asio/ip/host_name.hpp +++ b/include/boost/asio/ip/host_name.hpp @@ -1,6 +1,6 @@ // -// host_name.hpp -// ~~~~~~~~~~~~~ +// ip/host_name.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,45 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include +#include -#include -#include -#include +#include namespace boost { namespace asio { namespace ip { /// Get the current host name. -std::string host_name(); +BOOST_ASIO_DECL std::string host_name(); /// Get the current host name. -std::string host_name(boost::system::error_code& ec); - -inline std::string host_name() -{ - char name[1024]; - boost::system::error_code ec; - if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) - { - boost::asio::detail::throw_error(ec); - return std::string(); - } - return std::string(name); -} - -inline std::string host_name(boost::system::error_code& ec) -{ - char name[1024]; - if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) - return std::string(); - return std::string(name); -} +BOOST_ASIO_DECL std::string host_name(boost::system::error_code& ec); } // namespace ip } // namespace asio @@ -61,4 +37,8 @@ inline std::string host_name(boost::system::error_code& ec) #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IP_HOST_NAME_HPP diff --git a/include/boost/asio/ip/icmp.hpp b/include/boost/asio/ip/icmp.hpp index 5d2fcabd..ca5d4348 100644 --- a/include/boost/asio/ip/icmp.hpp +++ b/include/boost/asio/ip/icmp.hpp @@ -1,6 +1,6 @@ // -// icmp.hpp -// ~~~~~~~~ +// ip/icmp.hpp +// ~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include +#include #include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/impl/address.hpp b/include/boost/asio/ip/impl/address.hpp new file mode 100644 index 00000000..c19d25d8 --- /dev/null +++ b/include/boost/asio/ip/impl/address.hpp @@ -0,0 +1,55 @@ +// +// ip/impl/address.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_HPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address& addr) +{ + boost::system::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_HPP diff --git a/include/boost/asio/ip/impl/address.ipp b/include/boost/asio/ip/impl/address.ipp new file mode 100644 index 00000000..70513b78 --- /dev/null +++ b/include/boost/asio/ip/impl/address.ipp @@ -0,0 +1,188 @@ +// +// ip/impl/address.ipp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_IPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +address::address() + : type_(ipv4), + ipv4_address_(), + ipv6_address_() +{ +} + +address::address(const boost::asio::ip::address_v4& ipv4_address) + : type_(ipv4), + ipv4_address_(ipv4_address), + ipv6_address_() +{ +} + +address::address(const boost::asio::ip::address_v6& ipv6_address) + : type_(ipv6), + ipv4_address_(), + ipv6_address_(ipv6_address) +{ +} + +address::address(const address& other) + : type_(other.type_), + ipv4_address_(other.ipv4_address_), + ipv6_address_(other.ipv6_address_) +{ +} + +address& address::operator=(const address& other) +{ + type_ = other.type_; + ipv4_address_ = other.ipv4_address_; + ipv6_address_ = other.ipv6_address_; + return *this; +} + +address& address::operator=(const boost::asio::ip::address_v4& ipv4_address) +{ + type_ = ipv4; + ipv4_address_ = ipv4_address; + ipv6_address_ = boost::asio::ip::address_v6(); + return *this; +} + +address& address::operator=(const boost::asio::ip::address_v6& ipv6_address) +{ + type_ = ipv6; + ipv4_address_ = boost::asio::ip::address_v4(); + ipv6_address_ = ipv6_address; + return *this; +} + +boost::asio::ip::address_v4 address::to_v4() const +{ + if (type_ != ipv4) + { + std::bad_cast ex; + boost::throw_exception(ex); + } + return ipv4_address_; +} + +boost::asio::ip::address_v6 address::to_v6() const +{ + if (type_ != ipv6) + { + std::bad_cast ex; + boost::throw_exception(ex); + } + return ipv6_address_; +} + +std::string address::to_string() const +{ + if (type_ == ipv6) + return ipv6_address_.to_string(); + return ipv4_address_.to_string(); +} + +std::string address::to_string(boost::system::error_code& ec) const +{ + if (type_ == ipv6) + return ipv6_address_.to_string(ec); + return ipv4_address_.to_string(ec); +} + +address address::from_string(const char* str) +{ + boost::system::error_code ec; + address addr = from_string(str, ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +address address::from_string(const char* str, boost::system::error_code& ec) +{ + boost::asio::ip::address_v6 ipv6_address = + boost::asio::ip::address_v6::from_string(str, ec); + if (!ec) + { + address tmp; + tmp.type_ = ipv6; + tmp.ipv6_address_ = ipv6_address; + return tmp; + } + + boost::asio::ip::address_v4 ipv4_address = + boost::asio::ip::address_v4::from_string(str, ec); + if (!ec) + { + address tmp; + tmp.type_ = ipv4; + tmp.ipv4_address_ = ipv4_address; + return tmp; + } + + return address(); +} + +address address::from_string(const std::string& str) +{ + return from_string(str.c_str()); +} + +address address::from_string(const std::string& str, + boost::system::error_code& ec) +{ + return from_string(str.c_str(), ec); +} + +bool operator==(const address& a1, const address& a2) +{ + if (a1.type_ != a2.type_) + return false; + if (a1.type_ == address::ipv6) + return a1.ipv6_address_ == a2.ipv6_address_; + return a1.ipv4_address_ == a2.ipv4_address_; +} + +bool operator<(const address& a1, const address& a2) +{ + if (a1.type_ < a2.type_) + return true; + if (a1.type_ > a2.type_) + return false; + if (a1.type_ == address::ipv6) + return a1.ipv6_address_ < a2.ipv6_address_; + return a1.ipv4_address_ < a2.ipv4_address_; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_IPP diff --git a/include/boost/asio/ip/impl/address_v4.hpp b/include/boost/asio/ip/impl/address_v4.hpp new file mode 100644 index 00000000..7e798e89 --- /dev/null +++ b/include/boost/asio/ip/impl/address_v4.hpp @@ -0,0 +1,55 @@ +// +// ip/impl/address_v4.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V4_HPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V4_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address_v4& addr) +{ + boost::system::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V4_HPP diff --git a/include/boost/asio/ip/impl/address_v4.ipp b/include/boost/asio/ip/impl/address_v4.ipp new file mode 100644 index 00000000..3cdcbf1c --- /dev/null +++ b/include/boost/asio/ip/impl/address_v4.ipp @@ -0,0 +1,164 @@ +// +// ip/impl/address_v4.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V4_IPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V4_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +address_v4::address_v4(const address_v4::bytes_type& bytes) +{ +#if UCHAR_MAX > 0xFF + if (bytes[0] > 0xFF || bytes[1] > 0xFF + || bytes[2] > 0xFF || bytes[3] > 0xFF) + { + std::out_of_range ex("address_v4 from bytes_type"); + boost::throw_exception(ex); + } +#endif // UCHAR_MAX > 0xFF + + using namespace std; // For memcpy. + memcpy(&addr_.s_addr, bytes.elems, 4); +} + +address_v4::address_v4(unsigned long addr) +{ +#if ULONG_MAX > 0xFFFFFFFF + if (addr > 0xFFFFFFFF) + { + std::out_of_range ex("address_v4 from unsigned long"); + boost::throw_exception(ex); + } +#endif // ULONG_MAX > 0xFFFFFFFF + + addr_.s_addr = boost::asio::detail::socket_ops::host_to_network_long(addr); +} + +address_v4::bytes_type address_v4::to_bytes() const +{ + using namespace std; // For memcpy. + bytes_type bytes; + memcpy(bytes.elems, &addr_.s_addr, 4); + return bytes; +} + +unsigned long address_v4::to_ulong() const +{ + return boost::asio::detail::socket_ops::network_to_host_long(addr_.s_addr); +} + +std::string address_v4::to_string() const +{ + boost::system::error_code ec; + std::string addr = to_string(ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +std::string address_v4::to_string(boost::system::error_code& ec) const +{ + char addr_str[boost::asio::detail::max_addr_v4_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str, + boost::asio::detail::max_addr_v4_str_len, 0, ec); + if (addr == 0) + return std::string(); + return addr; +} + +address_v4 address_v4::from_string(const char* str) +{ + boost::system::error_code ec; + address_v4 addr = from_string(str, ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +address_v4 address_v4::from_string( + const char* str, boost::system::error_code& ec) +{ + address_v4 tmp; + if (boost::asio::detail::socket_ops::inet_pton( + AF_INET, str, &tmp.addr_, 0, ec) <= 0) + return address_v4(); + return tmp; +} + +address_v4 address_v4::from_string(const std::string& str) +{ + return from_string(str.c_str()); +} + +address_v4 address_v4::from_string( + const std::string& str, boost::system::error_code& ec) +{ + return from_string(str.c_str(), ec); +} + +bool address_v4::is_class_a() const +{ + return IN_CLASSA(to_ulong()); +} + +bool address_v4::is_class_b() const +{ + return IN_CLASSB(to_ulong()); +} + +bool address_v4::is_class_c() const +{ + return IN_CLASSC(to_ulong()); +} + +bool address_v4::is_multicast() const +{ + return IN_MULTICAST(to_ulong()); +} + +address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask) +{ + return address_v4(addr.to_ulong() | ~mask.to_ulong()); +} + +address_v4 address_v4::netmask(const address_v4& addr) +{ + if (addr.is_class_a()) + return address_v4(0xFF000000); + if (addr.is_class_b()) + return address_v4(0xFFFF0000); + if (addr.is_class_c()) + return address_v4(0xFFFFFF00); + return address_v4(0xFFFFFFFF); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V4_IPP diff --git a/include/boost/asio/ip/impl/address_v6.hpp b/include/boost/asio/ip/impl/address_v6.hpp new file mode 100644 index 00000000..8b39e3e0 --- /dev/null +++ b/include/boost/asio/ip/impl/address_v6.hpp @@ -0,0 +1,55 @@ +// +// ip/impl/address_v6.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_HPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V6_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address_v6& addr) +{ + boost::system::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V6_HPP diff --git a/include/boost/asio/ip/impl/address_v6.ipp b/include/boost/asio/ip/impl/address_v6.ipp new file mode 100644 index 00000000..a06dfe5f --- /dev/null +++ b/include/boost/asio/ip/impl/address_v6.ipp @@ -0,0 +1,286 @@ +// +// ip/impl/address_v6.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +address_v6::address_v6() + : scope_id_(0) +{ + boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; + addr_ = tmp_addr; +} + +address_v6::address_v6(const address_v6::bytes_type& bytes, + unsigned long scope_id) + : scope_id_(scope_id) +{ +#if UCHAR_MAX > 0xFF + for (std::size_t i = 0; i < bytes.size(); ++i) + { + if (bytes[i] > 0xFF) + { + std::out_of_range ex("address_v6 from bytes_type"); + boost::throw_exception(ex); + } + } +#endif // UCHAR_MAX > 0xFF + + using namespace std; // For memcpy. + memcpy(addr_.s6_addr, bytes.elems, 16); +} + +address_v6::address_v6(const address_v6& other) + : addr_(other.addr_), + scope_id_(other.scope_id_) +{ +} + +address_v6& address_v6::operator=(const address_v6& other) +{ + addr_ = other.addr_; + scope_id_ = other.scope_id_; + return *this; +} + +address_v6::bytes_type address_v6::to_bytes() const +{ + using namespace std; // For memcpy. + bytes_type bytes; + memcpy(bytes.elems, addr_.s6_addr, 16); + return bytes; +} + +std::string address_v6::to_string() const +{ + boost::system::error_code ec; + std::string addr = to_string(ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +std::string address_v6::to_string(boost::system::error_code& ec) const +{ + char addr_str[boost::asio::detail::max_addr_v6_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str, + boost::asio::detail::max_addr_v6_str_len, scope_id_, ec); + if (addr == 0) + return std::string(); + return addr; +} + +address_v6 address_v6::from_string(const char* str) +{ + boost::system::error_code ec; + address_v6 addr = from_string(str, ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +address_v6 address_v6::from_string( + const char* str, boost::system::error_code& ec) +{ + address_v6 tmp; + if (boost::asio::detail::socket_ops::inet_pton( + AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0) + return address_v6(); + return tmp; +} + +address_v6 address_v6::from_string(const std::string& str) +{ + return from_string(str.c_str()); +} + +address_v6 address_v6::from_string( + const std::string& str, boost::system::error_code& ec) +{ + return from_string(str.c_str(), ec); +} + +address_v4 address_v6::to_v4() const +{ + if (!is_v4_mapped() && !is_v4_compatible()) + { + std::bad_cast ex; + boost::throw_exception(ex); + } + + address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], + addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; + return address_v4(v4_bytes); +} + +bool address_v6::is_loopback() const +{ +#if defined(__BORLANDC__) + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); +#else + using namespace boost::asio::detail; + return IN6_IS_ADDR_LOOPBACK(&addr_) != 0; +#endif +} + +bool address_v6::is_unspecified() const +{ +#if defined(__BORLANDC__) + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); +#else + using namespace boost::asio::detail; + return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0; +#endif +} + +bool address_v6::is_link_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0; +} + +bool address_v6::is_site_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_SITELOCAL(&addr_) != 0; +} + +bool address_v6::is_v4_mapped() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_V4MAPPED(&addr_) != 0; +} + +bool address_v6::is_v4_compatible() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_V4COMPAT(&addr_) != 0; +} + +bool address_v6::is_multicast() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MULTICAST(&addr_) != 0; +} + +bool address_v6::is_multicast_global() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0; +} + +bool address_v6::is_multicast_link_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0; +} + +bool address_v6::is_multicast_node_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0; +} + +bool address_v6::is_multicast_org_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0; +} + +bool address_v6::is_multicast_site_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0; +} + +bool operator==(const address_v6& a1, const address_v6& a2) +{ + using namespace std; // For memcmp. + return memcmp(&a1.addr_, &a2.addr_, + sizeof(boost::asio::detail::in6_addr_type)) == 0 + && a1.scope_id_ == a2.scope_id_; +} + +bool operator<(const address_v6& a1, const address_v6& a2) +{ + using namespace std; // For memcmp. + int memcmp_result = memcmp(&a1.addr_, &a2.addr_, + sizeof(boost::asio::detail::in6_addr_type)); + if (memcmp_result < 0) + return true; + if (memcmp_result > 0) + return false; + return a1.scope_id_ < a2.scope_id_; +} + +address_v6 address_v6::loopback() +{ + address_v6 tmp; + boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT; + tmp.addr_ = tmp_addr; + return tmp; +} + +address_v6 address_v6::v4_mapped(const address_v4& addr) +{ + address_v4::bytes_type v4_bytes = addr.to_bytes(); + bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, + v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; + return address_v6(v6_bytes); +} + +address_v6 address_v6::v4_compatible(const address_v4& addr) +{ + address_v4::bytes_type v4_bytes = addr.to_bytes(); + bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; + return address_v6(v6_bytes); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP diff --git a/include/boost/asio/ip/impl/basic_endpoint.hpp b/include/boost/asio/ip/impl/basic_endpoint.hpp new file mode 100644 index 00000000..474c1933 --- /dev/null +++ b/include/boost/asio/ip/impl/basic_endpoint.hpp @@ -0,0 +1,57 @@ +// +// ip/impl/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_BASIC_ENDPOINT_HPP +#define BOOST_ASIO_IP_IMPL_BASIC_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const basic_endpoint& endpoint) +{ + boost::asio::ip::detail::endpoint tmp_ep(endpoint.address(), endpoint.port()); + boost::system::error_code ec; + std::string s = tmp_ep.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_BASIC_ENDPOINT_HPP diff --git a/include/boost/asio/ip/impl/host_name.ipp b/include/boost/asio/ip/impl/host_name.ipp new file mode 100644 index 00000000..a5ba5824 --- /dev/null +++ b/include/boost/asio/ip/impl/host_name.ipp @@ -0,0 +1,56 @@ +// +// ip/impl/host_name.ipp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_HOST_NAME_IPP +#define BOOST_ASIO_IP_IMPL_HOST_NAME_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +std::string host_name() +{ + char name[1024]; + boost::system::error_code ec; + if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) + { + boost::asio::detail::throw_error(ec); + return std::string(); + } + return std::string(name); +} + +std::string host_name(boost::system::error_code& ec) +{ + char name[1024]; + if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) + return std::string(); + return std::string(name); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_HOST_NAME_IPP diff --git a/include/boost/asio/ip/multicast.hpp b/include/boost/asio/ip/multicast.hpp index 3aab7f08..e4d9f88e 100644 --- a/include/boost/asio/ip/multicast.hpp +++ b/include/boost/asio/ip/multicast.hpp @@ -1,6 +1,6 @@ // -// multicast.hpp -// ~~~~~~~~~~~~~ +// ip/multicast.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/ip/resolver_query_base.hpp b/include/boost/asio/ip/resolver_query_base.hpp index 7fe16504..0173e119 100644 --- a/include/boost/asio/ip/resolver_query_base.hpp +++ b/include/boost/asio/ip/resolver_query_base.hpp @@ -1,6 +1,6 @@ // -// resolver_query_base.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// ip/resolver_query_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/ip/resolver_service.hpp b/include/boost/asio/ip/resolver_service.hpp index ba59f6d5..b13e0adb 100644 --- a/include/boost/asio/ip/resolver_service.hpp +++ b/include/boost/asio/ip/resolver_service.hpp @@ -1,6 +1,6 @@ // -// resolver_service.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// ip/resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include +#include +#include #include #include #include -#include -#include + +#include namespace boost { namespace asio { @@ -73,13 +73,14 @@ public: explicit resolver_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< resolver_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new resolver implementation. @@ -131,8 +132,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace ip diff --git a/include/boost/asio/ip/tcp.hpp b/include/boost/asio/ip/tcp.hpp index 541c95c7..20261488 100644 --- a/include/boost/asio/ip/tcp.hpp +++ b/include/boost/asio/ip/tcp.hpp @@ -1,6 +1,6 @@ // -// tcp.hpp -// ~~~~~~~ +// ip/tcp.hpp +// ~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include #include +#include +#include #include #include #include #include -#include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/udp.hpp b/include/boost/asio/ip/udp.hpp index e592e066..4d78692d 100644 --- a/include/boost/asio/ip/udp.hpp +++ b/include/boost/asio/ip/udp.hpp @@ -1,6 +1,6 @@ // -// udp.hpp -// ~~~~~~~ +// ip/udp.hpp +// ~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/unicast.hpp b/include/boost/asio/ip/unicast.hpp index c97e6fd1..1f331de6 100644 --- a/include/boost/asio/ip/unicast.hpp +++ b/include/boost/asio/ip/unicast.hpp @@ -1,6 +1,6 @@ // -// unicast.hpp -// ~~~~~~~~~~~ +// ip/unicast.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/ip/v6_only.hpp b/include/boost/asio/ip/v6_only.hpp index 9adcbffc..e9aab314 100644 --- a/include/boost/asio/ip/v6_only.hpp +++ b/include/boost/asio/ip/v6_only.hpp @@ -1,6 +1,6 @@ // -// v6_only.hpp -// ~~~~~~~~~~~ +// ip/v6_only.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/is_read_buffered.hpp b/include/boost/asio/is_read_buffered.hpp index f0989a2b..e429e6d7 100644 --- a/include/boost/asio/is_read_buffered.hpp +++ b/include/boost/asio/is_read_buffered.hpp @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - +#include #include #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/is_write_buffered.hpp b/include/boost/asio/is_write_buffered.hpp index bcdf77d1..fff68d6a 100644 --- a/include/boost/asio/is_write_buffered.hpp +++ b/include/boost/asio/is_write_buffered.hpp @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - +#include #include #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/local/basic_endpoint.hpp b/include/boost/asio/local/basic_endpoint.hpp index 1e4057ff..2cd93f6c 100644 --- a/include/boost/asio/local/basic_endpoint.hpp +++ b/include/boost/asio/local/basic_endpoint.hpp @@ -1,6 +1,6 @@ // -// basic_endpoint.hpp -// ~~~~~~~~~~~~~~~~~~ +// local/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Derived from a public domain implementation written by Daniel Casimiro. @@ -16,30 +16,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) -# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 -# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +#include #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) +#include + +#if !defined(BOOST_NO_IOSTREAM) +# include +#endif // !defined(BOOST_NO_IOSTREAM) + +#include namespace boost { namespace asio { @@ -75,34 +63,30 @@ public: /// Default constructor. basic_endpoint() { - init("", 0); } /// Construct an endpoint using the specified path name. basic_endpoint(const char* path) + : impl_(path) { - using namespace std; // For strlen. - init(path, strlen(path)); } /// Construct an endpoint using the specified path name. basic_endpoint(const std::string& path) + : impl_(path) { - init(path.data(), path.length()); } /// Copy constructor. basic_endpoint(const basic_endpoint& other) - : data_(other.data_), - path_length_(other.path_length_) + : impl_(other.impl_) { } /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) { - data_ = other.data_; - path_length_ = other.path_length_; + impl_ = other.impl_; return *this; } @@ -115,123 +99,96 @@ public: /// Get the underlying endpoint in the native type. data_type* data() { - return &data_.base; + return impl_.data(); } /// Get the underlying endpoint in the native type. const data_type* data() const { - return &data_.base; + return impl_.data(); } /// Get the underlying size of the endpoint in the native type. std::size_t size() const { - return path_length_ - + offsetof(boost::asio::detail::sockaddr_un_type, sun_path); + return impl_.size(); } /// Set the underlying size of the endpoint in the native type. void resize(std::size_t size) { - if (size > sizeof(boost::asio::detail::sockaddr_un_type)) - { - boost::system::system_error e(boost::asio::error::invalid_argument); - boost::throw_exception(e); - } - else if (size == 0) - { - path_length_ = 0; - } - else - { - path_length_ = size - - offsetof(boost::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_ - 1] == 0) - --path_length_; - } + impl_.resize(size); } /// Get the capacity of the endpoint in the native type. std::size_t capacity() const { - return sizeof(boost::asio::detail::sockaddr_un_type); + return impl_.capacity(); } /// Get the path associated with the endpoint. std::string path() const { - return std::string(data_.local.sun_path, path_length_); + return impl_.path(); } /// Set the path associated with the endpoint. void path(const char* p) { - using namespace std; // For strlen. - init(p, strlen(p)); + impl_.path(p); } /// Set the path associated with the endpoint. void path(const std::string& p) { - init(p.data(), p.length()); + impl_.path(p); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.path() == e2.path(); + return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.path() != e2.path(); + return !(e1.impl_ == e2.impl_); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.path() < e2.path(); + return e1.impl_ < e2.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator>(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e2.impl_ < e1.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator<=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e2 < e1); + } + + /// Compare endpoints for ordering. + friend bool operator>=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e1 < e2); } private: - // The underlying UNIX socket address. - union data_union - { - boost::asio::detail::socket_addr_type base; - boost::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. - boost::system::error_code ec(boost::asio::error::name_too_long); - boost::asio::detail::throw_error(ec); - } - - using namespace std; // For memcpy. - data_.local = boost::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; - } + // The underlying UNIX domain endpoint. + boost::asio::local::detail::endpoint impl_; }; /// Output an endpoint as a string. @@ -259,9 +216,9 @@ std::basic_ostream& operator<<( } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_LOCAL_BASIC_ENDPOINT_HPP diff --git a/include/boost/asio/local/connect_pair.hpp b/include/boost/asio/local/connect_pair.hpp index 697a0d24..cb08777a 100644 --- a/include/boost/asio/local/connect_pair.hpp +++ b/include/boost/asio/local/connect_pair.hpp @@ -1,6 +1,6 @@ // -// connect_pair.hpp -// ~~~~~~~~~~~~~~~~ +// local/connect_pair.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace local { @@ -74,8 +76,9 @@ inline boost::system::error_code connect_pair( if (socket1.assign(protocol, sv[0], ec)) { boost::system::error_code temp_ec; - boost::asio::detail::socket_ops::close(sv[0], temp_ec); - boost::asio::detail::socket_ops::close(sv[1], temp_ec); + boost::asio::detail::socket_ops::state_type state[2] = { 0, 0 }; + boost::asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec); + boost::asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec); return ec; } @@ -83,7 +86,8 @@ inline boost::system::error_code connect_pair( { boost::system::error_code temp_ec; socket1.close(temp_ec); - boost::asio::detail::socket_ops::close(sv[1], temp_ec); + boost::asio::detail::socket_ops::state_type state = 0; + boost::asio::detail::socket_ops::close(sv[1], state, true, temp_ec); return ec; } @@ -94,9 +98,9 @@ inline boost::system::error_code connect_pair( } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_LOCAL_CONNECT_PAIR_HPP diff --git a/include/boost/asio/local/datagram_protocol.hpp b/include/boost/asio/local/datagram_protocol.hpp index 1441ee6a..2d78773e 100644 --- a/include/boost/asio/local/datagram_protocol.hpp +++ b/include/boost/asio/local/datagram_protocol.hpp @@ -1,6 +1,6 @@ // -// datagram_protocol.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// local/datagram_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include + +#include + namespace boost { namespace asio { namespace local { @@ -72,9 +74,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP diff --git a/include/boost/asio/local/detail/endpoint.hpp b/include/boost/asio/local/detail/endpoint.hpp new file mode 100644 index 00000000..5fb72979 --- /dev/null +++ b/include/boost/asio/local/detail/endpoint.hpp @@ -0,0 +1,135 @@ +// +// local/detail/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 BOOST_ASIO_LOCAL_DETAIL_ENDPOINT_HPP +#define BOOST_ASIO_LOCAL_DETAIL_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace local { +namespace detail { + +// Helper class for implementing a UNIX domain endpoint. +class endpoint +{ +public: + // Default constructor. + BOOST_ASIO_DECL endpoint(); + + // Construct an endpoint using the specified path name. + BOOST_ASIO_DECL endpoint(const char* path); + + // Construct an endpoint using the specified path name. + BOOST_ASIO_DECL endpoint(const std::string& path); + + // Copy constructor. + endpoint(const endpoint& other) + : data_(other.data_), + path_length_(other.path_length_) + { + } + + // Assign from another endpoint. + endpoint& operator=(const endpoint& other) + { + data_ = other.data_; + path_length_ = other.path_length_; + return *this; + } + + // Get the underlying endpoint in the native type. + boost::asio::detail::socket_addr_type* data() + { + return &data_.base; + } + + // Get the underlying endpoint in the native type. + const boost::asio::detail::socket_addr_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(boost::asio::detail::sockaddr_un_type, sun_path); + } + + // Set the underlying size of the endpoint in the native type. + BOOST_ASIO_DECL void resize(std::size_t size); + + // Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return sizeof(boost::asio::detail::sockaddr_un_type); + } + + // Get the path associated with the endpoint. + BOOST_ASIO_DECL std::string path() const; + + // Set the path associated with the endpoint. + BOOST_ASIO_DECL void path(const char* p); + + // Set the path associated with the endpoint. + BOOST_ASIO_DECL void path(const std::string& p); + + // Compare two endpoints for equality. + BOOST_ASIO_DECL friend bool operator==( + const endpoint& e1, const endpoint& e2); + + // Compare endpoints for ordering. + BOOST_ASIO_DECL friend bool operator<( + const endpoint& e1, const endpoint& e2); + +private: + // The underlying UNIX socket address. + union data_union + { + boost::asio::detail::socket_addr_type base; + boost::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. + BOOST_ASIO_DECL void init(const char* path, std::size_t path_length); +}; + +} // namespace detail +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#endif // BOOST_ASIO_LOCAL_DETAIL_ENDPOINT_HPP diff --git a/include/boost/asio/local/detail/impl/endpoint.ipp b/include/boost/asio/local/detail/impl/endpoint.ipp new file mode 100644 index 00000000..ffbc44ed --- /dev/null +++ b/include/boost/asio/local/detail/impl/endpoint.ipp @@ -0,0 +1,130 @@ +// +// local/detail/impl/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 BOOST_ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP +#define BOOST_ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace local { +namespace detail { + +endpoint::endpoint() +{ + init("", 0); +} + +endpoint::endpoint(const char* path) +{ + using namespace std; // For strlen. + init(path, strlen(path)); +} + +endpoint::endpoint(const std::string& path) +{ + init(path.data(), path.length()); +} + +void endpoint::resize(std::size_t size) +{ + if (size > sizeof(boost::asio::detail::sockaddr_un_type)) + { + boost::system::error_code ec(boost::asio::error::invalid_argument); + boost::asio::detail::throw_error(ec); + } + else if (size == 0) + { + path_length_ = 0; + } + else + { + path_length_ = size + - offsetof(boost::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_ - 1] == 0) + --path_length_; + } +} + +std::string endpoint::path() const +{ + return std::string(data_.local.sun_path, path_length_); +} + +void endpoint::path(const char* p) +{ + using namespace std; // For strlen. + init(p, strlen(p)); +} + +void endpoint::path(const std::string& p) +{ + init(p.data(), p.length()); +} + +bool operator==(const endpoint& e1, const endpoint& e2) +{ + return e1.path() == e2.path(); +} + +bool operator<(const endpoint& e1, const endpoint& e2) +{ + return e1.path() < e2.path(); +} + +void endpoint::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. + boost::system::error_code ec(boost::asio::error::name_too_long); + boost::asio::detail::throw_error(ec); + } + + using namespace std; // For memcpy. + data_.local = boost::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; +} + +} // namespace detail +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#endif // BOOST_ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP diff --git a/include/boost/asio/local/stream_protocol.hpp b/include/boost/asio/local/stream_protocol.hpp index f341a8b6..723c348c 100644 --- a/include/boost/asio/local/stream_protocol.hpp +++ b/include/boost/asio/local/stream_protocol.hpp @@ -1,6 +1,6 @@ // -// stream_protocol.hpp -// ~~~~~~~~~~~~~~~~~~~ +// local/stream_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) #include #include #include -#include #include +#include -#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ - || defined(GENERATING_DOCUMENTATION) +#include namespace boost { namespace asio { @@ -82,9 +84,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_LOCAL_STREAM_PROTOCOL_HPP diff --git a/include/boost/asio/placeholders.hpp b/include/boost/asio/placeholders.hpp index 55b6fd70..2940edaf 100644 --- a/include/boost/asio/placeholders.hpp +++ b/include/boost/asio/placeholders.hpp @@ -15,12 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/posix/basic_descriptor.hpp b/include/boost/asio/posix/basic_descriptor.hpp index ff9cb870..56ec9d8d 100644 --- a/include/boost/asio/posix/basic_descriptor.hpp +++ b/include/boost/asio/posix/basic_descriptor.hpp @@ -1,6 +1,6 @@ // -// basic_descriptor.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// posix/basic_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) #include +#include #include #include -#include + +#include namespace boost { namespace asio { @@ -293,4 +294,7 @@ protected: #include +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + #endif // BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP diff --git a/include/boost/asio/posix/basic_stream_descriptor.hpp b/include/boost/asio/posix/basic_stream_descriptor.hpp index d83a7f7a..0f70604b 100644 --- a/include/boost/asio/posix/basic_stream_descriptor.hpp +++ b/include/boost/asio/posix/basic_stream_descriptor.hpp @@ -1,6 +1,6 @@ // -// basic_stream_descriptor.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// posix/basic_stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace posix { @@ -298,9 +296,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP diff --git a/include/boost/asio/posix/descriptor_base.hpp b/include/boost/asio/posix/descriptor_base.hpp index ca93f4d4..70bac638 100644 --- a/include/boost/asio/posix/descriptor_base.hpp +++ b/include/boost/asio/posix/descriptor_base.hpp @@ -1,6 +1,6 @@ // -// descriptor_base.hpp -// ~~~~~~~~~~~~~~~~~~~ +// posix/descriptor_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) #include #include +#include + namespace boost { namespace asio { namespace posix { @@ -92,4 +92,7 @@ protected: #include +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + #endif // BOOST_ASIO_POSIX_DESCRIPTOR_BASE_HPP diff --git a/include/boost/asio/posix/stream_descriptor.hpp b/include/boost/asio/posix/stream_descriptor.hpp index 3b01618d..30b7e372 100644 --- a/include/boost/asio/posix/stream_descriptor.hpp +++ b/include/boost/asio/posix/stream_descriptor.hpp @@ -1,6 +1,6 @@ // -// stream_descriptor.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// posix/stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) +#include + namespace boost { namespace asio { namespace posix { @@ -36,6 +36,4 @@ typedef basic_stream_descriptor<> stream_descriptor; #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_HPP diff --git a/include/boost/asio/posix/stream_descriptor_service.hpp b/include/boost/asio/posix/stream_descriptor_service.hpp index 89b9ef4f..c2034da1 100644 --- a/include/boost/asio/posix/stream_descriptor_service.hpp +++ b/include/boost/asio/posix/stream_descriptor_service.hpp @@ -1,6 +1,6 @@ // -// stream_descriptor_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// posix/stream_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,28 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) -# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 -# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#include #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include #include +#include + namespace boost { namespace asio { namespace posix { @@ -181,9 +171,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP diff --git a/include/boost/asio/raw_socket_service.hpp b/include/boost/asio/raw_socket_service.hpp index 23427d7f..0db83b60 100644 --- a/include/boost/asio/raw_socket_service.hpp +++ b/include/boost/asio/raw_socket_service.hpp @@ -15,16 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -32,6 +26,8 @@ # include #endif +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/read.hpp b/include/boost/asio/read.hpp index 40ccc008..d2339d59 100644 --- a/include/boost/asio/read.hpp +++ b/include/boost/asio/read.hpp @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - -#include +#include #include +#include + namespace boost { namespace asio { @@ -538,8 +535,8 @@ void async_read(AsyncReadStream& s, basic_streambuf& b, } // namespace asio } // namespace boost -#include - #include +#include + #endif // BOOST_ASIO_READ_HPP diff --git a/include/boost/asio/read_at.hpp b/include/boost/asio/read_at.hpp index 133f143e..27bad65e 100644 --- a/include/boost/asio/read_at.hpp +++ b/include/boost/asio/read_at.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include -#include - -#include +#include #include +#include + namespace boost { namespace asio { @@ -571,8 +568,8 @@ void async_read_at(AsyncRandomAccessReadDevice& d, } // namespace asio } // namespace boost -#include - #include +#include + #endif // BOOST_ASIO_READ_AT_HPP diff --git a/include/boost/asio/read_until.hpp b/include/boost/asio/read_until.hpp index ec6cb426..aa9d2ba6 100644 --- a/include/boost/asio/read_until.hpp +++ b/include/boost/asio/read_until.hpp @@ -15,27 +15,22 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_NO_IOSTREAM) -#include #include -#include #include #include #include #include #include -#include - #include +#include #include +#include + namespace boost { namespace asio { @@ -916,10 +911,10 @@ void async_read_until(AsyncReadStream& s, } // namespace asio } // namespace boost -#include +#include + +#include #endif // !defined(BOOST_NO_IOSTREAM) -#include - #endif // BOOST_ASIO_READ_UNTIL_HPP diff --git a/include/boost/asio/serial_port.hpp b/include/boost/asio/serial_port.hpp index 00546e83..97757394 100644 --- a/include/boost/asio/serial_port.hpp +++ b/include/boost/asio/serial_port.hpp @@ -16,13 +16,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) +#include + namespace boost { namespace asio { @@ -35,6 +35,4 @@ typedef basic_serial_port<> serial_port; #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_SERIAL_PORT_HPP diff --git a/include/boost/asio/serial_port_base.hpp b/include/boost/asio/serial_port_base.hpp index 5f966392..a050df2f 100644 --- a/include/boost/asio/serial_port_base.hpp +++ b/include/boost/asio/serial_port_base.hpp @@ -16,32 +16,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) -# if defined(BOOST_ASIO_HAS_IOCP) \ - || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# define BOOST_ASIO_HAS_SERIAL_PORT 1 -# endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // !defined(BOOST_ASIO_DISABLE_STREAM_HANDLE) +#include #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# include # include -# include #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include #include +#include #if defined(GENERATING_DOCUMENTATION) # define BOOST_ASIO_OPTION_STORAGE implementation_defined @@ -51,6 +37,8 @@ # define BOOST_ASIO_OPTION_STORAGE termios #endif +#include + namespace boost { namespace asio { @@ -68,9 +56,11 @@ public: public: explicit baud_rate(unsigned int rate = 0); unsigned int value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: unsigned int value_; @@ -84,11 +74,13 @@ public: { public: enum type { none, software, hardware }; - explicit flow_control(type t = none); + BOOST_ASIO_DECL explicit flow_control(type t = none); type value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: type value_; @@ -102,11 +94,13 @@ public: { public: enum type { none, odd, even }; - explicit parity(type t = none); + BOOST_ASIO_DECL explicit parity(type t = none); type value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: type value_; @@ -120,11 +114,13 @@ public: { public: enum type { one, onepointfive, two }; - explicit stop_bits(type t = one); + BOOST_ASIO_DECL explicit stop_bits(type t = one); type value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: type value_; @@ -137,11 +133,13 @@ public: class character_size { public: - explicit character_size(unsigned int t = 8); + BOOST_ASIO_DECL explicit character_size(unsigned int t = 8); unsigned int value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: unsigned int value_; @@ -163,13 +161,16 @@ private: } // namespace asio } // namespace boost -#include +#include #undef BOOST_ASIO_OPTION_STORAGE +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_SERIAL_PORT_BASE_HPP diff --git a/include/boost/asio/serial_port_service.hpp b/include/boost/asio/serial_port_service.hpp index f1a23446..b1c83010 100644 --- a/include/boost/asio/serial_port_service.hpp +++ b/include/boost/asio/serial_port_service.hpp @@ -15,24 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { @@ -201,9 +198,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_SERIAL_PORT_SERVICE_HPP diff --git a/include/boost/asio/socket_acceptor_service.hpp b/include/boost/asio/socket_acceptor_service.hpp index 184580fb..3f7436b7 100644 --- a/include/boost/asio/socket_acceptor_service.hpp +++ b/include/boost/asio/socket_acceptor_service.hpp @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include #include -#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -28,6 +26,8 @@ # include #endif +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/socket_base.hpp b/include/boost/asio/socket_base.hpp index 75015bf6..083ffb6e 100644 --- a/include/boost/asio/socket_base.hpp +++ b/include/boost/asio/socket_base.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include #include #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/basic_context.hpp b/include/boost/asio/ssl/basic_context.hpp index acaa080d..9f9423ef 100644 --- a/include/boost/asio/ssl/basic_context.hpp +++ b/include/boost/asio/ssl/basic_context.hpp @@ -1,6 +1,6 @@ // -// basic_context.hpp -// ~~~~~~~~~~~~~~~~~ +// ssl/basic_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,17 +16,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - +#include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/context.hpp b/include/boost/asio/ssl/context.hpp index e07608bb..2a0c2c41 100644 --- a/include/boost/asio/ssl/context.hpp +++ b/include/boost/asio/ssl/context.hpp @@ -1,6 +1,6 @@ // -// context.hpp -// ~~~~~~~~~~~ +// ssl/context.hpp +// ~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,8 +16,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include @@ -32,6 +31,4 @@ typedef basic_context context; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_SSL_CONTEXT_HPP diff --git a/include/boost/asio/ssl/context_base.hpp b/include/boost/asio/ssl/context_base.hpp index 119d0727..8121500d 100644 --- a/include/boost/asio/ssl/context_base.hpp +++ b/include/boost/asio/ssl/context_base.hpp @@ -1,6 +1,6 @@ // -// context_base.hpp -// ~~~~~~~~~~~~~~~~ +// ssl/context_base.hpp +// ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include +#include + namespace boost { namespace asio { namespace ssl { diff --git a/include/boost/asio/ssl/context_service.hpp b/include/boost/asio/ssl/context_service.hpp index 4e33348e..689438d8 100644 --- a/include/boost/asio/ssl/context_service.hpp +++ b/include/boost/asio/ssl/context_service.hpp @@ -1,6 +1,6 @@ // -// context_service.hpp -// ~~~~~~~~~~~~~~~~~~~ +// ssl/context_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,19 +16,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - #include #include -#include #include #include +#include + namespace boost { namespace asio { namespace ssl { diff --git a/include/boost/asio/ssl/detail/openssl_context_service.hpp b/include/boost/asio/ssl/detail/openssl_context_service.hpp index 0180c76e..17348349 100644 --- a/include/boost/asio/ssl/detail/openssl_context_service.hpp +++ b/include/boost/asio/ssl/detail/openssl_context_service.hpp @@ -1,6 +1,6 @@ // -// openssl_context_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_context_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,21 +16,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include - #include #include -#include #include #include #include +#include + namespace boost { namespace asio { namespace ssl { diff --git a/include/boost/asio/ssl/detail/openssl_init.hpp b/include/boost/asio/ssl/detail/openssl_init.hpp index c1043a30..07bd1601 100644 --- a/include/boost/asio/ssl/detail/openssl_init.hpp +++ b/include/boost/asio/ssl/detail/openssl_init.hpp @@ -1,6 +1,6 @@ // -// openssl_init.hpp -// ~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,20 +16,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include #include -#include - #include #include #include +#include + namespace boost { namespace asio { namespace ssl { diff --git a/include/boost/asio/ssl/detail/openssl_operation.hpp b/include/boost/asio/ssl/detail/openssl_operation.hpp index 89b21f63..2eeb023c 100644 --- a/include/boost/asio/ssl/detail/openssl_operation.hpp +++ b/include/boost/asio/ssl/detail/openssl_operation.hpp @@ -1,6 +1,6 @@ // -// openssl_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // @@ -15,19 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include - #include -#include -#include #include +#include #include +#include +#include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/detail/openssl_stream_service.hpp b/include/boost/asio/ssl/detail/openssl_stream_service.hpp index 5d9a99cd..a554921f 100644 --- a/include/boost/asio/ssl/detail/openssl_stream_service.hpp +++ b/include/boost/asio/ssl/detail/openssl_stream_service.hpp @@ -1,6 +1,6 @@ // -// stream_service.hpp -// ~~~~~~~~~~~~~~~~~~ +// ssl/detail/stream_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,9 +16,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include @@ -26,17 +24,17 @@ #include #include #include -#include - +#include #include #include -#include -#include -#include #include #include #include #include +#include +#include + +#include namespace boost { namespace asio { @@ -93,7 +91,7 @@ private: : base_handler(io_service) , handler_(handler) { - set_func(boost::bind( + this->set_func(boost::bind( &io_handler::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } @@ -117,7 +115,7 @@ private: : base_handler(io_service) , handler_(handler) { - set_func(boost::bind( + this->set_func(boost::bind( &handshake_handler::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } @@ -142,7 +140,7 @@ private: : base_handler(io_service), handler_(handler) { - set_func(boost::bind( + this->set_func(boost::bind( &shutdown_handler::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } diff --git a/include/boost/asio/ssl/detail/openssl_types.hpp b/include/boost/asio/ssl/detail/openssl_types.hpp index 2c493c39..712c5539 100644 --- a/include/boost/asio/ssl/detail/openssl_types.hpp +++ b/include/boost/asio/ssl/detail/openssl_types.hpp @@ -1,6 +1,6 @@ // -// openssl_types.hpp -// ~~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include - -#include +#include #include #include #include #include -#include - -#include +#include #endif // BOOST_ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP diff --git a/include/boost/asio/ssl/stream.hpp b/include/boost/asio/ssl/stream.hpp index 5f70020d..c83d8e2e 100644 --- a/include/boost/asio/ssl/stream.hpp +++ b/include/boost/asio/ssl/stream.hpp @@ -1,6 +1,6 @@ // -// stream.hpp -// ~~~~~~~~~~ +// ssl/stream.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,20 +16,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include #include -#include - +#include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/stream_base.hpp b/include/boost/asio/ssl/stream_base.hpp index 3238fe4a..2d967d01 100644 --- a/include/boost/asio/ssl/stream_base.hpp +++ b/include/boost/asio/ssl/stream_base.hpp @@ -1,6 +1,6 @@ // -// stream_base.hpp -// ~~~~~~~~~~~~~~~ +// ssl/stream_base.hpp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/stream_service.hpp b/include/boost/asio/ssl/stream_service.hpp index 502f5123..303f8794 100644 --- a/include/boost/asio/ssl/stream_service.hpp +++ b/include/boost/asio/ssl/stream_service.hpp @@ -1,6 +1,6 @@ // -// stream_service.hpp -// ~~~~~~~~~~~~~~~~~~ +// ssl/stream_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,19 +16,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include -#include - #include -#include #include -#include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/strand.hpp b/include/boost/asio/strand.hpp index a64d4867..e0850308 100644 --- a/include/boost/asio/strand.hpp +++ b/include/boost/asio/strand.hpp @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/stream_socket_service.hpp b/include/boost/asio/stream_socket_service.hpp index 15aa6832..101eacbe 100644 --- a/include/boost/asio/stream_socket_service.hpp +++ b/include/boost/asio/stream_socket_service.hpp @@ -15,16 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -32,6 +26,8 @@ # include #endif +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/streambuf.hpp b/include/boost/asio/streambuf.hpp index c112e64d..30196ad7 100644 --- a/include/boost/asio/streambuf.hpp +++ b/include/boost/asio/streambuf.hpp @@ -15,12 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if !defined(BOOST_NO_IOSTREAM) +#include + namespace boost { namespace asio { @@ -32,6 +32,4 @@ typedef basic_streambuf<> streambuf; #endif // !defined(BOOST_NO_IOSTREAM) -#include - #endif // BOOST_ASIO_STREAMBUF_HPP diff --git a/include/boost/asio/time_traits.hpp b/include/boost/asio/time_traits.hpp index e0f40ca1..9043d7dc 100644 --- a/include/boost/asio/time_traits.hpp +++ b/include/boost/asio/time_traits.hpp @@ -15,14 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include // Must come before posix_time. #include #include #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/windows/basic_handle.hpp b/include/boost/asio/windows/basic_handle.hpp index 7bbdb0d3..58bb54dc 100644 --- a/include/boost/asio/windows/basic_handle.hpp +++ b/include/boost/asio/windows/basic_handle.hpp @@ -1,6 +1,6 @@ // -// basic_handle.hpp -// ~~~~~~~~~~~~~~~~ +// windows/basic_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) #include -#include #include +#include + +#include namespace boost { namespace asio { @@ -224,4 +226,8 @@ protected: #include +#endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + // || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + #endif // BOOST_ASIO_WINDOWS_BASIC_HANDLE_HPP diff --git a/include/boost/asio/windows/basic_random_access_handle.hpp b/include/boost/asio/windows/basic_random_access_handle.hpp index 06239df6..5c403d02 100644 --- a/include/boost/asio/windows/basic_random_access_handle.hpp +++ b/include/boost/asio/windows/basic_random_access_handle.hpp @@ -1,6 +1,6 @@ // -// basic_random_access_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/basic_random_access_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace windows { @@ -314,9 +312,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP diff --git a/include/boost/asio/windows/basic_stream_handle.hpp b/include/boost/asio/windows/basic_stream_handle.hpp index 329cc6fc..340e4024 100644 --- a/include/boost/asio/windows/basic_stream_handle.hpp +++ b/include/boost/asio/windows/basic_stream_handle.hpp @@ -1,6 +1,6 @@ // -// basic_stream_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// windows/basic_stream_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,20 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) -#include #include -#include -#include - #include #include #include #include -#if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) +#include namespace boost { namespace asio { @@ -296,9 +294,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP diff --git a/include/boost/asio/windows/overlapped_ptr.hpp b/include/boost/asio/windows/overlapped_ptr.hpp index 58802723..24a199f3 100644 --- a/include/boost/asio/windows/overlapped_ptr.hpp +++ b/include/boost/asio/windows/overlapped_ptr.hpp @@ -1,6 +1,6 @@ // -// overlapped_ptr.hpp -// ~~~~~~~~~~~~~~~~~~ +// windows/overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) -# if defined(BOOST_ASIO_HAS_IOCP) -# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 -# endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +#include #if defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include + +#include + namespace boost { namespace asio { namespace windows { @@ -112,9 +108,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_OVERLAPPED_PTR_HPP diff --git a/include/boost/asio/windows/random_access_handle.hpp b/include/boost/asio/windows/random_access_handle.hpp index 7707aac1..03d7055b 100644 --- a/include/boost/asio/windows/random_access_handle.hpp +++ b/include/boost/asio/windows/random_access_handle.hpp @@ -1,6 +1,6 @@ // -// random_access_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/random_access_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include + namespace boost { namespace asio { namespace windows { @@ -36,6 +36,4 @@ typedef basic_random_access_handle<> random_access_handle; #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP diff --git a/include/boost/asio/windows/random_access_handle_service.hpp b/include/boost/asio/windows/random_access_handle_service.hpp index 1dcbee4b..e5a2e11c 100644 --- a/include/boost/asio/windows/random_access_handle_service.hpp +++ b/include/boost/asio/windows/random_access_handle_service.hpp @@ -1,6 +1,6 @@ // -// random_access_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/random_access_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,28 +15,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) -# if defined(BOOST_ASIO_HAS_IOCP) -# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 -# endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +#include #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace windows { @@ -174,9 +166,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP diff --git a/include/boost/asio/windows/stream_handle.hpp b/include/boost/asio/windows/stream_handle.hpp index 8e9e4670..ca2a56c5 100644 --- a/include/boost/asio/windows/stream_handle.hpp +++ b/include/boost/asio/windows/stream_handle.hpp @@ -1,6 +1,6 @@ // -// stream_handle.hpp -// ~~~~~~~~~~~~~~~~~~ +// windows/stream_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include + namespace boost { namespace asio { namespace windows { @@ -36,6 +36,4 @@ typedef basic_stream_handle<> stream_handle; #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_STREAM_HANDLE_HPP diff --git a/include/boost/asio/windows/stream_handle_service.hpp b/include/boost/asio/windows/stream_handle_service.hpp index cc6c6e86..e5346461 100644 --- a/include/boost/asio/windows/stream_handle_service.hpp +++ b/include/boost/asio/windows/stream_handle_service.hpp @@ -1,6 +1,6 @@ // -// stream_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/stream_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,27 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) -# if defined(BOOST_ASIO_HAS_IOCP) -# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 -# endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +#include #if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace windows { @@ -172,9 +163,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP diff --git a/include/boost/asio/write.hpp b/include/boost/asio/write.hpp index 2a95735d..0ec08797 100644 --- a/include/boost/asio/write.hpp +++ b/include/boost/asio/write.hpp @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - -#include +#include #include +#include + namespace boost { namespace asio { @@ -535,8 +532,8 @@ void async_write(AsyncWriteStream& s, basic_streambuf& b, } // namespace asio } // namespace boost -#include - #include +#include + #endif // BOOST_ASIO_WRITE_HPP diff --git a/include/boost/asio/write_at.hpp b/include/boost/asio/write_at.hpp index 74f080a3..a078a703 100644 --- a/include/boost/asio/write_at.hpp +++ b/include/boost/asio/write_at.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include -#include - -#include +#include #include +#include + namespace boost { namespace asio { @@ -558,8 +555,8 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, } // namespace asio } // namespace boost -#include - #include +#include + #endif // BOOST_ASIO_WRITE_AT_HPP diff --git a/test/Jamfile b/test/Jamfile index 220727e4..c2c38ac1 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -26,6 +26,7 @@ if $(UNIX) template asio_unit_test : @boost/libs/thread/build/boost_thread + @boost/libs/regex/build/boost_regex @boost_system/libs/system/build/boost_system : ../../.. @boost @boost_system BOOST_ALL_NO_LIB=1 diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8a7f5f9b..6148d2e2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -39,6 +39,7 @@ project /boost/date_time//boost_date_time /boost/system//boost_system /boost/thread//boost_thread + /boost/regex//boost_regex BOOST_ALL_NO_LIB=1 multi LINUX:_XOPEN_SOURCE=600 diff --git a/test/buffer.cpp b/test/buffer.cpp index a11f15f9..48139932 100644 --- a/test/buffer.cpp +++ b/test/buffer.cpp @@ -16,6 +16,7 @@ // Test that header file is self-contained. #include +#include #include "unit_test.hpp" //------------------------------------------------------------------------------ diff --git a/test/buffered_read_stream.cpp b/test/buffered_read_stream.cpp index 8015a5f4..f3d0a2ef 100644 --- a/test/buffered_read_stream.cpp +++ b/test/buffered_read_stream.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "unit_test.hpp" typedef boost::asio::buffered_read_stream< diff --git a/test/buffered_stream.cpp b/test/buffered_stream.cpp index 0ea15fed..ae6f4529 100644 --- a/test/buffered_stream.cpp +++ b/test/buffered_stream.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "unit_test.hpp" typedef boost::asio::buffered_stream< diff --git a/test/buffered_write_stream.cpp b/test/buffered_write_stream.cpp index f29fff58..b7e444e0 100644 --- a/test/buffered_write_stream.cpp +++ b/test/buffered_write_stream.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "unit_test.hpp" typedef boost::asio::buffered_write_stream< diff --git a/test/buffers_iterator.cpp b/test/buffers_iterator.cpp index 2bcc3b37..226e470e 100644 --- a/test/buffers_iterator.cpp +++ b/test/buffers_iterator.cpp @@ -16,6 +16,7 @@ // Test that header file is self-contained. #include +#include #include #include "unit_test.hpp" @@ -212,18 +213,18 @@ void test() bi11 += 1; bi12 += 1; - static_cast(bi13 - bi1); - static_cast(bi14 - bi2); - static_cast(bi15 - bi3); - static_cast(bi16 - bi4); - static_cast(bi17 - bi5); - static_cast(bi18 - bi6); - static_cast(bi19 - bi7); - static_cast(bi20 - bi8); - static_cast(bi21 - bi9); - static_cast(bi22 - bi10); - static_cast(bi23 - bi11); - static_cast(bi24 - bi12); + (void)static_cast(bi13 - bi1); + (void)static_cast(bi14 - bi2); + (void)static_cast(bi15 - bi3); + (void)static_cast(bi16 - bi4); + (void)static_cast(bi17 - bi5); + (void)static_cast(bi18 - bi6); + (void)static_cast(bi19 - bi7); + (void)static_cast(bi20 - bi8); + (void)static_cast(bi21 - bi9); + (void)static_cast(bi22 - bi10); + (void)static_cast(bi23 - bi11); + (void)static_cast(bi24 - bi12); } catch (std::exception&) { diff --git a/test/ip/multicast.cpp b/test/ip/multicast.cpp index 510bea65..2541cb62 100644 --- a/test/ip/multicast.cpp +++ b/test/ip/multicast.cpp @@ -76,7 +76,7 @@ void test() ip::multicast::hops hops2; sock.get_option(hops2); hops1 = 1; - static_cast(hops1.value()); + (void)static_cast(hops1.value()); // enable_loopback class. @@ -85,9 +85,9 @@ void test() ip::multicast::enable_loopback enable_loopback2; sock.get_option(enable_loopback2); enable_loopback1 = true; - static_cast(enable_loopback1); - static_cast(!enable_loopback1); - static_cast(enable_loopback1.value()); + (void)static_cast(enable_loopback1); + (void)static_cast(!enable_loopback1); + (void)static_cast(enable_loopback1.value()); } catch (std::exception&) { diff --git a/test/ip/tcp.cpp b/test/ip/tcp.cpp index 95f550ef..d3e72f50 100644 --- a/test/ip/tcp.cpp +++ b/test/ip/tcp.cpp @@ -54,9 +54,9 @@ void test() ip::tcp::no_delay no_delay2; sock.get_option(no_delay2); no_delay1 = true; - static_cast(no_delay1); - static_cast(!no_delay1); - static_cast(no_delay1.value()); + (void)static_cast(no_delay1); + (void)static_cast(!no_delay1); + (void)static_cast(no_delay1.value()); } catch (std::exception&) { @@ -551,6 +551,68 @@ void test() //------------------------------------------------------------------------------ +// ip_tcp_resolver_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::tcp::resolver compile and link correctly. Runtime failures are ignored. + +namespace ip_tcp_resolver_compile { + +void resolve_handler(const boost::system::error_code&, + boost::asio::ip::tcp::resolver::iterator) +{ +} + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_service ios; + boost::system::error_code ec; + ip::tcp::resolver::query q(ip::tcp::v4(), "localhost", "0"); + ip::tcp::endpoint e(ip::address_v4::loopback(), 0); + + // basic_resolver constructors. + + ip::tcp::resolver resolver(ios); + + // basic_io_object functions. + + io_service& ios_ref = resolver.io_service(); + (void)ios_ref; + + // basic_resolver functions. + + resolver.cancel(); + + ip::tcp::resolver::iterator iter1 = resolver.resolve(q); + (void)iter1; + + ip::tcp::resolver::iterator iter2 = resolver.resolve(q, ec); + (void)iter2; + + ip::tcp::resolver::iterator iter3 = resolver.resolve(e); + (void)iter3; + + ip::tcp::resolver::iterator iter4 = resolver.resolve(e, ec); + (void)iter4; + + resolver.async_resolve(q, resolve_handler); + + resolver.async_resolve(e, resolve_handler); + } + catch (std::exception&) + { + } +} + +} // namespace ip_tcp_resolver_compile + +//------------------------------------------------------------------------------ + test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("ip/tcp"); @@ -559,5 +621,6 @@ test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&ip_tcp_socket_compile::test)); test->add(BOOST_TEST_CASE(&ip_tcp_socket_runtime::test)); test->add(BOOST_TEST_CASE(&ip_tcp_acceptor_runtime::test)); + test->add(BOOST_TEST_CASE(&ip_tcp_resolver_compile::test)); return test; } diff --git a/test/ip/udp.cpp b/test/ip/udp.cpp index b9b296f7..6cbcc806 100644 --- a/test/ip/udp.cpp +++ b/test/ip/udp.cpp @@ -334,10 +334,73 @@ void test() //------------------------------------------------------------------------------ +// ip_udp_resolver_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::udp::resolver compile and link correctly. Runtime failures are ignored. + +namespace ip_udp_resolver_compile { + +void resolve_handler(const boost::system::error_code&, + boost::asio::ip::udp::resolver::iterator) +{ +} + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_service ios; + boost::system::error_code ec; + ip::udp::resolver::query q(ip::udp::v4(), "localhost", "0"); + ip::udp::endpoint e(ip::address_v4::loopback(), 0); + + // basic_resolver constructors. + + ip::udp::resolver resolver(ios); + + // basic_io_object functions. + + io_service& ios_ref = resolver.io_service(); + (void)ios_ref; + + // basic_resolver functions. + + resolver.cancel(); + + ip::udp::resolver::iterator iter1 = resolver.resolve(q); + (void)iter1; + + ip::udp::resolver::iterator iter2 = resolver.resolve(q, ec); + (void)iter2; + + ip::udp::resolver::iterator iter3 = resolver.resolve(e); + (void)iter3; + + ip::udp::resolver::iterator iter4 = resolver.resolve(e, ec); + (void)iter4; + + resolver.async_resolve(q, resolve_handler); + + resolver.async_resolve(e, resolve_handler); + } + catch (std::exception&) + { + } +} + +} // namespace ip_udp_resolver_compile + +//------------------------------------------------------------------------------ + test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("ip/udp"); test->add(BOOST_TEST_CASE(&ip_udp_socket_compile::test)); test->add(BOOST_TEST_CASE(&ip_udp_socket_runtime::test)); + test->add(BOOST_TEST_CASE(&ip_udp_resolver_compile::test)); return test; } diff --git a/test/ip/unicast.cpp b/test/ip/unicast.cpp index 67af4734..06ad0599 100644 --- a/test/ip/unicast.cpp +++ b/test/ip/unicast.cpp @@ -46,7 +46,7 @@ void test() ip::unicast::hops hops2; sock.get_option(hops2); hops1 = 1; - static_cast(hops1.value()); + (void)static_cast(hops1.value()); } catch (std::exception&) { diff --git a/test/ip/v6_only.cpp b/test/ip/v6_only.cpp index 74d9ca9f..8186047a 100644 --- a/test/ip/v6_only.cpp +++ b/test/ip/v6_only.cpp @@ -47,9 +47,9 @@ void test() ip::v6_only v6_only2; sock.get_option(v6_only2); v6_only1 = true; - static_cast(v6_only1); - static_cast(!v6_only1); - static_cast(v6_only1.value()); + (void)static_cast(v6_only1); + (void)static_cast(!v6_only1); + (void)static_cast(v6_only1.value()); } catch (std::exception&) { diff --git a/test/read.cpp b/test/read.cpp index 1e9401d8..baa4ad9f 100644 --- a/test/read.cpp +++ b/test/read.cpp @@ -16,9 +16,11 @@ // Test that header file is self-contained. #include +#include #include #include #include +#include #include #include #include @@ -61,7 +63,7 @@ public: } template - bool check(const Const_Buffers& buffers, size_t length) + bool check_buffers(const Const_Buffers& buffers, size_t length) { if (length != position_) return false; @@ -135,6 +137,16 @@ private: static const char read_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +void test_2_arg_zero_buffers_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + std::vector buffers; + + size_t bytes_transferred = boost::asio::read(s, buffers); + BOOST_CHECK(bytes_transferred == 0); +} + void test_2_arg_mutable_buffers_1_read() { boost::asio::io_service ios; @@ -147,21 +159,21 @@ void test_2_arg_mutable_buffers_1_read() memset(read_buf, 0, sizeof(read_buf)); size_t bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_2_arg_multi_buffers_read() @@ -177,21 +189,21 @@ void test_2_arg_multi_buffers_read() memset(read_buf, 0, sizeof(read_buf)); size_t bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_2_arg_streambuf_read() @@ -205,7 +217,7 @@ void test_2_arg_streambuf_read() size_t bytes_transferred = boost::asio::read(s, sb); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -213,7 +225,7 @@ void test_2_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -221,7 +233,7 @@ void test_2_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); } bool old_style_transfer_all(const boost::system::error_code& ec, @@ -249,7 +261,7 @@ void test_3_arg_mutable_buffers_1_read() size_t bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -257,7 +269,7 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -265,14 +277,14 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -280,7 +292,7 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -288,14 +300,14 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -303,7 +315,7 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -311,14 +323,14 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -326,7 +338,7 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -334,47 +346,47 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_3_arg_multi_buffers_read() @@ -391,7 +403,7 @@ void test_3_arg_multi_buffers_read() size_t bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -399,7 +411,7 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -407,14 +419,14 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -422,7 +434,7 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -430,14 +442,14 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -445,7 +457,7 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -453,14 +465,14 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -468,7 +480,7 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -476,47 +488,47 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_3_arg_streambuf_read() @@ -531,7 +543,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -540,7 +552,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -549,7 +561,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -557,7 +569,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -566,7 +578,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); BOOST_CHECK(sb.size() == 1); - BOOST_CHECK(s.check(sb.data(), 1)); + BOOST_CHECK(s.check_buffers(sb.data(), 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -575,7 +587,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -583,7 +595,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -592,7 +604,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -601,7 +613,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -609,7 +621,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -618,7 +630,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); BOOST_CHECK(sb.size() == 42); - BOOST_CHECK(s.check(sb.data(), 42)); + BOOST_CHECK(s.check_buffers(sb.data(), 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -627,14 +639,14 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); BOOST_CHECK(sb.size() == 50); - BOOST_CHECK(s.check(sb.data(), 50)); + BOOST_CHECK(s.check_buffers(sb.data(), 50)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -642,7 +654,7 @@ void test_3_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -650,14 +662,14 @@ void test_3_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); bytes_transferred = boost::asio::read(s, sb, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -665,7 +677,7 @@ void test_3_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -673,7 +685,7 @@ void test_3_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); } void test_4_arg_mutable_buffers_1_read() @@ -690,7 +702,7 @@ void test_4_arg_mutable_buffers_1_read() size_t bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -700,7 +712,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -710,7 +722,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -719,7 +731,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -729,7 +741,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -739,7 +751,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -748,7 +760,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -758,7 +770,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -768,7 +780,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -777,7 +789,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -787,7 +799,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -797,7 +809,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -805,7 +817,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -815,7 +827,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -825,14 +837,14 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -841,7 +853,7 @@ void test_4_arg_mutable_buffers_1_read() error = boost::system::error_code(); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -850,7 +862,7 @@ void test_4_arg_mutable_buffers_1_read() error = boost::system::error_code(); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); } @@ -869,7 +881,7 @@ void test_4_arg_multi_buffers_read() size_t bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -879,7 +891,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -889,7 +901,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -898,7 +910,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -908,7 +920,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -918,7 +930,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -927,7 +939,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -937,7 +949,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -947,7 +959,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -956,7 +968,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -966,7 +978,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -976,7 +988,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -984,7 +996,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -994,7 +1006,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1004,14 +1016,14 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1020,7 +1032,7 @@ void test_4_arg_multi_buffers_read() error = boost::system::error_code(); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1029,7 +1041,7 @@ void test_4_arg_multi_buffers_read() error = boost::system::error_code(); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); } @@ -1046,7 +1058,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1057,7 +1069,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1068,7 +1080,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1078,7 +1090,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1089,7 +1101,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); BOOST_CHECK(sb.size() == 1); - BOOST_CHECK(s.check(sb.data(), 1)); + BOOST_CHECK(s.check_buffers(sb.data(), 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1100,7 +1112,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1110,7 +1122,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1121,7 +1133,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1132,7 +1144,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1142,7 +1154,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1153,7 +1165,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); BOOST_CHECK(sb.size() == 42); - BOOST_CHECK(s.check(sb.data(), 42)); + BOOST_CHECK(s.check_buffers(sb.data(), 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1164,7 +1176,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); BOOST_CHECK(sb.size() == 50); - BOOST_CHECK(s.check(sb.data(), 50)); + BOOST_CHECK(s.check_buffers(sb.data(), 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1173,7 +1185,7 @@ void test_4_arg_streambuf_read() old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1184,7 +1196,7 @@ void test_4_arg_streambuf_read() old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1195,7 +1207,7 @@ void test_4_arg_streambuf_read() old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1203,7 +1215,7 @@ void test_4_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1213,7 +1225,7 @@ void test_4_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1223,7 +1235,7 @@ void test_4_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); } @@ -1254,7 +1266,7 @@ void test_3_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1268,7 +1280,7 @@ void test_3_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1282,7 +1294,7 @@ void test_3_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_3_arg_multi_buffers_async_read() @@ -1305,7 +1317,7 @@ void test_3_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1319,7 +1331,7 @@ void test_3_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1333,7 +1345,7 @@ void test_3_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_3_arg_streambuf_async_read() @@ -1354,7 +1366,7 @@ void test_3_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1369,7 +1381,7 @@ void test_3_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1384,7 +1396,7 @@ void test_3_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); } void test_4_arg_mutable_buffers_1_async_read() @@ -1406,7 +1418,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1420,7 +1432,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1434,7 +1446,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1447,7 +1459,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1461,7 +1473,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1475,7 +1487,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1488,7 +1500,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1502,7 +1514,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1516,7 +1528,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1529,7 +1541,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1543,7 +1555,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1557,7 +1569,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1570,7 +1582,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1584,7 +1596,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1598,7 +1610,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1611,7 +1623,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1625,7 +1637,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1639,7 +1651,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_4_arg_multi_buffers_async_read() @@ -1662,7 +1674,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1676,7 +1688,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1690,7 +1702,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1703,7 +1715,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1717,7 +1729,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1731,7 +1743,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1744,7 +1756,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1758,7 +1770,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1772,7 +1784,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1785,7 +1797,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1799,7 +1811,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1813,7 +1825,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1826,7 +1838,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1840,7 +1852,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1854,7 +1866,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1867,7 +1879,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1881,7 +1893,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1895,7 +1907,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_4_arg_streambuf_async_read() @@ -1916,7 +1928,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1931,7 +1943,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1946,7 +1958,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -1960,7 +1972,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1975,7 +1987,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 1); - BOOST_CHECK(s.check(sb.data(), 1)); + BOOST_CHECK(s.check_buffers(sb.data(), 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1990,7 +2002,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -2004,7 +2016,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -2019,7 +2031,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -2034,7 +2046,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -2048,7 +2060,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -2063,7 +2075,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 42); - BOOST_CHECK(s.check(sb.data(), 42)); + BOOST_CHECK(s.check_buffers(sb.data(), 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -2078,7 +2090,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 50); - BOOST_CHECK(s.check(sb.data(), 50)); + BOOST_CHECK(s.check_buffers(sb.data(), 50)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -2092,7 +2104,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -2107,7 +2119,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -2122,7 +2134,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -2136,7 +2148,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -2151,7 +2163,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -2166,12 +2178,13 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); } test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("read"); + test->add(BOOST_TEST_CASE(&test_2_arg_zero_buffers_read)); test->add(BOOST_TEST_CASE(&test_2_arg_mutable_buffers_1_read)); test->add(BOOST_TEST_CASE(&test_2_arg_multi_buffers_read)); test->add(BOOST_TEST_CASE(&test_2_arg_streambuf_read)); diff --git a/test/read_at.cpp b/test/read_at.cpp index 48a668c5..36fd1c29 100644 --- a/test/read_at.cpp +++ b/test/read_at.cpp @@ -16,11 +16,13 @@ // Test that header file is self-contained. #include +#include #include #include #include #include #include +#include #include "unit_test.hpp" using namespace std; // For memcmp, memcpy and memset. @@ -63,7 +65,7 @@ public: } template - bool check(boost::uint64_t offset, + bool check_buffers(boost::uint64_t offset, const Const_Buffers& buffers, size_t length) { if (offset + length > max_length) @@ -139,7 +141,7 @@ private: static const char read_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -void test_3_arg_read_at() +void test_3_arg_mutable_buffers_1_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -151,41 +153,144 @@ void test_3_arg_read_at() memset(read_buf, 0, sizeof(read_buf)); size_t bytes_transferred = boost::asio::read_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_3_arg_multi_buffers_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_3_arg_streambuf_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read_at(s, 0, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); } bool old_style_transfer_all(const boost::system::error_code& ec, @@ -200,7 +305,7 @@ size_t short_transfer(const boost::system::error_code& ec, return !!ec ? 0 : 3; } -void test_4_arg_read_at() +void test_4_arg_mutable_buffers_1_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -213,14 +318,14 @@ void test_4_arg_read_at() size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -228,7 +333,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -236,7 +341,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -244,7 +349,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -252,21 +357,21 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -274,7 +379,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -282,7 +387,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -290,7 +395,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -298,21 +403,21 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -320,7 +425,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -328,7 +433,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -336,7 +441,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -344,21 +449,21 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -366,7 +471,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -374,7 +479,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -382,7 +487,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -390,21 +495,21 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -412,7 +517,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -420,7 +525,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -428,7 +533,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -436,50 +541,643 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); } -void test_5_arg_read_at() +void test_4_arg_multi_buffers_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_4_arg_streambuf_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(0, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); +} + +void test_5_arg_mutable_buffers_1_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -493,7 +1191,7 @@ void test_5_arg_read_at() size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -501,7 +1199,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -511,7 +1209,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -521,7 +1219,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -531,7 +1229,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -541,7 +1239,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -550,7 +1248,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -559,7 +1257,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -569,7 +1267,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -579,7 +1277,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -589,7 +1287,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -599,7 +1297,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -608,7 +1306,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -617,7 +1315,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -627,7 +1325,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -637,7 +1335,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -647,7 +1345,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -657,7 +1355,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -666,7 +1364,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -675,7 +1373,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -685,7 +1383,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -695,7 +1393,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -705,7 +1403,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -715,7 +1413,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -723,7 +1421,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -731,7 +1429,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -741,7 +1439,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -751,7 +1449,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -761,7 +1459,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -771,7 +1469,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -779,7 +1477,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -787,7 +1485,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -797,7 +1495,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -807,7 +1505,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -817,7 +1515,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -827,7 +1525,746 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); +} + +void test_5_arg_multi_buffers_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); +} + +void test_5_arg_streambuf_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(0, sb.data(), 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(0, sb.data(), 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(0, sb.data(), 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); BOOST_CHECK(!error); } @@ -839,7 +2276,7 @@ void async_read_handler(const boost::system::error_code& e, BOOST_CHECK(bytes_transferred == expected_bytes_transferred); } -void test_4_arg_async_read_at() +void test_4_arg_mutable_buffers_1_async_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -858,7 +2295,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -871,7 +2308,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -885,7 +2322,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -899,7 +2336,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -913,7 +2350,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -927,10 +2364,197 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); } -void test_5_arg_async_read_at() +void test_4_arg_multi_buffers_async_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_4_arg_streambuf_async_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read_at(s, 0, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); +} + +void test_5_arg_mutable_buffers_1_async_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -950,7 +2574,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -964,7 +2588,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -979,7 +2603,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -994,7 +2618,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1009,7 +2633,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1024,7 +2648,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1038,7 +2662,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1052,7 +2676,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1067,7 +2691,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1082,7 +2706,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1097,7 +2721,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1112,7 +2736,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1126,7 +2750,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1140,7 +2764,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1155,7 +2779,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1170,7 +2794,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1185,7 +2809,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1200,7 +2824,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1214,7 +2838,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1228,7 +2852,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1243,7 +2867,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1258,7 +2882,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1273,7 +2897,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1288,7 +2912,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1301,7 +2925,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1314,7 +2938,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1328,7 +2952,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1342,7 +2966,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1356,7 +2980,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1370,7 +2994,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1383,7 +3007,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1396,7 +3020,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1410,7 +3034,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1424,7 +3048,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1438,7 +3062,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1452,16 +3076,1111 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_5_arg_multi_buffers_async_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_5_arg_streambuf_async_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(0, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); } test_suite* init_unit_test_suite(int, char*[]) { - test_suite* test = BOOST_TEST_SUITE("read"); - test->add(BOOST_TEST_CASE(&test_3_arg_read_at)); - test->add(BOOST_TEST_CASE(&test_4_arg_read_at)); - test->add(BOOST_TEST_CASE(&test_5_arg_read_at)); - test->add(BOOST_TEST_CASE(&test_4_arg_async_read_at)); - test->add(BOOST_TEST_CASE(&test_5_arg_async_read_at)); + test_suite* test = BOOST_TEST_SUITE("read_at"); + test->add(BOOST_TEST_CASE(&test_3_arg_mutable_buffers_1_read_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_multi_buffers_read_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_streambuf_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_streambuf_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_mutable_buffers_1_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_multi_buffers_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_streambuf_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_async_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_async_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_streambuf_async_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_mutable_buffers_1_async_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_multi_buffers_async_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_streambuf_async_read_at)); return test; } diff --git a/test/serial_port_base.cpp b/test/serial_port_base.cpp index 2dd7f46f..ade5650f 100644 --- a/test/serial_port_base.cpp +++ b/test/serial_port_base.cpp @@ -46,7 +46,7 @@ void test() port.set_option(baud_rate1); serial_port_base::baud_rate baud_rate2; port.get_option(baud_rate2); - static_cast(baud_rate2.value()); + (void)static_cast(baud_rate2.value()); // flow_control class. @@ -55,7 +55,8 @@ void test() port.set_option(flow_control1); serial_port_base::flow_control flow_control2; port.get_option(flow_control2); - static_cast(flow_control2.value()); + (void)static_cast( + flow_control2.value()); // parity class. @@ -63,7 +64,7 @@ void test() port.set_option(parity1); serial_port_base::parity parity2; port.get_option(parity2); - static_cast(parity2.value()); + (void)static_cast(parity2.value()); // stop_bits class. @@ -71,7 +72,7 @@ void test() port.set_option(stop_bits1); serial_port_base::stop_bits stop_bits2; port.get_option(stop_bits2); - static_cast(stop_bits2.value()); + (void)static_cast(stop_bits2.value()); // character_size class. @@ -79,7 +80,7 @@ void test() port.set_option(character_size1); serial_port_base::character_size character_size2; port.get_option(character_size2); - static_cast(character_size2.value()); + (void)static_cast(character_size2.value()); } catch (std::exception&) { diff --git a/test/socket_base.cpp b/test/socket_base.cpp index baaf0e4f..635428d5 100644 --- a/test/socket_base.cpp +++ b/test/socket_base.cpp @@ -60,9 +60,9 @@ void test() socket_base::broadcast broadcast2; sock.get_option(broadcast2); broadcast1 = true; - static_cast(broadcast1); - static_cast(!broadcast1); - static_cast(broadcast1.value()); + (void)static_cast(broadcast1); + (void)static_cast(!broadcast1); + (void)static_cast(broadcast1.value()); // debug class. @@ -71,9 +71,9 @@ void test() socket_base::debug debug2; sock.get_option(debug2); debug1 = true; - static_cast(debug1); - static_cast(!debug1); - static_cast(debug1.value()); + (void)static_cast(debug1); + (void)static_cast(!debug1); + (void)static_cast(debug1.value()); // do_not_route class. @@ -82,9 +82,9 @@ void test() socket_base::do_not_route do_not_route2; sock.get_option(do_not_route2); do_not_route1 = true; - static_cast(do_not_route1); - static_cast(!do_not_route1); - static_cast(do_not_route1.value()); + (void)static_cast(do_not_route1); + (void)static_cast(!do_not_route1); + (void)static_cast(do_not_route1.value()); // keep_alive class. @@ -93,9 +93,9 @@ void test() socket_base::keep_alive keep_alive2; sock.get_option(keep_alive2); keep_alive1 = true; - static_cast(keep_alive1); - static_cast(!keep_alive1); - static_cast(keep_alive1.value()); + (void)static_cast(keep_alive1); + (void)static_cast(!keep_alive1); + (void)static_cast(keep_alive1.value()); // send_buffer_size class. @@ -104,7 +104,7 @@ void test() socket_base::send_buffer_size send_buffer_size2; sock.get_option(send_buffer_size2); send_buffer_size1 = 1; - static_cast(send_buffer_size1.value()); + (void)static_cast(send_buffer_size1.value()); // send_low_watermark class. @@ -113,7 +113,7 @@ void test() socket_base::send_low_watermark send_low_watermark2; sock.get_option(send_low_watermark2); send_low_watermark1 = 1; - static_cast(send_low_watermark1.value()); + (void)static_cast(send_low_watermark1.value()); // receive_buffer_size class. @@ -122,7 +122,7 @@ void test() socket_base::receive_buffer_size receive_buffer_size2; sock.get_option(receive_buffer_size2); receive_buffer_size1 = 1; - static_cast(receive_buffer_size1.value()); + (void)static_cast(receive_buffer_size1.value()); // receive_low_watermark class. @@ -131,7 +131,7 @@ void test() socket_base::receive_low_watermark receive_low_watermark2; sock.get_option(receive_low_watermark2); receive_low_watermark1 = 1; - static_cast(receive_low_watermark1.value()); + (void)static_cast(receive_low_watermark1.value()); // reuse_address class. @@ -140,9 +140,9 @@ void test() socket_base::reuse_address reuse_address2; sock.get_option(reuse_address2); reuse_address1 = true; - static_cast(reuse_address1); - static_cast(!reuse_address1); - static_cast(reuse_address1.value()); + (void)static_cast(reuse_address1); + (void)static_cast(!reuse_address1); + (void)static_cast(reuse_address1.value()); // linger class. @@ -151,9 +151,9 @@ void test() socket_base::linger linger2; sock.get_option(linger2); linger1.enabled(true); - static_cast(linger1.enabled()); + (void)static_cast(linger1.enabled()); linger1.timeout(1); - static_cast(linger1.timeout()); + (void)static_cast(linger1.timeout()); // enable_connection_aborted class. @@ -162,9 +162,9 @@ void test() socket_base::enable_connection_aborted enable_connection_aborted2; sock.get_option(enable_connection_aborted2); enable_connection_aborted1 = true; - static_cast(enable_connection_aborted1); - static_cast(!enable_connection_aborted1); - static_cast(enable_connection_aborted1.value()); + (void)static_cast(enable_connection_aborted1); + (void)static_cast(!enable_connection_aborted1); + (void)static_cast(enable_connection_aborted1.value()); // non_blocking_io class. diff --git a/test/write.cpp b/test/write.cpp index bdffbabc..4775fbc6 100644 --- a/test/write.cpp +++ b/test/write.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include "unit_test.hpp" @@ -62,7 +63,7 @@ public: } template - bool check(const Const_Buffers& buffers, size_t length) + bool check_buffers(const Const_Buffers& buffers, size_t length) { if (length != position_) return false; @@ -138,6 +139,16 @@ static const char write_data[] static char mutable_write_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +void test_2_arg_zero_buffers_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + std::vector buffers; + + size_t bytes_transferred = boost::asio::write(s, buffers); + BOOST_CHECK(bytes_transferred == 0); +} + void test_2_arg_const_buffers_1_write() { boost::asio::io_service ios; @@ -148,19 +159,19 @@ void test_2_arg_const_buffers_1_write() s.reset(); size_t bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_2_arg_mutable_buffers_1_write() @@ -173,19 +184,19 @@ void test_2_arg_mutable_buffers_1_write() s.reset(); size_t bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); } void test_2_arg_multi_buffers_write() @@ -199,19 +210,19 @@ void test_2_arg_multi_buffers_write() s.reset(); size_t bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } bool old_style_transfer_all(const boost::system::error_code& ec, @@ -237,115 +248,115 @@ void test_3_arg_const_buffers_1_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_3_arg_mutable_buffers_1_write() @@ -359,115 +370,115 @@ void test_3_arg_mutable_buffers_1_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); } void test_3_arg_multi_buffers_write() @@ -482,115 +493,115 @@ void test_3_arg_multi_buffers_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_4_arg_const_buffers_1_write() @@ -605,7 +616,7 @@ void test_4_arg_const_buffers_1_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -614,7 +625,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -623,7 +634,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -631,7 +642,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -640,7 +651,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -649,7 +660,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -657,7 +668,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -666,7 +677,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -675,7 +686,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -683,7 +694,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -692,7 +703,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -701,14 +712,14 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -717,7 +728,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -726,13 +737,13 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -740,7 +751,7 @@ void test_4_arg_const_buffers_1_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -748,7 +759,7 @@ void test_4_arg_const_buffers_1_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); } @@ -764,7 +775,7 @@ void test_4_arg_mutable_buffers_1_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -773,7 +784,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -782,7 +793,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -790,7 +801,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -799,7 +810,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -808,7 +819,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -816,7 +827,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -825,7 +836,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -834,7 +845,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -842,7 +853,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -851,7 +862,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -860,14 +871,14 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -876,7 +887,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -885,13 +896,13 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -899,7 +910,7 @@ void test_4_arg_mutable_buffers_1_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -907,7 +918,7 @@ void test_4_arg_mutable_buffers_1_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); } @@ -924,7 +935,7 @@ void test_4_arg_multi_buffers_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -933,7 +944,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -942,7 +953,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -950,7 +961,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -959,7 +970,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -968,7 +979,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -976,7 +987,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -985,7 +996,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -994,7 +1005,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -1002,7 +1013,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1011,7 +1022,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -1020,14 +1031,14 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1036,7 +1047,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1045,13 +1056,13 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1059,7 +1070,7 @@ void test_4_arg_multi_buffers_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1067,7 +1078,7 @@ void test_4_arg_multi_buffers_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); } @@ -1096,7 +1107,7 @@ void test_3_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1109,7 +1120,7 @@ void test_3_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1122,7 +1133,7 @@ void test_3_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_3_arg_mutable_buffers_1_async_write() @@ -1142,7 +1153,7 @@ void test_3_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1155,7 +1166,7 @@ void test_3_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); @@ -1168,7 +1179,7 @@ void test_3_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); } void test_3_arg_multi_buffers_async_write() @@ -1189,7 +1200,7 @@ void test_3_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1202,7 +1213,7 @@ void test_3_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1215,7 +1226,7 @@ void test_3_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_4_arg_const_buffers_1_async_write() @@ -1235,7 +1246,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1248,7 +1259,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1261,7 +1272,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); called = false; @@ -1273,7 +1284,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1286,7 +1297,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); @@ -1299,7 +1310,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1311,7 +1322,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1324,7 +1335,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); @@ -1337,7 +1348,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1349,7 +1360,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1362,7 +1373,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); @@ -1375,7 +1386,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); called = false; @@ -1387,7 +1398,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1400,7 +1411,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1413,7 +1424,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); called = false; @@ -1425,7 +1436,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1438,7 +1449,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1451,7 +1462,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_4_arg_mutable_buffers_1_async_write() @@ -1471,7 +1482,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1484,7 +1495,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); @@ -1497,7 +1508,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); called = false; @@ -1509,7 +1520,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1522,7 +1533,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); @@ -1535,7 +1546,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1547,7 +1558,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1560,7 +1571,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); @@ -1573,7 +1584,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1585,7 +1596,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1598,7 +1609,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); @@ -1611,7 +1622,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); called = false; @@ -1623,7 +1634,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1636,7 +1647,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); @@ -1649,7 +1660,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); called = false; @@ -1661,7 +1672,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1674,7 +1685,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); @@ -1687,7 +1698,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); } void test_4_arg_multi_buffers_async_write() @@ -1708,7 +1719,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1721,7 +1732,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1734,7 +1745,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); called = false; @@ -1746,7 +1757,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1759,7 +1770,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); @@ -1772,7 +1783,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1784,7 +1795,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1797,7 +1808,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); @@ -1810,7 +1821,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1822,7 +1833,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1835,7 +1846,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); @@ -1848,7 +1859,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); called = false; @@ -1860,7 +1871,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1873,7 +1884,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1886,7 +1897,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); called = false; @@ -1898,7 +1909,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1911,7 +1922,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1924,12 +1935,13 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("write"); + test->add(BOOST_TEST_CASE(&test_2_arg_zero_buffers_write)); test->add(BOOST_TEST_CASE(&test_2_arg_const_buffers_1_write)); test->add(BOOST_TEST_CASE(&test_2_arg_mutable_buffers_1_write)); test->add(BOOST_TEST_CASE(&test_2_arg_multi_buffers_write)); diff --git a/test/write_at.cpp b/test/write_at.cpp index c46e86d2..9334c2bf 100644 --- a/test/write_at.cpp +++ b/test/write_at.cpp @@ -16,6 +16,7 @@ // Test that header file is self-contained. #include +#include #include #include #include @@ -56,7 +57,7 @@ public: } template - bool check(boost::uint64_t offset, + bool check_buffers(boost::uint64_t offset, const Const_Buffers& buffers, size_t length) { if (offset + length > max_length) @@ -131,8 +132,10 @@ private: static const char write_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +static char mutable_write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -void test_3_arg_write_at() +void test_3_arg_const_buffers_1_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -142,36 +145,121 @@ void test_3_arg_write_at() s.reset(); size_t bytes_transferred = boost::asio::write_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_3_arg_mutable_buffers_1_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); +} + +void test_3_arg_multi_buffers_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); } bool old_style_transfer_all(const boost::system::error_code& ec, @@ -186,7 +274,7 @@ size_t short_transfer(const boost::system::error_code& ec, return !!ec ? 0 : 3; } -void test_4_arg_write_at() +void test_4_arg_const_buffers_1_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -197,238 +285,723 @@ void test_4_arg_write_at() size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); } -void test_5_arg_write_at() +void test_4_arg_mutable_buffers_1_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); +} + +void test_4_arg_multi_buffers_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_5_arg_const_buffers_1_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -440,14 +1013,14 @@ void test_5_arg_write_at() size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -456,7 +1029,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -465,7 +1038,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -474,7 +1047,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -483,7 +1056,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -491,7 +1064,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -499,7 +1072,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -508,7 +1081,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -517,7 +1090,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -526,7 +1099,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -535,7 +1108,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -543,7 +1116,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -551,7 +1124,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -560,7 +1133,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -569,7 +1142,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -578,7 +1151,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -587,7 +1160,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -595,7 +1168,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -603,7 +1176,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -612,7 +1185,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -621,7 +1194,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -630,7 +1203,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); BOOST_CHECK(!error); s.reset(); @@ -639,21 +1212,21 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -662,7 +1235,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -671,7 +1244,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -680,7 +1253,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -689,21 +1262,21 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -712,7 +1285,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -721,7 +1294,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -730,7 +1303,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -739,7 +1312,638 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); +} + +void test_5_arg_mutable_buffers_1_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); +} + +void test_5_arg_multi_buffers_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); } @@ -751,7 +1955,7 @@ void async_write_handler(const boost::system::error_code& e, BOOST_CHECK(bytes_transferred == expected_bytes_transferred); } -void test_4_arg_async_write_at() +void test_4_arg_const_buffers_1_async_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -768,7 +1972,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -780,7 +1984,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -793,7 +1997,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -806,7 +2010,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -819,7 +2023,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -832,7 +2036,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); called = false; @@ -844,10 +2048,203 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); } -void test_5_arg_async_write_at() +void test_4_arg_mutable_buffers_1_async_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); +} + +void test_4_arg_multi_buffers_async_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +void test_5_arg_const_buffers_1_async_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -865,7 +2262,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -878,7 +2275,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -892,7 +2289,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -906,7 +2303,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -920,7 +2317,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -934,7 +2331,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); called = false; @@ -947,7 +2344,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -960,7 +2357,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -974,7 +2371,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); s.reset(); s.next_write_length(1); @@ -988,7 +2385,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); s.reset(); s.next_write_length(10); @@ -1002,7 +2399,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(10); @@ -1016,7 +2413,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); called = false; @@ -1029,7 +2426,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1042,7 +2439,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1056,7 +2453,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(1); @@ -1070,7 +2467,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); s.next_write_length(10); @@ -1084,7 +2481,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(10); @@ -1098,7 +2495,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); called = false; @@ -1111,7 +2508,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1124,7 +2521,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1138,7 +2535,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); s.reset(); s.next_write_length(1); @@ -1152,7 +2549,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); s.reset(); s.next_write_length(10); @@ -1166,7 +2563,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); s.reset(); s.next_write_length(10); @@ -1180,7 +2577,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); s.reset(); called = false; @@ -1192,7 +2589,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1204,7 +2601,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1217,7 +2614,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1230,7 +2627,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1243,7 +2640,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1256,7 +2653,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1268,7 +2665,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1280,7 +2677,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1293,7 +2690,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1306,7 +2703,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1319,7 +2716,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1332,16 +2729,1003 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_5_arg_mutable_buffers_1_async_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); +} + +void test_5_arg_multi_buffers_async_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); } test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("write_at"); - test->add(BOOST_TEST_CASE(&test_3_arg_write_at)); - test->add(BOOST_TEST_CASE(&test_4_arg_write_at)); - test->add(BOOST_TEST_CASE(&test_5_arg_write_at)); - test->add(BOOST_TEST_CASE(&test_4_arg_async_write_at)); - test->add(BOOST_TEST_CASE(&test_5_arg_async_write_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_const_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_mutable_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_multi_buffers_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_const_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_const_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_mutable_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_multi_buffers_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_const_buffers_1_async_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_async_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_async_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_const_buffers_1_async_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_mutable_buffers_1_async_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_multi_buffers_async_write_at)); return test; }