close_socket is in stream_traits.hpp

This commit is contained in:
Vinnie Falco
2019-02-05 21:03:20 -08:00
parent 5a7a1a3f6c
commit dc02f63050
8 changed files with 218 additions and 227 deletions

View File

@ -1,3 +1,9 @@
Version 211:
* close_socket is in stream_traits.hpp
--------------------------------------------------------------------------------
Version 210: Version 210:
* Tidy up read implementation * Tidy up read implementation

View File

@ -23,7 +23,6 @@
#include <boost/beast/core/buffers_range.hpp> #include <boost/beast/core/buffers_range.hpp>
#include <boost/beast/core/buffers_suffix.hpp> #include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/core/buffers_to_string.hpp> #include <boost/beast/core/buffers_to_string.hpp>
#include <boost/beast/core/close_socket.hpp>
#include <boost/beast/core/dynamic_buffer_ref.hpp> #include <boost/beast/core/dynamic_buffer_ref.hpp>
#include <boost/beast/core/error.hpp> #include <boost/beast/core/error.hpp>
#include <boost/beast/core/file.hpp> #include <boost/beast/core/file.hpp>

View File

@ -1,133 +0,0 @@
//
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CLOSE_SOCKET_HPP
#define BOOST_BEAST_CLOSE_SOCKET_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/static_const.hpp>
#include <boost/asio/basic_socket.hpp>
namespace boost {
namespace beast {
/** Default socket close function.
This function is not meant to be called directly. Instead, it
is called automatically when using @ref close_socket. To enable
closure of user-defined types or classes derived from a particular
user-defined type, this function should be overloaded in the
corresponding namespace for the type in question.
@see close_socket
*/
template<class Protocol BOOST_ASIO_SVC_TPARAM>
void
beast_close_socket(
net::basic_socket<Protocol BOOST_ASIO_SVC_TPARAM>& sock)
{
boost::system::error_code ec;
sock.close(ec);
}
namespace detail {
struct close_socket_impl
{
template<class T>
void
operator()(T& t) const
{
using beast::beast_close_socket;
beast_close_socket(t);
}
};
} // detail
/** Close a socket or socket-like object.
This function attempts to close an object representing a socket.
In this context, a socket is an object for which an unqualified
call to the function `void beast_close_socket(Socket&)` is
well-defined. The function `beast_close_socket` is a
<em>customization point</em>, allowing user-defined types to
provide an algorithm for performing the close operation by
overloading this function for the type in question.
Since the customization point is a function call, the normal
rules for finding the correct overload are applied including
the rules for argument-dependent lookup ("ADL"). This permits
classes derived from a type for which a customization is provided
to inherit the customization point.
An overload for the networking class template `net::basic_socket`
is provided, which implements the close algorithm for all socket-like
objects (hence the name of this customization point). When used
in conjunction with @ref get_lowest_layer, a generic algorithm
operating on a layered stream can perform a closure of the underlying
socket without knowing the exact list of concrete types.
@par Example 1
The following generic function synchronously sends a message
on the stream, then closes the socket.
@code
template <class WriteStream>
void hello_and_close (WriteStream& stream)
{
net::write(stream, net::const_buffer("Hello, world!", 13));
close_socket(get_lowest_layer(stream));
}
@endcode
To enable closure of user defined types, it is necessary to provide
an overload of the function `beast_close_socket` for the type.
@par Example 2
The following code declares a user-defined type which contains a
private socket, and provides an overload of the customization
point which closes the private socket.
@code
class my_socket
{
net::ip::tcp::socket sock_;
public:
my_socket(net::io_context& ioc)
: sock_(ioc)
{
}
friend void beast_close_socket(my_socket& s)
{
error_code ec;
s.sock_.close(ec);
// ignore the error
}
};
@endcode
@param sock The socket to close. If the customization point is not
defined for the type of this object, or one of its base classes,
then a compiler error results.
@see beast_close_socket
*/
#if BOOST_BEAST_DOXYGEN
template<class Socket>
void
close_socket(Socket& sock);
#else
BOOST_BEAST_INLINE_VARIABLE(close_socket, detail::close_socket_impl)
#endif
} // beast
} // boost
#endif

View File

@ -11,7 +11,9 @@
#define BOOST_BEAST_STREAM_TRAITS_HPP #define BOOST_BEAST_STREAM_TRAITS_HPP
#include <boost/beast/core/detail/config.hpp> #include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/static_const.hpp>
#include <boost/beast/core/detail/stream_traits.hpp> #include <boost/beast/core/detail/stream_traits.hpp>
#include <boost/asio/basic_socket.hpp>
namespace boost { namespace boost {
namespace beast { namespace beast {
@ -424,6 +426,118 @@ using is_async_stream = std::integral_constant<bool,
is_async_read_stream<T>::value && is_async_write_stream<T>::value>; is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
#endif #endif
//------------------------------------------------------------------------------
/** Default socket close function.
This function is not meant to be called directly. Instead, it
is called automatically when using @ref close_socket. To enable
closure of user-defined types or classes derived from a particular
user-defined type, this function should be overloaded in the
corresponding namespace for the type in question.
@see close_socket
*/
template<class Protocol BOOST_ASIO_SVC_TPARAM>
void
beast_close_socket(
net::basic_socket<Protocol BOOST_ASIO_SVC_TPARAM>& sock)
{
boost::system::error_code ec;
sock.close(ec);
}
namespace detail {
struct close_socket_impl
{
template<class T>
void
operator()(T& t) const
{
using beast::beast_close_socket;
beast_close_socket(t);
}
};
} // detail
/** Close a socket or socket-like object.
This function attempts to close an object representing a socket.
In this context, a socket is an object for which an unqualified
call to the function `void beast_close_socket(Socket&)` is
well-defined. The function `beast_close_socket` is a
<em>customization point</em>, allowing user-defined types to
provide an algorithm for performing the close operation by
overloading this function for the type in question.
Since the customization point is a function call, the normal
rules for finding the correct overload are applied including
the rules for argument-dependent lookup ("ADL"). This permits
classes derived from a type for which a customization is provided
to inherit the customization point.
An overload for the networking class template `net::basic_socket`
is provided, which implements the close algorithm for all socket-like
objects (hence the name of this customization point). When used
in conjunction with @ref get_lowest_layer, a generic algorithm
operating on a layered stream can perform a closure of the underlying
socket without knowing the exact list of concrete types.
@par Example 1
The following generic function synchronously sends a message
on the stream, then closes the socket.
@code
template <class WriteStream>
void hello_and_close (WriteStream& stream)
{
net::write(stream, net::const_buffer("Hello, world!", 13));
close_socket(get_lowest_layer(stream));
}
@endcode
To enable closure of user defined types, it is necessary to provide
an overload of the function `beast_close_socket` for the type.
@par Example 2
The following code declares a user-defined type which contains a
private socket, and provides an overload of the customization
point which closes the private socket.
@code
class my_socket
{
net::ip::tcp::socket sock_;
public:
my_socket(net::io_context& ioc)
: sock_(ioc)
{
}
friend void beast_close_socket(my_socket& s)
{
error_code ec;
s.sock_.close(ec);
// ignore the error
}
};
@endcode
@param sock The socket to close. If the customization point is not
defined for the type of this object, or one of its base classes,
then a compiler error results.
@see beast_close_socket
*/
#if BOOST_BEAST_DOXYGEN
template<class Socket>
void
close_socket(Socket& sock);
#else
BOOST_BEAST_INLINE_VARIABLE(close_socket, detail::close_socket_impl)
#endif
} // beast } // beast
} // boost } // boost

View File

@ -42,7 +42,6 @@ add_executable (tests-beast-core
buffers_range.cpp buffers_range.cpp
buffers_suffix.cpp buffers_suffix.cpp
buffers_to_string.cpp buffers_to_string.cpp
close_socket.cpp
dynamic_buffer_ref.cpp dynamic_buffer_ref.cpp
error.cpp error.cpp
file.cpp file.cpp

View File

@ -30,7 +30,6 @@ local SOURCES =
buffers_range.cpp buffers_range.cpp
buffers_suffix.cpp buffers_suffix.cpp
buffers_to_string.cpp buffers_to_string.cpp
close_socket.cpp
dynamic_buffer_ref.cpp dynamic_buffer_ref.cpp
error.cpp error.cpp
file.cpp file.cpp

View File

@ -25,97 +25,6 @@ namespace beast {
class close_socket_test : public beast::unit_test::suite class close_socket_test : public beast::unit_test::suite
{ {
public: public:
template<class T>
struct layer
{
T t;
template<class U>
explicit
layer(U&& u)
: t(std::forward<U>(u))
{
}
T& next_layer()
{
return t;
}
};
void
testClose()
{
net::io_context ioc;
{
net::ip::tcp::socket sock(ioc);
sock.open(net::ip::tcp::v4());
BEAST_EXPECT(sock.is_open());
close_socket(get_lowest_layer(sock));
BEAST_EXPECT(! sock.is_open());
}
{
using type = layer<net::ip::tcp::socket>;
type layer(ioc);
layer.next_layer().open(net::ip::tcp::v4());
BEAST_EXPECT(layer.next_layer().is_open());
BOOST_STATIC_ASSERT(detail::has_next_layer<type>::value);
BOOST_STATIC_ASSERT((std::is_same<
typename std::decay<decltype(get_lowest_layer(layer))>::type,
lowest_layer_type<decltype(layer)>>::value));
BOOST_STATIC_ASSERT(std::is_same<net::ip::tcp::socket&,
decltype(get_lowest_layer(layer))>::value);
BOOST_STATIC_ASSERT(std::is_same<net::ip::tcp::socket,
lowest_layer_type<decltype(layer)>>::value);
close_socket(get_lowest_layer(layer));
BEAST_EXPECT(! layer.next_layer().is_open());
}
{
test::stream ts(ioc);
close_socket(ts);
}
}
//--------------------------------------------------------------------------
template <class WriteStream>
void hello_and_close (WriteStream& stream)
{
net::write(stream, net::const_buffer("Hello, world!", 13));
close_socket(get_lowest_layer(stream));
}
class my_socket
{
net::ip::tcp::socket sock_;
public:
my_socket(net::io_context& ioc)
: sock_(ioc)
{
}
friend void beast_close_socket(my_socket& s)
{
error_code ec;
s.sock_.close(ec);
// ignore the error
}
};
void
testJavadocs()
{
BEAST_EXPECT(&close_socket_test::template hello_and_close<net::ip::tcp::socket>);
{
net::io_context ioc;
my_socket s(ioc);
close_socket(s);
}
}
//--------------------------------------------------------------------------
void void
run() override run() override
{ {

View File

@ -12,7 +12,12 @@
#include <boost/beast/_experimental/unit_test/suite.hpp> #include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/core/error.hpp> #include <boost/beast/core/error.hpp>
#include <boost/beast/_experimental/test/stream.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/write.hpp>
#include <utility>
namespace boost { namespace boost {
namespace beast { namespace beast {
@ -267,6 +272,97 @@ public:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
template<class T>
struct layer
{
T t;
template<class U>
explicit
layer(U&& u)
: t(std::forward<U>(u))
{
}
T& next_layer()
{
return t;
}
};
void
testClose()
{
net::io_context ioc;
{
net::ip::tcp::socket sock(ioc);
sock.open(net::ip::tcp::v4());
BEAST_EXPECT(sock.is_open());
close_socket(get_lowest_layer(sock));
BEAST_EXPECT(! sock.is_open());
}
{
using type = layer<net::ip::tcp::socket>;
type layer(ioc);
layer.next_layer().open(net::ip::tcp::v4());
BEAST_EXPECT(layer.next_layer().is_open());
BOOST_STATIC_ASSERT(detail::has_next_layer<type>::value);
BOOST_STATIC_ASSERT((std::is_same<
typename std::decay<decltype(get_lowest_layer(layer))>::type,
lowest_layer_type<decltype(layer)>>::value));
BOOST_STATIC_ASSERT(std::is_same<net::ip::tcp::socket&,
decltype(get_lowest_layer(layer))>::value);
BOOST_STATIC_ASSERT(std::is_same<net::ip::tcp::socket,
lowest_layer_type<decltype(layer)>>::value);
close_socket(get_lowest_layer(layer));
BEAST_EXPECT(! layer.next_layer().is_open());
}
{
test::stream ts(ioc);
close_socket(ts);
}
}
//--------------------------------------------------------------------------
template <class WriteStream>
void hello_and_close (WriteStream& stream)
{
net::write(stream, net::const_buffer("Hello, world!", 13));
close_socket(get_lowest_layer(stream));
}
class my_socket
{
net::ip::tcp::socket sock_;
public:
my_socket(net::io_context& ioc)
: sock_(ioc)
{
}
friend void beast_close_socket(my_socket& s)
{
error_code ec;
s.sock_.close(ec);
// ignore the error
}
};
void
testCloseJavadoc()
{
BEAST_EXPECT(&stream_traits_test::template hello_and_close<net::ip::tcp::socket>);
{
net::io_context ioc;
my_socket s(ioc);
close_socket(s);
}
}
//--------------------------------------------------------------------------
void void
run() override run() override
{ {
@ -274,6 +370,8 @@ public:
testGetLowestLayerJavadoc(); testGetLowestLayerJavadoc();
testExecutorType(); testExecutorType();
testExecutorTypeJavadoc(); testExecutorTypeJavadoc();
testClose();
testCloseJavadoc();
} }
}; };