Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ned14/llfio.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2022-05-11 23:34:02 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2022-05-11 23:34:02 +0300
commit55696ec43579b34e22e5ed9a2680cbb8c72442d3 (patch)
treebf0d2fba31a9033fae0be5310d151ee9dcd0b169
parentd06bf6d6c2e1a23fb9eee3cb0c1056abc52de471 (diff)
Fix warnings pre-C++20 recently introduced and bring TLS sockets reference implementation closer to the WG21 proposal paper.
-rw-r--r--example/.clang-format57
-rw-r--r--example/use_cases.cpp195
-rw-r--r--include/llfio/revision.hpp6
-rw-r--r--include/llfio/v2.0/detail/impl/tls_socket_sources/openssl.ipp14
-rw-r--r--include/llfio/v2.0/tls_socket_handle.hpp10
5 files changed, 275 insertions, 7 deletions
diff --git a/example/.clang-format b/example/.clang-format
new file mode 100644
index 00000000..2ae6fd03
--- /dev/null
+++ b/example/.clang-format
@@ -0,0 +1,57 @@
+---
+Language: Cpp
+AccessModifierOffset: -2
+ConstructorInitializerIndentWidth: 4
+AlignEscapedNewlinesLeft: false
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakTemplateDeclarations: false
+AlwaysBreakBeforeMultilineStrings: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Allman
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializersBeforeComma: true
+BinPackParameters: true
+ColumnLimit: 78
+CommentPragmas: '^!<'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ContinuationIndentWidth: 0
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IndentCaseLabels: false
+IndentFunctionDeclarationAfterType: false
+IndentWidth: 2
+IndentWrappedFunctionNames: false
+MaxEmptyLinesToKeep: 2
+KeepEmptyLinesAtTheStartOfBlocks: true
+NamespaceIndentation: All
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakString: 1000
+PenaltyBreakFirstLessLess: 120
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+Standard: Cpp11
+SpaceAfterCStyleCast: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: Never
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInParentheses: false
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInContainerLiterals: true
+TabWidth: 8
+UseTab: Never
+...
+
diff --git a/example/use_cases.cpp b/example/use_cases.cpp
index 334e1cc6..0269c68b 100644
--- a/example/use_cases.cpp
+++ b/example/use_cases.cpp
@@ -1,5 +1,5 @@
/* Examples of LLFIO use
-(C) 2018 Niall Douglas <http://www.nedproductions.biz/> (2 commits)
+(C) 2018 - 2022 Niall Douglas <http://www.nedproductions.biz/> (2 commits)
File Created: Aug 2018
@@ -307,6 +307,199 @@ void sparse_array()
}
#endif
+void tls_socket_server()
+{
+ //! [tls_socket_server]
+ namespace llfio = LLFIO_V2_NAMESPACE;
+ std::string host; // set to one of my network cards
+
+ // Get me a FIPS 140 compliant source of TLS sockets which uses kernel
+ // sockets, this call takes bits set and bits masked, so the implementation
+ // features bitfield is masked for the FIPS 140 bit, and only if that is set
+ // is the TLS socket source considered.
+ //
+ // The need for a kernel sockets based TLS implementation is so poll() will
+ // work, as it requires kernel sockets compatible input.
+ static constexpr auto required_features =
+ llfio::tls_socket_source_implementation_features::FIPS_140_2
+ | llfio::tls_socket_source_implementation_features::kernel_sockets;
+ llfio::tls_socket_source_ptr tls_socket_source =
+ llfio::tls_socket_source_registry::default_source(required_features,
+ required_features).instantiate().value();
+
+ // Create a listening TLS socket on any IP family.
+ llfio::listening_tls_socket_handle_ptr serversocket = tls_socket_source
+ ->multiplexable_listening_socket(llfio::ip::family::any).value();
+
+ // The default is to NOT authenticate the TLS certificates of those connecting
+ // in with the system's TLS certificate store. If you wanted something
+ // different, you'd set that now using:
+ // serversocket->set_authentication_certificates_path()
+
+ // Bind the listening TLS socket to port 8989 on the NIC described by host
+ // ip::address incidentally is inspired by ASIO's class, it is very
+ // similar. I only made it more constexpr.
+ serversocket->bind(llfio::ip::make_address(host+":8989").value()).value();
+
+ // poll() works on three spans. We deliberately have separate poll_what
+ // storage so we can avoid having to reset topoll's contents per poll()
+ std::vector<llfio::pollable_handle *> pollable_handles;
+ std::vector<llfio::poll_what> topoll, whatchanged;
+
+ // We will want to know about new inbound connections to our listening
+ // socket
+ pollable_handles.push_back(serversocket.get());
+ topoll.push_back(llfio::poll_what::is_readable);
+ whatchanged.push_back(llfio::poll_what::none);
+
+ // Connected socket state
+ struct connected_socket {
+ // The connected socket
+ llfio::tls_socket_handle_ptr socket;
+
+ // The endpoint from which it connected
+ llfio::ip::address endpoint;
+
+ // The size of registered buffer actually allocated (we request system
+ // page size, the DMA controller may return that or more)
+ size_t rbuf_storage_length{llfio::utils::page_size()};
+ size_t wbuf_storage_length{llfio::utils::page_size()};
+
+ // These are shared ptrs to memory potentially registered with the NIC's
+ // DMA controller and therefore i/o using them would be true whole system
+ // zero copy
+ llfio::tls_socket_handle::registered_buffer_type rbuf_storage, wbuf_storage;
+
+ // These spans of byte and const byte index into buffer storage and get
+ // updated by each i/o operation to describe what was done
+ llfio::tls_socket_handle::buffer_type rbuf;
+ llfio::tls_socket_handle::const_buffer_type wbuf;
+
+ explicit connected_socket(std::pair<llfio::tls_socket_handle_ptr, llfio::ip::address> s)
+ : socket(std::move(s.first))
+ , endpoint(std::move(s.second))
+ , rbuf_storage(socket->allocate_registered_buffer(rbuf_storage_length).value())
+ , wbuf_storage(socket->allocate_registered_buffer(wbuf_storage_length).value())
+ , rbuf(*rbuf_storage) // fill this buffer
+ , wbuf(wbuf_storage->data(), 0) // nothing to write
+ {}
+ };
+ std::vector<connected_socket> connected_sockets;
+
+ // Begin the processing loop
+ for(;;) {
+ // We need to clear whatchanged before use, as it accumulates bits set.
+ std::fill(whatchanged.begin(), whatchanged.end(), llfio::poll_what::none);
+
+ // As with all LLFIO calls, you can set a deadline here so this call
+ // times out. The default as usual is wait until infinity.
+ size_t handles_changed
+ = llfio::poll(whatchanged, {pollable_handles}, topoll).value();
+
+ // Loop the polled handles looking for events changed.
+ for(size_t handleidx = 0;
+ handles_changed > 0 && handleidx < pollable_handles.size();
+ handleidx++) {
+ if(whatchanged[handleidx] == llfio::poll_what::none) {
+ continue;
+ }
+ if(0 == handleidx) {
+ // This is the listening socket, and there is a new connection to be
+ // read, as listening socket defines its read operation to be
+ // connected sockets and the endpoint they connected from.
+ std::pair<llfio::tls_socket_handle_ptr, llfio::ip::address> s;
+ serversocket->read({s}).value();
+ connected_sockets.emplace_back(std::move(s));
+
+ // Watch this connected socket going forth for data to read or failure
+ pollable_handles.push_back(connected_sockets.back().socket.get());
+ topoll.push_back(llfio::poll_what::is_readable|llfio::poll_what::is_errored);
+ whatchanged.push_back(llfio::poll_what::none);
+ handles_changed--;
+ continue;
+ }
+ // There has been an event on this socket
+ auto &sock = connected_sockets[handleidx - 1];
+ handles_changed--;
+ if(whatchanged[handleidx] & llfio::poll_what::is_errored) {
+ // Force it closed and ignore it from polling going forth
+ sock.socket->close().value();
+ sock.rbuf_storage.reset();
+ sock.wbuf_storage.reset();
+ pollable_handles[handleidx] = nullptr;
+ }
+ if(whatchanged[handleidx] & llfio::poll_what::is_readable) {
+ // Set up the buffer to fill. Note the scatter buffer list
+ // based API.
+ sock.rbuf = *sock.rbuf_storage;
+ sock.socket->read({{&sock.rbuf, 1}}).value();
+ // sock.rbuf has its size adjusted to bytes read
+ }
+ if(whatchanged[handleidx] & llfio::poll_what::is_writable) {
+ // If this was set in topoll, it means write buffers
+ // were full at some point, and we are now being told
+ // there is space to write some more
+ if(!sock.wbuf.empty()) {
+ // Take a copy of the buffer to write, as it will be
+ // modified in place with what was written
+ auto b(sock.wbuf);
+ sock.socket->write({{&b, 1}}).value();
+ // Adjust the buffer to yet to write
+ sock.wbuf = {sock.wbuf.data() + b.size(), sock.wbuf.size() - b.size() };
+ }
+ if(sock.wbuf.empty()) {
+ // Nothing more to write, so no longer poll for this
+ topoll[handleidx]&=~llfio::poll_what::is_writable;
+ }
+ }
+
+ // Process buffers read and written for this socket ...
+ }
+ }
+ //! [tls_socket_server]
+}
+
+void wrap_tls_socket()
+{
+ //! [wrap_tls_socket]
+ namespace llfio = LLFIO_V2_NAMESPACE;
+
+ // I want a TLS socket source which supports wrapping externally
+ // supplied byte_socket_handle instances
+ static constexpr auto required_features =
+ llfio::tls_socket_source_implementation_features::supports_wrap;
+ llfio::tls_socket_source_ptr tls_socket_source =
+ llfio::tls_socket_source_registry::default_source(required_features,
+ required_features).instantiate().value();
+
+ // Create a raw kernel socket. This could also be your custom
+ // subclass of byte_socket_handle or listening_byte_socket_handle.
+ //
+ // byte_socket_handle and listening_byte_socket_handle default
+ // to your OS kernel's BSD socket implementation, but their
+ // implementation is completely customisable. In fact, tls_socket_ptr
+ // points at an unknown (i.e. ABI erased) byte_socket_handle implementation.
+ llfio::byte_socket_handle rawsocket
+ = llfio::byte_socket_handle::byte_socket(llfio::ip::family::any).value();
+
+ llfio::listening_byte_socket_handle rawlsocket
+ = llfio::listening_byte_socket_handle::listening_byte_socket(llfio::ip::family::any).value();
+
+ // Attempt to wrap the raw socket with TLS. Note the "attempt" part,
+ // just because a TLS implementation supports wrapping doesn't mean
+ // that it will wrap this specific raw socket, it may error out.
+ //
+ // Note also that no ownership of the raw socket is taken - you must
+ // NOT move it in memory until the TLS wrapped socket is done with it.
+ llfio::tls_socket_handle_ptr securesocket
+ = tls_socket_source->wrap(&rawsocket).value();
+
+ llfio::listening_tls_socket_handle_ptr serversocket
+ = tls_socket_source->wrap(&rawlsocket).value();
+
+ //! [wrap_tls_socket]
+}
+
int main()
{
return 0;
diff --git a/include/llfio/revision.hpp b/include/llfio/revision.hpp
index 1e6b67a4..7eb59194 100644
--- a/include/llfio/revision.hpp
+++ b/include/llfio/revision.hpp
@@ -1,4 +1,4 @@
// Note the second line of this file must ALWAYS be the git SHA, third line ALWAYS the git SHA update time
-#define LLFIO_PREVIOUS_COMMIT_REF ceeaddba4c571291d42690a54424e8bf8cf4d5dd
-#define LLFIO_PREVIOUS_COMMIT_DATE "2022-04-16 23:05:51 +00:00"
-#define LLFIO_PREVIOUS_COMMIT_UNIQUE ceeaddba
+#define LLFIO_PREVIOUS_COMMIT_REF d06bf6d6c2e1a23fb9eee3cb0c1056abc52de471
+#define LLFIO_PREVIOUS_COMMIT_DATE "2022-05-06 10:05:54 +00:00"
+#define LLFIO_PREVIOUS_COMMIT_UNIQUE d06bf6d6
diff --git a/include/llfio/v2.0/detail/impl/tls_socket_sources/openssl.ipp b/include/llfio/v2.0/detail/impl/tls_socket_sources/openssl.ipp
index 09c830c7..03963aa8 100644
--- a/include/llfio/v2.0/detail/impl/tls_socket_sources/openssl.ipp
+++ b/include/llfio/v2.0/detail/impl/tls_socket_sources/openssl.ipp
@@ -1275,7 +1275,12 @@ public:
int _bread(BIO *bio, char *buffer, size_t bytes, size_t *read)
{
LLFIO_LOG_FUNCTION_CALL(this);
- auto ret = [=, this]() mutable
+ auto ret = [=
+#if __cplusplus >= 202000L || _HAS_CXX20
+ ,
+ this
+#endif
+ ]() mutable
{
assert(_lock_holder.owns_lock());
*read = 0;
@@ -1374,7 +1379,12 @@ public:
int _bwrite(BIO *bio, const char *buffer, size_t bytes, size_t *written)
{
LLFIO_LOG_FUNCTION_CALL(this);
- auto ret = [=, this]() mutable
+ auto ret = [=
+#if __cplusplus >= 202000L || _HAS_CXX20
+ ,
+ this
+#endif
+ ]() mutable
{
assert(_lock_holder.owns_lock());
*written = 0;
diff --git a/include/llfio/v2.0/tls_socket_handle.hpp b/include/llfio/v2.0/tls_socket_handle.hpp
index 6cefca74..08333af0 100644
--- a/include/llfio/v2.0/tls_socket_handle.hpp
+++ b/include/llfio/v2.0/tls_socket_handle.hpp
@@ -309,6 +309,8 @@ system_implementation = (1U << 1U), //!< This socket source is the "system" rat
io_multiplexer = (1U << 2U), //!< This socket source provides an i/o multiplexer
supports_wrap = (1U << 3U), //!< This socket source may be able to wrap third party plain sockets
+FIPS_140_2 = (1U << 16U), //!< This socket source provides FIPS_140_2 compliant algorithms
+
all = 0xffffffff //!< All bits set
} //
QUICKCPPLIB_BITFIELD_END(tls_socket_source_implementation_features) //
@@ -533,6 +535,10 @@ if(string_view(buffer, b.size()) != "World") {
// rather than hard close
sock->shutdown_and_close(std::chrono::seconds(3)).value();
```
+
+Fuller fat example:
+
+ \snippet use_cases.cpp tls_socket_server
*/
class LLFIO_DECL tls_socket_source_registry
{
@@ -552,16 +558,18 @@ public:
//! Convenience overload retrieving TLS socket sources, preferring system over third party implementations.
static tls_socket_source_implementation_information
default_source(tls_socket_source_implementation_features set = tls_socket_source_implementation_features::none,
- tls_socket_source_implementation_features mask = tls_socket_source_implementation_features::system_implementation) noexcept
+ tls_socket_source_implementation_features mask = tls_socket_source_implementation_features::none) noexcept
{
tls_socket_source_implementation_information ret{"no implementation available"};
set |= tls_socket_source_implementation_features::system_implementation;
+ mask |= tls_socket_source_implementation_features::system_implementation;
auto filled = sources({&ret, 1}, set, mask);
if(!filled.empty())
{
return ret;
}
set &= ~tls_socket_source_implementation_features::system_implementation;
+ mask &= ~tls_socket_source_implementation_features::system_implementation;
filled = sources({&ret, 1}, set, mask);
if(!filled.empty())
{