]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/boost/beast/core/impl/basic_stream.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / beast / core / impl / basic_stream.hpp
index 0e70f7cefb4a953be080021ee3b44437bcb7b00e..73fb91697578b8c7e711e60e1227ab5de4f74315 100644 (file)
@@ -269,6 +269,8 @@ class transfer_op
                 std::move(*this));
     }
 
+    static bool never_pending_;
+
 public:
     template<class Handler_>
     transfer_op(
@@ -278,10 +280,25 @@ public:
         : async_base<Handler, Executor>(
             std::forward<Handler_>(h), s.get_executor())
         , impl_(s.impl_)
-        , pg_(state().pending)
+        , pg_()
         , b_(b)
     {
-        (*this)({});
+        if (buffer_bytes(b_) == 0 && state().pending)
+        {
+            // Workaround:
+            // Corner case discovered in https://github.com/boostorg/beast/issues/2065
+            // Enclosing SSL stream wishes to complete a 0-length write early by
+            // executing a 0-length read against the underlying stream.
+            // This can occur even if an existing async_read is in progress.
+            // In this specific case, we will complete the async op with no error
+            // in order to prevent assertions and/or internal corruption of the basic_stream
+            this->complete(false, error_code(), 0);
+        }
+        else
+        {
+            pg_.assign(state().pending);
+            (*this)({});
+        }
     }
 
     void
@@ -296,7 +313,14 @@ public:
             {
                 // make sure we perform the no-op
                 BOOST_ASIO_CORO_YIELD
-                async_perform(0, is_read{});
+                {
+                    BOOST_ASIO_HANDLER_LOCATION((
+                        __FILE__, __LINE__,
+                        (isRead ? "basic_stream::async_read_some"
+                            : "basic_stream::async_write_some")));
+
+                    async_perform(0, is_read{});
+                }
                 // apply the timeout manually, otherwise
                 // behavior varies across platforms.
                 if(state().timer.expiry() <= clock_type::now())
@@ -309,12 +333,19 @@ public:
 
             // if a timeout is active, wait on the timer
             if(state().timer.expiry() != never())
+            {
+                BOOST_ASIO_HANDLER_LOCATION((
+                    __FILE__, __LINE__,
+                    (isRead ? "basic_stream::async_read_some"
+                        : "basic_stream::async_write_some")));
+
                 state().timer.async_wait(
                     timeout_handler<decltype(this->get_executor())>{
                         state(),
                         impl_,
                         state().tick,
                         this->get_executor()});
+            }
 
             // check rate limit, maybe wait
             std::size_t amount;
@@ -323,7 +354,14 @@ public:
             {
                 ++impl_->waiting;
                 BOOST_ASIO_CORO_YIELD
-                impl_->timer.async_wait(std::move(*this));
+                {
+                    BOOST_ASIO_HANDLER_LOCATION((
+                        __FILE__, __LINE__,
+                        (isRead ? "basic_stream::async_read_some"
+                            : "basic_stream::async_write_some")));
+
+                    impl_->timer.async_wait(std::move(*this));
+                }
                 if(ec)
                 {
                     // socket was closed, or a timeout
@@ -347,7 +385,14 @@ public:
             }
 
             BOOST_ASIO_CORO_YIELD
-            async_perform(amount, is_read{});
+            {
+                BOOST_ASIO_HANDLER_LOCATION((
+                    __FILE__, __LINE__,
+                    (isRead ? "basic_stream::async_read_some"
+                        : "basic_stream::async_write_some")));
+
+                async_perform(amount, is_read{});
+            }
 
             if(state().timer.expiry() != never())
             {
@@ -408,12 +453,22 @@ public:
         , pg1_(impl_->write.pending)
     {
         if(state().timer.expiry() != stream_base::never())
+        {
+            BOOST_ASIO_HANDLER_LOCATION((
+                __FILE__, __LINE__,
+                "basic_stream::async_connect"));
+
             impl_->write.timer.async_wait(
                 timeout_handler<decltype(this->get_executor())>{
                     state(),
                     impl_,
                     state().tick,
                     this->get_executor()});
+        }
+
+        BOOST_ASIO_HANDLER_LOCATION((
+            __FILE__, __LINE__,
+            "basic_stream::async_connect"));
 
         impl_->socket.async_connect(
             ep, std::move(*this));
@@ -435,12 +490,22 @@ public:
         , pg1_(impl_->write.pending)
     {
         if(state().timer.expiry() != stream_base::never())
+        {
+            BOOST_ASIO_HANDLER_LOCATION((
+                __FILE__, __LINE__,
+                "basic_stream::async_connect"));
+
             impl_->write.timer.async_wait(
                 timeout_handler<decltype(this->get_executor())>{
                     state(),
                     impl_,
                     state().tick,
                     this->get_executor()});
+        }
+
+        BOOST_ASIO_HANDLER_LOCATION((
+            __FILE__, __LINE__,
+            "basic_stream::async_connect"));
 
         net::async_connect(impl_->socket,
             eps, cond, std::move(*this));
@@ -462,12 +527,22 @@ public:
         , pg1_(impl_->write.pending)
     {
         if(state().timer.expiry() != stream_base::never())
+        {
+            BOOST_ASIO_HANDLER_LOCATION((
+                __FILE__, __LINE__,
+                "basic_stream::async_connect"));
+
             impl_->write.timer.async_wait(
                 timeout_handler<decltype(this->get_executor())>{
                     state(),
                     impl_,
                     state().tick,
                     this->get_executor()});
+        }
+
+        BOOST_ASIO_HANDLER_LOCATION((
+            __FILE__, __LINE__,
+            "basic_stream::async_connect"));
 
         net::async_connect(impl_->socket,
             begin, end, cond, std::move(*this));
@@ -681,7 +756,12 @@ basic_stream(basic_stream&& other)
     : impl_(boost::make_shared<impl_type>(
         std::move(*other.impl_)))
 {
-    // VFALCO I'm not sure this implementation is correct...
+    // Explainer: Asio's sockets provide the guarantee that a moved-from socket
+    // will be in a state as-if newly created. i.e.:
+    // * having the same (valid) executor
+    // * the socket shall not be open
+    // We provide the same guarantee by moving the impl rather than the pointer
+    // controlling its lifetime.
 }
 
 //------------------------------------------------------------------------------
@@ -699,7 +779,7 @@ release_socket() ->
 template<class Protocol, class Executor, class RatePolicy>
 void
 basic_stream<Protocol, Executor, RatePolicy>::
-expires_after(std::chrono::nanoseconds expiry_time)
+expires_after(net::steady_timer::duration expiry_time)
 {
     // If assert goes off, it means that there are
     // already read or write (or connect) operations
@@ -776,7 +856,7 @@ close()
 //------------------------------------------------------------------------------
 
 template<class Protocol, class Executor, class RatePolicy>
-template<class ConnectHandler>
+template<BOOST_BEAST_ASYNC_TPARAM1 ConnectHandler>
 BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)
 basic_stream<Protocol, Executor, RatePolicy>::
 async_connect(
@@ -795,7 +875,7 @@ async_connect(
 template<class Protocol, class Executor, class RatePolicy>
 template<
     class EndpointSequence,
-    class RangeConnectHandler,
+    BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
     class>
 BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void(error_code, typename Protocol::endpoint))
 basic_stream<Protocol, Executor, RatePolicy>::
@@ -817,7 +897,7 @@ template<class Protocol, class Executor, class RatePolicy>
 template<
     class EndpointSequence,
     class ConnectCondition,
-    class RangeConnectHandler,
+    BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
     class>
 BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
 basic_stream<Protocol, Executor, RatePolicy>::
@@ -839,7 +919,7 @@ async_connect(
 template<class Protocol, class Executor, class RatePolicy>
 template<
     class Iterator,
-    class IteratorConnectHandler>
+    BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler>
 BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
 basic_stream<Protocol, Executor, RatePolicy>::
 async_connect(
@@ -860,7 +940,7 @@ template<class Protocol, class Executor, class RatePolicy>
 template<
     class Iterator,
     class ConnectCondition,
-    class IteratorConnectHandler>
+    BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler>
 BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
 basic_stream<Protocol, Executor, RatePolicy>::
 async_connect(
@@ -881,7 +961,7 @@ async_connect(
 //------------------------------------------------------------------------------
 
 template<class Protocol, class Executor, class RatePolicy>
-template<class MutableBufferSequence, class ReadHandler>
+template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
 basic_stream<Protocol, Executor, RatePolicy>::
 async_read_some(
@@ -901,7 +981,7 @@ async_read_some(
 }
 
 template<class Protocol, class Executor, class RatePolicy>
-template<class ConstBufferSequence, class WriteHandler>
+template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
 basic_stream<Protocol, Executor, RatePolicy>::
 async_write_some(